📄 request.c
字号:
#ifdef HAVE_SENDFILE retval = io_shuffle_sendfile(current);#else retval = io_shuffle(current);#endif 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 TIMED_OUT: 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_sock); 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(trailer); break; case 1: /* more to do */ current->time_last = current_time; current = current->next; break; default: log_error_doc(current); fprintf(stderr, "Unknown retval in process.c - " "Status: %d, retval: %d\n", current->status, retval); current->status = DEAD; 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; req->logline = req->client_stream; if (strlen(req->logline) < 5) { /* minimum length req'd. */ log_error_doc(req); fprintf(stderr, "Request too short: \"%s\"\n", req->logline); send_r_bad_request(req); return 0; } 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_doc(req); fprintf(stderr, "malformed request: \"%s\"\n", req->logline); send_r_not_implemented(req); return 0; } req->http_version = HTTP10; /* 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_doc(req); fprintf(stderr, "URI too long %d: \"%s\"\n", MAX_HEADER_LENGTH, req->logline); send_r_bad_request(req); return 0; } /* check for absolute URL */ if (!memcmp(stop, SERVER_METHOD, strlen(SERVER_METHOD)) && !memcmp(stop + strlen(SERVER_METHOD), "://", 3)) { char *host; /* we have an absolute URL */ /* advance STOP until first '/' after host */ stop += strlen(SERVER_METHOD) + 3; host = stop; /* if *host is '/' there is no host in the URI * if *host is ' ' there is corruption in the URI * if *host is '\0' there is nothing after http:// */ if (*host == '/' || *host == ' ' || *host == '\0') { /* nothing *at all* after http:// */ /* no host in absolute URI */ log_error_doc(req); /* we don't need to log req->logline, because log_error_doc does */ fprintf(stderr, "bogus absolute URI\n"); send_r_bad_request(req); return 0; } /* OK. The 'host' is at least 1 char long. * advance to '/', or end of host+url (' ' or ''\0') */ while(*stop != '\0' && *stop != '/' && *stop != ' ') ++stop; if (*stop != '/') { /* *stop is '\0' or ' ' */ /* host is valid, but there is no URL. */ log_error_doc(req); fprintf(stderr, "no URL in absolute URI: \"%s\"\n", req->logline); send_r_bad_request(req); return 0; } /* we have http://X/ where X is not ' ' or '/' (or '\0') */ /* since stop2 stops on '\0' and ' ', it *must* be after stop */ /* still, a safety check (belts and suspenders) */ if (stop2 < stop) { /* Corruption in absolute URI */ /* This prevents a DoS attack from format string attacks */ log_error_doc(req); fprintf(stderr, "Error: corruption in absolute URI:" "\"%s\". This should not happen.\n", req->logline); send_r_bad_request(req); return 0; } /* copy the URI */ memcpy(req->request_uri, stop, stop2 - stop); /* place a NIL in the file spot to terminate host */ *stop = '\0'; /* place host */ /* according to RFC2616 -- 1. If Request-URI is an absoluteURI, the host is part of the Request-URI. Any Host header field value in the request MUST be ignored. Since we ignore any Host header if req->host is already set, well, we rock! */ req->header_host = host; /* this includes the port! (if any) */ } else { /* copy the URI */ memcpy(req->request_uri, stop, stop2 - stop); } req->request_uri[stop2 - stop] = '\0'; /* METHOD URL\0 */ if (*stop2 == '\0') req->http_version = HTTP09; else 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; if (*stop2 == '\0') { req->http_version = HTTP09; } else { /* scan in HTTP/major.minor */ if (sscanf(stop2, "HTTP/%u.%u", &p1, &p2) == 2) { /* HTTP/{0.9,1.0,1.1} */ if (p1 == 0 && p2 == 9) { req->http_version = HTTP09; } else if (p1 == 1 && p2 == 0) { req->http_version = HTTP10; } else if (p1 == 1 && p2 == 1) { req->http_version = HTTP11; req->keepalive = KA_ACTIVE; /* enable keepalive */ /* Disable send_r_continue because some clients * *still* don't work with it, Python 2.2 being one * see bug 227361 at the sourceforge web site. * fixed in revision 1.52 of httplib.py, dated * 2002-06-28 (perhaps Python 2.3 will * contain the fix.) * * Also, send_r_continue should *only* be * used if the expect header was sent. */ /* send_r_continue(req); */ } else { goto BAD_VERSION; } } else { goto BAD_VERSION; } } } if (req->method == M_HEAD && req->http_version == HTTP09) { log_error("method is HEAD but version is HTTP/0.9"); send_r_bad_request(req); return 0; } req->cgi_env_index = common_cgi_env_count; return 1; BAD_VERSION: log_error_doc(req); 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) { log_error_doc(req); fputs("No logline in process_header_end\n", stderr); send_r_error(req); return 0; } /* Percent-decode request */ if (unescape_uri(req->request_uri, &(req->query_string)) == 0) { log_error_doc(req); fputs("URI contains bogus characters\n", stderr); send_r_bad_request(req); return 0; } /* clean pathname */ clean_pathname(req->request_uri); if (req->request_uri[0] != '/') { log_error("URI does not begin with '/'\n"); send_r_bad_request(req); return 0; } if (vhost_root) { char *c; if (!req->header_host) { req->host = strdup(default_vhost); } else { req->host = strdup(req->header_host); } if (!req->host) { log_error_doc(req); fputs("unable to strdup default_vhost/req->header_host\n", stderr); send_r_error(req); return 0; } strlower(req->host); /* check for port, and remove * we essentially ignore the port, because we cannot * as yet report a different port than the one we are * listening on */ c = strchr(req->host, ':'); if (c) *c = '\0'; if (check_host(req->host) < 1) { log_error_doc(req); fputs("host invalid!\n", stderr); send_r_bad_request(req); return 0; } } if (translate_uri(req) == 0) { /* unescape, parse uri */ /* errors already logged */ SQUASH_KA(req); return 0; /* failure, close down */ } if (req->method == M_POST) { req->post_data_fd = create_temporary_file(1, NULL, 0); if (req->post_data_fd == 0) { /* errors already logged */ send_r_error(req); return 0; } if (fcntl(req->post_data_fd, F_SETFD, 1) == -1) { boa_perror(req, "unable to set close-on-exec for req->post_data_fd!"); close(req->post_data_fd); req->post_data_fd = 0; return 0; } return 1; /* success */ } if (req->cgi_type) { 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) { log_error_doc(req); fprintf(stderr, "header \"%s\" does not contain ':'\n", line); return 0; } *value++ = '\0'; /* overwrite the : */ to_upper(line); /* header types are case-insensitive */ /* the code below *does* catch '\0' due to the c = *value test */ while ((c = *value) && (c == ' ' || c == '\t')) value++; /* if c == '\0' there was no 'value' for the key */ if (c == '\0') { /* return now to bypass any parsing or assignment */ return 1; } switch (line[0]) { case 'A': if (!memcmp(line, "ACCEPT", 7)) {#ifdef ACCEPT_ON add_accept_header(req, value);#endif return 1; } break; case 'C': if (!memcmp(line, "CONTENT_TYPE", 13) && !req->content_type) { req->content_type = value; return 1; } else if (!memcmp(line, "CONTENT_LENGTH", 15) && !req->content_length) { req->content_length = value; return 1; } else if (!memcmp(line, "CONNECTION", 11) && ka_max && req->keepalive != KA_STOPPED) { req->keepalive = (!strncasecmp(value, "Keep-Alive", 10) ? KA_ACTIVE : KA_STOPPED); return 1; } break; case 'H': if (!memcmp(line, "HOST", 5) && !req->header_host) { req->header_host = value; /* may be complete garbage! */ return 1; } break; case 'I': if (!memcmp(line, "IF_MODIFIED_SINCE", 18) && !req->if_modified_since) { req->if_modified_since = value; return 1; } break; case 'R': /* Need agent and referer for logs */ if (!memcmp(line, "REFERER", 8)) { req->header_referer = value; if (!add_cgi_env(req, "REFERER", value, 1)) { /* errors already logged */ return 0; } } else if (!memcmp(line, "RANGE", 6)) { if (req->ranges && req->ranges->stop == INT_MAX) { /* there was an error parsing, ignore */ return 1; } else if (!range_parse(req, value)) { /* unable to parse range */ send_r_invalid_range(req); return 0; } /* req->ranges */ } break; case 'U': if (!memcmp(line, "USER_AGENT", 11)) { req->header_user_agent = value; if (!add_cgi_env(req, "USER_AGENT", value, 1)) { /* errors already logged */ return 0; } return 1; } break; default: /* no default */ break; } /* switch */ return add_cgi_env(req, line, value, 1);}#ifdef ACCEPT_ON/* * 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, const char *mime_type){ int l = strlen(req->accept); int l2 = strlen(mime_type); if ((l + l2 + 2) >= MAX_HEADER_LENGTH) return; if (req->accept[0] == '\0') { memcpy(req->accept, mime_type, l2 + 1); } else { req->accept[l] = ','; req->accept[l + 1] = ' '; memcpy(req->accept + l + 2, mime_type, l2 + 1); /* the +1 is for the '\0' */ }}#endifvoid 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 + -