예제 #1
0
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;
}
예제 #2
0
파일: request.c 프로젝트: dulton/boa_onvif
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;
}