📄 request.c
字号:
* return value from handler functions, all of which return -1 * to indicate a block, 0 on completion and 1 to remain on the * ready list for more procesing. */void process_requests(int server_s){ 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: 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 */ } 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 + -