diff options
| author | Arno Töll <debian@toell.net> | 2012-01-08 22:53:17 +0100 |
|---|---|---|
| committer | Arno Töll <debian@toell.net> | 2012-01-08 22:53:17 +0100 |
| commit | e072a2dd866b7cb9f14319b80326a4e7fd16fcdf (patch) | |
| tree | a49dfc56d94a26011fe157835ff6cbe14edbd8a9 /modules/http | |
| parent | 0890390c00801651d08d3794e13b31a5dabbf5ef (diff) | |
| download | apache2-e072a2dd866b7cb9f14319b80326a4e7fd16fcdf.tar.gz | |
Imported Upstream version 2.3.16-beta
Diffstat (limited to 'modules/http')
| -rw-r--r-- | modules/http/byterange_filter.c | 469 | ||||
| -rw-r--r-- | modules/http/chunk_filter.c | 11 | ||||
| -rw-r--r-- | modules/http/config.m4 (renamed from modules/http/config2.m4) | 4 | ||||
| -rw-r--r-- | modules/http/http_core.c | 154 | ||||
| -rw-r--r-- | modules/http/http_etag.c | 6 | ||||
| -rw-r--r-- | modules/http/http_filters.c | 185 | ||||
| -rw-r--r-- | modules/http/http_protocol.c | 82 | ||||
| -rw-r--r-- | modules/http/http_request.c | 180 | ||||
| -rw-r--r-- | modules/http/mod_core.h | 95 | ||||
| -rw-r--r-- | modules/http/mod_mime.c | 65 | ||||
| -rw-r--r-- | modules/http/mod_mime.dep | 29 | ||||
| -rw-r--r-- | modules/http/mod_mime.mak | 353 |
12 files changed, 692 insertions, 941 deletions
diff --git a/modules/http/byterange_filter.c b/modules/http/byterange_filter.c index ef3c79f7..b2c678da 100644 --- a/modules/http/byterange_filter.c +++ b/modules/http/byterange_filter.c @@ -19,6 +19,7 @@ */ #include "apr.h" + #include "apr_strings.h" #include "apr_buckets.h" #include "apr_lib.h" @@ -29,7 +30,6 @@ #define APR_WANT_MEMFUNC #include "apr_want.h" -#define CORE_PRIVATE #include "util_filter.h" #include "ap_config.h" #include "httpd.h" @@ -58,9 +58,259 @@ #ifndef AP_DEFAULT_MAX_RANGES #define AP_DEFAULT_MAX_RANGES 200 #endif +#ifndef AP_DEFAULT_MAX_OVERLAPS +#define AP_DEFAULT_MAX_OVERLAPS 20 +#endif +#ifndef AP_DEFAULT_MAX_REVERSALS +#define AP_DEFAULT_MAX_REVERSALS 20 +#endif +#define MAX_PREALLOC_RANGES 100 + +APLOG_USE_MODULE(http); + +typedef struct indexes_t { + apr_off_t start; + apr_off_t end; +} indexes_t; + +/* + * Returns: number of ranges (merged) or -1 for no-good + */ static int ap_set_byterange(request_rec *r, apr_off_t clength, - apr_array_header_t **indexes); + apr_array_header_t **indexes, + int *overlaps, int *reversals) +{ + const char *range; + const char *if_range; + const char *match; + const char *ct; + char *cur; + apr_array_header_t *merged; + int num_ranges = 0, unsatisfiable = 0; + apr_off_t ostart = 0, oend = 0, sum_lengths = 0; + int in_merge = 0; + indexes_t *idx; + int ranges = 1; + int i; + const char *it; + + *overlaps = 0; + *reversals = 0; + + if (r->assbackwards) { + return 0; + } + + /* + * Check for Range request-header (HTTP/1.1) or Request-Range for + * backwards-compatibility with second-draft Luotonen/Franks + * byte-ranges (e.g. Netscape Navigator 2-3). + * + * We support this form, with Request-Range, and (farther down) we + * send multipart/x-byteranges instead of multipart/byteranges for + * Request-Range based requests to work around a bug in Netscape + * Navigator 2-3 and MSIE 3. + */ + + if (!(range = apr_table_get(r->headers_in, "Range"))) { + range = apr_table_get(r->headers_in, "Request-Range"); + } + + if (!range || strncasecmp(range, "bytes=", 6) || r->status != HTTP_OK) { + return 0; + } + + /* is content already a single range? */ + if (apr_table_get(r->headers_out, "Content-Range")) { + return 0; + } + + /* 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))) { + return 0; + } + + /* + * Check the If-Range header for Etag or Date. + * Note that this check will return false (as required) if either + * of the two etags are weak. + */ + 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)) { + return 0; + } + } + else if (!(match = apr_table_get(r->headers_out, "Last-Modified")) + || (strcmp(if_range, match) != 0)) { + return 0; + } + } + + range += 6; + it = range; + while (*it) { + if (*it++ == ',') { + ranges++; + } + } + it = range; + if (ranges > MAX_PREALLOC_RANGES) { + ranges = MAX_PREALLOC_RANGES; + } + *indexes = apr_array_make(r->pool, ranges, sizeof(indexes_t)); + while ((cur = ap_getword(r->pool, &range, ','))) { + char *dash; + char *errp; + apr_off_t number, start, end; + + if (!*cur) + break; + + /* + * Per RFC 2616 14.35.1: If there is at least one syntactically invalid + * byte-range-spec, we must ignore the whole header. + */ + + if (!(dash = strchr(cur, '-'))) { + return 0; + } + + if (dash == cur) { + /* In the form "-5" */ + if (apr_strtoff(&number, dash+1, &errp, 10) || *errp) { + return 0; + } + if (number < 1) { + return 0; + } + start = clength - number; + end = clength - 1; + } + else { + *dash++ = '\0'; + if (apr_strtoff(&number, cur, &errp, 10) || *errp) { + return 0; + } + start = number; + if (*dash) { + if (apr_strtoff(&number, dash, &errp, 10) || *errp) { + return 0; + } + end = number; + if (start > end) { + return 0; + } + } + else { /* "5-" */ + end = clength - 1; + /* + * special case: 0- + * ignore all other ranges provided + * return as a single range: 0- + */ + if (start == 0) { + num_ranges = 0; + sum_lengths = 0; + in_merge = 1; + oend = end; + ostart = start; + apr_array_clear(*indexes); + break; + } + } + } + + if (start < 0) { + start = 0; + } + if (start >= clength) { + unsatisfiable = 1; + continue; + } + if (end >= clength) { + end = clength - 1; + } + + if (!in_merge) { + /* new set */ + ostart = start; + oend = end; + in_merge = 1; + continue; + } + in_merge = 0; + + if (start >= ostart && end <= oend) { + in_merge = 1; + } + + if (start < ostart && end >= ostart-1) { + ostart = start; + ++*reversals; + in_merge = 1; + } + if (end >= oend && start <= oend+1 ) { + oend = end; + in_merge = 1; + } + + if (in_merge) { + ++*overlaps; + continue; + } else { + idx = (indexes_t *)apr_array_push(*indexes); + idx->start = ostart; + idx->end = oend; + sum_lengths += oend - ostart + 1; + /* new set again */ + in_merge = 1; + ostart = start; + oend = end; + num_ranges++; + } + } + + if (in_merge) { + idx = (indexes_t *)apr_array_push(*indexes); + idx->start = ostart; + idx->end = oend; + sum_lengths += oend - ostart + 1; + num_ranges++; + } + else if (num_ranges == 0 && unsatisfiable) { + /* If all ranges are unsatisfiable, we should return 416 */ + return -1; + } + if (sum_lengths > clength) { + ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, + "Sum of ranges larger than file, ignoring."); + return 0; + } + + /* + * create the merged table now, now that we know we need it + */ + merged = apr_array_make(r->pool, num_ranges, sizeof(char *)); + idx = (indexes_t *)(*indexes)->elts; + for (i = 0; i < (*indexes)->nelts; i++, idx++) { + char **new = (char **)apr_array_push(merged); + *new = apr_psprintf(r->pool, "%" APR_OFF_T_FMT "-%" APR_OFF_T_FMT, + idx->start, idx->end); + } + + r->status = HTTP_PARTIAL_CONTENT; + r->range = apr_array_pstrcat(r->pool, merged, ','); + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01583) + "Range: %s | %s (%d : %d : %"APR_OFF_T_FMT")", + it, r->range, *overlaps, *reversals, clength); + + return num_ranges; +} /* * Here we try to be compatible with clients that want multipart/x-byteranges @@ -178,22 +428,6 @@ static apr_status_t copy_brigade_range(apr_bucket_brigade *bb, return APR_SUCCESS; } -typedef struct indexes_t { - apr_off_t start; - apr_off_t end; -} indexes_t; - -static int get_max_ranges(request_rec *r) { - core_dir_config *core_conf = ap_get_module_config(r->per_dir_config, - &core_module); - if (core_conf->max_ranges >= 0 || core_conf->max_ranges == AP_MAXRANGES_UNLIMITED) { - return core_conf->max_ranges; - } - - /* Any other negative val means the default */ - return AP_DEFAULT_MAX_RANGES; -} - static apr_status_t send_416(ap_filter_t *f, apr_bucket_brigade *tmpbb) { apr_bucket *e; @@ -222,14 +456,24 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_byterange_filter(ap_filter_t *f, apr_status_t rv; int found = 0; int num_ranges; - char *boundary = NULL; char *bound_head = NULL; apr_array_header_t *indexes; indexes_t *idx; int i; int original_status; - int max_ranges = get_max_ranges(r); - + int max_ranges, max_overlaps, max_reversals; + int overlaps = 0, reversals = 0; + core_dir_config *core_conf = ap_get_core_module_config(r->per_dir_config); + + max_ranges = ( (core_conf->max_ranges >= 0 || core_conf->max_ranges == AP_MAXRANGES_UNLIMITED) + ? core_conf->max_ranges + : AP_DEFAULT_MAX_RANGES ); + max_overlaps = ( (core_conf->max_overlaps >= 0 || core_conf->max_overlaps == AP_MAXRANGES_UNLIMITED) + ? core_conf->max_overlaps + : AP_DEFAULT_MAX_OVERLAPS ); + max_reversals = ( (core_conf->max_reversals >= 0 || core_conf->max_reversals == AP_MAXRANGES_UNLIMITED) + ? core_conf->max_reversals + : AP_DEFAULT_MAX_REVERSALS ); /* * Iterate through the brigade until reaching EOS or a bucket with * unknown length. @@ -253,10 +497,13 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_byterange_filter(ap_filter_t *f, } original_status = r->status; - num_ranges = ap_set_byterange(r, clength, &indexes); + num_ranges = ap_set_byterange(r, clength, &indexes, &overlaps, &reversals); - /* We have nothing to do, get out of the way. */ - if (num_ranges == 0 || (max_ranges >= 0 && num_ranges > max_ranges)) { + /* No Ranges or we hit a limit? We have nothing to do, get out of the way. */ + if (num_ranges == 0 || + (max_ranges >= 0 && num_ranges > max_ranges) || + (max_overlaps >= 0 && overlaps > max_overlaps) || + (max_reversals >= 0 && reversals > max_reversals)) { r->status = original_status; ap_remove_output_filter(f); return ap_pass_brigade(f->next, bb); @@ -271,17 +518,15 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_byterange_filter(ap_filter_t *f, if (num_ranges > 1) { /* Is ap_make_content_type required here? */ const char *orig_ct = ap_make_content_type(r, r->content_type); - boundary = apr_psprintf(r->pool, "%" APR_UINT64_T_HEX_FMT "%lx", - (apr_uint64_t)r->request_time, c->id); ap_set_content_type(r, apr_pstrcat(r->pool, "multipart", use_range_x(r) ? "/x-" : "/", "byteranges; boundary=", - boundary, NULL)); + ap_multipart_boundary, NULL)); - if (strcasecmp(orig_ct, NO_CONTENT_TYPE)) { + if (orig_ct) { bound_head = apr_pstrcat(r->pool, - CRLF "--", boundary, + CRLF "--", ap_multipart_boundary, CRLF "Content-type: ", orig_ct, CRLF "Content-range: bytes ", @@ -290,7 +535,7 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_byterange_filter(ap_filter_t *f, else { /* if we have no type for the content, do our best */ bound_head = apr_pstrcat(r->pool, - CRLF "--", boundary, + CRLF "--", ap_multipart_boundary, CRLF "Content-range: bytes ", NULL); } @@ -306,7 +551,7 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_byterange_filter(ap_filter_t *f, rv = copy_brigade_range(bb, tmpbb, range_start, range_end); if (rv != APR_SUCCESS ) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01584) "copy_brigade_range() failed [%" APR_OFF_T_FMT "-%" APR_OFF_T_FMT ",%" APR_OFF_T_FMT "]", range_start, range_end, clength); @@ -362,7 +607,8 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_byterange_filter(ap_filter_t *f, char *end; /* add the final boundary */ - end = apr_pstrcat(r->pool, CRLF "--", boundary, "--" CRLF, NULL); + end = apr_pstrcat(r->pool, CRLF "--", ap_multipart_boundary, "--" CRLF, + NULL); ap_xlate_proto_to_ascii(end, strlen(end)); e = apr_bucket_pool_create(end, strlen(end), r->pool, c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bsend, e); @@ -378,162 +624,3 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_byterange_filter(ap_filter_t *f, /* send our multipart output */ return ap_pass_brigade(f->next, bsend); } - -static int ap_set_byterange(request_rec *r, apr_off_t clength, - apr_array_header_t **indexes) -{ - const char *range; - const char *if_range; - const char *match; - const char *ct; - char *cur; - int num_ranges = 0, unsatisfiable = 0; - apr_off_t sum_lengths = 0; - indexes_t *idx; - int ranges = 1; - const char *it; - - if (r->assbackwards) { - return 0; - } - - /* - * Check for Range request-header (HTTP/1.1) or Request-Range for - * backwards-compatibility with second-draft Luotonen/Franks - * byte-ranges (e.g. Netscape Navigator 2-3). - * - * We support this form, with Request-Range, and (farther down) we - * send multipart/x-byteranges instead of multipart/byteranges for - * Request-Range based requests to work around a bug in Netscape - * Navigator 2-3 and MSIE 3. - */ - - if (!(range = apr_table_get(r->headers_in, "Range"))) { - range = apr_table_get(r->headers_in, "Request-Range"); - } - - if (!range || strncasecmp(range, "bytes=", 6) || r->status != HTTP_OK) { - return 0; - } - - /* is content already a single range? */ - if (apr_table_get(r->headers_out, "Content-Range")) { - return 0; - } - - /* 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))) { - return 0; - } - - /* - * Check the If-Range header for Etag or Date. - * Note that this check will return false (as required) if either - * of the two etags are weak. - */ - 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)) { - return 0; - } - } - else if (!(match = apr_table_get(r->headers_out, "Last-Modified")) - || (strcmp(if_range, match) != 0)) { - return 0; - } - } - - range += 6; - it = range; - while (*it) { - if (*it++ == ',') { - ranges++; - } - } - it = range; - *indexes = apr_array_make(r->pool, ranges, sizeof(indexes_t)); - while ((cur = ap_getword(r->pool, &range, ','))) { - char *dash; - char *errp; - apr_off_t number, start, end; - - if (!*cur) - break; - - /* - * Per RFC 2616 14.35.1: If there is at least one syntactically invalid - * byte-range-spec, we must ignore the whole header. - */ - - if (!(dash = strchr(cur, '-'))) { - return 0; - } - - if (dash == cur) { - /* In the form "-5" */ - if (apr_strtoff(&number, dash+1, &errp, 10) || *errp) { - return 0; - } - if (number < 1) { - return 0; - } - start = clength - number; - end = clength - 1; - } - else { - *dash++ = '\0'; - if (apr_strtoff(&number, cur, &errp, 10) || *errp) { - return 0; - } - start = number; - if (*dash) { - if (apr_strtoff(&number, dash, &errp, 10) || *errp) { - return 0; - } - end = number; - if (start > end) { - return 0; - } - } - else { /* "5-" */ - end = clength - 1; - } - } - - if (start < 0) { - start = 0; - } - if (start >= clength) { - unsatisfiable = 1; - continue; - } - if (end >= clength) { - end = clength - 1; - } - - idx = (indexes_t *)apr_array_push(*indexes); - idx->start = start; - idx->end = end; - sum_lengths += end - start + 1; - /* new set again */ - num_ranges++; - } - - if (num_ranges == 0 && unsatisfiable) { - /* If all ranges are unsatisfiable, we should return 416 */ - return -1; - } - if (sum_lengths >= clength) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, - "Sum of ranges not smaller than file, ignoring."); - return 0; - } - - r->status = HTTP_PARTIAL_CONTENT; - r->range = it; - - return num_ranges; -} diff --git a/modules/http/chunk_filter.c b/modules/http/chunk_filter.c index b680185b..17fbabdb 100644 --- a/modules/http/chunk_filter.c +++ b/modules/http/chunk_filter.c @@ -24,7 +24,6 @@ #define APR_WANT_STRFUNC #include "apr_want.h" -#define CORE_PRIVATE #include "httpd.h" #include "http_config.h" #include "http_connection.h" @@ -50,11 +49,11 @@ apr_status_t ap_http_chunk_filter(ap_filter_t *f, apr_bucket_brigade *b) #define ASCII_CRLF "\015\012" #define ASCII_ZERO "\060" conn_rec *c = f->r->connection; - apr_bucket_brigade *more; + apr_bucket_brigade *more, *tmp; apr_bucket *e; apr_status_t rv; - for (more = NULL; b; b = more, more = NULL) { + for (more = tmp = NULL; b; b = more, more = NULL) { apr_off_t bytes = 0; apr_bucket *eos = NULL; apr_bucket *flush = NULL; @@ -86,7 +85,7 @@ apr_status_t ap_http_chunk_filter(ap_filter_t *f, apr_bucket_brigade *b) if (APR_BUCKET_IS_FLUSH(e)) { flush = e; if (e != APR_BRIGADE_LAST(b)) { - more = apr_brigade_split(b, APR_BUCKET_NEXT(e)); + more = apr_brigade_split_ex(b, APR_BUCKET_NEXT(e), tmp); } break; } @@ -106,7 +105,7 @@ apr_status_t ap_http_chunk_filter(ap_filter_t *f, apr_bucket_brigade *b) * block so we pass down what we have so far. */ bytes += len; - more = apr_brigade_split(b, APR_BUCKET_NEXT(e)); + more = apr_brigade_split_ex(b, APR_BUCKET_NEXT(e), tmp); break; } else { @@ -190,6 +189,8 @@ apr_status_t ap_http_chunk_filter(ap_filter_t *f, apr_bucket_brigade *b) if (rv != APR_SUCCESS || eos != NULL) { return rv; } + tmp = b; + apr_brigade_cleanup(tmp); } return APR_SUCCESS; } diff --git a/modules/http/config2.m4 b/modules/http/config.m4 index 87a7cc8a..64960075 100644 --- a/modules/http/config2.m4 +++ b/modules/http/config.m4 @@ -14,7 +14,7 @@ elif test "$enable_http" = "shared"; then AC_MSG_ERROR([mod_http can not be built as a shared DSO]) fi -APACHE_MODULE(http, HTTP protocol handling, $http_objects, , static) -APACHE_MODULE(mime, mapping of file-extension to MIME, , , yes) +APACHE_MODULE(http,[HTTP protocol handling. The http module is a basic one that enables the server to function as an HTTP server. It is only useful to disable it if you want to use another protocol module instead. Don't disable this module unless you are really sure what you are doing. Note: This module will always be linked statically.], $http_objects, , static) +APACHE_MODULE(mime, mapping of file-extension to MIME. Disabling this module is normally not recommended., , , yes) APACHE_MODPATH_FINISH diff --git a/modules/http/http_core.c b/modules/http/http_core.c index be1e1138..663810a5 100644 --- a/modules/http/http_core.c +++ b/modules/http/http_core.c @@ -20,7 +20,6 @@ #define APR_WANT_STRFUNC #include "apr_want.h" -#define CORE_PRIVATE #include "httpd.h" #include "http_config.h" #include "http_connection.h" @@ -42,44 +41,45 @@ AP_DECLARE_DATA ap_filter_rec_t *ap_chunk_filter_handle; AP_DECLARE_DATA ap_filter_rec_t *ap_http_outerror_filter_handle; AP_DECLARE_DATA ap_filter_rec_t *ap_byterange_filter_handle; -static int ap_process_http_connection(conn_rec *c); +AP_DECLARE_DATA const char *ap_multipart_boundary; + +/* If we are using an MPM That Supports Async Connections, + * use a different processing function + */ +static int async_mpm = 0; static const char *set_keep_alive_timeout(cmd_parms *cmd, void *dummy, const char *arg) { - const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); + apr_interval_time_t timeout; + const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE); if (err != NULL) { return err; } - cmd->server->keep_alive_timeout = apr_time_from_sec(atoi(arg)); + /* Stolen from mod_proxy.c */ + if (ap_timeout_parameter_parse(arg, &timeout, "s") != APR_SUCCESS) + return "KeepAliveTimeout has wrong format"; + cmd->server->keep_alive_timeout = timeout; return NULL; } static const char *set_keep_alive(cmd_parms *cmd, void *dummy, - const char *arg) + int arg) { - const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); + const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE); if (err != NULL) { return err; } - /* We've changed it to On/Off, but used to use numbers - * so we accept anything but "Off" or "0" as "On" - */ - if (!strcasecmp(arg, "off") || !strcmp(arg, "0")) { - cmd->server->keep_alive = 0; - } - else { - cmd->server->keep_alive = 1; - } + cmd->server->keep_alive = arg; return NULL; } static const char *set_keep_alive_max(cmd_parms *cmd, void *dummy, const char *arg) { - const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); + const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE); if (err != NULL) { return err; } @@ -94,21 +94,21 @@ static const command_rec http_cmds[] = { AP_INIT_TAKE1("MaxKeepAliveRequests", set_keep_alive_max, NULL, RSRC_CONF, "Maximum number of Keep-Alive requests per connection, " "or 0 for infinite"), - AP_INIT_TAKE1("KeepAlive", set_keep_alive, NULL, RSRC_CONF, + AP_INIT_FLAG("KeepAlive", set_keep_alive, NULL, RSRC_CONF, "Whether persistent connections should be On or Off"), { NULL } }; static const char *http_scheme(const request_rec *r) { - /* - * The http module shouldn't return anything other than + /* + * The http module shouldn't return anything other than * "http" (the default) or "https". */ if (r->server->server_scheme && (strcmp(r->server->server_scheme, "https") == 0)) return "https"; - + return "http"; } @@ -117,7 +117,7 @@ static apr_port_t http_port(const request_rec *r) if (r->server->server_scheme && (strcmp(r->server->server_scheme, "https") == 0)) return DEFAULT_HTTPS_PORT; - + return DEFAULT_HTTP_PORT; } @@ -126,14 +126,11 @@ static int ap_process_http_async_connection(conn_rec *c) request_rec *r; conn_state_t *cs = c->cs; - if (c->clogging_input_filters) { - return ap_process_http_connection(c); - } - + AP_DEBUG_ASSERT(cs != NULL); AP_DEBUG_ASSERT(cs->state == CONN_STATE_READ_REQUEST_LINE); while (cs->state == CONN_STATE_READ_REQUEST_LINE) { - ap_update_child_status(c->sbh, SERVER_BUSY_READ, NULL); + ap_update_child_status_from_conn(c->sbh, SERVER_BUSY_READ, c); if ((r = ap_read_request(c))) { @@ -141,25 +138,24 @@ static int ap_process_http_async_connection(conn_rec *c) /* process the request if it was read without error */ ap_update_child_status(c->sbh, SERVER_BUSY_WRITE, r); - if (r->status == HTTP_OK) - ap_process_request(r); - - if (ap_extended_status) - ap_increment_counts(c->sbh, r); + if (r->status == HTTP_OK) { + cs->state = CONN_STATE_HANDLER; + ap_process_async_request(r); + /* After the call to ap_process_request, the + * request pool may have been deleted. We set + * r=NULL here to ensure that any dereference + * of r that might be added later in this function + * will result in a segfault immediately instead + * of nondeterministic failures later. + */ + r = NULL; + } - if (c->keepalive != AP_CONN_KEEPALIVE || c->aborted - || ap_graceful_stop_signalled()) { + if (cs->state != CONN_STATE_WRITE_COMPLETION && + cs->state != CONN_STATE_SUSPENDED) { + /* Something went wrong; close the connection */ cs->state = CONN_STATE_LINGER; } - else if (!c->data_in_input_filters) { - cs->state = CONN_STATE_CHECK_REQUEST_LINE_READABLE; - } - - /* else we are pipelining. Stay in READ_REQUEST_LINE state - * and stay in the loop - */ - - apr_pool_destroy(r->pool); } else { /* ap_read_request failed - client may have closed */ cs->state = CONN_STATE_LINGER; @@ -169,40 +165,54 @@ static int ap_process_http_async_connection(conn_rec *c) return OK; } -static int ap_process_http_connection(conn_rec *c) +static int ap_process_http_sync_connection(conn_rec *c) { request_rec *r; + conn_state_t *cs = c->cs; apr_socket_t *csd = NULL; + int mpm_state = 0; /* * Read and process each request found on our connection * until no requests are left or we decide to close. */ - ap_update_child_status(c->sbh, SERVER_BUSY_READ, NULL); + ap_update_child_status_from_conn(c->sbh, SERVER_BUSY_READ, c); while ((r = ap_read_request(c)) != NULL) { c->keepalive = AP_CONN_UNKNOWN; /* process the request if it was read without error */ ap_update_child_status(c->sbh, SERVER_BUSY_WRITE, r); - if (r->status == HTTP_OK) + if (r->status == HTTP_OK) { + if (cs) + cs->state = CONN_STATE_HANDLER; ap_process_request(r); - - if (ap_extended_status) - ap_increment_counts(c->sbh, r); + /* After the call to ap_process_request, the + * request pool will have been deleted. We set + * r=NULL here to ensure that any dereference + * of r that might be added later in this function + * will result in a segfault immediately instead + * of nondeterministic failures later. + */ + r = NULL; + } if (c->keepalive != AP_CONN_KEEPALIVE || c->aborted) break; - ap_update_child_status(c->sbh, SERVER_BUSY_KEEPALIVE, r); - apr_pool_destroy(r->pool); + ap_update_child_status(c->sbh, SERVER_BUSY_KEEPALIVE, NULL); - if (ap_graceful_stop_signalled()) + if (ap_mpm_query(AP_MPMQ_MPM_STATE, &mpm_state)) { break; + } + + if (mpm_state == AP_MPMQ_STOPPING) { + break; + } if (!csd) { - csd = ap_get_module_config(c->conn_config, &core_module); + csd = ap_get_conn_socket(c); } apr_socket_opt_set(csd, APR_INCOMPLETE_READ, 1); apr_socket_timeout_set(csd, c->base_server->keep_alive_timeout); @@ -212,6 +222,16 @@ static int ap_process_http_connection(conn_rec *c) return OK; } +static int ap_process_http_connection(conn_rec *c) +{ + if (async_mpm && !c->clogging_input_filters) { + return ap_process_http_async_connection(c); + } + else { + return ap_process_http_sync_connection(c); + } +} + static int http_create_request(request_rec *r) { if (!r->main && !r->prev) { @@ -237,23 +257,23 @@ static int http_send_options(request_rec *r) return DECLINED; } -static void register_hooks(apr_pool_t *p) +static int http_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) { - /** - * If we ae using an MPM That Supports Async Connections, - * use a different processing function - */ - int async_mpm = 0; - if (ap_mpm_query(AP_MPMQ_IS_ASYNC, &async_mpm) == APR_SUCCESS - && async_mpm == 1) { - ap_hook_process_connection(ap_process_http_async_connection, NULL, - NULL, APR_HOOK_REALLY_LAST); - } - else { - ap_hook_process_connection(ap_process_http_connection, NULL, NULL, - APR_HOOK_REALLY_LAST); + apr_uint64_t val; + if (ap_mpm_query(AP_MPMQ_IS_ASYNC, &async_mpm) != APR_SUCCESS) { + async_mpm = 0; } + ap_random_insecure_bytes(&val, sizeof(val)); + ap_multipart_boundary = apr_psprintf(p, "%0" APR_UINT64_T_HEX_FMT, val); + return OK; +} + +static void register_hooks(apr_pool_t *p) +{ + ap_hook_post_config(http_post_config, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_process_connection(ap_process_http_connection, NULL, NULL, + APR_HOOK_REALLY_LAST); ap_hook_map_to_storage(ap_send_http_trace,NULL,NULL,APR_HOOK_MIDDLE); ap_hook_map_to_storage(http_send_options,NULL,NULL,APR_HOOK_MIDDLE); ap_hook_http_scheme(http_scheme,NULL,NULL,APR_HOOK_REALLY_LAST); @@ -277,7 +297,7 @@ static void register_hooks(apr_pool_t *p) ap_method_registry_init(p); } -module AP_MODULE_DECLARE_DATA http_module = { +AP_DECLARE_MODULE(http) = { STANDARD20_MODULE_STUFF, NULL, /* create per-directory config structure */ NULL, /* merge per-directory config structures */ diff --git a/modules/http/http_etag.c b/modules/http/http_etag.c index a7d3d9c0..7f3c6d93 100644 --- a/modules/http/http_etag.c +++ b/modules/http/http_etag.c @@ -20,7 +20,6 @@ #define APR_WANT_STRFUNC #include "apr_want.h" -#define CORE_PRIVATE #include "httpd.h" #include "http_config.h" #include "http_connection.h" @@ -71,8 +70,7 @@ AP_DECLARE(char *) ap_make_etag(request_rec *r, int force_weak) etag_components_t etag_bits; etag_components_t bits_added; - cfg = (core_dir_config *)ap_get_module_config(r->per_dir_config, - &core_module); + cfg = (core_dir_config *)ap_get_core_module_config(r->per_dir_config); etag_bits = (cfg->etag_bits & (~ cfg->etag_remove)) | cfg->etag_add; /* @@ -110,7 +108,7 @@ AP_DECLARE(char *) ap_make_etag(request_rec *r, int force_weak) weak_len = sizeof(ETAG_WEAK); } - if (r->finfo.filetype != 0) { + if (r->finfo.filetype != APR_NOFILE) { /* * ETag gets set to [W/]"inode-size-mtime", modulo any * FileETag keywords. diff --git a/modules/http/http_filters.c b/modules/http/http_filters.c index 1aed70b2..500b5cf2 100644 --- a/modules/http/http_filters.c +++ b/modules/http/http_filters.c @@ -29,7 +29,6 @@ #define APR_WANT_MEMFUNC #include "apr_want.h" -#define CORE_PRIVATE #include "util_filter.h" #include "ap_config.h" #include "httpd.h" @@ -56,6 +55,8 @@ #include <unistd.h> #endif +APLOG_USE_MODULE(http); + #define INVALID_CHAR -2 static long get_chunk_size(char *); @@ -77,6 +78,7 @@ typedef struct http_filter_ctx { apr_bucket_brigade *bb; } http_ctx_t; +/* bail out if some error in the HTTP input filter happens */ static apr_status_t bail_out_on_error(http_ctx_t *ctx, ap_filter_t *f, int http_error) @@ -92,6 +94,11 @@ static apr_status_t bail_out_on_error(http_ctx_t *ctx, e = apr_bucket_eos_create(f->c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, e); ctx->eos_sent = 1; + /* If chunked encoding / content-length are corrupt, we may treat parts + * of this request's body as the next one's headers. + * To be safe, disable keep-alive. + */ + f->r->connection->keepalive = AP_CONN_CLOSE; return ap_pass_brigade(f->r->output_filters, bb); } @@ -103,7 +110,7 @@ static apr_status_t get_remaining_chunk_line(http_ctx_t *ctx, apr_off_t brigade_length; apr_bucket *e; const char *lineend; - apr_size_t len; + apr_size_t len = 0; /* * As the brigade b should have been requested in mode AP_MODE_GETLINE @@ -153,8 +160,9 @@ static apr_status_t get_remaining_chunk_line(http_ctx_t *ctx, if (lineend[len - 1] != APR_ASCII_LF) { return APR_EAGAIN; } - /* Line is complete. So reset ctx->linesize for next round. */ + /* Line is complete. So reset ctx for next round. */ ctx->linesize = 0; + ctx->pos = ctx->chunk_ln; return APR_SUCCESS; } @@ -259,12 +267,12 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, /* Something that isn't in HTTP, unless some future * edition defines new transfer ecodings, is unsupported. */ - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r, + ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, f->r, APLOGNO(01585) "Unknown Transfer-Encoding: %s", tenc); return bail_out_on_error(ctx, f, HTTP_NOT_IMPLEMENTED); } else { - ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, f->r, + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, f->r, APLOGNO(01586) "Unknown Transfer-Encoding: %s; using Content-Length", tenc); tenc = NULL; } @@ -273,7 +281,6 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, char *endstr; ctx->state = BODY_LENGTH; - errno = 0; /* Protects against over/underflow, non-digit chars in the * string (excluding leading space) (the endstr checks) @@ -282,7 +289,7 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, || endstr == lenp || *endstr || ctx->remaining < 0) { ctx->remaining = 0; - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r, + ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, f->r, APLOGNO(01587) "Invalid Content-Length"); return bail_out_on_error(ctx, f, HTTP_REQUEST_ENTITY_TOO_LARGE); @@ -292,7 +299,7 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, * time, stop it here if it is invalid. */ if (ctx->limit && ctx->limit < ctx->remaining) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r, + ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, f->r, APLOGNO(01588) "Requested content-length of %" APR_OFF_T_FMT " is larger than the configured limit" " of %" APR_OFF_T_FMT, ctx->remaining, ctx->limit); @@ -336,7 +343,8 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, */ f->r->expecting_100 = 0; tmp = apr_pstrcat(f->r->pool, AP_SERVER_PROTOCOL, " ", - ap_get_status_line(100), CRLF CRLF, NULL); + ap_get_status_line(HTTP_CONTINUE), CRLF CRLF, + NULL); len = strlen(tmp); ap_xlate_proto_to_ascii(tmp, len); apr_brigade_cleanup(bb); @@ -376,7 +384,7 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, ctx->remaining = get_chunk_size(ctx->chunk_ln); if (ctx->remaining == INVALID_CHAR) { rv = APR_EGENERAL; - http_error = HTTP_SERVICE_UNAVAILABLE; + http_error = HTTP_BAD_REQUEST; } } } @@ -384,11 +392,11 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, /* Detect chunksize error (such as overflow) */ if (rv != APR_SUCCESS || ctx->remaining < 0) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, "Error reading first chunk %s ", + ap_log_rerror(APLOG_MARK, APLOG_INFO, rv, f->r, APLOGNO(01589) "Error reading first chunk %s ", (ctx->remaining < 0) ? "(overflow)" : ""); ctx->remaining = 0; /* Reset it in case we have to * come back here later */ - if (APR_STATUS_IS_TIMEUP(rv)) { + if (APR_STATUS_IS_TIMEUP(rv)) { http_error = HTTP_REQUEST_TIME_OUT; } return bail_out_on_error(ctx, f, http_error); @@ -481,7 +489,7 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, ctx->remaining = get_chunk_size(ctx->chunk_ln); if (ctx->remaining == INVALID_CHAR) { rv = APR_EGENERAL; - http_error = HTTP_SERVICE_UNAVAILABLE; + http_error = HTTP_BAD_REQUEST; } } } @@ -490,11 +498,11 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, /* Detect chunksize error (such as overflow) */ if (rv != APR_SUCCESS || ctx->remaining < 0) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, "Error reading chunk %s ", + ap_log_rerror(APLOG_MARK, APLOG_INFO, rv, f->r, APLOGNO(01590) "Error reading chunk %s ", (ctx->remaining < 0) ? "(overflow)" : ""); ctx->remaining = 0; /* Reset it in case we have to * come back here later */ - if (APR_STATUS_IS_TIMEUP(rv)) { + if (APR_STATUS_IS_TIMEUP(rv)) { http_error = HTTP_REQUEST_TIME_OUT; } return bail_out_on_error(ctx, f, http_error); @@ -559,7 +567,7 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, * really count. This seems to be up for interpretation. */ ctx->limit_used += totalread; if (ctx->limit < ctx->limit_used) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r, + ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, f->r, APLOGNO(01591) "Read content-length of %" APR_OFF_T_FMT " is larger than the configured limit" " of %" APR_OFF_T_FMT, ctx->limit_used, ctx->limit); @@ -647,23 +655,10 @@ static int form_header_field(header_struct *h, #if APR_CHARSET_EBCDIC char *headfield; apr_size_t len; - apr_size_t name_len; - apr_size_t val_len; - char *next; - - name_len = strlen(fieldname); - val_len = strlen(fieldval); - len = name_len + val_len + 4; /* 4 for ": " plus CRLF */ - headfield = (char *)apr_palloc(h->pool, len + 1); - memcpy(headfield, fieldname, name_len); - next = headfield + name_len; - *next++ = ':'; - *next++ = ' '; - memcpy(next, fieldval, val_len); - next += val_len; - *next++ = CR; - *next++ = LF; - *next = 0; + + headfield = apr_pstrcat(h->pool, fieldname, ": ", fieldval, CRLF, NULL); + len = strlen(headfield); + ap_xlate_proto_to_ascii(headfield, len); apr_brigade_write(h->bb, NULL, NULL, headfield, len); #else @@ -803,6 +798,16 @@ static apr_status_t send_all_header_fields(header_struct *h, t_elt++; } while (t_elt < t_end); + if (APLOGrtrace4(r)) { + t_elt = (const apr_table_entry_t *)(elts->elts); + do { + ap_log_rerror(APLOG_MARK, APLOG_TRACE4, 0, r, " %s: %s", + ap_escape_logitem(r->pool, t_elt->key), + ap_escape_logitem(r->pool, t_elt->val)); + t_elt++; + } while (t_elt < t_end); + } + #if APR_CHARSET_EBCDIC { apr_size_t len; @@ -824,12 +829,21 @@ static void validate_status_line(request_rec *r) { char *end; - if (r->status_line - && (strlen(r->status_line) <= 4 + if (r->status_line) { + int len = strlen(r->status_line); + if (len < 3 || apr_strtoi64(r->status_line, &end, 10) != r->status - || *end != ' ' - || (end - 3) != r->status_line)) { - r->status_line = NULL; + || (end - 3) != r->status_line + || (len >= 4 && ! apr_isspace(r->status_line[3]))) { + r->status_line = NULL; + } + /* Since we passed the above check, we know that length three + * is equivalent to only a 3 digit numeric http status. + * RFC2616 mandates a trailing space, let's add it. + */ + else if (len == 3) { + r->status_line = apr_pstrcat(r->pool, r->status_line, " ", NULL); + } } } @@ -876,8 +890,10 @@ static void basic_http_header_check(request_rec *r, static void basic_http_header(request_rec *r, apr_bucket_brigade *bb, const char *protocol) { - char *date; - const char *server; + char *date = NULL; + const char *proxy_date = NULL; + const char *server = NULL; + const char *us = ap_get_server_banner(); header_struct h; struct iovec vec[4]; @@ -916,8 +932,6 @@ static void basic_http_header(request_rec *r, apr_bucket_brigade *bb, * generate a new server header / date header */ if (r->proxyreq != PROXYREQ_NONE) { - const char *proxy_date; - proxy_date = apr_table_get(r->headers_out, "Date"); if (!proxy_date) { /* @@ -927,65 +941,59 @@ static void basic_http_header(request_rec *r, apr_bucket_brigade *bb, */ date = apr_palloc(r->pool, APR_RFC822_DATE_LEN); ap_recent_rfc822_date(date, r->request_time); - proxy_date = date; } - form_header_field(&h, "Date", proxy_date); server = apr_table_get(r->headers_out, "Server"); - if (server) { - form_header_field(&h, "Server", server); - } } else { date = apr_palloc(r->pool, APR_RFC822_DATE_LEN); ap_recent_rfc822_date(date, r->request_time); - form_header_field(&h, "Date", date); - form_header_field(&h, "Server", ap_get_server_banner()); } + form_header_field(&h, "Date", proxy_date ? proxy_date : date ); + + if (!server && *us) + server = us; + if (server) + form_header_field(&h, "Server", server); + + if (APLOGrtrace3(r)) { + ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r, + "Response sent with status %d%s", + r->status, + APLOGrtrace4(r) ? ", headers:" : ""); + + /* + * Date and Server are less interesting, use TRACE5 for them while + * using TRACE4 for the other headers. + */ + ap_log_rerror(APLOG_MARK, APLOG_TRACE5, 0, r, " %s: %s", "Date", + proxy_date ? proxy_date : date ); + if (server) + ap_log_rerror(APLOG_MARK, APLOG_TRACE5, 0, r, " %s: %s", "Server", + server); + } + + /* unset so we don't send them again */ apr_table_unset(r->headers_out, "Date"); /* Avoid bogosity */ - apr_table_unset(r->headers_out, "Server"); + if (server) { + apr_table_unset(r->headers_out, "Server"); + } } AP_DECLARE(void) ap_basic_http_header(request_rec *r, apr_bucket_brigade *bb) { - const char *protocol; + const char *protocol = NULL; basic_http_header_check(r, &protocol); basic_http_header(r, bb, protocol); } -/* Navigator versions 2.x, 3.x and 4.0 betas up to and including 4.0b2 - * have a header parsing bug. If the terminating \r\n occur starting - * at offset 256, 257 or 258 of output then it will not properly parse - * the headers. Curiously it doesn't exhibit this problem at 512, 513. - * We are guessing that this is because their initial read of a new request - * uses a 256 byte buffer, and subsequent reads use a larger buffer. - * So the problem might exist at different offsets as well. - * - * This should also work on keepalive connections assuming they use the - * same small buffer for the first read of each new request. - * - * At any rate, we check the bytes written so far and, if we are about to - * tickle the bug, we instead insert a bogus padding header. Since the bug - * manifests as a broken image in Navigator, users blame the server. :( - * It is more expensive to check the User-Agent than it is to just add the - * bytes, so we haven't used the BrowserMatch feature here. - */ static void terminate_header(apr_bucket_brigade *bb) { - char tmp[] = "X-Pad: avoid browser bug" CRLF; char crlf[] = CRLF; - apr_off_t len; apr_size_t buflen; - (void) apr_brigade_length(bb, 1, &len); - - if (len >= 255 && len <= 257) { - buflen = strlen(tmp); - ap_xlate_proto_to_ascii(tmp, buflen); - apr_brigade_write(bb, NULL, NULL, tmp, buflen); - } buflen = strlen(crlf); ap_xlate_proto_to_ascii(crlf, buflen); apr_brigade_write(bb, NULL, NULL, crlf, buflen); @@ -1012,8 +1020,7 @@ AP_DECLARE_NONSTD(int) ap_send_http_trace(request_rec *r) while (r->prev) { r = r->prev; } - conf = (core_server_config *)ap_get_module_config(r->server->module_config, - &core_module); + conf = ap_get_core_module_config(r->server->module_config); if (conf->trace_enable == AP_TRACE_DISABLE) { apr_table_setn(r->notes, "error-notes", @@ -1022,7 +1029,7 @@ AP_DECLARE_NONSTD(int) ap_send_http_trace(request_rec *r) } if (conf->trace_enable == AP_TRACE_EXTENDED) - /* XX should be = REQUEST_CHUNKED_PASS */ + /* XXX: should be = REQUEST_CHUNKED_PASS */ body = REQUEST_CHUNKED_DECHUNK; else body = REQUEST_NO_BODY; @@ -1118,7 +1125,7 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f, request_rec *r = f->r; conn_rec *c = r->connection; const char *clheader; - const char *protocol; + const char *protocol = NULL; apr_bucket *e; apr_bucket_brigade *b2; header_struct h; @@ -1191,7 +1198,7 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f, if (apr_table_get(r->subprocess_env, "force-no-vary") != NULL) { apr_table_unset(r->headers_out, "Vary"); r->proto_num = HTTP_VERSION(1,0); - apr_table_set(r->subprocess_env, "force-response-1.0", "1"); + apr_table_setn(r->subprocess_env, "force-response-1.0", "1"); } else { fixup_vary(r); @@ -1215,7 +1222,7 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f, } ctype = ap_make_content_type(r, r->content_type); - if (strcasecmp(ctype, NO_CONTENT_TYPE)) { + if (ctype) { apr_table_setn(r->headers_out, "Content-Type", ctype); } @@ -1464,12 +1471,12 @@ AP_DECLARE(int) ap_setup_client_block(request_rec *r, int read_policy) if (tenc) { if (strcasecmp(tenc, "chunked")) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(01592) "Unknown Transfer-Encoding %s", tenc); return HTTP_NOT_IMPLEMENTED; } if (r->read_body == REQUEST_CHUNKED_ERROR) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(01593) "chunked Transfer-Encoding forbidden: %s", r->uri); return (lenp) ? HTTP_BAD_REQUEST : HTTP_LENGTH_REQUIRED; } @@ -1482,7 +1489,7 @@ AP_DECLARE(int) ap_setup_client_block(request_rec *r, int read_policy) if (apr_strtoff(&r->remaining, lenp, &endstr, 10) || *endstr || r->remaining < 0) { r->remaining = 0; - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(01594) "Invalid Content-Length"); return HTTP_BAD_REQUEST; } @@ -1490,7 +1497,7 @@ AP_DECLARE(int) ap_setup_client_block(request_rec *r, int read_policy) if ((r->read_body == REQUEST_NO_BODY) && (r->read_chunked || (r->remaining > 0))) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(01595) "%s with body is not allowed for %s", r->method, r->uri); return HTTP_REQUEST_ENTITY_TOO_LARGE; } @@ -1499,8 +1506,7 @@ AP_DECLARE(int) ap_setup_client_block(request_rec *r, int read_policy) { /* Make sure ap_getline() didn't leave any droppings. */ core_request_config *req_cfg = - (core_request_config *)ap_get_module_config(r->request_config, - &core_module); + (core_request_config *)ap_get_core_module_config(r->request_config); AP_DEBUG_ASSERT(APR_BRIGADE_EMPTY(req_cfg->bb)); } #endif @@ -1663,4 +1669,3 @@ apr_status_t ap_http_outerror_filter(ap_filter_t *f, return ap_pass_brigade(f->next, b); } - diff --git a/modules/http/http_protocol.c b/modules/http/http_protocol.c index 6812c490..10165478 100644 --- a/modules/http/http_protocol.c +++ b/modules/http/http_protocol.c @@ -32,7 +32,6 @@ #define APR_WANT_MEMFUNC #include "apr_want.h" -#define CORE_PRIVATE #include "util_filter.h" #include "ap_config.h" #include "httpd.h" @@ -59,21 +58,15 @@ #include <unistd.h> #endif +APLOG_USE_MODULE(http); + /* New Apache routine to map status codes into array indicies * e.g. 100 -> 0, 101 -> 1, 200 -> 2 ... * The number of status lines must equal the value of RESPONSE_CODES (httpd.h) * and must be listed in order. */ -#ifdef UTS21 -/* The second const triggers an assembler bug on UTS 2.1. - * Another workaround is to move some code out of this file into another, - * but this is easier. Dave Dykstra, 3/31/99 - */ -static const char * status_lines[RESPONSE_CODES] = -#else static const char * const status_lines[RESPONSE_CODES] = -#endif { "100 Continue", "101 Switching Protocols", @@ -158,6 +151,21 @@ AP_IMPLEMENT_HOOK_VOID(insert_error_filter, (request_rec *r), (r)) */ #define METHOD_NUMBER_LAST 62 +static int is_mpm_running(void) +{ + int mpm_state = 0; + + if (ap_mpm_query(AP_MPMQ_MPM_STATE, &mpm_state)) { + return 0; + } + + if (mpm_state == AP_MPMQ_STOPPING) { + return 0; + } + + return 1; +} + AP_DECLARE(int) ap_set_keepalive(request_rec *r) { @@ -220,7 +228,7 @@ AP_DECLARE(int) ap_set_keepalive(request_rec *r) || apr_table_get(r->headers_in, "Via")) && ((ka_sent = ap_find_token(r->pool, conn, "keep-alive")) || (r->proto_num >= HTTP_VERSION(1,1))) - && !ap_graceful_stop_signalled()) { + && is_mpm_running()) { r->connection->keepalive = AP_CONN_KEEPALIVE; r->connection->keepalives++; @@ -489,7 +497,7 @@ AP_DECLARE(int) ap_method_register(apr_pool_t *p, const char *methname) /* The method registry has run out of dynamically * assignable method numbers. Log this and return M_INVALID. */ - ap_log_perror(APLOG_MARK, APLOG_ERR, 0, p, + ap_log_perror(APLOG_MARK, APLOG_ERR, 0, p, APLOGNO(01610) "Maximum new request methods %d reached while " "registering method %s.", METHOD_NUMBER_LAST, methname); @@ -773,7 +781,7 @@ static char *make_allow(request_rec *r) apr_hash_index_t *hi = apr_hash_first(r->pool, methods_registry); /* For TRACE below */ core_server_config *conf = - ap_get_module_config(r->server->module_config, &core_module); + ap_get_core_module_config(r->server->module_config); mask = r->allowed_methods->method_mask; @@ -838,19 +846,12 @@ AP_DECLARE(void) ap_set_content_type(request_rec *r, const char *ct) } else if (!r->content_type || strcmp(r->content_type, ct)) { r->content_type = ct; - - /* Insert filters requested by the AddOutputFiltersByType - * configuration directive. Content-type filters must be - * inserted after the content handlers have run because - * only then, do we reliably know the content-type. - */ - ap_add_output_filters_by_type(r); } } AP_DECLARE(void) ap_set_accept_ranges(request_rec *r) { - core_dir_config *d = ap_get_module_config(r->per_dir_config, &core_module); + core_dir_config *d = ap_get_core_module_config(r->per_dir_config); apr_table_setn(r->headers_out, "Accept-Ranges", (d->max_ranges == AP_MAXRANGES_NORANGES) ? "none" : "bytes"); @@ -1084,14 +1085,13 @@ static const char *get_canned_error_string(int status, "misconfiguration and was unable to complete\n" "your request.</p>\n" "<p>Please contact the server " - "administrator,\n ", + "administrator at \n ", ap_escape_html(r->pool, r->server->server_admin), - " and inform them of the time the " + " to inform them of the time this " "error occurred,\n" - "and anything you might have done that " - "may have\n" - "caused the error.</p>\n" + " and the actions you performed just before " + "this error.</p>\n" "<p>More information about this error " "may be available\n" "in the server error log.</p>\n", @@ -1193,7 +1193,7 @@ AP_DECLARE(void) ap_send_error_response(request_rec *r, int recursive_error) if (apr_table_get(r->subprocess_env, "suppress-error-charset") != NULL) { core_request_config *request_conf = - ap_get_module_config(r->request_config, &core_module); + ap_get_core_module_config(r->request_config); request_conf->suppress_charset = 1; /* avoid adding default * charset later */ @@ -1242,16 +1242,28 @@ AP_DECLARE(void) ap_send_error_response(request_rec *r, int recursive_error) const char *h1; /* Accept a status_line set by a module, but only if it begins - * with the 3 digit status code + * with the correct 3 digit status code */ - if (r->status_line != NULL - && strlen(r->status_line) > 4 /* long enough */ - && apr_isdigit(r->status_line[0]) - && apr_isdigit(r->status_line[1]) - && apr_isdigit(r->status_line[2]) - && apr_isspace(r->status_line[3]) - && apr_isalnum(r->status_line[4])) { - title = r->status_line; + if (r->status_line) { + char *end; + int len = strlen(r->status_line); + if (len >= 3 + && apr_strtoi64(r->status_line, &end, 10) == r->status + && (end - 3) == r->status_line + && (len < 4 || apr_isspace(r->status_line[3])) + && (len < 5 || apr_isalnum(r->status_line[4]))) { + /* Since we passed the above check, we know that length three + * is equivalent to only a 3 digit numeric http status. + * RFC2616 mandates a trailing space, let's add it. + * If we have an empty reason phrase, we also add "Unknown Reason". + */ + if (len == 3) { + r->status_line = apr_pstrcat(r->pool, r->status_line, " Unknown Reason", NULL); + } else if (len == 4) { + r->status_line = apr_pstrcat(r->pool, r->status_line, "Unknown Reason", NULL); + } + title = r->status_line; + } } /* folks decided they didn't want the error code in the H1 text */ diff --git a/modules/http/http_request.c b/modules/http/http_request.c index 9d63aca8..ce16de92 100644 --- a/modules/http/http_request.c +++ b/modules/http/http_request.c @@ -31,7 +31,6 @@ #define APR_WANT_STRFUNC #include "apr_want.h" -#define CORE_PRIVATE #include "ap_config.h" #include "httpd.h" #include "http_config.h" @@ -50,6 +49,8 @@ #include <stdarg.h> #endif +APLOG_USE_MODULE(http); + /***************************************************************** * * Mainline request processing... @@ -98,7 +99,7 @@ AP_DECLARE(void) ap_die(int type, request_rec *r) * next->frec == ap_http_header_filter */ if (next) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01579) "Custom error page caused AP_FILTER_ERROR"); type = HTTP_INTERNAL_SERVER_ERROR; } @@ -207,7 +208,7 @@ AP_DECLARE(void) ap_die(int type, request_rec *r) * dying with a recursive server error... */ recursive_error = HTTP_INTERNAL_SERVER_ERROR; - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01580) "Invalid error redirection directive: %s", custom_response); } @@ -215,48 +216,62 @@ AP_DECLARE(void) ap_die(int type, request_rec *r) ap_send_error_response(r_1st_err, recursive_error); } -static void check_pipeline_flush(request_rec *r) +static void check_pipeline(conn_rec *c) { - apr_bucket *e; - apr_bucket_brigade *bb; - conn_rec *c = r->connection; - /* ### if would be nice if we could PEEK without a brigade. that would - ### allow us to defer creation of the brigade to when we actually - ### need to send a FLUSH. */ - bb = apr_brigade_create(r->pool, c->bucket_alloc); + if (c->keepalive != AP_CONN_CLOSE) { + apr_status_t rv; + apr_bucket_brigade *bb = apr_brigade_create(c->pool, c->bucket_alloc); - /* Flush the filter contents if: - * - * 1) the connection will be closed - * 2) there isn't a request ready to be read - */ - /* ### shouldn't this read from the connection input filters? */ - /* ### is zero correct? that means "read one line" */ - if (r->connection->keepalive != AP_CONN_CLOSE) { - if (ap_get_brigade(r->input_filters, bb, AP_MODE_EATCRLF, - APR_NONBLOCK_READ, 0) != APR_SUCCESS) { - c->data_in_input_filters = 0; /* we got APR_EOF or an error */ + rv = ap_get_brigade(c->input_filters, bb, AP_MODE_SPECULATIVE, + APR_NONBLOCK_READ, 1); + if (rv != APR_SUCCESS || APR_BRIGADE_EMPTY(bb)) { + /* + * Error or empty brigade: There is no data present in the input + * filter + */ + c->data_in_input_filters = 0; } else { c->data_in_input_filters = 1; - return; /* don't flush */ } + apr_brigade_destroy(bb); } +} - e = apr_bucket_flush_create(c->bucket_alloc); - /* We just send directly to the connection based filters. At - * this point, we know that we have seen all of the data - * (request finalization sent an EOS bucket, which empties all - * of the request filters). We just want to flush the buckets - * if something hasn't been sent to the network yet. - */ - APR_BRIGADE_INSERT_HEAD(bb, e); - ap_pass_brigade(r->connection->output_filters, bb); +AP_DECLARE(void) ap_process_request_after_handler(request_rec *r) +{ + apr_bucket_brigade *bb; + apr_bucket *b; + conn_rec *c = r->connection; + + /* Send an EOR bucket through the output filter chain. When + * this bucket is destroyed, the request will be logged and + * its pool will be freed + */ + bb = apr_brigade_create(r->connection->pool, r->connection->bucket_alloc); + b = ap_bucket_eor_create(r->connection->bucket_alloc, r); + APR_BRIGADE_INSERT_HEAD(bb, b); + + ap_pass_brigade(r->connection->output_filters, bb); + + /* From here onward, it is no longer safe to reference r + * or r->pool, because r->pool may have been destroyed + * already by the EOR bucket's cleanup function. + */ + + if (c->cs) + c->cs->state = CONN_STATE_WRITE_COMPLETION; + check_pipeline(c); + AP_PROCESS_REQUEST_RETURN((uintptr_t)r, r->uri, r->status); + if (ap_extended_status) { + ap_time_process_request(c->sbh, STOP_PREQUEST); + } } -void ap_process_request(request_rec *r) +void ap_process_async_request(request_rec *r) { + conn_rec *c = r->connection; int access_status; /* Give quick handlers a shot at serving the request on the fast @@ -273,8 +288,28 @@ void ap_process_request(request_rec *r) * Use this hook with extreme care and only if you know what you are * doing. */ - if (ap_extended_status) + AP_PROCESS_REQUEST_ENTRY((uintptr_t)r, r->uri); + if (ap_extended_status) { ap_time_process_request(r->connection->sbh, START_PREQUEST); + } + + if (APLOGrtrace4(r)) { + int i; + const apr_array_header_t *t_h = apr_table_elts(r->headers_in); + const apr_table_entry_t *t_elt = (apr_table_entry_t *)t_h->elts; + ap_log_rerror(APLOG_MARK, APLOG_TRACE4, 0, r, + "Headers received from client:"); + for (i = 0; i < t_h->nelts; i++, t_elt++) { + ap_log_rerror(APLOG_MARK, APLOG_TRACE4, 0, r, " %s: %s", + ap_escape_logitem(r->pool, t_elt->key), + ap_escape_logitem(r->pool, t_elt->val)); + } + } + +#if APR_HAS_THREADS + apr_thread_mutex_create(&r->invoke_mtx, APR_THREAD_MUTEX_DEFAULT, r->pool); + apr_thread_mutex_lock(r->invoke_mtx); +#endif access_status = ap_run_quick_handler(r, 0); /* Not a look-up request */ if (access_status == DECLINED) { access_status = ap_process_request_internal(r); @@ -283,6 +318,25 @@ void ap_process_request(request_rec *r) } } + if (access_status == SUSPENDED) { + /* TODO: Should move these steps into a generic function, so modules + * working on a suspended request can also call _ENTRY again. + */ + AP_PROCESS_REQUEST_RETURN((uintptr_t)r, r->uri, access_status); + if (ap_extended_status) { + ap_time_process_request(c->sbh, STOP_PREQUEST); + } + if (c->cs) + c->cs->state = CONN_STATE_SUSPENDED; +#if APR_HAS_THREADS + apr_thread_mutex_unlock(r->invoke_mtx); +#endif + return; + } +#if APR_HAS_THREADS + apr_thread_mutex_unlock(r->invoke_mtx); +#endif + if (access_status == DONE) { /* e.g., something not in storage like TRACE */ access_status = OK; @@ -296,18 +350,40 @@ void ap_process_request(request_rec *r) ap_die(access_status, r); } - /* - * We want to flush the last packet if this isn't a pipelining connection - * *before* we start into logging. Suppose that the logging causes a DNS - * lookup to occur, which may have a high latency. If we hold off on - * this packet, then it'll appear like the link is stalled when really - * it's the application that's stalled. - */ - check_pipeline_flush(r); - ap_update_child_status(r->connection->sbh, SERVER_BUSY_LOG, r); - ap_run_log_transaction(r); - if (ap_extended_status) - ap_time_process_request(r->connection->sbh, STOP_PREQUEST); + ap_process_request_after_handler(r); +} + +void ap_process_request(request_rec *r) +{ + apr_bucket_brigade *bb; + apr_bucket *b; + conn_rec *c = r->connection; + apr_status_t rv; + + ap_process_async_request(r); + + if (!c->data_in_input_filters) { + bb = apr_brigade_create(c->pool, c->bucket_alloc); + b = apr_bucket_flush_create(c->bucket_alloc); + APR_BRIGADE_INSERT_HEAD(bb, b); + rv = ap_pass_brigade(c->output_filters, bb); + if (APR_STATUS_IS_TIMEUP(rv)) { + /* + * Notice a timeout as an error message. This might be + * valuable for detecting clients with broken network + * connections or possible DoS attacks. + * + * It is still safe to use r / r->pool here as the eor bucket + * could not have been destroyed in the event of a timeout. + */ + ap_log_rerror(APLOG_MARK, APLOG_INFO, rv, r, APLOGNO(01581) + "Timeout while writing data for URI %s to the" + " client", r->unparsed_uri); + } + } + if (ap_extended_status) { + ap_time_process_request(c->sbh, STOP_PREQUEST); + } } static apr_table_t *rename_original_env(apr_pool_t *p, apr_table_t *t) @@ -363,6 +439,9 @@ static request_rec *internal_internal_redirect(const char *new_uri, new->prev = r; r->next = new; + new->useragent_addr = r->useragent_addr; + new->useragent_ip = r->useragent_ip; + /* Must have prev and next pointers set before calling create_request * hook. */ @@ -385,6 +464,11 @@ static request_rec *internal_internal_redirect(const char *new_uri, new->headers_in = r->headers_in; new->headers_out = apr_table_make(r->pool, 12); + if (ap_is_HTTP_REDIRECT(new->status)) { + const char *location = apr_table_get(r->headers_out, "Location"); + if (location) + apr_table_setn(new->headers_out, "Location", location); + } new->err_headers_out = r->err_headers_out; new->subprocess_env = rename_original_env(r->pool, r->subprocess_env); new->notes = apr_table_make(r->pool, 5); @@ -416,7 +500,7 @@ static request_rec *internal_internal_redirect(const char *new_uri, nextf = f->next; if (f->r == r && f->frec != ap_subreq_core_filter_handle) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01582) "dropping filter '%s' in internal redirect from %s to %s", f->frec->name, r->unparsed_uri, new_uri); @@ -542,6 +626,8 @@ AP_DECLARE(void) ap_internal_redirect(const char *new_uri, request_rec *r) request_rec *new = internal_internal_redirect(new_uri, r); int access_status; + AP_INTERNAL_REDIRECT(r->uri, new_uri); + /* ap_die was already called, if an error occured */ if (!new) { return; diff --git a/modules/http/mod_core.h b/modules/http/mod_core.h deleted file mode 100644 index 79810d00..00000000 --- a/modules/http/mod_core.h +++ /dev/null @@ -1,95 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -/** - * @file mod_core.h - * @brief mod_core private header file - * - * @defgroup MOD_CORE mod_core - * @ingroup APACHE_MODS - * @{ - */ - -#ifndef MOD_CORE_H -#define MOD_CORE_H - -#include "apr.h" -#include "apr_buckets.h" - -#include "httpd.h" -#include "util_filter.h" - - -#ifdef __cplusplus -extern "C" { -#endif - -/* Handles for core filters */ -extern AP_DECLARE_DATA ap_filter_rec_t *ap_http_input_filter_handle; -extern AP_DECLARE_DATA ap_filter_rec_t *ap_http_header_filter_handle; -extern AP_DECLARE_DATA ap_filter_rec_t *ap_chunk_filter_handle; -extern AP_DECLARE_DATA ap_filter_rec_t *ap_http_outerror_filter_handle; -extern AP_DECLARE_DATA ap_filter_rec_t *ap_byterange_filter_handle; - -/* - * These (input) filters are internal to the mod_core operation. - */ -apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, - ap_input_mode_t mode, apr_read_type_e block, - apr_off_t readbytes); - -/* HTTP/1.1 chunked transfer encoding filter. */ -apr_status_t ap_http_chunk_filter(ap_filter_t *f, apr_bucket_brigade *b); - -/* Filter to handle any error buckets on output */ -apr_status_t ap_http_outerror_filter(ap_filter_t *f, - apr_bucket_brigade *b); - -char *ap_response_code_string(request_rec *r, int error_index); - -/** - * Send the minimal part of an HTTP response header. - * @param r The current request - * @param bb The brigade to add the header to. - * @warning Modules should be very careful about using this, and should - * the default behavior. Much of the HTTP/1.1 implementation - * correctness depends on the full headers. - * @deffunc void ap_basic_http_header(request_rec *r, apr_bucket_brigade *bb) - */ -AP_DECLARE(void) ap_basic_http_header(request_rec *r, apr_bucket_brigade *bb); - -/** - * Send an appropriate response to an http TRACE request. - * @param r The current request - * @tip returns DONE or the HTTP status error if it handles the TRACE, - * or DECLINED if the request was not for TRACE. - * request method was not TRACE. - */ -AP_DECLARE_NONSTD(int) ap_send_http_trace(request_rec *r); - -/** - * Send an appropriate response to an http OPTIONS request. - * @param r The current request - */ -AP_DECLARE(int) ap_send_http_options(request_rec *r); - -#ifdef __cplusplus -} -#endif - -#endif /* !MOD_CORE_H */ -/** @} */ diff --git a/modules/http/mod_mime.c b/modules/http/mod_mime.c index eed6ebd9..9e445544 100644 --- a/modules/http/mod_mime.c +++ b/modules/http/mod_mime.c @@ -182,10 +182,10 @@ static void remove_items(apr_pool_t *p, apr_array_header_t *remove, APR_HASH_KEY_STRING); if (exinfo && *(const char**)((char *)exinfo + suffix[i].offset)) { extension_info *copyinfo = exinfo; - exinfo = (extension_info*)apr_palloc(p, sizeof(*exinfo)); + exinfo = apr_pmemdup(p, copyinfo, sizeof(*exinfo)); apr_hash_set(mappings, suffix[i].name, APR_HASH_KEY_STRING, exinfo); - memcpy(exinfo, copyinfo, sizeof(*exinfo)); + *(const char**)((char *)exinfo + suffix[i].offset) = NULL; } } @@ -440,7 +440,7 @@ static int mime_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, types_confname = ap_server_root_relative(p, types_confname); if (!types_confname) { - ap_log_error(APLOG_MARK, APLOG_ERR, APR_EBADPATH, s, + ap_log_error(APLOG_MARK, APLOG_ERR, APR_EBADPATH, s, APLOGNO(01596) "Invalid mime types config path %s", (const char *)ap_get_module_config(s->module_config, &mime_module)); @@ -448,7 +448,7 @@ static int mime_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, } if ((status = ap_pcfg_openfile(&f, ptemp, types_confname)) != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_ERR, status, s, + ap_log_error(APLOG_MARK, APLOG_ERR, status, s, APLOGNO(01597) "could not open mime types config file %s.", types_confname); return HTTP_INTERNAL_SERVER_ERROR; @@ -562,7 +562,7 @@ static content_type *analyze_ct(request_rec *r, const char *s) cp++; } if (!*cp) { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, APLOGNO(01598) "mod_mime: analyze_ct: cannot get media type from '%s'", (const char *) mp); return (NULL); @@ -572,7 +572,7 @@ static content_type *analyze_ct(request_rec *r, const char *s) cp++; } while (*cp && (*cp != '/') && !apr_isspace(*cp) && (*cp != ';')); if (!*cp || (*cp == ';')) { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, APLOGNO(01599) "Cannot get media type from '%s'", (const char *) mp); return (NULL); @@ -581,7 +581,7 @@ static content_type *analyze_ct(request_rec *r, const char *s) cp++; } if (*cp != '/') { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, APLOGNO(01600) "mod_mime: analyze_ct: cannot get media type from '%s'", (const char *) mp); return (NULL); @@ -595,7 +595,7 @@ static content_type *analyze_ct(request_rec *r, const char *s) cp++; } if (!*cp) { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, APLOGNO(01601) "Cannot get media subtype."); return (NULL); } @@ -616,7 +616,7 @@ static content_type *analyze_ct(request_rec *r, const char *s) cp++; /* skip the ';' */ cp = zap_sp(cp); if (cp == NULL || *cp == '\0') { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, APLOGNO(01602) "Cannot get media parameter."); return (NULL); } @@ -637,14 +637,14 @@ static content_type *analyze_ct(request_rec *r, const char *s) else if (*cp == '=') { attribute = zap_sp_and_dup(p, mp, cp, NULL); if (attribute == NULL || *attribute == '\0') { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, APLOGNO(01603) "Cannot get media parameter."); return (NULL); } cp++; cp = zap_sp(cp); if (cp == NULL || *cp == '\0') { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, APLOGNO(01604) "Cannot get media parameter."); return (NULL); } @@ -652,7 +652,7 @@ static content_type *analyze_ct(request_rec *r, const char *s) continue; } else { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, APLOGNO(01605) "Cannot get media parameter."); return (NULL); } @@ -681,14 +681,14 @@ static content_type *analyze_ct(request_rec *r, const char *s) cp++; } if (*cp != ';' && *cp != '\0') { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, APLOGNO(01606) "Cannot get media parameter."); return(NULL); } quoted = 0; } else { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, APLOGNO(01607) "Cannot get media parameter."); return (NULL); } @@ -703,7 +703,7 @@ static content_type *analyze_ct(request_rec *r, const char *s) break; } else { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, APLOGNO(01608) "Cannot get media parameter."); return (NULL); } @@ -711,7 +711,7 @@ static content_type *analyze_ct(request_rec *r, const char *s) } value = zap_sp_and_dup(p, mp, cp, NULL); if (value == NULL || *value == '\0') { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ss, APLOGNO(01609) "Cannot get media parameter."); return (NULL); } @@ -755,7 +755,7 @@ static int find_ct(request_rec *r) mime_dir_config *conf; apr_array_header_t *exception_list; char *ext; - const char *fn, *type, *charset = NULL, *resource_name; + const char *fn, *fntmp, *type, *charset = NULL, *resource_name; int found_metadata = 0; if (r->finfo.filetype == APR_DIR) { @@ -788,12 +788,27 @@ static int find_ct(request_rec *r) ++fn; } + /* The exception list keeps track of those filename components that * are not associated with extensions indicating metadata. * The base name is always the first exception (i.e., "txt.html" has * a basename of "txt" even though it might look like an extension). + * Leading dots are considered to be part of the base name (a file named + * ".png" is likely not a png file but just a hidden file called png). */ - ext = ap_getword(r->pool, &fn, '.'); + fntmp = fn; + while (*fntmp == '.') + fntmp++; + fntmp = ap_strchr_c(fntmp, '.'); + if (fntmp) { + ext = apr_pstrmemdup(r->pool, fn, fntmp - fn); + fn = fntmp + 1; + } + else { + ext = apr_pstrdup(r->pool, fn); + fn += strlen(fn); + } + *((const char **)apr_array_push(exception_list)) = ext; /* Parse filename extensions which can be in any order @@ -801,6 +816,7 @@ static int find_ct(request_rec *r) while (*fn && (ext = ap_getword(r->pool, &fn, '.'))) { const extension_info *exinfo = NULL; int found; + char *extcase; if (*ext == '\0') { /* ignore empty extensions "bad..html" */ continue; @@ -808,6 +824,9 @@ static int find_ct(request_rec *r) found = 0; + /* Save the ext in extcase before converting it to lower case. + */ + extcase = apr_pstrdup(r->pool, ext); ap_str_tolower(ext); if (conf->extension_mappings != NULL) { @@ -863,7 +882,7 @@ static int find_ct(request_rec *r) found = 1; } /* The following extensions are not 'Found'. That is, they don't - * make any contribution to metadata negotation, so they must have + * make any contribution to metadata negotiation, so they must have * been explicitly requested by name. */ if (exinfo->handler && r->proxyreq == PROXYREQ_NONE) { @@ -873,8 +892,8 @@ static int find_ct(request_rec *r) } } /* XXX Two significant problems; 1, we don't check to see if we are - * setting redundant filters. 2, we insert these in the types config - * hook, which may be too early (dunno.) + * setting redundant filters. 2, we insert these in the types + * config hook, which may be too early (dunno.) */ if (exinfo->input_filters && r->proxyreq == PROXYREQ_NONE) { const char *filter, *filters = exinfo->input_filters; @@ -902,7 +921,7 @@ static int find_ct(request_rec *r) found_metadata = 1; } else { - *((const char **) apr_array_push(exception_list)) = ext; + *((const char **) apr_array_push(exception_list)) = extcase; } } @@ -996,7 +1015,7 @@ static void register_hooks(apr_pool_t *p) */ } -module AP_MODULE_DECLARE_DATA mime_module = { +AP_DECLARE_MODULE(mime) = { STANDARD20_MODULE_STUFF, create_mime_dir_config, /* create per-directory config structure */ merge_mime_dir_configs, /* merge per-directory config structures */ diff --git a/modules/http/mod_mime.dep b/modules/http/mod_mime.dep deleted file mode 100644 index 9f977b42..00000000 --- a/modules/http/mod_mime.dep +++ /dev/null @@ -1,29 +0,0 @@ -# Microsoft Developer Studio Generated Dependency File, included by mod_mime.mak - -..\..\build\win32\httpd.rc : \ - "..\..\include\ap_release.h"\ - - -.\mod_mime.c : \ - "..\..\include\ap_config.h"\ - "..\..\include\ap_mmn.h"\ - "..\..\include\ap_regex.h"\ - "..\..\include\ap_release.h"\ - "..\..\include\http_config.h"\ - "..\..\include\http_log.h"\ - "..\..\include\http_protocol.h"\ - "..\..\include\http_request.h"\ - "..\..\include\httpd.h"\ - "..\..\include\os.h"\ - "..\..\include\util_cfgtree.h"\ - "..\..\include\util_filter.h"\ - "..\..\srclib\apr-util\include\apr_hooks.h"\ - "..\..\srclib\apr-util\include\apr_optional_hooks.h"\ - "..\..\srclib\apr-util\include\apr_uri.h"\ - "..\..\srclib\apr\include\apr_hash.h"\ - "..\..\srclib\apr\include\apr_lib.h"\ - "..\..\srclib\apr\include\apr_mmap.h"\ - "..\..\srclib\apr\include\apr_poll.h"\ - "..\..\srclib\apr\include\apr_portable.h"\ - "..\..\srclib\apr\include\apr_strings.h"\ - diff --git a/modules/http/mod_mime.mak b/modules/http/mod_mime.mak deleted file mode 100644 index e2e945bf..00000000 --- a/modules/http/mod_mime.mak +++ /dev/null @@ -1,353 +0,0 @@ -# Microsoft Developer Studio Generated NMAKE File, Based on mod_mime.dsp -!IF "$(CFG)" == "" -CFG=mod_mime - Win32 Release -!MESSAGE No configuration specified. Defaulting to mod_mime - Win32 Release. -!ENDIF - -!IF "$(CFG)" != "mod_mime - Win32 Release" && "$(CFG)" != "mod_mime - Win32 Debug" -!MESSAGE Invalid configuration "$(CFG)" specified. -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "mod_mime.mak" CFG="mod_mime - Win32 Release" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "mod_mime - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "mod_mime - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE -!ERROR An invalid configuration is specified. -!ENDIF - -!IF "$(OS)" == "Windows_NT" -NULL= -!ELSE -NULL=nul -!ENDIF - -!IF "$(CFG)" == "mod_mime - Win32 Release" - -OUTDIR=.\Release -INTDIR=.\Release -DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep -# Begin Custom Macros -OutDir=.\Release -# End Custom Macros - -!IF "$(RECURSE)" == "0" - -ALL : "$(OUTDIR)\mod_mime.so" "$(DS_POSTBUILD_DEP)" - -!ELSE - -ALL : "libhttpd - Win32 Release" "libaprutil - Win32 Release" "libapr - Win32 Release" "$(OUTDIR)\mod_mime.so" "$(DS_POSTBUILD_DEP)" - -!ENDIF - -!IF "$(RECURSE)" == "1" -CLEAN :"libapr - Win32 ReleaseCLEAN" "libaprutil - Win32 ReleaseCLEAN" "libhttpd - Win32 ReleaseCLEAN" -!ELSE -CLEAN : -!ENDIF - -@erase "$(INTDIR)\mod_mime.obj" - -@erase "$(INTDIR)\mod_mime.res" - -@erase "$(INTDIR)\mod_mime_src.idb" - -@erase "$(INTDIR)\mod_mime_src.pdb" - -@erase "$(OUTDIR)\mod_mime.exp" - -@erase "$(OUTDIR)\mod_mime.lib" - -@erase "$(OUTDIR)\mod_mime.pdb" - -@erase "$(OUTDIR)\mod_mime.so" - -"$(OUTDIR)" : - if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" - -CPP=cl.exe -CPP_PROJ=/nologo /MD /W3 /Zi /O2 /Oy- /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_mime_src" /FD /c - -.c{$(INTDIR)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(INTDIR)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(INTDIR)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.c{$(INTDIR)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(INTDIR)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(INTDIR)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -MTL=midl.exe -MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 -RSC=rc.exe -RSC_PROJ=/l 0x409 /fo"$(INTDIR)\mod_mime.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_mime.so" /d LONG_NAME="mime_module for Apache" -BSC32=bscmake.exe -BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_mime.bsc" -BSC32_SBRS= \ - -LINK32=link.exe -LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_mime.pdb" /debug /out:"$(OUTDIR)\mod_mime.so" /implib:"$(OUTDIR)\mod_mime.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_mime.so /opt:ref -LINK32_OBJS= \ - "$(INTDIR)\mod_mime.obj" \ - "$(INTDIR)\mod_mime.res" \ - "..\..\srclib\apr\Release\libapr-1.lib" \ - "..\..\srclib\apr-util\Release\libaprutil-1.lib" \ - "..\..\Release\libhttpd.lib" - -"$(OUTDIR)\mod_mime.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -TargetPath=.\Release\mod_mime.so -SOURCE="$(InputPath)" -PostBuild_Desc=Embed .manifest -DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep - -# Begin Custom Macros -OutDir=.\Release -# End Custom Macros - -"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\mod_mime.so" - if exist .\Release\mod_mime.so.manifest mt.exe -manifest .\Release\mod_mime.so.manifest -outputresource:.\Release\mod_mime.so;2 - echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" - -!ELSEIF "$(CFG)" == "mod_mime - Win32 Debug" - -OUTDIR=.\Debug -INTDIR=.\Debug -DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep -# Begin Custom Macros -OutDir=.\Debug -# End Custom Macros - -!IF "$(RECURSE)" == "0" - -ALL : "$(OUTDIR)\mod_mime.so" "$(DS_POSTBUILD_DEP)" - -!ELSE - -ALL : "libhttpd - Win32 Debug" "libaprutil - Win32 Debug" "libapr - Win32 Debug" "$(OUTDIR)\mod_mime.so" "$(DS_POSTBUILD_DEP)" - -!ENDIF - -!IF "$(RECURSE)" == "1" -CLEAN :"libapr - Win32 DebugCLEAN" "libaprutil - Win32 DebugCLEAN" "libhttpd - Win32 DebugCLEAN" -!ELSE -CLEAN : -!ENDIF - -@erase "$(INTDIR)\mod_mime.obj" - -@erase "$(INTDIR)\mod_mime.res" - -@erase "$(INTDIR)\mod_mime_src.idb" - -@erase "$(INTDIR)\mod_mime_src.pdb" - -@erase "$(OUTDIR)\mod_mime.exp" - -@erase "$(OUTDIR)\mod_mime.lib" - -@erase "$(OUTDIR)\mod_mime.pdb" - -@erase "$(OUTDIR)\mod_mime.so" - -"$(OUTDIR)" : - if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" - -CPP=cl.exe -CPP_PROJ=/nologo /MDd /W3 /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_mime_src" /FD /EHsc /c - -.c{$(INTDIR)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(INTDIR)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(INTDIR)}.obj:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.c{$(INTDIR)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cpp{$(INTDIR)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -.cxx{$(INTDIR)}.sbr:: - $(CPP) @<< - $(CPP_PROJ) $< -<< - -MTL=midl.exe -MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 -RSC=rc.exe -RSC_PROJ=/l 0x409 /fo"$(INTDIR)\mod_mime.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_mime.so" /d LONG_NAME="mime_module for Apache" -BSC32=bscmake.exe -BSC32_FLAGS=/nologo /o"$(OUTDIR)\mod_mime.bsc" -BSC32_SBRS= \ - -LINK32=link.exe -LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_mime.pdb" /debug /out:"$(OUTDIR)\mod_mime.so" /implib:"$(OUTDIR)\mod_mime.lib" /base:@..\..\os\win32\BaseAddr.ref,mod_mime.so -LINK32_OBJS= \ - "$(INTDIR)\mod_mime.obj" \ - "$(INTDIR)\mod_mime.res" \ - "..\..\srclib\apr\Debug\libapr-1.lib" \ - "..\..\srclib\apr-util\Debug\libaprutil-1.lib" \ - "..\..\Debug\libhttpd.lib" - -"$(OUTDIR)\mod_mime.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) - $(LINK32) @<< - $(LINK32_FLAGS) $(LINK32_OBJS) -<< - -TargetPath=.\Debug\mod_mime.so -SOURCE="$(InputPath)" -PostBuild_Desc=Embed .manifest -DS_POSTBUILD_DEP=$(INTDIR)\postbld.dep - -# Begin Custom Macros -OutDir=.\Debug -# End Custom Macros - -"$(DS_POSTBUILD_DEP)" : "$(OUTDIR)\mod_mime.so" - if exist .\Debug\mod_mime.so.manifest mt.exe -manifest .\Debug\mod_mime.so.manifest -outputresource:.\Debug\mod_mime.so;2 - echo Helper for Post-build step > "$(DS_POSTBUILD_DEP)" - -!ENDIF - - -!IF "$(NO_EXTERNAL_DEPS)" != "1" -!IF EXISTS("mod_mime.dep") -!INCLUDE "mod_mime.dep" -!ELSE -!MESSAGE Warning: cannot find "mod_mime.dep" -!ENDIF -!ENDIF - - -!IF "$(CFG)" == "mod_mime - Win32 Release" || "$(CFG)" == "mod_mime - Win32 Debug" - -!IF "$(CFG)" == "mod_mime - Win32 Release" - -"libapr - Win32 Release" : - cd ".\..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release" - cd "..\..\modules\http" - -"libapr - Win32 ReleaseCLEAN" : - cd ".\..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Release" RECURSE=1 CLEAN - cd "..\..\modules\http" - -!ELSEIF "$(CFG)" == "mod_mime - Win32 Debug" - -"libapr - Win32 Debug" : - cd ".\..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug" - cd "..\..\modules\http" - -"libapr - Win32 DebugCLEAN" : - cd ".\..\..\srclib\apr" - $(MAKE) /$(MAKEFLAGS) /F ".\libapr.mak" CFG="libapr - Win32 Debug" RECURSE=1 CLEAN - cd "..\..\modules\http" - -!ENDIF - -!IF "$(CFG)" == "mod_mime - Win32 Release" - -"libaprutil - Win32 Release" : - cd ".\..\..\srclib\apr-util" - $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release" - cd "..\..\modules\http" - -"libaprutil - Win32 ReleaseCLEAN" : - cd ".\..\..\srclib\apr-util" - $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Release" RECURSE=1 CLEAN - cd "..\..\modules\http" - -!ELSEIF "$(CFG)" == "mod_mime - Win32 Debug" - -"libaprutil - Win32 Debug" : - cd ".\..\..\srclib\apr-util" - $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug" - cd "..\..\modules\http" - -"libaprutil - Win32 DebugCLEAN" : - cd ".\..\..\srclib\apr-util" - $(MAKE) /$(MAKEFLAGS) /F ".\libaprutil.mak" CFG="libaprutil - Win32 Debug" RECURSE=1 CLEAN - cd "..\..\modules\http" - -!ENDIF - -!IF "$(CFG)" == "mod_mime - Win32 Release" - -"libhttpd - Win32 Release" : - cd ".\..\.." - $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release" - cd ".\modules\http" - -"libhttpd - Win32 ReleaseCLEAN" : - cd ".\..\.." - $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Release" RECURSE=1 CLEAN - cd ".\modules\http" - -!ELSEIF "$(CFG)" == "mod_mime - Win32 Debug" - -"libhttpd - Win32 Debug" : - cd ".\..\.." - $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug" - cd ".\modules\http" - -"libhttpd - Win32 DebugCLEAN" : - cd ".\..\.." - $(MAKE) /$(MAKEFLAGS) /F ".\libhttpd.mak" CFG="libhttpd - Win32 Debug" RECURSE=1 CLEAN - cd ".\modules\http" - -!ENDIF - -SOURCE=..\..\build\win32\httpd.rc - -!IF "$(CFG)" == "mod_mime - Win32 Release" - - -"$(INTDIR)\mod_mime.res" : $(SOURCE) "$(INTDIR)" - $(RSC) /l 0x409 /fo"$(INTDIR)\mod_mime.res" /i "../../include" /i "../../srclib/apr/include" /i ".\..\..\build\win32" /d "NDEBUG" /d BIN_NAME="mod_mime.so" /d LONG_NAME="mime_module for Apache" $(SOURCE) - - -!ELSEIF "$(CFG)" == "mod_mime - Win32 Debug" - - -"$(INTDIR)\mod_mime.res" : $(SOURCE) "$(INTDIR)" - $(RSC) /l 0x409 /fo"$(INTDIR)\mod_mime.res" /i "../../include" /i "../../srclib/apr/include" /i ".\..\..\build\win32" /d "_DEBUG" /d BIN_NAME="mod_mime.so" /d LONG_NAME="mime_module for Apache" $(SOURCE) - - -!ENDIF - -SOURCE=.\mod_mime.c - -"$(INTDIR)\mod_mime.obj" : $(SOURCE) "$(INTDIR)" - - - -!ENDIF - |
