Sorry for chiming in so late :-(.

On 12/05/2016 03:34 PM, j...@apache.org wrote:
> Modified: httpd/httpd/branches/2.4.x/server/protocol.c
> URL: 
> http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/server/protocol.c?rev=1772678&r1=1772677&r2=1772678&view=diff
> ==============================================================================
> --- httpd/httpd/branches/2.4.x/server/protocol.c (original)
> +++ httpd/httpd/branches/2.4.x/server/protocol.c Mon Dec  5 14:34:29 2016

> @@ -617,58 +646,269 @@ static int read_request_line(request_rec
>      }
>  
>      r->request_time = apr_time_now();
> -    ll = r->the_request;
> -    r->method = ap_getword_white(r->pool, &ll);
>  
> -    uri = ap_getword_white(r->pool, &ll);
> +    r->method = r->the_request;
>  
> -    if (!*r->method || !*uri) {
> -        r->status    = HTTP_BAD_REQUEST;
> -        r->proto_num = HTTP_VERSION(1,0);
> -        r->protocol  = apr_pstrdup(r->pool, "HTTP/1.0");
> -        return 0;
> +    /* If there is whitespace before a method, skip it and mark in error */
> +    if (apr_isspace(*r->method)) {
> +        deferred_error = rrl_badwhitespace; 
> +        for ( ; apr_isspace(*r->method); ++r->method)
> +            ; 
> +    }
> +
> +    /* Scan the method up to the next whitespace, ensure it contains only
> +     * valid http-token characters, otherwise mark in error
> +     */
> +    if (strict) {
> +        ll = (char*) ap_scan_http_token(r->method);
> +    }
> +    else {
> +        ll = (char*) ap_scan_vchar_obstext(r->method);
> +    }
> +
> +    if (((ll == r->method) || (*ll && !apr_isspace(*ll)))
> +            && deferred_error == rrl_none) {
> +        deferred_error = rrl_badmethod;
> +        ll = strpbrk(ll, "\t\n\v\f\r ");
> +    }
> +
> +    /* Verify method terminated with a single SP, or mark as specific error 
> */
> +    if (!ll) {
> +        if (deferred_error == rrl_none)
> +            deferred_error = rrl_missinguri;
> +        r->protocol = uri = "";
> +        len = 0;
> +        goto rrl_done;
> +    }
> +    else if (strict && ll[0] && apr_isspace(ll[1])
> +             && deferred_error == rrl_none) {
> +        deferred_error = rrl_excesswhitespace; 
> +    }
> +
> +    /* Advance uri pointer over leading whitespace, NUL terminate the method
> +     * If non-SP whitespace is encountered, mark as specific error
> +     */
> +    for (uri = ll; apr_isspace(*uri); ++uri) 
> +        if (*uri != ' ' && deferred_error == rrl_none)
> +            deferred_error = rrl_badwhitespace; 
> +    *ll = '\0';
> +
> +    if (!*uri && deferred_error == rrl_none)
> +        deferred_error = rrl_missinguri;
> +
> +    /* Scan the URI up to the next whitespace, ensure it contains no raw
> +     * control characters, otherwise mark in error
> +     */
> +    ll = (char*) ap_scan_vchar_obstext(uri);
> +    if (ll == uri || (*ll && !apr_isspace(*ll))) {
> +        deferred_error = rrl_baduri;
> +        ll = strpbrk(ll, "\t\n\v\f\r ");
> +    }
> +
> +    /* Verify URI terminated with a single SP, or mark as specific error */
> +    if (!ll) {
> +        r->protocol = "";
> +        len = 0;
> +        goto rrl_done;
> +    }
> +    else if (strict && ll[0] && apr_isspace(ll[1])
> +             && deferred_error == rrl_none) {
> +        deferred_error = rrl_excesswhitespace; 
> +    }
> +
> +    /* Advance protocol pointer over leading whitespace, NUL terminate the 
> uri
> +     * If non-SP whitespace is encountered, mark as specific error
> +     */
> +    for (r->protocol = ll; apr_isspace(*r->protocol); ++r->protocol) 
> +        if (*r->protocol != ' ' && deferred_error == rrl_none)
> +            deferred_error = rrl_badwhitespace; 
> +    *ll = '\0';
> +
> +    /* Scan the protocol up to the next whitespace, validation comes later */
> +    if (!(ll = (char*) ap_scan_vchar_obstext(r->protocol))) {
> +        len = strlen(r->protocol);
> +        goto rrl_done;
> +    }
> +    len = ll - r->protocol;
> +
> +    /* Advance over trailing whitespace, if found mark in error,
> +     * determine if trailing text is found, unconditionally mark in error,
> +     * finally NUL terminate the protocol string
> +     */
> +    if (*ll && !apr_isspace(*ll)) {
> +        deferred_error = rrl_badprotocol;
> +    }
> +    else if (strict && *ll) {
> +        deferred_error = rrl_excesswhitespace;
>      }
> +    else {
> +        for ( ; apr_isspace(*ll); ++ll)
> +            if (*ll != ' ' && deferred_error == rrl_none)
> +                deferred_error = rrl_badwhitespace; 
> +        if (*ll && deferred_error == rrl_none)
> +            deferred_error = rrl_trailingtext;
> +    }
> +    *((char *)r->protocol + len) = '\0';
> +
> +rrl_done:
> +    /* For internal integrety and palloc efficiency, reconstruct the_request
> +     * in one palloc, using only single SP characters, per spec.
> +     */
> +    r->the_request = apr_pstrcat(r->pool, r->method, *uri ? " " : NULL, uri,
> +                                 *r->protocol ? " " : NULL, r->protocol, 
> NULL);
>  
> -    /* Provide quick information about the request method as soon as known */
> +    if (len == 8
> +            && r->protocol[0] == 'H' && r->protocol[1] == 'T'
> +            && r->protocol[2] == 'T' && r->protocol[3] == 'P'
> +            && r->protocol[4] == '/' && apr_isdigit(r->protocol[5])
> +            && r->protocol[6] == '.' && apr_isdigit(r->protocol[7])
> +            && r->protocol[5] != '0') {
> +        r->assbackwards = 0;
> +        r->proto_num = HTTP_VERSION(r->protocol[5] - '0', r->protocol[7] - 
> '0');
> +    }
> +    else if (len == 8
> +                 && (r->protocol[0] == 'H' || r->protocol[0] == 'h')
> +                 && (r->protocol[1] == 'T' || r->protocol[1] == 't')
> +                 && (r->protocol[2] == 'T' || r->protocol[2] == 't')
> +                 && (r->protocol[3] == 'P' || r->protocol[3] == 'p')
> +                 && r->protocol[4] == '/' && apr_isdigit(r->protocol[5])
> +                 && r->protocol[6] == '.' && apr_isdigit(r->protocol[7])
> +                 && r->protocol[5] != '0') {
> +        r->assbackwards = 0;
> +        r->proto_num = HTTP_VERSION(r->protocol[5] - '0', r->protocol[7] - 
> '0');
> +        if (strict && deferred_error == rrl_none)
> +            deferred_error = rrl_badprotocol;
> +        else
> +            memcpy((char*)r->protocol, "HTTP", 4);
> +    }
> +    else if (r->protocol[0]) {
> +        r->assbackwards = 0;
> +        r->proto_num = HTTP_VERSION(1,0);
> +        /* Defer setting the r->protocol string till error msg is composed */
> +        if (strict && deferred_error == rrl_none)
> +            deferred_error = rrl_badprotocol;
> +        else
> +            r->protocol  = "HTTP/1.0";

Hm. r->protocol is not const char*. Shouldn't we use

apr_pstrdup(r->pool, "HTTP/1.0");

> +    }
> +    else {
> +        r->assbackwards = 1;
> +        r->protocol = "HTTP/0.9";
> +        r->proto_num = HTTP_VERSION(0, 9);
> +    }
>  
> +    /* Determine the method_number and parse the uri prior to invoking error
> +     * handling, such that these fields are available for subsitution
> +     */
>      r->method_number = ap_method_number_of(r->method);
> -    if (r->method_number == M_GET && r->method[0] == 'H') {
> +    if (r->method_number == M_GET && r->method[0] == 'H')
>          r->header_only = 1;
> -    }
>  
>      ap_parse_uri(r, uri);
> -    if (r->status != HTTP_OK) {
> -        r->proto_num = HTTP_VERSION(1,0);
> -        r->protocol  = apr_pstrdup(r->pool, "HTTP/1.0");
> +
> +    /* With the request understood, we can consider HTTP/0.9 specific errors 
> */
> +    if (r->proto_num == HTTP_VERSION(0, 9) && deferred_error == rrl_none) {
> +        if (conf->http09_enable == AP_HTTP09_DISABLE)
> +            deferred_error = rrl_reject09;
> +        else if (strict && (r->method_number != M_GET || r->header_only))
> +            deferred_error = rrl_badmethod09;
> +    }
> +
> +    /* Now that the method, uri and protocol are all processed,
> +     * we can safely resume any deferred error reporting
> +     */
> +    if (deferred_error != rrl_none) {
> +        if (deferred_error == rrl_badmethod)
> +            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03445)
> +                          "HTTP Request Line; Invalid method token: '%.*s'",
> +                          field_name_len(r->method), r->method);
> +        else if (deferred_error == rrl_badmethod09)
> +            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03444)
> +                          "HTTP Request Line; Invalid method token: '%.*s'"
> +                          " (only GET is allowed for HTTP/0.9 requests)",
> +                          field_name_len(r->method), r->method);
> +        else if (deferred_error == rrl_missinguri)
> +            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03446)
> +                          "HTTP Request Line; Missing URI");
> +        else if (deferred_error == rrl_baduri)
> +            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03454)
> +                          "HTTP Request Line; URI incorrectly encoded: 
> '%.*s'",
> +                          field_name_len(r->uri), r->uri);
> +        else if (deferred_error == rrl_badwhitespace)
> +            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03447)
> +                          "HTTP Request Line; Invalid whitespace");
> +        else if (deferred_error == rrl_excesswhitespace)
> +            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03448)
> +                          "HTTP Request Line; Excess whitespace "
> +                          "(disallowed by HttpProtocolOptions Strict");
> +        else if (deferred_error == rrl_trailingtext)
> +            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03449)
> +                          "HTTP Request Line; Extraneous text found '%.*s' "
> +                          "(perhaps whitespace was injected?)",
> +                          field_name_len(ll), ll);
> +        else if (deferred_error == rrl_reject09)
> +            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02401)
> +                          "HTTP Request Line; Rejected HTTP/0.9 request");
> +        else if (deferred_error == rrl_badprotocol)
> +            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02418)
> +                          "HTTP Request Line; Unrecognized protocol '%.*s' "
> +                          "(perhaps whitespace was injected?)",
> +                          field_name_len(r->protocol), r->protocol);


Don't we miss a

r->protocol  = apr_pstrdup(r->pool, "HTTP/1.0");

in this case?

> +        r->status = HTTP_BAD_REQUEST;
> +        goto rrl_failed;
> +    }
> +
> +    if (conf->http_methods == AP_HTTP_METHODS_REGISTERED
> +            && r->method_number == M_INVALID) {
> +        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02423)
> +                      "HTTP Request Line; Unrecognized HTTP method: '%.*s' "
> +                      "(disallowed by RegisteredMethods)",
> +                      field_name_len(r->method), r->method);
> +        r->status = HTTP_NOT_IMPLEMENTED;
> +        /* This can't happen in an HTTP/0.9 request, we verified GET above */
>          return 0;
>      }
>  


Regards

RĂ¼diger

Reply via email to