📄 request.c
字号:
int retval = 0;
request *current, *trailer;
if (pending_requests) {
get_request(server_s);
#ifdef ORIGINAL_BEHAVIOR
pending_requests = 0;
#endif
}
current = request_ready;
while (current) {
time(¤t_time);
if (current->buffer_end && /* there is data in the buffer */
current->status != DEAD && current->status != DONE) {
retval = req_flush(current);
/*
* retval can be -2=error, -1=blocked, or bytes left
*/
if (retval == -2) { /* error */
current->status = DEAD;
retval = 0;
} else if (retval >= 0) {
/* notice the >= which is different from below?
Here, we may just be flushing headers.
We don't want to return 0 because we are not DONE
or DEAD */
retval = 1;
}
} else {
switch (current->status) {
case READ_HEADER:
/*-->changed by dxw 2005-10-23*/
if(gflag&¤t->is_cgi==CGI){
retval=1;
}
else{
current->is_cgi=0;
retval=read_header(current);
}
/*<--*/
break;
case ONE_CR:
case ONE_LF:
case TWO_CR:
retval = read_header(current);
break;
case BODY_READ:
retval = read_body(current);
break;
case BODY_WRITE:
retval = write_body(current);
break;
case WRITE:
retval = process_get(current);
break;
case PIPE_READ:
retval = read_from_pipe(current);
break;
case PIPE_WRITE:
retval = write_from_pipe(current);
break;
case DONE:
/* a non-status that will terminate the request */
retval = req_flush(current);
/*
* retval can be -2=error, -1=blocked, or bytes left
*/
if (retval == -2) { /* error */
current->status = DEAD;
retval = 0;
} else if (retval > 0) {
retval = 1;
}
break;
case DEAD:
retval = 0;
current->buffer_end = 0;
SQUASH_KA(current);
break;
default:
retval = 0;
fprintf(stderr, "Unknown status (%d), "
"closing!\n", current->status);
current->status = DEAD;
break;
}
}
if (sigterm_flag)
SQUASH_KA(current);
/* we put this here instead of after the switch so that
* if we are on the last request, and get_request is successful,
* current->next is valid!
*/
if (pending_requests)
get_request(server_s);
switch (retval) {
case -1: /* request blocked */
trailer = current;
current = current->next;
block_request(trailer);
break;
case 0: /* request complete */
current->time_last = current_time;
trailer = current;
current = current->next;
free_request(&request_ready, trailer);
break;
case 1: /* more to do */
current->time_last = current_time;
current = current->next;
break;
default:
log_error_time();
fprintf(stderr, "Unknown retval in process.c - "
"Status: %d, retval: %d\n", current->status, retval);
current = current->next;
break;
}
}
}
/*
* Name: process_logline
*
* Description: This is called with the first req->header_line received
* by a request, called "logline" because it is logged to a file.
* It is parsed to determine request type and method, then passed to
* translate_uri for further parsing. Also sets up CGI environment if
* needed.
*/
int process_logline(request * req)
{
char *stop, *stop2;
static char *SIMPLE_HTTP_VERSION = "HTTP/0.9";
req->logline = req->client_stream;
if (!memcmp(req->logline, "GET ", 4))
req->method = M_GET;
else if (!memcmp(req->logline, "HEAD ", 5))
/* head is just get w/no body */
req->method = M_HEAD;
else if (!memcmp(req->logline, "POST ", 5))
req->method = M_POST;
else {
log_error_time();
fprintf(stderr, "malformed request: \"%s\"\n", req->logline);
send_r_not_implemented(req);
return 0;
}
req->http_version = SIMPLE_HTTP_VERSION;
req->simple = 1;
/* Guaranteed to find ' ' since we matched a method above */
stop = req->logline + 3;
if (*stop != ' ')
++stop;
/* scan to start of non-whitespace */
while (*(++stop) == ' ');
stop2 = stop;
/* scan to end of non-whitespace */
while (*stop2 != '\0' && *stop2 != ' ')
++stop2;
if (stop2 - stop > MAX_HEADER_LENGTH) {
log_error_time();
fprintf(stderr, "URI too long %d: \"%s\"\n", MAX_HEADER_LENGTH,
req->logline);
send_r_bad_request(req);
return 0;
}
memcpy(req->request_uri, stop, stop2 - stop);
req->request_uri[stop2 - stop] = '\0';
if (*stop2 == ' ') {
/* if found, we should get an HTTP/x.x */
unsigned int p1, p2;
/* scan to end of whitespace */
++stop2;
while (*stop2 == ' ' && *stop2 != '\0')
++stop2;
/* scan in HTTP/major.minor */
if (sscanf(stop2, "HTTP/%u.%u", &p1, &p2) == 2) {
/* HTTP/{0.9,1.0,1.1} */
if (p1 == 1 && (p2 == 0 || p2 == 1)) {
req->http_version = stop2;
req->simple = 0;
} else if (p1 > 1 || (p1 != 0 && p2 > 1)) {
goto BAD_VERSION;
}
} else {
goto BAD_VERSION;
}
}
if (req->method == M_HEAD && req->simple) {
send_r_bad_request(req);
return 0;
}
req->cgi_env_index = COMMON_CGI_COUNT;
return 1;
BAD_VERSION:
log_error_time();
fprintf(stderr, "bogus HTTP version: \"%s\"\n", stop2);
send_r_bad_request(req);
return 0;
}
/*
* Name: process_header_end
*
* Description: takes a request and performs some final checking before
* init_cgi or init_get
* Returns 0 for error or NPH, or 1 for success
*/
int process_header_end(request * req)
{
if (!req->logline) {
send_r_error(req);
return 0;
}
/* Percent-decode request */
if (unescape_uri(req->request_uri, &(req->query_string)) == 0) {
log_error_doc(req);
fputs("Problem unescaping uri\n", stderr);
send_r_bad_request(req);
return 0;
}
/* clean pathname */
clean_pathname(req->request_uri);
if (req->request_uri[0] != '/') {
send_r_bad_request(req);
return 0;
}
if (translate_uri(req) == 0) { /* unescape, parse uri */
SQUASH_KA(req);
return 0; /* failure, close down */
}
/*-->changed by dxw 2005-10-23*/
if(gflag&&req->is_cgi==CGI){
return -1;
}
else if(req->is_cgi==CGI){
gflag=1;
(void) time(&cgi_last_time);
}
/*<--*/
if (req->method == M_POST) {
req->post_data_fd = create_temporary_file(1, NULL, 0);
if (req->post_data_fd == 0)
return(0);
return(1); /* success */
}
if (req->is_cgi) {
return init_cgi(req);
}
req->status = WRITE;
return init_get(req); /* get and head */
}
/*
* Name: process_option_line
*
* Description: Parses the contents of req->header_line and takes
* appropriate action.
*/
int process_option_line(request * req)
{
char c, *value, *line = req->header_line;
/* Start by aggressively hacking the in-place copy of the header line */
#ifdef FASCIST_LOGGING
log_error_time();
fprintf(stderr, "%s:%d - Parsing \"%s\"\n", __FILE__, __LINE__, line);
#endif
value = strchr(line, ':');
if (value == NULL)
return 0;
*value++ = '\0'; /* overwrite the : */
to_upper(line); /* header types are case-insensitive */
while ((c = *value) && (c == ' ' || c == '\t'))
value++;
if (!memcmp(line, "IF_MODIFIED_SINCE", 18) && !req->if_modified_since)
req->if_modified_since = value;
else if (!memcmp(line, "CONTENT_TYPE", 13) && !req->content_type)
req->content_type = value;
else if (!memcmp(line, "CONTENT_LENGTH", 15) && !req->content_length)
req->content_length = value;
else if (!memcmp(line, "CONNECTION", 11) &&
ka_max && req->keepalive != KA_STOPPED) {
req->keepalive = (!strncasecmp(value, "Keep-Alive", 10) ?
KA_ACTIVE : KA_STOPPED);
}
/* #ifdef ACCEPT_ON */
else if (!memcmp(line, "ACCEPT", 7))
add_accept_header(req, value);
/* #endif */
/* Need agent and referer for logs */
else if (!memcmp(line, "REFERER", 8)) {
req->header_referer = value;
if (!add_cgi_env(req, "REFERER", value, 1))
return 0;
} else if (!memcmp(line, "USER_AGENT", 11)) {
req->header_user_agent = value;
if (!add_cgi_env(req, "USER_AGENT", value, 1))
return 0;
} else {
if (!add_cgi_env(req, line, value, 1))
return 0;
}
return 1;
}
/*
* Name: add_accept_header
* Description: Adds a mime_type to a requests accept char buffer
* silently ignore any that don't fit -
* shouldn't happen because of relative buffer sizes
*/
void add_accept_header(request * req, char *mime_type)
{
#ifdef ACCEPT_ON
int l = strlen(req->accept);
int l2 = strlen(mime_type);
if ((l + l2 + 2) >= MAX_HEADER_LENGTH)
return;
if (req->accept[0] == '\0')
strcpy(req->accept, mime_type);
else {
req->accept[l] = ',';
req->accept[l + 1] = ' ';
memcpy(req->accept + l + 2, mime_type, l2 + 1);
/* the +1 is for the '\0' */
/*
sprintf(req->accept + l, ", %s", mime_type);
*/
}
#endif
}
void free_requests(void)
{
request *ptr, *next;
ptr = request_free;
while (ptr != NULL) {
next = ptr->next;
free(ptr);
ptr = next;
}
request_free = NULL;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -