static void write_request()

in wb/wb.c [1494:1818]


static void write_request(struct connection * c)
{
    if (started >= requests) {
        return;
    }

    do {
        apr_time_t tnow;
        apr_size_t l = c->rwrite;
        apr_status_t e = APR_SUCCESS; /* prevent gcc warning */

        tnow = lasttime = apr_time_now();

        /*
         * First time round ?
         */
        if (c->rwrite == 0) {
#ifdef _WAF_BENCH_ //  "-F" a packet file to be sent, 
            // Need write request, get the packet to be sent
            // g_pkt_length > 0 means the packet file is loaded
            // packet content is also loaded to g_pkt_array
            // might be merged to connection's members to support multi-thread
            if (g_pkt_length) {
                static apr_time_t start_time_new_round;
                int pkt_id = get_write_pkt_id(c->socknum);
                if (pkt_id == 0)
                    start_time_new_round = apr_time_now() - g_pkt_array[0].pkt_time_to_send;
                request = g_pkt_array[pkt_id].pkt_data;
                reqlen = g_pkt_array[pkt_id].pkt_length;
                while  (apr_time_now() < start_time_new_round+ g_pkt_array[pkt_id].pkt_time_to_send)
                     apr_sleep(1);
            } 

            int hdr_delim = 0;
            int header_len = 0;
            
            if (g_add_connection_close || g_opt_prefix || g_sub_string_num) {  // packet need to be modify
                static ulong req_sent = 0;

                // keep original request length when adding seq#
                // since later on reqlen will be changed
                if (!g_pkt_length) { 
                    static int original_reqlen;
                    if (!req_sent) 
                        original_reqlen = reqlen;
                    else
                        reqlen = original_reqlen;
                }

                char req_id_string[1024]; // normally len of id string < 1024
                int req_id_string_len = 0;
                sprintf(req_id_string, "%lu",req_sent++);
                req_id_string_len = strlen(req_id_string);

                g_new_header_len = 0;
                // g_new_header[0] = '\0';
                g_request_end = NULL;

                char *request_pos; // use this as processing position of request
                char *new_pos = NULL;

                request_pos = request; // start position of request
                if (g_opt_prefix) {// prepare the URL prefix string and its length
                    int method_length = 0;
                    // find the position in request header for URL:[SPACE]*METHOD[SPACE]+URL
                    // skip leading space
                    while (*request_pos && isspace(*request_pos)) request_pos++;
                    // skip the leading HTTP methods string
                    while (*request_pos && !isspace(*request_pos)) request_pos++;
                    // skip remaining space again
                    while (*request_pos && isspace(*request_pos))request_pos++;

                    method_length = request_pos - request;
                    if (!*request_pos && method_length < 4) 
                        fprintf(stderr, "Error! Request does not have a valid method:\n%s", request), exit(1);
                    
                    memcpy(g_new_header, request, method_length);
                    g_new_header[method_length] = 0;
                    strcat(g_new_header,"/");
                    strcat(g_new_header,g_opt_prefix);
                    strcat(g_new_header,req_id_string);
                    if (*request_pos != '/')
                        strcat(g_new_header,"/");
                    
                    g_new_header_len = strlen(g_new_header);
                } // end of URL prefix

                // duplicate the whole request header
                // starting from URL position
                if (g_request_end = memmem(request_pos, reqlen, "\r\n\r\n", 4))
                    hdr_delim = 4;
                /*
                 * this next line is so that we talk to NCSA 1.5 which blatantly
                 * breaks the http specifaction
                 */
                else if (g_request_end = memmem(request_pos, reqlen, "\n\n", 2)) 
                    hdr_delim = 2;
                else if (g_request_end = memmem(request_pos, reqlen, "\r\r", 2)) 
                    hdr_delim = 2;
                else {
                    fprintf(stderr, "Error! Request does not have a valid header(end with 2 LNs):\n%s", request);
                    exit(1);
                }
                    
                g_request_end += hdr_delim;


                // prepare the new header buffer
                int new_estimated_len;
                // assume each sub_string appears no than 10 times with less than 10-digits seq
                new_estimated_len = g_new_header_len + (g_request_end - request_pos) + reqlen + g_sub_string_num * 10 * 10 + 1;
                if (new_estimated_len > g_header_len_MAX) {
                    g_header_len_MAX = new_estimated_len; 
                    char *new_header;
                    new_header = xmalloc(g_header_len_MAX);
                    if (g_new_header) {
                        memcpy(new_header, g_new_header, g_new_header_len);
                        free(g_new_header);
                    }
                    g_new_header = new_header;
                }
                // copy the remaining header bytes  
                //memcpy(g_new_header + g_new_header_len, request_pos, g_request_end - request_pos );
                //g_new_header_len += g_request_end - request_pos ;

                // copy the remaining request bytes 
                header_len = g_new_header_len + g_request_end - request_pos - hdr_delim;
                memcpy(g_new_header + g_new_header_len, request_pos, request+reqlen - request_pos );
                g_new_header_len += (request + reqlen - request_pos) ;



                // mark its end so that we can use strstr
                g_new_header[g_new_header_len] = 0;
                char * new_request_end = g_new_header + g_new_header_len;

                // enumerate to process all sub_strings
                int i;
                for (i = 0; i < g_sub_string_num; i ++) {
                    char *sub;
                    while (sub = strstr(g_new_header, g_sub_string[i])) { 
                        if (sub - new_request_end > 0)
                            break;

                        char *copy_pos;
                        int copy_bytes;
                        int sub_len, j;

                        sub_len = strlen(g_sub_string[i]);
                        copy_pos = sub + sub_len;
                        copy_bytes = g_new_header_len-(copy_pos-g_new_header)+1;

                        if (sub_len > req_id_string_len)
                            for (j = 0; j < copy_bytes; j ++)
                                *(sub+req_id_string_len+j) = *(sub+sub_len+j);
                        else if (sub_len < req_id_string_len)
                            for (j = 0; j < copy_bytes; j ++)
                                *(sub+sub_len+j) = *(sub+req_id_string_len+j);
                        //memmove(sub+req_id_string_len, copy_pos, 
                        memcpy(sub, req_id_string, req_id_string_len);
                        g_new_header_len += req_id_string_len;
                    }
                }
                // g_new_header_len = strlen(g_new_header);
                // reqlen += g_new_header_len - (g_request_end - request);
                reqlen = g_new_header_len;

                char *connection_hdr;
                connection_hdr = strcasestr(g_new_header,"\r\nConnection:");
                if (connection_hdr == NULL) {
                    connection_hdr = strcasestr(g_new_header,"\n\nConnection:");
                }
                
                //if always connection:close, remove old connection:type
                if (g_add_connection_close == 2 && connection_hdr != NULL ) {
                    char * connection_hdr_end = strstr(connection_hdr + sizeof("\r\nConnection:") - 1, "\r\n");
                    if (connection_hdr_end == NULL) {
                        connection_hdr_end = strstr(connection_hdr + sizeof("\n\nConnection:") - 1, "\n\n");
                    }
                    
                    if (connection_hdr_end == NULL || connection_hdr_end > new_request_end) {
                        break;
                    }

                    int moved_bytes = g_new_header_len - (connection_hdr - g_new_header);
                    int j;

                    g_new_header_len = g_new_header_len - (connection_hdr_end - connection_hdr);
                    header_len = header_len - (connection_hdr_end - connection_hdr);

                    for (j = 0; j < moved_bytes; j++) {
                        *connection_hdr++ = *connection_hdr_end ++;
                    }
                    connection_hdr = NULL;
                }

                // add connection:close header to the request
                if (g_add_connection_close && (connection_hdr == NULL || connection_hdr >= new_request_end)) {
                    char conn_str[]="\r\nConnection: Close";
                    int conn_str_len = sizeof(conn_str) - 1;
                    char *dst = g_new_header+g_new_header_len+conn_str_len;
                    char *src = g_new_header+g_new_header_len;
                    int moved_bytes = g_new_header_len + 1 - header_len;
                    int j;

                    // move the data to get the space for connection string
                    for (j = 0; j < moved_bytes; j ++)
                        *dst-- = *src --;

                    // now copy the connection string
                    memcpy(g_new_header + header_len, conn_str, conn_str_len);              
                    // g_new_header_len = strlen(g_new_header);
                    g_new_header_len += conn_str_len;
                    //reqlen += g_new_header_len - (g_request_end - request);
                    reqlen = g_new_header_len;
                }
                request = g_new_header;
            } // end of all prefix adding
#endif // _WAF_BENCH_ , "-F" a packet file to be sent, 

            apr_socket_timeout_set(c->aprsock, 0);
            c->connect = tnow;
            c->rwrote = 0;
            c->rwrite = reqlen;
            if (send_body)
                c->rwrite += postlen;
            l = c->rwrite;
        }
        else if (tnow > c->connect + aprtimeout) {
            printf("Send request timed out!\n");
            close_connection(c);
            return;
        }

// #ifdef _WAF_BENCH_ // avoid copying post data to request
//         // check whether it's time to send header from request
//         // or it's time to send body from postdata with postlen
//         // if c->rwrote <= reqlen, meaning it's header (request)
//         // Otherwise, it's in body, so send postdata
         char *sendbuf = NULL; // point to the buffer to be sent
         if (c->rwrote < reqlen) {
             l = reqlen - c->rwrote;
             sendbuf = request + c->rwrote;
         } else if (send_body) {
             l = reqlen + postlen - c->rwrote;
             sendbuf = postdata + c->rwrote - reqlen;
         }
// 
//         if (c->rwrote < g_new_header_len) { // send prefix only
//             sendbuf = g_new_header + c->rwrote;
//             if (l > g_new_header_len - c->rwrote) 
//                 l = g_new_header_len - c->rwrote; 
//         } else if (c->rwrote < reqlen) { // send request header
//             // c->rwrote is the sent bytes, so start from there
//             if (g_new_header_len && g_request_end)
//                 sendbuf = g_request_end + c->rwrote - g_new_header_len; 
//             else
//                 sendbuf = request + c->rwrote;
//             // and make sure it's not exceeding request buffer
//             // because the remaining bytes are in body part
//             if (l > reqlen - c->rwrote) 
//                 l = reqlen - c->rwrote; 
//         } else  // send postdata, reqlen is already sent
//             sendbuf = postdata + c->rwrote - reqlen;
         if (verbosity >= 2) {
             printf("writing request(%zu bytes)=>[",l);
             fwrite(sendbuf, l, 1, stdout);
             printf("]\n");
         }
// #endif // _WAF_BENCH_ // avoid copying post data to request

#ifdef USE_SSL
        if (c->ssl) {
// #ifdef _WAF_BENCH_ // avoid copying post data to request
//             e = SSL_write(c->ssl, sendbuf, l);
// #else
            e = SSL_write(c->ssl, sendbuf, l);
// #endif // _WAF_BENCH_ // avoid copying post data to request
            if (e <= 0) {
                switch (SSL_get_error(c->ssl, e)) {
                case SSL_ERROR_WANT_READ:
                    set_polled_events(c, APR_POLLIN);
                    break;
                case SSL_ERROR_WANT_WRITE:
                    set_polled_events(c, APR_POLLOUT);
                    break;
                default:
                    BIO_printf(bio_err, "SSL write failed - closing connection\n");
                    ERR_print_errors(bio_err);
                    close_connection (c);
                    break;
                }
                return;
            }
            l = e;
        }
        else
#endif
        {
// #ifdef _WAF_BENCH_ // avoid copying post data to request
//             e = apr_socket_send(c->aprsock, sendbuf, &l);
// #else
            e = apr_socket_send(c->aprsock, sendbuf, &l);
// #endif // _WAF_BENCH_ // avoid copying post data to request
            if (e != APR_SUCCESS && !l) {
                if (!APR_STATUS_IS_EAGAIN(e)) {
                    epipe++;
                    printf("Send request failed!\n");
                    close_connection(c);
                }
                else {
                    set_polled_events(c, APR_POLLOUT);
                }
                return;
            }
        }
        totalposted += l;
        c->rwrote += l;
        c->rwrite -= l;
    } while (c->rwrite);

    c->endwrite = lasttime = apr_time_now();
    started++;
    set_conn_state(c, STATE_READ);
}