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);
}