static void free_request(request * req) { int i; /* free_request should *never* get called by anything but process_requests */ if (req->buffer_end && req->status < TIMED_OUT) { /* WARN("request sent to free_request before DONE."); */ req->status = DONE; /* THIS IS THE SAME CODE EXECUTED BY THE 'DONE' SECTION * of process_requests. It must be exactly the same! */ i = req_flush(req); /* * retval can be -2=error, -1=blocked, or bytes left */ if (i == -2) { /* error */ req->status = DEAD; } else if (i > 0) { return; } } /* put request on the free list */ dequeue(&request_ready, req); /* dequeue from ready or block list */ /* set response status to 408 if the client has timed out */ if (req->status == TIMED_OUT && req->response_status == 0) req->response_status = 408; /* always log */ log_access(req); if (req->mmap_entry_var) release_mmap(req->mmap_entry_var); else if (req->data_mem) munmap(req->data_mem, req->filesize); if (req->data_fd) { close(req->data_fd); BOA_FD_CLR(req, req->data_fd, BOA_READ); } if (req->post_data_fd) { close(req->post_data_fd); BOA_FD_CLR(req, req->post_data_fd, BOA_WRITE); } if (req->response_status >= 400) status.errors++; for (i = COMMON_CGI_COUNT; i < req->cgi_env_index; ++i) { if (req->cgi_env[i]) { free(req->cgi_env[i]); } else { log_error_time(); fprintf(stderr, "Warning: CGI Environment contains NULL value" "(index %d of %d).\n", i, req->cgi_env_index); } } if (req->pathname) free(req->pathname); if (req->path_info) free(req->path_info); if (req->path_translated) free(req->path_translated); if (req->script_name) free(req->script_name); if (req->host) free(req->host); if (req->ranges) ranges_reset(req); if (req->status < TIMED_OUT && (req->keepalive == KA_ACTIVE) && (req->response_status < 500 && req->response_status != 0) && req->kacount > 0) { sanitize_request(req, 0); --(req->kacount); status.requests++; enqueue(&request_block, req); BOA_FD_SET(req, req->fd, BOA_READ); BOA_FD_CLR(req, req->fd, BOA_WRITE); return; } /* While debugging some weird errors, Jon Nelson learned that some versions of Netscape Navigator break the HTTP specification. Some research on the issue brought up: http://www.apache.org/docs/misc/known_client_problems.html As quoted here: " Trailing CRLF on POSTs This is a legacy issue. The CERN webserver required POST data to have an extra CRLF following it. Thus many clients send an extra CRLF that is not included in the Content-Length of the request. Apache works around this problem by eating any empty lines which appear before a request. " Boa will (for now) hack around this stupid bug in Netscape (and Internet Exploder) by reading up to 32k after the connection is all but closed. This should eliminate any remaining spurious crlf sent by the client. Building bugs *into* software to be compatible is just plain wrong */ if (req->method == M_POST) { char buf[32768]; read(req->fd, buf, sizeof(buf)); } close(req->fd); BOA_FD_CLR(req, req->fd, BOA_READ); BOA_FD_CLR(req, req->fd, BOA_WRITE); total_connections--; enqueue(&request_free, req); return; }
static void free_request(request ** list_head_addr, request * req) { int i; /* free_request should *never* get called by anything but process_requests */ if (req->buffer_end && req->status != DEAD) { req->status = DONE; return; } /* put request on the free list */ dequeue(list_head_addr, req); /* dequeue from ready or block list */ if (req->logline) /* access log */ log_access(req); if (req->mmap_entry_var) release_mmap(req->mmap_entry_var); else if (req->data_mem) munmap(req->data_mem, req->filesize); if (req->data_fd) close(req->data_fd); if (req->post_data_fd) close(req->post_data_fd); if (req->response_status >= 400) status.errors++; for (i = COMMON_CGI_COUNT; i < req->cgi_env_index; ++i) { if (req->cgi_env[i]) { free(req->cgi_env[i]); } else { log_error_time(); fprintf(stderr, "Warning: CGI Environment contains NULL value" \ "(index %d of %d).\n", i, req->cgi_env_index); } } if (req->pathname) free(req->pathname); if (req->path_info) free(req->path_info); if (req->path_translated) free(req->path_translated); if (req->script_name) free(req->script_name); if ((req->keepalive == KA_ACTIVE) && (req->response_status < 500) && req->kacount > 0) { int bytes_to_move; request *conn = new_request(); if (!conn) { /* errors already reported */ enqueue(&request_free, req); close(req->fd); total_connections--; return; } conn->fd = req->fd; conn->status = READ_HEADER; conn->header_line = conn->client_stream; conn->kacount = req->kacount - 1; /* close enough and we avoid a call to time(NULL) */ conn->time_last = req->time_last; /* for log file and possible use by CGI programs */ memcpy(conn->remote_ip_addr, req->remote_ip_addr, NI_MAXHOST); memcpy(conn->local_ip_addr, req->local_ip_addr, NI_MAXHOST); /* for possible use by CGI programs */ conn->remote_port = req->remote_port; status.requests++; /* we haven't parsed beyond req->parse_pos, so... */ bytes_to_move = req->client_stream_pos - req->parse_pos; if (bytes_to_move) { memcpy(conn->client_stream, req->client_stream + req->parse_pos, bytes_to_move); conn->client_stream_pos = bytes_to_move; } enqueue(&request_block, conn); BOA_FD_SET(conn->fd, &block_read_fdset); enqueue(&request_free, req); return; } /* While debugging some weird errors, Jon Nelson learned that some versions of Netscape Navigator break the HTTP specification. Some research on the issue brought up: http://www.apache.org/docs/misc/known_client_problems.html As quoted here: " Trailing CRLF on POSTs This is a legacy issue. The CERN webserver required POST data to have an extra CRLF following it. Thus many clients send an extra CRLF that is not included in the Content-Length of the request. Apache works around this problem by eating any empty lines which appear before a request. " Boa will (for now) hack around this stupid bug in Netscape (and Internet Exploder) by reading up to 32k after the connection is all but closed. This should eliminate any remaining spurious crlf sent by the client. Building bugs *into* software to be compatable is just plain wrong */ if (req->method == M_POST) { char buf[32768]; read(req->fd, buf, 32768); } close(req->fd); total_connections--; enqueue(&request_free, req); return; }