Loading modules/http/http_protocol.c +450 −383 Original line number Diff line number Diff line Loading @@ -104,7 +104,8 @@ AP_DECLARE(int) ap_set_keepalive(request_rec *r) { int ka_sent = 0; int wimpy = ap_find_token(r->pool, apr_table_get(r->headers_out, "Connection"), "close"); apr_table_get(r->headers_out, "Connection"), "close"); const char *conn = apr_table_get(r->headers_in, "Connection"); /* The following convoluted conditional determines whether or not Loading Loading @@ -161,14 +162,17 @@ AP_DECLARE(int) ap_set_keepalive(request_rec *r) /* If they sent a Keep-Alive token, send one back */ if (ka_sent) { if (r->server->keep_alive_max) if (r->server->keep_alive_max) { apr_table_setn(r->headers_out, "Keep-Alive", apr_psprintf(r->pool, "timeout=%d, max=%d", r->server->keep_alive_timeout, left)); else r->server->keep_alive_timeout, left)); } else { apr_table_setn(r->headers_out, "Keep-Alive", apr_psprintf(r->pool, "timeout=%d", r->server->keep_alive_timeout)); } apr_table_mergen(r->headers_out, "Connection", "Keep-Alive"); } Loading @@ -183,8 +187,9 @@ AP_DECLARE(int) ap_set_keepalive(request_rec *r) * as HTTP/1.0, but pass our request along with our HTTP/1.1 tag * to a HTTP/1.1 client. Better safe than sorry. */ if (!wimpy) if (!wimpy) { apr_table_mergen(r->headers_out, "Connection", "close"); } r->connection->keepalive = 0; Loading Loading @@ -345,7 +350,8 @@ AP_DECLARE(int) ap_method_register(apr_pool_t *p, const char *methname) * assignable method numbers. Log this and return M_INVALID. */ ap_log_perror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, p, "Maximum new request methods %d reached while registering method %s.", "Maximum new request methods %d reached while " "registering method %s.", METHOD_NUMBER_LAST, methname); return M_INVALID; } Loading @@ -370,56 +376,72 @@ AP_DECLARE(int) ap_method_number_of(const char *method) switch (*method) { case 'H': if (strcmp(method, "HEAD") == 0) if (strcmp(method, "HEAD") == 0) { return M_GET; /* see header_only in request_rec */ } break; case 'G': if (strcmp(method, "GET") == 0) if (strcmp(method, "GET") == 0) { return M_GET; } break; case 'P': if (strcmp(method, "POST") == 0) if (strcmp(method, "POST") == 0) { return M_POST; if (strcmp(method, "PUT") == 0) } if (strcmp(method, "PUT") == 0) { return M_PUT; if (strcmp(method, "PATCH") == 0) } if (strcmp(method, "PATCH") == 0) { return M_PATCH; if (strcmp(method, "PROPFIND") == 0) } if (strcmp(method, "PROPFIND") == 0) { return M_PROPFIND; if (strcmp(method, "PROPPATCH") == 0) } if (strcmp(method, "PROPPATCH") == 0) { return M_PROPPATCH; } break; case 'D': if (strcmp(method, "DELETE") == 0) if (strcmp(method, "DELETE") == 0) { return M_DELETE; } break; case 'C': if (strcmp(method, "CONNECT") == 0) if (strcmp(method, "CONNECT") == 0) { return M_CONNECT; if (strcmp(method, "COPY") == 0) } if (strcmp(method, "COPY") == 0) { return M_COPY; } break; case 'M': if (strcmp(method, "MKCOL") == 0) if (strcmp(method, "MKCOL") == 0) { return M_MKCOL; if (strcmp(method, "MOVE") == 0) } if (strcmp(method, "MOVE") == 0) { return M_MOVE; } break; case 'O': if (strcmp(method, "OPTIONS") == 0) if (strcmp(method, "OPTIONS") == 0) { return M_OPTIONS; } break; case 'T': if (strcmp(method, "TRACE") == 0) if (strcmp(method, "TRACE") == 0) { return M_TRACE; } break; case 'L': if (strcmp(method, "LOCK") == 0) if (strcmp(method, "LOCK") == 0) { return M_LOCK; } break; case 'U': if (strcmp(method, "UNLOCK") == 0) if (strcmp(method, "UNLOCK") == 0) { return M_UNLOCK; } break; } Loading @@ -428,9 +450,10 @@ AP_DECLARE(int) ap_method_number_of(const char *method) methnum = (int*)apr_hash_get(methods_registry, method, APR_HASH_KEY_STRING); if (methnum != NULL) if (methnum != NULL) { return *methnum; } } return M_INVALID; } Loading Loading @@ -495,15 +518,17 @@ typedef struct http_filter_ctx { /* This is the input filter for HTTP requests. It handles chunked and * content-length bodies. This can only be inserted/used after the headers * are successfully parsed. */ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, ap_input_mode_t mode, apr_off_t *readbytes) apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, ap_input_mode_t mode, apr_off_t *readbytes) { apr_bucket *e; http_ctx_t *ctx = f->ctx; apr_status_t rv; /* just get out of the way of this thing. */ if (mode == AP_MODE_PEEK) if (mode == AP_MODE_PEEK) { return ap_get_brigade(f->next, b, mode, readbytes); } if (!ctx) { const char *tenc, *lenp; Loading Loading @@ -536,10 +561,8 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, ap_input_mode } } if (!ctx->remaining) { switch (ctx->state) { if (!ctx->remaining) { switch (ctx->state) { case BODY_NONE: break; case BODY_LENGTH: Loading @@ -564,8 +587,7 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, ap_input_mode ctx->state = BODY_CHUNK; ctx->remaining = get_chunk_size(line); if (!ctx->remaining) { if (!ctx->remaining) { /* Handle trailers by calling get_mime_headers again! */ e = apr_bucket_eos_create(); APR_BRIGADE_INSERT_TAIL(b, e); Loading @@ -586,11 +608,13 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, ap_input_mode rv = ap_get_brigade(f->next, b, mode, readbytes); if (rv != APR_SUCCESS) if (rv != APR_SUCCESS) { return rv; } if (ctx->state != BODY_NONE) if (ctx->state != BODY_NONE) { ctx->remaining -= *readbytes; } return APR_SUCCESS; } Loading Loading @@ -744,14 +768,14 @@ static void basic_http_header_check(request_rec *r, return; } if (!r->status_line) if (!r->status_line) { r->status_line = status_lines[ap_index_of_response(r->status)]; } /* kluge around broken browsers when indicated by force-response-1.0 */ if (r->proto_num == HTTP_VERSION(1,0) && apr_table_get(r->subprocess_env, "force-response-1.0")) { *protocol = "HTTP/1.0"; r->connection->keepalive = -1; } Loading @@ -759,7 +783,8 @@ static void basic_http_header_check(request_rec *r, *protocol = AP_SERVER_PROTOCOL; } if (r->proto_num > HTTP_VERSION(1,0) && apr_table_get(r->subprocess_env, "downgrade-1.0")) { if (r->proto_num > HTTP_VERSION(1,0) && apr_table_get(r->subprocess_env, "downgrade-1.0")) { r->proto_num = HTTP_VERSION(1,0); } } Loading Loading @@ -893,15 +918,18 @@ AP_DECLARE_NONSTD(int) ap_send_http_trace(request_rec *r) apr_bucket_brigade *b; header_struct h; if (r->method_number != M_TRACE) if (r->method_number != M_TRACE) { return DECLINED; } /* Get the original request */ while (r->prev) while (r->prev) { r = r->prev; } if ((rv = ap_setup_client_block(r, REQUEST_NO_BODY))) if ((rv = ap_setup_client_block(r, REQUEST_NO_BODY))) { return rv; } r->content_type = "message/http"; Loading @@ -921,13 +949,15 @@ AP_DECLARE_NONSTD(int) ap_send_http_trace(request_rec *r) AP_DECLARE(int) ap_send_http_options(request_rec *r) { if (r->assbackwards) if (r->assbackwards) { return DECLINED; } apr_table_setn(r->headers_out, "Allow", make_allow(r)); /* the request finalization will send an EOS, which will flush all the headers out (including the Allow header) */ * the headers out (including the Allow header) */ return OK; } Loading Loading @@ -1014,8 +1044,7 @@ typedef struct header_filter_ctx { int headers_sent; } header_filter_ctx; AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter( ap_filter_t *f, AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f, apr_bucket_brigade *b) { int i; Loading Loading @@ -1065,9 +1094,10 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter( * header field tables into a single table. If we don't do this, our * later attempts to set or unset a given fieldname might be bypassed. */ if (!apr_is_empty_table(r->err_headers_out)) if (!apr_is_empty_table(r->err_headers_out)) { r->headers_out = apr_table_overlay(r->pool, r->err_headers_out, r->headers_out); } /* * Remove the 'Vary' header field if the client can't handle it. Loading Loading @@ -1132,9 +1162,9 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter( * because well behaved 2.0 handlers will send their data down the stack, * and we will compute a real C-L for the head request. RBB */ if (r->header_only && (clheader = apr_table_get(r->headers_out, "Content-Length")) && !strcmp(clheader, "0")) { if (r->header_only && (clheader = apr_table_get(r->headers_out, "Content-Length")) && !strcmp(clheader, "0")) { apr_table_unset(r->headers_out, "Content-Length"); } Loading Loading @@ -1269,8 +1299,8 @@ AP_DECLARE(int) ap_setup_client_block(request_rec *r, int read_policy) r->remaining = atol(lenp); } if ((r->read_body == REQUEST_NO_BODY) && (r->read_chunked || (r->remaining > 0))) { if ((r->read_body == REQUEST_NO_BODY) && (r->read_chunked || (r->remaining > 0))) { ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, "%s with body is not allowed for %s", r->method, r->uri); return HTTP_REQUEST_ENTITY_TOO_LARGE; Loading @@ -1281,7 +1311,8 @@ AP_DECLARE(int) ap_setup_client_block(request_rec *r, int read_policy) /* XXX shouldn't we enforce this for chunked encoding too? */ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, "Request content-length of %s is larger than " "the configured limit of %" APR_OFF_T_FMT, lenp, max_body); "the configured limit of %" APR_OFF_T_FMT, lenp, max_body); return HTTP_REQUEST_ENTITY_TOO_LARGE; } Loading @@ -1302,8 +1333,9 @@ AP_DECLARE(int) ap_should_client_block(request_rec *r) { /* First check if we have already read the request body */ if (r->read_length || (!r->read_chunked && (r->remaining <= 0))) if (r->read_length || (!r->read_chunked && (r->remaining <= 0))) { return 0; } if (r->expecting_100 && r->proto_num >= HTTP_VERSION(1,1)) { char *tmp; Loading Loading @@ -1362,7 +1394,8 @@ static long get_chunk_size(char *b) * hold a chunk-size line, including any extensions. For now, we'll leave * that to the caller, at least until we can come up with a better solution. */ AP_DECLARE(long) ap_get_client_block(request_rec *r, char *buffer, apr_size_t bufsiz) AP_DECLARE(long) ap_get_client_block(request_rec *r, char *buffer, apr_size_t bufsiz) { apr_size_t total; apr_status_t rv; Loading Loading @@ -1409,7 +1442,8 @@ AP_DECLARE(long) ap_get_client_block(request_rec *r, char *buffer, apr_size_t bu && !APR_BUCKET_IS_EOS(b)) { apr_size_t len_read; if ((rv = apr_bucket_read(b, &tempbuf, &len_read, APR_BLOCK_READ)) != APR_SUCCESS) { if ((rv = apr_bucket_read(b, &tempbuf, &len_read, APR_BLOCK_READ)) != APR_SUCCESS) { return -1; } if (total + len_read > bufsiz) { Loading @@ -1419,9 +1453,9 @@ AP_DECLARE(long) ap_get_client_block(request_rec *r, char *buffer, apr_size_t bu memcpy(buffer, tempbuf, len_read); buffer += len_read; total += len_read; /* XXX the next two fields shouldn't be mucked with here, as they are in terms * of bytes in the unfiltered body; gotta see if anybody else actually uses * these /* XXX the next two fields shouldn't be mucked with here, * as they are in terms of bytes in the unfiltered body; * gotta see if anybody else actually uses these */ r->read_length += len_read; /* XXX yank me? */ old = b; Loading @@ -1442,17 +1476,19 @@ AP_DECLARE(long) ap_get_client_block(request_rec *r, char *buffer, apr_size_t bu * Since we return an error status if the request is malformed, this * routine should be called at the beginning of a no-body handler, e.g., * * if ((retval = ap_discard_request_body(r)) != OK) * if ((retval = ap_discard_request_body(r)) != OK) { * return retval; * } */ AP_DECLARE(int) ap_discard_request_body(request_rec *r) { int rv; if (r->read_length == 0) { /* if not read already */ if ((rv = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK))) if ((rv = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK))) { return rv; } } /* In order to avoid sending 100 Continue when we already know the * final response status, and yet not kill the connection if there is Loading @@ -1467,12 +1503,14 @@ AP_DECLARE(int) ap_discard_request_body(request_rec *r) return OK; } while ((rv = ap_get_client_block(r, dumpbuf, HUGE_STRING_LEN)) > 0) while ((rv = ap_get_client_block(r, dumpbuf, HUGE_STRING_LEN)) > 0) { continue; } if (rv < 0) if (rv < 0) { return HTTP_BAD_REQUEST; } } return OK; } Loading @@ -1493,13 +1531,12 @@ static const char *add_optional_notes(request_rec *r, return result; } static const char *get_canned_error_string(int status, request_rec *r, const char *location) /* construct and return the default error message for a given * HTTP defined error code */ static const char *get_canned_error_string(int status, request_rec *r, const char *location) { apr_pool_t *p = r->pool; const char *error_notes, *h1, *s1; Loading @@ -1515,7 +1552,8 @@ static const char *get_canned_error_string(int status, NULL)); case HTTP_SEE_OTHER: return(apr_pstrcat(p, "<p>The answer to your request is located <a href=\"", "<p>The answer to your request is located " "<a href=\"", ap_escape_html(r->pool, location), "\">here</a>.</p>\n", NULL)); Loading @@ -1524,8 +1562,8 @@ static const char *get_canned_error_string(int status, "<p>This resource is only accessible " "through the proxy\n", ap_escape_html(r->pool, location), "<br />\nYou will need to " "configure your client to use that proxy.</p>\n", "<br />\nYou will need to configure " "your client to use that proxy.</p>\n", NULL)); case HTTP_PROXY_AUTHENTICATION_REQUIRED: case HTTP_UNAUTHORIZED: Loading Loading @@ -1579,12 +1617,14 @@ static const char *get_canned_error_string(int status, return(add_optional_notes(r, s1, "error-notes", "</p>\n")); case HTTP_PRECONDITION_FAILED: return(apr_pstrcat(p, "<p>The precondition on the request for the URL ", "<p>The precondition on the request " "for the URL ", ap_escape_html(r->pool, r->uri), " evaluated to false.</p>\n", NULL)); case HTTP_NOT_IMPLEMENTED: s1 = apr_pstrcat(p, "<p>", s1 = apr_pstrcat(p, "<p>", ap_escape_html(r->pool, r->method), " to ", ap_escape_html(r->pool, r->uri), " not supported.<br />\n", Loading @@ -1596,7 +1636,8 @@ static const char *get_canned_error_string(int status, return(add_optional_notes(r, s1, "error-notes", "</p>\n")); case HTTP_VARIANT_ALSO_VARIES: return(apr_pstrcat(p, "<p>A variant for the requested resource\n<pre>\n", "<p>A variant for the requested " "resource\n<pre>\n", ap_escape_html(r->pool, r->uri), "\n</pre>\nis itself a negotiable resource. " "This indicates a configuration error.</p>\n", Loading @@ -1609,7 +1650,8 @@ static const char *get_canned_error_string(int status, ap_escape_html(r->pool, r->uri), "<br />\nis no longer available on this server " "and there is no forwarding address.\n" "Please remove all references to this resource.</p>\n", "Please remove all references to this " "resource.</p>\n", NULL)); case HTTP_REQUEST_ENTITY_TOO_LARGE: return(apr_pstrcat(p, Loading @@ -1633,11 +1675,14 @@ static const char *get_canned_error_string(int status, "of the selected resource.</p>\n"); case HTTP_EXPECTATION_FAILED: return(apr_pstrcat(p, "<p>The expectation given in the Expect request-header" "<p>The expectation given in the Expect " "request-header" "\nfield could not be met by this server.</p>\n" "<p>The client sent<pre>\n Expect: ", apr_table_get(r->headers_in, "Expect"), "\n</pre>\n" "but we only allow the 100-continue expectation.</p>\n", apr_table_get(r->headers_in, "Expect"), "\n</pre>\n" "but we only allow the 100-continue " "expectation.</p>\n", NULL)); case HTTP_UNPROCESSABLE_ENTITY: return("<p>The server understands the media type of the\n" Loading Loading @@ -1675,22 +1720,29 @@ static const char *get_canned_error_string(int status, * that is totally safe for any user to see (ie lacks paths, * database passwords, etc.) */ if (((error_notes = apr_table_get(r->notes, "error-notes")) != NULL) if (((error_notes = apr_table_get(r->notes, "error-notes")) != NULL) && (h1 = apr_table_get(r->notes, "verbose-error-to")) != NULL && (strcmp(h1, "*") == 0)) { return(apr_pstrcat(p, error_notes, "<p />\n", NULL)); } else { return(apr_pstrcat(p, "<p>The server encountered an internal error or\n" "<p>The server encountered an internal " "error or\n" "misconfiguration and was unable to complete\n" "your request.</p>\n" "<p>Please contact the server administrator,\n ", ap_escape_html(r->pool, r->server->server_admin), " and inform them of the time the error occurred,\n" "and anything you might have done that may have\n" "<p>Please contact the server " "administrator,\n ", ap_escape_html(r->pool, r->server->server_admin), " and inform them of the time the " "error occurred,\n" "and anything you might have done that " "may have\n" "caused the error.</p>\n" "<p>More information about this error may be available\n" "<p>More information about this error " "may be available\n" "in the server error log.</p>\n", NULL)); } Loading @@ -1703,7 +1755,8 @@ static const char *get_canned_error_string(int status, * which some people consider to be a breach of privacy. Until we * can figure out a way to remove the pathname, leave this commented. * * if ((error_notes = apr_table_get(r->notes, "error-notes")) != NULL) { * if ((error_notes = apr_table_get(r->notes, * "error-notes")) != NULL) { * return(apr_pstrcat(p, error_notes, "<p />\n", NULL); * } * else { Loading Loading @@ -1917,7 +1970,8 @@ AP_DECLARE(void) ap_copy_method_list(ap_method_list_t *dest, /* * Invoke a callback routine for each method in the specified list. */ AP_DECLARE_NONSTD(void) ap_method_list_do(int (*comp) (void *urec, const char *mname, AP_DECLARE_NONSTD(void) ap_method_list_do(int (*comp) (void *urec, const char *mname, int mnum), void *rec, const ap_method_list_t *ml, ...) Loading Loading @@ -2128,10 +2182,12 @@ AP_DECLARE(void) ap_set_etag(request_rec *r) /* merge variant_etag and vlv into a structured etag */ variant_etag[strlen(variant_etag) - 1] = '\0'; if (vlv_weak) if (vlv_weak) { vlv += 3; else } else { vlv++; } etag = apr_pstrcat(r->pool, variant_etag, ";", vlv, NULL); } Loading @@ -2143,8 +2199,9 @@ static int parse_byterange(char *range, apr_off_t clength, { char *dash = strchr(range, '-'); if (!dash) if (!dash) { return 0; } if ((dash == range)) { /* In the form "-5" */ Loading @@ -2155,20 +2212,25 @@ static int parse_byterange(char *range, apr_off_t clength, *dash = '\0'; dash++; *start = atol(range); if (*dash) if (*dash) { *end = atol(dash); else /* "5-" */ } else { /* "5-" */ *end = clength - 1; } } if (*start < 0) if (*start < 0) { *start = 0; } if (*end >= clength) if (*end >= clength) { *end = clength - 1; } if (*start > *end) if (*start > *end) { return -1; } return (*start > 0 || *end < clength); } Loading @@ -2191,8 +2253,8 @@ typedef struct byterange_ctx { static int use_range_x(request_rec *r) { const char *ua; return (apr_table_get(r->headers_in, "Request-Range") || ((ua = apr_table_get(r->headers_in, "User-Agent")) return (apr_table_get(r->headers_in, "Request-Range") || ((ua = apr_table_get(r->headers_in, "User-Agent")) && ap_strstr_c(ua, "MSIE 3"))); } Loading @@ -2200,8 +2262,7 @@ static int use_range_x(request_rec *r) #define PARTITION_ERR_FMT "apr_brigade_partition() failed " \ "[%" APR_OFF_T_FMT ",%" APR_OFF_T_FMT "]" AP_CORE_DECLARE_NONSTD(apr_status_t) ap_byterange_filter( ap_filter_t *f, AP_CORE_DECLARE_NONSTD(apr_status_t) ap_byterange_filter(ap_filter_t *f, apr_bucket_brigade *bb) { #define MIN_LENGTH(len1, len2) ((len1 > len2) ? len2 : len1) Loading Loading @@ -2240,9 +2301,10 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_byterange_filter( if (num_ranges > 1) { ctx->orig_ct = r->content_type; r->content_type = apr_pstrcat(r->pool, "multipart", use_range_x(r) ? "/x-" : "/", "byteranges; boundary=", r->boundary, NULL); r->content_type = apr_pstrcat(r->pool, "multipart", use_range_x(r) ? "/x-" : "/", "byteranges; boundary=", r->boundary, NULL); } /* create a brigade in case we never call ap_save_brigade() */ Loading Loading @@ -2285,8 +2347,9 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_byterange_filter( /* this brigade holds what we will be sending */ bsend = apr_brigade_create(r->pool); while ((current = ap_getword(r->pool, &r->range, ',')) && (rv = parse_byterange(current, clength, &range_start, &range_end))) { while ((current = ap_getword(r->pool, &r->range, ',')) && (rv = parse_byterange(current, clength, &range_start, &range_end))) { apr_bucket *e2; apr_bucket *ec; Loading Loading @@ -2381,8 +2444,9 @@ static int ap_set_byterange(request_rec *r) apr_off_t range_end; int num_ranges; if (r->assbackwards) if (r->assbackwards) { return 0; } /* is content already a single range? */ if (apr_table_get(r->headers_out, "Content-Range")) { Loading @@ -2390,9 +2454,9 @@ static int ap_set_byterange(request_rec *r) } /* is content already a multiple range? */ if ((ct = apr_table_get(r->headers_out, "Content-Type")) && (!strncasecmp(ct, "multipart/byteranges", 20) || !strncasecmp(ct, "multipart/x-byteranges", 22))) { if ((ct = apr_table_get(r->headers_out, "Content-Type")) && (!strncasecmp(ct, "multipart/byteranges", 20) || !strncasecmp(ct, "multipart/x-byteranges", 22))) { return 0; } Loading @@ -2406,8 +2470,9 @@ static int ap_set_byterange(request_rec *r) * Navigator 2-3 and MSIE 3. */ if (!(range = apr_table_get(r->headers_in, "Range"))) if (!(range = apr_table_get(r->headers_in, "Range"))) { range = apr_table_get(r->headers_in, "Request-Range"); } if (!range || strncasecmp(range, "bytes=", 6)) { return 0; Loading @@ -2419,14 +2484,16 @@ static int ap_set_byterange(request_rec *r) */ if ((if_range = apr_table_get(r->headers_in, "If-Range"))) { if (if_range[0] == '"') { if (!(match = apr_table_get(r->headers_out, "Etag")) || (strcmp(if_range, match) != 0)) if (!(match = apr_table_get(r->headers_out, "Etag")) || (strcmp(if_range, match) != 0)) { return 0; } else if (!(match = apr_table_get(r->headers_out, "Last-Modified")) || (strcmp(if_range, match) != 0)) } else if (!(match = apr_table_get(r->headers_out, "Last-Modified")) || (strcmp(if_range, match) != 0)) { return 0; } } /* would be nice to pick this up from f->ctx */ ct = ap_make_content_type(r, r->content_type); Loading Loading
modules/http/http_protocol.c +450 −383 Original line number Diff line number Diff line Loading @@ -104,7 +104,8 @@ AP_DECLARE(int) ap_set_keepalive(request_rec *r) { int ka_sent = 0; int wimpy = ap_find_token(r->pool, apr_table_get(r->headers_out, "Connection"), "close"); apr_table_get(r->headers_out, "Connection"), "close"); const char *conn = apr_table_get(r->headers_in, "Connection"); /* The following convoluted conditional determines whether or not Loading Loading @@ -161,14 +162,17 @@ AP_DECLARE(int) ap_set_keepalive(request_rec *r) /* If they sent a Keep-Alive token, send one back */ if (ka_sent) { if (r->server->keep_alive_max) if (r->server->keep_alive_max) { apr_table_setn(r->headers_out, "Keep-Alive", apr_psprintf(r->pool, "timeout=%d, max=%d", r->server->keep_alive_timeout, left)); else r->server->keep_alive_timeout, left)); } else { apr_table_setn(r->headers_out, "Keep-Alive", apr_psprintf(r->pool, "timeout=%d", r->server->keep_alive_timeout)); } apr_table_mergen(r->headers_out, "Connection", "Keep-Alive"); } Loading @@ -183,8 +187,9 @@ AP_DECLARE(int) ap_set_keepalive(request_rec *r) * as HTTP/1.0, but pass our request along with our HTTP/1.1 tag * to a HTTP/1.1 client. Better safe than sorry. */ if (!wimpy) if (!wimpy) { apr_table_mergen(r->headers_out, "Connection", "close"); } r->connection->keepalive = 0; Loading Loading @@ -345,7 +350,8 @@ AP_DECLARE(int) ap_method_register(apr_pool_t *p, const char *methname) * assignable method numbers. Log this and return M_INVALID. */ ap_log_perror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, p, "Maximum new request methods %d reached while registering method %s.", "Maximum new request methods %d reached while " "registering method %s.", METHOD_NUMBER_LAST, methname); return M_INVALID; } Loading @@ -370,56 +376,72 @@ AP_DECLARE(int) ap_method_number_of(const char *method) switch (*method) { case 'H': if (strcmp(method, "HEAD") == 0) if (strcmp(method, "HEAD") == 0) { return M_GET; /* see header_only in request_rec */ } break; case 'G': if (strcmp(method, "GET") == 0) if (strcmp(method, "GET") == 0) { return M_GET; } break; case 'P': if (strcmp(method, "POST") == 0) if (strcmp(method, "POST") == 0) { return M_POST; if (strcmp(method, "PUT") == 0) } if (strcmp(method, "PUT") == 0) { return M_PUT; if (strcmp(method, "PATCH") == 0) } if (strcmp(method, "PATCH") == 0) { return M_PATCH; if (strcmp(method, "PROPFIND") == 0) } if (strcmp(method, "PROPFIND") == 0) { return M_PROPFIND; if (strcmp(method, "PROPPATCH") == 0) } if (strcmp(method, "PROPPATCH") == 0) { return M_PROPPATCH; } break; case 'D': if (strcmp(method, "DELETE") == 0) if (strcmp(method, "DELETE") == 0) { return M_DELETE; } break; case 'C': if (strcmp(method, "CONNECT") == 0) if (strcmp(method, "CONNECT") == 0) { return M_CONNECT; if (strcmp(method, "COPY") == 0) } if (strcmp(method, "COPY") == 0) { return M_COPY; } break; case 'M': if (strcmp(method, "MKCOL") == 0) if (strcmp(method, "MKCOL") == 0) { return M_MKCOL; if (strcmp(method, "MOVE") == 0) } if (strcmp(method, "MOVE") == 0) { return M_MOVE; } break; case 'O': if (strcmp(method, "OPTIONS") == 0) if (strcmp(method, "OPTIONS") == 0) { return M_OPTIONS; } break; case 'T': if (strcmp(method, "TRACE") == 0) if (strcmp(method, "TRACE") == 0) { return M_TRACE; } break; case 'L': if (strcmp(method, "LOCK") == 0) if (strcmp(method, "LOCK") == 0) { return M_LOCK; } break; case 'U': if (strcmp(method, "UNLOCK") == 0) if (strcmp(method, "UNLOCK") == 0) { return M_UNLOCK; } break; } Loading @@ -428,9 +450,10 @@ AP_DECLARE(int) ap_method_number_of(const char *method) methnum = (int*)apr_hash_get(methods_registry, method, APR_HASH_KEY_STRING); if (methnum != NULL) if (methnum != NULL) { return *methnum; } } return M_INVALID; } Loading Loading @@ -495,15 +518,17 @@ typedef struct http_filter_ctx { /* This is the input filter for HTTP requests. It handles chunked and * content-length bodies. This can only be inserted/used after the headers * are successfully parsed. */ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, ap_input_mode_t mode, apr_off_t *readbytes) apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, ap_input_mode_t mode, apr_off_t *readbytes) { apr_bucket *e; http_ctx_t *ctx = f->ctx; apr_status_t rv; /* just get out of the way of this thing. */ if (mode == AP_MODE_PEEK) if (mode == AP_MODE_PEEK) { return ap_get_brigade(f->next, b, mode, readbytes); } if (!ctx) { const char *tenc, *lenp; Loading Loading @@ -536,10 +561,8 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, ap_input_mode } } if (!ctx->remaining) { switch (ctx->state) { if (!ctx->remaining) { switch (ctx->state) { case BODY_NONE: break; case BODY_LENGTH: Loading @@ -564,8 +587,7 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, ap_input_mode ctx->state = BODY_CHUNK; ctx->remaining = get_chunk_size(line); if (!ctx->remaining) { if (!ctx->remaining) { /* Handle trailers by calling get_mime_headers again! */ e = apr_bucket_eos_create(); APR_BRIGADE_INSERT_TAIL(b, e); Loading @@ -586,11 +608,13 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, ap_input_mode rv = ap_get_brigade(f->next, b, mode, readbytes); if (rv != APR_SUCCESS) if (rv != APR_SUCCESS) { return rv; } if (ctx->state != BODY_NONE) if (ctx->state != BODY_NONE) { ctx->remaining -= *readbytes; } return APR_SUCCESS; } Loading Loading @@ -744,14 +768,14 @@ static void basic_http_header_check(request_rec *r, return; } if (!r->status_line) if (!r->status_line) { r->status_line = status_lines[ap_index_of_response(r->status)]; } /* kluge around broken browsers when indicated by force-response-1.0 */ if (r->proto_num == HTTP_VERSION(1,0) && apr_table_get(r->subprocess_env, "force-response-1.0")) { *protocol = "HTTP/1.0"; r->connection->keepalive = -1; } Loading @@ -759,7 +783,8 @@ static void basic_http_header_check(request_rec *r, *protocol = AP_SERVER_PROTOCOL; } if (r->proto_num > HTTP_VERSION(1,0) && apr_table_get(r->subprocess_env, "downgrade-1.0")) { if (r->proto_num > HTTP_VERSION(1,0) && apr_table_get(r->subprocess_env, "downgrade-1.0")) { r->proto_num = HTTP_VERSION(1,0); } } Loading Loading @@ -893,15 +918,18 @@ AP_DECLARE_NONSTD(int) ap_send_http_trace(request_rec *r) apr_bucket_brigade *b; header_struct h; if (r->method_number != M_TRACE) if (r->method_number != M_TRACE) { return DECLINED; } /* Get the original request */ while (r->prev) while (r->prev) { r = r->prev; } if ((rv = ap_setup_client_block(r, REQUEST_NO_BODY))) if ((rv = ap_setup_client_block(r, REQUEST_NO_BODY))) { return rv; } r->content_type = "message/http"; Loading @@ -921,13 +949,15 @@ AP_DECLARE_NONSTD(int) ap_send_http_trace(request_rec *r) AP_DECLARE(int) ap_send_http_options(request_rec *r) { if (r->assbackwards) if (r->assbackwards) { return DECLINED; } apr_table_setn(r->headers_out, "Allow", make_allow(r)); /* the request finalization will send an EOS, which will flush all the headers out (including the Allow header) */ * the headers out (including the Allow header) */ return OK; } Loading Loading @@ -1014,8 +1044,7 @@ typedef struct header_filter_ctx { int headers_sent; } header_filter_ctx; AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter( ap_filter_t *f, AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f, apr_bucket_brigade *b) { int i; Loading Loading @@ -1065,9 +1094,10 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter( * header field tables into a single table. If we don't do this, our * later attempts to set or unset a given fieldname might be bypassed. */ if (!apr_is_empty_table(r->err_headers_out)) if (!apr_is_empty_table(r->err_headers_out)) { r->headers_out = apr_table_overlay(r->pool, r->err_headers_out, r->headers_out); } /* * Remove the 'Vary' header field if the client can't handle it. Loading Loading @@ -1132,9 +1162,9 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter( * because well behaved 2.0 handlers will send their data down the stack, * and we will compute a real C-L for the head request. RBB */ if (r->header_only && (clheader = apr_table_get(r->headers_out, "Content-Length")) && !strcmp(clheader, "0")) { if (r->header_only && (clheader = apr_table_get(r->headers_out, "Content-Length")) && !strcmp(clheader, "0")) { apr_table_unset(r->headers_out, "Content-Length"); } Loading Loading @@ -1269,8 +1299,8 @@ AP_DECLARE(int) ap_setup_client_block(request_rec *r, int read_policy) r->remaining = atol(lenp); } if ((r->read_body == REQUEST_NO_BODY) && (r->read_chunked || (r->remaining > 0))) { if ((r->read_body == REQUEST_NO_BODY) && (r->read_chunked || (r->remaining > 0))) { ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, "%s with body is not allowed for %s", r->method, r->uri); return HTTP_REQUEST_ENTITY_TOO_LARGE; Loading @@ -1281,7 +1311,8 @@ AP_DECLARE(int) ap_setup_client_block(request_rec *r, int read_policy) /* XXX shouldn't we enforce this for chunked encoding too? */ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, "Request content-length of %s is larger than " "the configured limit of %" APR_OFF_T_FMT, lenp, max_body); "the configured limit of %" APR_OFF_T_FMT, lenp, max_body); return HTTP_REQUEST_ENTITY_TOO_LARGE; } Loading @@ -1302,8 +1333,9 @@ AP_DECLARE(int) ap_should_client_block(request_rec *r) { /* First check if we have already read the request body */ if (r->read_length || (!r->read_chunked && (r->remaining <= 0))) if (r->read_length || (!r->read_chunked && (r->remaining <= 0))) { return 0; } if (r->expecting_100 && r->proto_num >= HTTP_VERSION(1,1)) { char *tmp; Loading Loading @@ -1362,7 +1394,8 @@ static long get_chunk_size(char *b) * hold a chunk-size line, including any extensions. For now, we'll leave * that to the caller, at least until we can come up with a better solution. */ AP_DECLARE(long) ap_get_client_block(request_rec *r, char *buffer, apr_size_t bufsiz) AP_DECLARE(long) ap_get_client_block(request_rec *r, char *buffer, apr_size_t bufsiz) { apr_size_t total; apr_status_t rv; Loading Loading @@ -1409,7 +1442,8 @@ AP_DECLARE(long) ap_get_client_block(request_rec *r, char *buffer, apr_size_t bu && !APR_BUCKET_IS_EOS(b)) { apr_size_t len_read; if ((rv = apr_bucket_read(b, &tempbuf, &len_read, APR_BLOCK_READ)) != APR_SUCCESS) { if ((rv = apr_bucket_read(b, &tempbuf, &len_read, APR_BLOCK_READ)) != APR_SUCCESS) { return -1; } if (total + len_read > bufsiz) { Loading @@ -1419,9 +1453,9 @@ AP_DECLARE(long) ap_get_client_block(request_rec *r, char *buffer, apr_size_t bu memcpy(buffer, tempbuf, len_read); buffer += len_read; total += len_read; /* XXX the next two fields shouldn't be mucked with here, as they are in terms * of bytes in the unfiltered body; gotta see if anybody else actually uses * these /* XXX the next two fields shouldn't be mucked with here, * as they are in terms of bytes in the unfiltered body; * gotta see if anybody else actually uses these */ r->read_length += len_read; /* XXX yank me? */ old = b; Loading @@ -1442,17 +1476,19 @@ AP_DECLARE(long) ap_get_client_block(request_rec *r, char *buffer, apr_size_t bu * Since we return an error status if the request is malformed, this * routine should be called at the beginning of a no-body handler, e.g., * * if ((retval = ap_discard_request_body(r)) != OK) * if ((retval = ap_discard_request_body(r)) != OK) { * return retval; * } */ AP_DECLARE(int) ap_discard_request_body(request_rec *r) { int rv; if (r->read_length == 0) { /* if not read already */ if ((rv = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK))) if ((rv = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK))) { return rv; } } /* In order to avoid sending 100 Continue when we already know the * final response status, and yet not kill the connection if there is Loading @@ -1467,12 +1503,14 @@ AP_DECLARE(int) ap_discard_request_body(request_rec *r) return OK; } while ((rv = ap_get_client_block(r, dumpbuf, HUGE_STRING_LEN)) > 0) while ((rv = ap_get_client_block(r, dumpbuf, HUGE_STRING_LEN)) > 0) { continue; } if (rv < 0) if (rv < 0) { return HTTP_BAD_REQUEST; } } return OK; } Loading @@ -1493,13 +1531,12 @@ static const char *add_optional_notes(request_rec *r, return result; } static const char *get_canned_error_string(int status, request_rec *r, const char *location) /* construct and return the default error message for a given * HTTP defined error code */ static const char *get_canned_error_string(int status, request_rec *r, const char *location) { apr_pool_t *p = r->pool; const char *error_notes, *h1, *s1; Loading @@ -1515,7 +1552,8 @@ static const char *get_canned_error_string(int status, NULL)); case HTTP_SEE_OTHER: return(apr_pstrcat(p, "<p>The answer to your request is located <a href=\"", "<p>The answer to your request is located " "<a href=\"", ap_escape_html(r->pool, location), "\">here</a>.</p>\n", NULL)); Loading @@ -1524,8 +1562,8 @@ static const char *get_canned_error_string(int status, "<p>This resource is only accessible " "through the proxy\n", ap_escape_html(r->pool, location), "<br />\nYou will need to " "configure your client to use that proxy.</p>\n", "<br />\nYou will need to configure " "your client to use that proxy.</p>\n", NULL)); case HTTP_PROXY_AUTHENTICATION_REQUIRED: case HTTP_UNAUTHORIZED: Loading Loading @@ -1579,12 +1617,14 @@ static const char *get_canned_error_string(int status, return(add_optional_notes(r, s1, "error-notes", "</p>\n")); case HTTP_PRECONDITION_FAILED: return(apr_pstrcat(p, "<p>The precondition on the request for the URL ", "<p>The precondition on the request " "for the URL ", ap_escape_html(r->pool, r->uri), " evaluated to false.</p>\n", NULL)); case HTTP_NOT_IMPLEMENTED: s1 = apr_pstrcat(p, "<p>", s1 = apr_pstrcat(p, "<p>", ap_escape_html(r->pool, r->method), " to ", ap_escape_html(r->pool, r->uri), " not supported.<br />\n", Loading @@ -1596,7 +1636,8 @@ static const char *get_canned_error_string(int status, return(add_optional_notes(r, s1, "error-notes", "</p>\n")); case HTTP_VARIANT_ALSO_VARIES: return(apr_pstrcat(p, "<p>A variant for the requested resource\n<pre>\n", "<p>A variant for the requested " "resource\n<pre>\n", ap_escape_html(r->pool, r->uri), "\n</pre>\nis itself a negotiable resource. " "This indicates a configuration error.</p>\n", Loading @@ -1609,7 +1650,8 @@ static const char *get_canned_error_string(int status, ap_escape_html(r->pool, r->uri), "<br />\nis no longer available on this server " "and there is no forwarding address.\n" "Please remove all references to this resource.</p>\n", "Please remove all references to this " "resource.</p>\n", NULL)); case HTTP_REQUEST_ENTITY_TOO_LARGE: return(apr_pstrcat(p, Loading @@ -1633,11 +1675,14 @@ static const char *get_canned_error_string(int status, "of the selected resource.</p>\n"); case HTTP_EXPECTATION_FAILED: return(apr_pstrcat(p, "<p>The expectation given in the Expect request-header" "<p>The expectation given in the Expect " "request-header" "\nfield could not be met by this server.</p>\n" "<p>The client sent<pre>\n Expect: ", apr_table_get(r->headers_in, "Expect"), "\n</pre>\n" "but we only allow the 100-continue expectation.</p>\n", apr_table_get(r->headers_in, "Expect"), "\n</pre>\n" "but we only allow the 100-continue " "expectation.</p>\n", NULL)); case HTTP_UNPROCESSABLE_ENTITY: return("<p>The server understands the media type of the\n" Loading Loading @@ -1675,22 +1720,29 @@ static const char *get_canned_error_string(int status, * that is totally safe for any user to see (ie lacks paths, * database passwords, etc.) */ if (((error_notes = apr_table_get(r->notes, "error-notes")) != NULL) if (((error_notes = apr_table_get(r->notes, "error-notes")) != NULL) && (h1 = apr_table_get(r->notes, "verbose-error-to")) != NULL && (strcmp(h1, "*") == 0)) { return(apr_pstrcat(p, error_notes, "<p />\n", NULL)); } else { return(apr_pstrcat(p, "<p>The server encountered an internal error or\n" "<p>The server encountered an internal " "error or\n" "misconfiguration and was unable to complete\n" "your request.</p>\n" "<p>Please contact the server administrator,\n ", ap_escape_html(r->pool, r->server->server_admin), " and inform them of the time the error occurred,\n" "and anything you might have done that may have\n" "<p>Please contact the server " "administrator,\n ", ap_escape_html(r->pool, r->server->server_admin), " and inform them of the time the " "error occurred,\n" "and anything you might have done that " "may have\n" "caused the error.</p>\n" "<p>More information about this error may be available\n" "<p>More information about this error " "may be available\n" "in the server error log.</p>\n", NULL)); } Loading @@ -1703,7 +1755,8 @@ static const char *get_canned_error_string(int status, * which some people consider to be a breach of privacy. Until we * can figure out a way to remove the pathname, leave this commented. * * if ((error_notes = apr_table_get(r->notes, "error-notes")) != NULL) { * if ((error_notes = apr_table_get(r->notes, * "error-notes")) != NULL) { * return(apr_pstrcat(p, error_notes, "<p />\n", NULL); * } * else { Loading Loading @@ -1917,7 +1970,8 @@ AP_DECLARE(void) ap_copy_method_list(ap_method_list_t *dest, /* * Invoke a callback routine for each method in the specified list. */ AP_DECLARE_NONSTD(void) ap_method_list_do(int (*comp) (void *urec, const char *mname, AP_DECLARE_NONSTD(void) ap_method_list_do(int (*comp) (void *urec, const char *mname, int mnum), void *rec, const ap_method_list_t *ml, ...) Loading Loading @@ -2128,10 +2182,12 @@ AP_DECLARE(void) ap_set_etag(request_rec *r) /* merge variant_etag and vlv into a structured etag */ variant_etag[strlen(variant_etag) - 1] = '\0'; if (vlv_weak) if (vlv_weak) { vlv += 3; else } else { vlv++; } etag = apr_pstrcat(r->pool, variant_etag, ";", vlv, NULL); } Loading @@ -2143,8 +2199,9 @@ static int parse_byterange(char *range, apr_off_t clength, { char *dash = strchr(range, '-'); if (!dash) if (!dash) { return 0; } if ((dash == range)) { /* In the form "-5" */ Loading @@ -2155,20 +2212,25 @@ static int parse_byterange(char *range, apr_off_t clength, *dash = '\0'; dash++; *start = atol(range); if (*dash) if (*dash) { *end = atol(dash); else /* "5-" */ } else { /* "5-" */ *end = clength - 1; } } if (*start < 0) if (*start < 0) { *start = 0; } if (*end >= clength) if (*end >= clength) { *end = clength - 1; } if (*start > *end) if (*start > *end) { return -1; } return (*start > 0 || *end < clength); } Loading @@ -2191,8 +2253,8 @@ typedef struct byterange_ctx { static int use_range_x(request_rec *r) { const char *ua; return (apr_table_get(r->headers_in, "Request-Range") || ((ua = apr_table_get(r->headers_in, "User-Agent")) return (apr_table_get(r->headers_in, "Request-Range") || ((ua = apr_table_get(r->headers_in, "User-Agent")) && ap_strstr_c(ua, "MSIE 3"))); } Loading @@ -2200,8 +2262,7 @@ static int use_range_x(request_rec *r) #define PARTITION_ERR_FMT "apr_brigade_partition() failed " \ "[%" APR_OFF_T_FMT ",%" APR_OFF_T_FMT "]" AP_CORE_DECLARE_NONSTD(apr_status_t) ap_byterange_filter( ap_filter_t *f, AP_CORE_DECLARE_NONSTD(apr_status_t) ap_byterange_filter(ap_filter_t *f, apr_bucket_brigade *bb) { #define MIN_LENGTH(len1, len2) ((len1 > len2) ? len2 : len1) Loading Loading @@ -2240,9 +2301,10 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_byterange_filter( if (num_ranges > 1) { ctx->orig_ct = r->content_type; r->content_type = apr_pstrcat(r->pool, "multipart", use_range_x(r) ? "/x-" : "/", "byteranges; boundary=", r->boundary, NULL); r->content_type = apr_pstrcat(r->pool, "multipart", use_range_x(r) ? "/x-" : "/", "byteranges; boundary=", r->boundary, NULL); } /* create a brigade in case we never call ap_save_brigade() */ Loading Loading @@ -2285,8 +2347,9 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_byterange_filter( /* this brigade holds what we will be sending */ bsend = apr_brigade_create(r->pool); while ((current = ap_getword(r->pool, &r->range, ',')) && (rv = parse_byterange(current, clength, &range_start, &range_end))) { while ((current = ap_getword(r->pool, &r->range, ',')) && (rv = parse_byterange(current, clength, &range_start, &range_end))) { apr_bucket *e2; apr_bucket *ec; Loading Loading @@ -2381,8 +2444,9 @@ static int ap_set_byterange(request_rec *r) apr_off_t range_end; int num_ranges; if (r->assbackwards) if (r->assbackwards) { return 0; } /* is content already a single range? */ if (apr_table_get(r->headers_out, "Content-Range")) { Loading @@ -2390,9 +2454,9 @@ static int ap_set_byterange(request_rec *r) } /* is content already a multiple range? */ if ((ct = apr_table_get(r->headers_out, "Content-Type")) && (!strncasecmp(ct, "multipart/byteranges", 20) || !strncasecmp(ct, "multipart/x-byteranges", 22))) { if ((ct = apr_table_get(r->headers_out, "Content-Type")) && (!strncasecmp(ct, "multipart/byteranges", 20) || !strncasecmp(ct, "multipart/x-byteranges", 22))) { return 0; } Loading @@ -2406,8 +2470,9 @@ static int ap_set_byterange(request_rec *r) * Navigator 2-3 and MSIE 3. */ if (!(range = apr_table_get(r->headers_in, "Range"))) if (!(range = apr_table_get(r->headers_in, "Range"))) { range = apr_table_get(r->headers_in, "Request-Range"); } if (!range || strncasecmp(range, "bytes=", 6)) { return 0; Loading @@ -2419,14 +2484,16 @@ static int ap_set_byterange(request_rec *r) */ if ((if_range = apr_table_get(r->headers_in, "If-Range"))) { if (if_range[0] == '"') { if (!(match = apr_table_get(r->headers_out, "Etag")) || (strcmp(if_range, match) != 0)) if (!(match = apr_table_get(r->headers_out, "Etag")) || (strcmp(if_range, match) != 0)) { return 0; } else if (!(match = apr_table_get(r->headers_out, "Last-Modified")) || (strcmp(if_range, match) != 0)) } else if (!(match = apr_table_get(r->headers_out, "Last-Modified")) || (strcmp(if_range, match) != 0)) { return 0; } } /* would be nice to pick this up from f->ctx */ ct = ap_make_content_type(r, r->content_type); Loading