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_COUNT; return 1; BAD_VERSION: log_error_doc(req); fprintf(stderr, "bogus HTTP version: \"%s\"\n", stop2); send_r_bad_request(req); return 0; }
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; }