1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements.  See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License.  You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 * http_protocol.c --- routines which directly communicate with the client.
19 *
20 * Code originally by Rob McCool; much redone by Robert S. Thau
21 * and the Apache Software Foundation.
22 */
23
24#include "apr.h"
25#include "apr_strings.h"
26#include "apr_buckets.h"
27#include "apr_lib.h"
28#include "apr_signal.h"
29
30#define APR_WANT_STDIO          /* for sscanf */
31#define APR_WANT_STRFUNC
32#define APR_WANT_MEMFUNC
33#include "apr_want.h"
34
35#include "util_filter.h"
36#include "ap_config.h"
37#include "httpd.h"
38#include "http_config.h"
39#include "http_core.h"
40#include "http_protocol.h"
41#include "http_main.h"
42#include "http_request.h"
43#include "http_vhost.h"
44#include "http_log.h"           /* For errors detected in basic auth common
45                                 * support code... */
46#include "apr_date.h"           /* For apr_date_parse_http and APR_DATE_BAD */
47#include "util_charset.h"
48#include "util_ebcdic.h"
49#include "util_time.h"
50#include "ap_mpm.h"
51
52#include "mod_core.h"
53
54#if APR_HAVE_STDARG_H
55#include <stdarg.h>
56#endif
57#if APR_HAVE_UNISTD_H
58#include <unistd.h>
59#endif
60
61APLOG_USE_MODULE(http);
62
63/* New Apache routine to map status codes into array indicies
64 *  e.g.  100 -> 0,  101 -> 1,  200 -> 2 ...
65 * The number of status lines must equal the value of
66 * RESPONSE_CODES (httpd.h) and must be listed in order.
67 * No gaps are allowed between X00 and the largest Xnn
68 * for any X (see ap_index_of_response).
69 * When adding a new code here, add a define to httpd.h
70 * as well.
71 */
72
73static const char * const status_lines[RESPONSE_CODES] =
74{
75    "100 Continue",
76    "101 Switching Protocols",
77    "102 Processing",
78#define LEVEL_200  3
79    "200 OK",
80    "201 Created",
81    "202 Accepted",
82    "203 Non-Authoritative Information",
83    "204 No Content",
84    "205 Reset Content",
85    "206 Partial Content",
86    "207 Multi-Status",
87    "208 Already Reported",
88    NULL, /* 209 */
89    NULL, /* 210 */
90    NULL, /* 211 */
91    NULL, /* 212 */
92    NULL, /* 213 */
93    NULL, /* 214 */
94    NULL, /* 215 */
95    NULL, /* 216 */
96    NULL, /* 217 */
97    NULL, /* 218 */
98    NULL, /* 219 */
99    NULL, /* 220 */
100    NULL, /* 221 */
101    NULL, /* 222 */
102    NULL, /* 223 */
103    NULL, /* 224 */
104    NULL, /* 225 */
105    "226 IM Used",
106#define LEVEL_300 30
107    "300 Multiple Choices",
108    "301 Moved Permanently",
109    "302 Found",
110    "303 See Other",
111    "304 Not Modified",
112    "305 Use Proxy",
113    NULL, /* 306 */
114    "307 Temporary Redirect",
115    "308 Permanent Redirect",
116#define LEVEL_400 39
117    "400 Bad Request",
118    "401 Unauthorized",
119    "402 Payment Required",
120    "403 Forbidden",
121    "404 Not Found",
122    "405 Method Not Allowed",
123    "406 Not Acceptable",
124    "407 Proxy Authentication Required",
125    "408 Request Timeout",
126    "409 Conflict",
127    "410 Gone",
128    "411 Length Required",
129    "412 Precondition Failed",
130    "413 Request Entity Too Large",
131    "414 Request-URI Too Long",
132    "415 Unsupported Media Type",
133    "416 Requested Range Not Satisfiable",
134    "417 Expectation Failed",
135    NULL, /* 418 */
136    NULL, /* 419 */
137    NULL, /* 420 */
138    NULL, /* 421 */
139    "422 Unprocessable Entity",
140    "423 Locked",
141    "424 Failed Dependency",
142    NULL, /* 425 */
143    "426 Upgrade Required",
144    NULL, /* 427 */
145    "428 Precondition Required",
146    "429 Too Many Requests",
147    NULL, /* 430 */
148    "431 Request Header Fields Too Large",
149#define LEVEL_500 71
150    "500 Internal Server Error",
151    "501 Not Implemented",
152    "502 Bad Gateway",
153    "503 Service Unavailable",
154    "504 Gateway Timeout",
155    "505 HTTP Version Not Supported",
156    "506 Variant Also Negotiates",
157    "507 Insufficient Storage",
158    "508 Loop Detected",
159    NULL, /* 509 */
160    "510 Not Extended",
161    "511 Network Authentication Required"
162};
163
164APR_HOOK_STRUCT(
165    APR_HOOK_LINK(insert_error_filter)
166)
167
168AP_IMPLEMENT_HOOK_VOID(insert_error_filter, (request_rec *r), (r))
169
170/* The index of the first bit field that is used to index into a limit
171 * bitmask. M_INVALID + 1 to METHOD_NUMBER_LAST.
172 */
173#define METHOD_NUMBER_FIRST (M_INVALID + 1)
174
175/* The max method number. Method numbers are used to shift bitmasks,
176 * so this cannot exceed 63, and all bits high is equal to -1, which is a
177 * special flag, so the last bit used has index 62.
178 */
179#define METHOD_NUMBER_LAST  62
180
181static int is_mpm_running(void)
182{
183    int mpm_state = 0;
184
185    if (ap_mpm_query(AP_MPMQ_MPM_STATE, &mpm_state)) {
186      return 0;
187    }
188
189    if (mpm_state == AP_MPMQ_STOPPING) {
190      return 0;
191    }
192
193    return 1;
194}
195
196
197AP_DECLARE(int) ap_set_keepalive(request_rec *r)
198{
199    int ka_sent = 0;
200    int left = r->server->keep_alive_max - r->connection->keepalives;
201    int wimpy = ap_find_token(r->pool,
202                              apr_table_get(r->headers_out, "Connection"),
203                              "close");
204    const char *conn = apr_table_get(r->headers_in, "Connection");
205
206    /* The following convoluted conditional determines whether or not
207     * the current connection should remain persistent after this response
208     * (a.k.a. HTTP Keep-Alive) and whether or not the output message
209     * body should use the HTTP/1.1 chunked transfer-coding.  In English,
210     *
211     *   IF  we have not marked this connection as errored;
212     *   and the client isn't expecting 100-continue (PR47087 - more
213     *       input here could be the client continuing when we're
214     *       closing the request).
215     *   and the response body has a defined length due to the status code
216     *       being 304 or 204, the request method being HEAD, already
217     *       having defined Content-Length or Transfer-Encoding: chunked, or
218     *       the request version being HTTP/1.1 and thus capable of being set
219     *       as chunked [we know the (r->chunked = 1) side-effect is ugly];
220     *   and the server configuration enables keep-alive;
221     *   and the server configuration has a reasonable inter-request timeout;
222     *   and there is no maximum # requests or the max hasn't been reached;
223     *   and the response status does not require a close;
224     *   and the response generator has not already indicated close;
225     *   and the client did not request non-persistence (Connection: close);
226     *   and    we haven't been configured to ignore the buggy twit
227     *       or they're a buggy twit coming through a HTTP/1.1 proxy
228     *   and    the client is requesting an HTTP/1.0-style keep-alive
229     *       or the client claims to be HTTP/1.1 compliant (perhaps a proxy);
230     *   and this MPM process is not already exiting
231     *   THEN we can be persistent, which requires more headers be output.
232     *
233     * Note that the condition evaluation order is extremely important.
234     */
235    if ((r->connection->keepalive != AP_CONN_CLOSE)
236        && !r->expecting_100
237        && ((r->status == HTTP_NOT_MODIFIED)
238            || (r->status == HTTP_NO_CONTENT)
239            || r->header_only
240            || apr_table_get(r->headers_out, "Content-Length")
241            || ap_find_last_token(r->pool,
242                                  apr_table_get(r->headers_out,
243                                                "Transfer-Encoding"),
244                                  "chunked")
245            || ((r->proto_num >= HTTP_VERSION(1,1))
246                && (r->chunked = 1))) /* THIS CODE IS CORRECT, see above. */
247        && r->server->keep_alive
248        && (r->server->keep_alive_timeout > 0)
249        && ((r->server->keep_alive_max == 0)
250            || (left > 0))
251        && !ap_status_drops_connection(r->status)
252        && !wimpy
253        && !ap_find_token(r->pool, conn, "close")
254        && (!apr_table_get(r->subprocess_env, "nokeepalive")
255            || apr_table_get(r->headers_in, "Via"))
256        && ((ka_sent = ap_find_token(r->pool, conn, "keep-alive"))
257            || (r->proto_num >= HTTP_VERSION(1,1)))
258        && is_mpm_running()) {
259
260        r->connection->keepalive = AP_CONN_KEEPALIVE;
261        r->connection->keepalives++;
262
263        /* If they sent a Keep-Alive token, send one back */
264        if (ka_sent) {
265            if (r->server->keep_alive_max) {
266                apr_table_setn(r->headers_out, "Keep-Alive",
267                       apr_psprintf(r->pool, "timeout=%d, max=%d",
268                            (int)apr_time_sec(r->server->keep_alive_timeout),
269                            left));
270            }
271            else {
272                apr_table_setn(r->headers_out, "Keep-Alive",
273                      apr_psprintf(r->pool, "timeout=%d",
274                            (int)apr_time_sec(r->server->keep_alive_timeout)));
275            }
276            apr_table_mergen(r->headers_out, "Connection", "Keep-Alive");
277        }
278
279        return 1;
280    }
281
282    /* Otherwise, we need to indicate that we will be closing this
283     * connection immediately after the current response.
284     *
285     * We only really need to send "close" to HTTP/1.1 clients, but we
286     * always send it anyway, because a broken proxy may identify itself
287     * as HTTP/1.0, but pass our request along with our HTTP/1.1 tag
288     * to a HTTP/1.1 client. Better safe than sorry.
289     */
290    if (!wimpy) {
291        apr_table_mergen(r->headers_out, "Connection", "close");
292    }
293
294    /*
295     * If we had previously been a keepalive connection and this
296     * is the last one, then bump up the number of keepalives
297     * we've had
298     */
299    if ((r->connection->keepalive != AP_CONN_CLOSE)
300        && r->server->keep_alive_max
301        && !left) {
302        r->connection->keepalives++;
303    }
304    r->connection->keepalive = AP_CONN_CLOSE;
305
306    return 0;
307}
308
309AP_DECLARE(ap_condition_e) ap_condition_if_match(request_rec *r,
310        apr_table_t *headers)
311{
312    const char *if_match, *etag;
313
314    /* A server MUST use the strong comparison function (see section 13.3.3)
315     * to compare the entity tags in If-Match.
316     */
317    if ((if_match = apr_table_get(r->headers_in, "If-Match")) != NULL) {
318        if (if_match[0] == '*'
319                || ((etag = apr_table_get(headers, "ETag")) == NULL
320                        && !ap_find_etag_strong(r->pool, if_match, etag))) {
321            return AP_CONDITION_STRONG;
322        }
323        else {
324            return AP_CONDITION_NOMATCH;
325        }
326    }
327
328    return AP_CONDITION_NONE;
329}
330
331AP_DECLARE(ap_condition_e) ap_condition_if_unmodified_since(request_rec *r,
332        apr_table_t *headers)
333{
334    const char *if_unmodified;
335
336    if_unmodified = apr_table_get(r->headers_in, "If-Unmodified-Since");
337    if (if_unmodified) {
338        apr_int64_t mtime, reqtime;
339
340        apr_time_t ius = apr_time_sec(apr_date_parse_http(if_unmodified));
341
342        /* All of our comparisons must be in seconds, because that's the
343         * highest time resolution the HTTP specification allows.
344         */
345        mtime = apr_time_sec(apr_date_parse_http(
346                        apr_table_get(headers, "Last-Modified")));
347        if (mtime == APR_DATE_BAD) {
348            mtime = apr_time_sec(r->mtime ? r->mtime : apr_time_now());
349        }
350
351        reqtime = apr_time_sec(apr_date_parse_http(
352                        apr_table_get(headers, "Date")));
353        if (!reqtime) {
354            reqtime = apr_time_sec(r->request_time);
355        }
356
357        if ((ius != APR_DATE_BAD) && (mtime > ius)) {
358            if (reqtime < mtime + 60) {
359                if (apr_table_get(r->headers_in, "Range")) {
360                    /* weak matches not allowed with Range requests */
361                    return AP_CONDITION_NOMATCH;
362                }
363                else {
364                    return AP_CONDITION_WEAK;
365                }
366            }
367            else {
368                return AP_CONDITION_STRONG;
369            }
370        }
371        else {
372            return AP_CONDITION_NOMATCH;
373        }
374    }
375
376    return AP_CONDITION_NONE;
377}
378
379AP_DECLARE(ap_condition_e) ap_condition_if_none_match(request_rec *r,
380        apr_table_t *headers)
381{
382    const char *if_nonematch, *etag;
383
384    if_nonematch = apr_table_get(r->headers_in, "If-None-Match");
385    if (if_nonematch != NULL) {
386
387        if (if_nonematch[0] == '*') {
388            return AP_CONDITION_STRONG;
389        }
390
391        /* See section 13.3.3 for rules on how to determine if two entities tags
392         * match. The weak comparison function can only be used with GET or HEAD
393         * requests.
394         */
395        if (r->method_number == M_GET) {
396            if ((etag = apr_table_get(headers, "ETag")) != NULL) {
397                if (apr_table_get(r->headers_in, "Range")) {
398                    if (ap_find_etag_strong(r->pool, if_nonematch, etag)) {
399                        return AP_CONDITION_STRONG;
400                    }
401                }
402                else {
403                    if (ap_find_etag_weak(r->pool, if_nonematch, etag)) {
404                        return AP_CONDITION_WEAK;
405                    }
406                }
407            }
408        }
409
410        else if ((etag = apr_table_get(headers, "ETag")) != NULL
411                && ap_find_etag_strong(r->pool, if_nonematch, etag)) {
412            return AP_CONDITION_STRONG;
413        }
414        return AP_CONDITION_NOMATCH;
415    }
416
417    return AP_CONDITION_NONE;
418}
419
420AP_DECLARE(ap_condition_e) ap_condition_if_modified_since(request_rec *r,
421        apr_table_t *headers)
422{
423    const char *if_modified_since;
424
425    if ((if_modified_since = apr_table_get(r->headers_in, "If-Modified-Since"))
426            != NULL) {
427        apr_int64_t mtime;
428        apr_int64_t ims, reqtime;
429
430        /* All of our comparisons must be in seconds, because that's the
431         * highest time resolution the HTTP specification allows.
432         */
433
434        mtime = apr_time_sec(apr_date_parse_http(
435                        apr_table_get(headers, "Last-Modified")));
436        if (mtime == APR_DATE_BAD) {
437            mtime = apr_time_sec(r->mtime ? r->mtime : apr_time_now());
438        }
439
440        reqtime = apr_time_sec(apr_date_parse_http(
441                        apr_table_get(headers, "Date")));
442        if (!reqtime) {
443            reqtime = apr_time_sec(r->request_time);
444        }
445
446        ims = apr_time_sec(apr_date_parse_http(if_modified_since));
447
448        if (ims >= mtime && ims <= reqtime) {
449            if (reqtime < mtime + 60) {
450                if (apr_table_get(r->headers_in, "Range")) {
451                    /* weak matches not allowed with Range requests */
452                    return AP_CONDITION_NOMATCH;
453                }
454                else {
455                    return AP_CONDITION_WEAK;
456                }
457            }
458            else {
459                return AP_CONDITION_STRONG;
460            }
461        }
462        else {
463            return AP_CONDITION_NOMATCH;
464        }
465    }
466
467    return AP_CONDITION_NONE;
468}
469
470AP_DECLARE(ap_condition_e) ap_condition_if_range(request_rec *r,
471        apr_table_t *headers)
472{
473    const char *if_range, *etag;
474
475    if ((if_range = apr_table_get(r->headers_in, "If-Range"))
476            && apr_table_get(r->headers_in, "Range")) {
477        if (if_range[0] == '"') {
478
479            if ((etag = apr_table_get(headers, "ETag"))
480                    && !strcmp(if_range, etag)) {
481                return AP_CONDITION_STRONG;
482            }
483            else {
484                return AP_CONDITION_NOMATCH;
485            }
486
487        }
488        else {
489            apr_int64_t mtime;
490            apr_int64_t rtime, reqtime;
491
492            /* All of our comparisons must be in seconds, because that's the
493             * highest time resolution the HTTP specification allows.
494             */
495
496            mtime = apr_time_sec(apr_date_parse_http(
497                            apr_table_get(headers, "Last-Modified")));
498            if (mtime == APR_DATE_BAD) {
499                mtime = apr_time_sec(r->mtime ? r->mtime : apr_time_now());
500            }
501
502            reqtime = apr_time_sec(apr_date_parse_http(
503                            apr_table_get(headers, "Date")));
504            if (!reqtime) {
505                reqtime = apr_time_sec(r->request_time);
506            }
507
508            rtime = apr_time_sec(apr_date_parse_http(if_range));
509
510            if (rtime == mtime) {
511                if (reqtime < mtime + 60) {
512                    /* weak matches not allowed with Range requests */
513                    return AP_CONDITION_NOMATCH;
514                }
515                else {
516                    return AP_CONDITION_STRONG;
517                }
518            }
519            else {
520                return AP_CONDITION_NOMATCH;
521            }
522        }
523    }
524
525    return AP_CONDITION_NONE;
526}
527
528AP_DECLARE(int) ap_meets_conditions(request_rec *r)
529{
530    int not_modified = -1; /* unset by default */
531    ap_condition_e cond;
532
533    /* Check for conditional requests --- note that we only want to do
534     * this if we are successful so far and we are not processing a
535     * subrequest or an ErrorDocument.
536     *
537     * The order of the checks is important, since ETag checks are supposed
538     * to be more accurate than checks relative to the modification time.
539     * However, not all documents are guaranteed to *have* ETags, and some
540     * might have Last-Modified values w/o ETags, so this gets a little
541     * complicated.
542     */
543
544    if (!ap_is_HTTP_SUCCESS(r->status) || r->no_local_copy) {
545        return OK;
546    }
547
548    /* If an If-Match request-header field was given
549     * AND the field value is not "*" (meaning match anything)
550     * AND if our strong ETag does not match any entity tag in that field,
551     *     respond with a status of 412 (Precondition Failed).
552     */
553    cond = ap_condition_if_match(r, r->headers_out);
554    if (AP_CONDITION_NOMATCH == cond) {
555        not_modified = 0;
556    }
557    else if (cond >= AP_CONDITION_WEAK) {
558        return HTTP_PRECONDITION_FAILED;
559    }
560
561    /* Else if a valid If-Unmodified-Since request-header field was given
562     * AND the requested resource has been modified since the time
563     * specified in this field, then the server MUST
564     *     respond with a status of 412 (Precondition Failed).
565     */
566    cond = ap_condition_if_unmodified_since(r, r->headers_out);
567    if (AP_CONDITION_NOMATCH == cond) {
568        not_modified = 0;
569    }
570    else if (cond >= AP_CONDITION_WEAK) {
571        return HTTP_PRECONDITION_FAILED;
572    }
573
574    /* If an If-None-Match request-header field was given
575     * AND the field value is "*" (meaning match anything)
576     *     OR our ETag matches any of the entity tags in that field, fail.
577     *
578     * If the request method was GET or HEAD, failure means the server
579     *    SHOULD respond with a 304 (Not Modified) response.
580     * For all other request methods, failure means the server MUST
581     *    respond with a status of 412 (Precondition Failed).
582     *
583     * GET or HEAD allow weak etag comparison, all other methods require
584     * strong comparison.  We can only use weak if it's not a range request.
585     */
586    cond = ap_condition_if_none_match(r, r->headers_out);
587    if (AP_CONDITION_NOMATCH == cond) {
588        not_modified = 0;
589    }
590    else if (cond >= AP_CONDITION_WEAK) {
591        if (r->method_number == M_GET) {
592            if (not_modified) {
593                not_modified = 1;
594            }
595        }
596        else {
597            return HTTP_PRECONDITION_FAILED;
598        }
599    }
600
601    /* If a valid If-Modified-Since request-header field was given
602     * AND it is a GET or HEAD request
603     * AND the requested resource has not been modified since the time
604     * specified in this field, then the server MUST
605     *    respond with a status of 304 (Not Modified).
606     * A date later than the server's current request time is invalid.
607     */
608    cond = ap_condition_if_modified_since(r, r->headers_out);
609    if (AP_CONDITION_NOMATCH == cond) {
610        not_modified = 0;
611    }
612    else if (cond >= AP_CONDITION_WEAK) {
613        if (r->method_number == M_GET) {
614            if (not_modified) {
615                not_modified = 1;
616            }
617        }
618    }
619
620    /* If an If-Range and an Range header is present, we must return
621     * 200 OK. The byterange filter will convert it to a range response.
622     */
623    cond = ap_condition_if_range(r, r->headers_out);
624    if (cond > AP_CONDITION_NONE) {
625        return OK;
626    }
627
628    if (not_modified == 1) {
629        return HTTP_NOT_MODIFIED;
630    }
631
632    return OK;
633}
634
635/**
636 * Singleton registry of additional methods. This maps new method names
637 * such as "MYGET" to methnums, which are int offsets into bitmasks.
638 *
639 * This follows the same technique as standard M_GET, M_POST, etc. These
640 * are dynamically assigned when modules are loaded and <Limit GET MYGET>
641 * directives are processed.
642 */
643static apr_hash_t *methods_registry = NULL;
644static int cur_method_number = METHOD_NUMBER_FIRST;
645
646/* internal function to register one method/number pair */
647static void register_one_method(apr_pool_t *p, const char *methname,
648                                int methnum)
649{
650    int *pnum = apr_palloc(p, sizeof(*pnum));
651
652    *pnum = methnum;
653    apr_hash_set(methods_registry, methname, APR_HASH_KEY_STRING, pnum);
654}
655
656/* This internal function is used to clear the method registry
657 * and reset the cur_method_number counter.
658 */
659static apr_status_t ap_method_registry_destroy(void *notused)
660{
661    methods_registry = NULL;
662    cur_method_number = METHOD_NUMBER_FIRST;
663    return APR_SUCCESS;
664}
665
666AP_DECLARE(void) ap_method_registry_init(apr_pool_t *p)
667{
668    methods_registry = apr_hash_make(p);
669    apr_pool_cleanup_register(p, NULL,
670                              ap_method_registry_destroy,
671                              apr_pool_cleanup_null);
672
673    /* put all the standard methods into the registry hash to ease the
674       mapping operations between name and number */
675    register_one_method(p, "GET", M_GET);
676    register_one_method(p, "PUT", M_PUT);
677    register_one_method(p, "POST", M_POST);
678    register_one_method(p, "DELETE", M_DELETE);
679    register_one_method(p, "CONNECT", M_CONNECT);
680    register_one_method(p, "OPTIONS", M_OPTIONS);
681    register_one_method(p, "TRACE", M_TRACE);
682    register_one_method(p, "PATCH", M_PATCH);
683    register_one_method(p, "PROPFIND", M_PROPFIND);
684    register_one_method(p, "PROPPATCH", M_PROPPATCH);
685    register_one_method(p, "MKCOL", M_MKCOL);
686    register_one_method(p, "COPY", M_COPY);
687    register_one_method(p, "MOVE", M_MOVE);
688    register_one_method(p, "LOCK", M_LOCK);
689    register_one_method(p, "UNLOCK", M_UNLOCK);
690    register_one_method(p, "VERSION-CONTROL", M_VERSION_CONTROL);
691    register_one_method(p, "CHECKOUT", M_CHECKOUT);
692    register_one_method(p, "UNCHECKOUT", M_UNCHECKOUT);
693    register_one_method(p, "CHECKIN", M_CHECKIN);
694    register_one_method(p, "UPDATE", M_UPDATE);
695    register_one_method(p, "LABEL", M_LABEL);
696    register_one_method(p, "REPORT", M_REPORT);
697    register_one_method(p, "MKWORKSPACE", M_MKWORKSPACE);
698    register_one_method(p, "MKACTIVITY", M_MKACTIVITY);
699    register_one_method(p, "BASELINE-CONTROL", M_BASELINE_CONTROL);
700    register_one_method(p, "MERGE", M_MERGE);
701}
702
703AP_DECLARE(int) ap_method_register(apr_pool_t *p, const char *methname)
704{
705    int *methnum;
706
707    if (methods_registry == NULL) {
708        ap_method_registry_init(p);
709    }
710
711    if (methname == NULL) {
712        return M_INVALID;
713    }
714
715    /* Check if the method was previously registered.  If it was
716     * return the associated method number.
717     */
718    methnum = (int *)apr_hash_get(methods_registry, methname,
719                                  APR_HASH_KEY_STRING);
720    if (methnum != NULL)
721        return *methnum;
722
723    if (cur_method_number > METHOD_NUMBER_LAST) {
724        /* The method registry  has run out of dynamically
725         * assignable method numbers. Log this and return M_INVALID.
726         */
727        ap_log_perror(APLOG_MARK, APLOG_ERR, 0, p, APLOGNO(01610)
728                      "Maximum new request methods %d reached while "
729                      "registering method %s.",
730                      METHOD_NUMBER_LAST, methname);
731        return M_INVALID;
732    }
733
734    register_one_method(p, methname, cur_method_number);
735    return cur_method_number++;
736}
737
738#define UNKNOWN_METHOD (-1)
739
740static int lookup_builtin_method(const char *method, apr_size_t len)
741{
742    /* Note: the following code was generated by the "shilka" tool from
743       the "cocom" parsing/compilation toolkit. It is an optimized lookup
744       based on analysis of the input keywords. Postprocessing was done
745       on the shilka output, but the basic structure and analysis is
746       from there. Should new HTTP methods be added, then manual insertion
747       into this code is fine, or simply re-running the shilka tool on
748       the appropriate input. */
749
750    /* Note: it is also quite reasonable to just use our method_registry,
751       but I'm assuming (probably incorrectly) we want more speed here
752       (based on the optimizations the previous code was doing). */
753
754    switch (len)
755    {
756    case 3:
757        switch (method[0])
758        {
759        case 'P':
760            return (method[1] == 'U'
761                    && method[2] == 'T'
762                    ? M_PUT : UNKNOWN_METHOD);
763        case 'G':
764            return (method[1] == 'E'
765                    && method[2] == 'T'
766                    ? M_GET : UNKNOWN_METHOD);
767        default:
768            return UNKNOWN_METHOD;
769        }
770
771    case 4:
772        switch (method[0])
773        {
774        case 'H':
775            return (method[1] == 'E'
776                    && method[2] == 'A'
777                    && method[3] == 'D'
778                    ? M_GET : UNKNOWN_METHOD);
779        case 'P':
780            return (method[1] == 'O'
781                    && method[2] == 'S'
782                    && method[3] == 'T'
783                    ? M_POST : UNKNOWN_METHOD);
784        case 'M':
785            return (method[1] == 'O'
786                    && method[2] == 'V'
787                    && method[3] == 'E'
788                    ? M_MOVE : UNKNOWN_METHOD);
789        case 'L':
790            return (method[1] == 'O'
791                    && method[2] == 'C'
792                    && method[3] == 'K'
793                    ? M_LOCK : UNKNOWN_METHOD);
794        case 'C':
795            return (method[1] == 'O'
796                    && method[2] == 'P'
797                    && method[3] == 'Y'
798                    ? M_COPY : UNKNOWN_METHOD);
799        default:
800            return UNKNOWN_METHOD;
801        }
802
803    case 5:
804        switch (method[2])
805        {
806        case 'T':
807            return (memcmp(method, "PATCH", 5) == 0
808                    ? M_PATCH : UNKNOWN_METHOD);
809        case 'R':
810            return (memcmp(method, "MERGE", 5) == 0
811                    ? M_MERGE : UNKNOWN_METHOD);
812        case 'C':
813            return (memcmp(method, "MKCOL", 5) == 0
814                    ? M_MKCOL : UNKNOWN_METHOD);
815        case 'B':
816            return (memcmp(method, "LABEL", 5) == 0
817                    ? M_LABEL : UNKNOWN_METHOD);
818        case 'A':
819            return (memcmp(method, "TRACE", 5) == 0
820                    ? M_TRACE : UNKNOWN_METHOD);
821        default:
822            return UNKNOWN_METHOD;
823        }
824
825    case 6:
826        switch (method[0])
827        {
828        case 'U':
829            switch (method[5])
830            {
831            case 'K':
832                return (memcmp(method, "UNLOCK", 6) == 0
833                        ? M_UNLOCK : UNKNOWN_METHOD);
834            case 'E':
835                return (memcmp(method, "UPDATE", 6) == 0
836                        ? M_UPDATE : UNKNOWN_METHOD);
837            default:
838                return UNKNOWN_METHOD;
839            }
840        case 'R':
841            return (memcmp(method, "REPORT", 6) == 0
842                    ? M_REPORT : UNKNOWN_METHOD);
843        case 'D':
844            return (memcmp(method, "DELETE", 6) == 0
845                    ? M_DELETE : UNKNOWN_METHOD);
846        default:
847            return UNKNOWN_METHOD;
848        }
849
850    case 7:
851        switch (method[1])
852        {
853        case 'P':
854            return (memcmp(method, "OPTIONS", 7) == 0
855                    ? M_OPTIONS : UNKNOWN_METHOD);
856        case 'O':
857            return (memcmp(method, "CONNECT", 7) == 0
858                    ? M_CONNECT : UNKNOWN_METHOD);
859        case 'H':
860            return (memcmp(method, "CHECKIN", 7) == 0
861                    ? M_CHECKIN : UNKNOWN_METHOD);
862        default:
863            return UNKNOWN_METHOD;
864        }
865
866    case 8:
867        switch (method[0])
868        {
869        case 'P':
870            return (memcmp(method, "PROPFIND", 8) == 0
871                    ? M_PROPFIND : UNKNOWN_METHOD);
872        case 'C':
873            return (memcmp(method, "CHECKOUT", 8) == 0
874                    ? M_CHECKOUT : UNKNOWN_METHOD);
875        default:
876            return UNKNOWN_METHOD;
877        }
878
879    case 9:
880        return (memcmp(method, "PROPPATCH", 9) == 0
881                ? M_PROPPATCH : UNKNOWN_METHOD);
882
883    case 10:
884        switch (method[0])
885        {
886        case 'U':
887            return (memcmp(method, "UNCHECKOUT", 10) == 0
888                    ? M_UNCHECKOUT : UNKNOWN_METHOD);
889        case 'M':
890            return (memcmp(method, "MKACTIVITY", 10) == 0
891                    ? M_MKACTIVITY : UNKNOWN_METHOD);
892        default:
893            return UNKNOWN_METHOD;
894        }
895
896    case 11:
897        return (memcmp(method, "MKWORKSPACE", 11) == 0
898                ? M_MKWORKSPACE : UNKNOWN_METHOD);
899
900    case 15:
901        return (memcmp(method, "VERSION-CONTROL", 15) == 0
902                ? M_VERSION_CONTROL : UNKNOWN_METHOD);
903
904    case 16:
905        return (memcmp(method, "BASELINE-CONTROL", 16) == 0
906                ? M_BASELINE_CONTROL : UNKNOWN_METHOD);
907
908    default:
909        return UNKNOWN_METHOD;
910    }
911
912    /* NOTREACHED */
913}
914
915/* Get the method number associated with the given string, assumed to
916 * contain an HTTP method.  Returns M_INVALID if not recognized.
917 *
918 * This is the first step toward placing method names in a configurable
919 * list.  Hopefully it (and other routines) can eventually be moved to
920 * something like a mod_http_methods.c, complete with config stuff.
921 */
922AP_DECLARE(int) ap_method_number_of(const char *method)
923{
924    int len = strlen(method);
925    int which = lookup_builtin_method(method, len);
926
927    if (which != UNKNOWN_METHOD)
928        return which;
929
930    /* check if the method has been dynamically registered */
931    if (methods_registry != NULL) {
932        int *methnum = apr_hash_get(methods_registry, method, len);
933
934        if (methnum != NULL) {
935            return *methnum;
936        }
937    }
938
939    return M_INVALID;
940}
941
942/*
943 * Turn a known method number into a name.
944 */
945AP_DECLARE(const char *) ap_method_name_of(apr_pool_t *p, int methnum)
946{
947    apr_hash_index_t *hi = apr_hash_first(p, methods_registry);
948
949    /* scan through the hash table, looking for a value that matches
950       the provided method number. */
951    for (; hi; hi = apr_hash_next(hi)) {
952        const void *key;
953        void *val;
954
955        apr_hash_this(hi, &key, NULL, &val);
956        if (*(int *)val == methnum)
957            return key;
958    }
959
960    /* it wasn't found in the hash */
961    return NULL;
962}
963
964/* The index is found by its offset from the x00 code of each level.
965 * Although this is fast, it will need to be replaced if some nutcase
966 * decides to define a high-numbered code before the lower numbers.
967 * If that sad event occurs, replace the code below with a linear search
968 * from status_lines[shortcut[i]] to status_lines[shortcut[i+1]-1];
969 * or use NULL to fill the gaps.
970 */
971AP_DECLARE(int) ap_index_of_response(int status)
972{
973    static int shortcut[6] = {0, LEVEL_200, LEVEL_300, LEVEL_400,
974    LEVEL_500, RESPONSE_CODES};
975    int i, pos;
976
977    if (status < 100) {               /* Below 100 is illegal for HTTP status */
978        return LEVEL_500;
979    }
980
981    for (i = 0; i < 5; i++) {
982        status -= 100;
983        if (status < 100) {
984            pos = (status + shortcut[i]);
985            if (pos < shortcut[i + 1] && status_lines[pos] != NULL) {
986                return pos;
987            }
988            else {
989                return LEVEL_500;            /* status unknown (falls in gap) */
990            }
991        }
992    }
993    return LEVEL_500;                         /* 600 or above is also illegal */
994}
995
996AP_DECLARE(const char *) ap_get_status_line(int status)
997{
998    return status_lines[ap_index_of_response(status)];
999}
1000
1001/* Build the Allow field-value from the request handler method mask.
1002 */
1003static char *make_allow(request_rec *r)
1004{
1005    apr_int64_t mask;
1006    apr_array_header_t *allow = apr_array_make(r->pool, 10, sizeof(char *));
1007    apr_hash_index_t *hi = apr_hash_first(r->pool, methods_registry);
1008    /* For TRACE below */
1009    core_server_config *conf =
1010        ap_get_core_module_config(r->server->module_config);
1011
1012    mask = r->allowed_methods->method_mask;
1013
1014    for (; hi; hi = apr_hash_next(hi)) {
1015        const void *key;
1016        void *val;
1017
1018        apr_hash_this(hi, &key, NULL, &val);
1019        if ((mask & (AP_METHOD_BIT << *(int *)val)) != 0) {
1020            *(const char **)apr_array_push(allow) = key;
1021
1022            /* the M_GET method actually refers to two methods */
1023            if (*(int *)val == M_GET)
1024                *(const char **)apr_array_push(allow) = "HEAD";
1025        }
1026    }
1027
1028    /* TRACE is tested on a per-server basis */
1029    if (conf->trace_enable != AP_TRACE_DISABLE)
1030        *(const char **)apr_array_push(allow) = "TRACE";
1031
1032    /* ### this is rather annoying. we should enforce registration of
1033       ### these methods */
1034    if ((mask & (AP_METHOD_BIT << M_INVALID))
1035        && (r->allowed_methods->method_list != NULL)
1036        && (r->allowed_methods->method_list->nelts != 0)) {
1037        apr_array_cat(allow, r->allowed_methods->method_list);
1038    }
1039
1040    return apr_array_pstrcat(r->pool, allow, ',');
1041}
1042
1043AP_DECLARE(int) ap_send_http_options(request_rec *r)
1044{
1045    if (r->assbackwards) {
1046        return DECLINED;
1047    }
1048
1049    apr_table_setn(r->headers_out, "Allow", make_allow(r));
1050
1051    /* the request finalization will send an EOS, which will flush all
1052     * the headers out (including the Allow header)
1053     */
1054
1055    return OK;
1056}
1057
1058AP_DECLARE(void) ap_set_content_type(request_rec *r, const char *ct)
1059{
1060    if (!ct) {
1061        r->content_type = NULL;
1062    }
1063    else if (!r->content_type || strcmp(r->content_type, ct)) {
1064        r->content_type = ct;
1065    }
1066}
1067
1068AP_DECLARE(void) ap_set_accept_ranges(request_rec *r)
1069{
1070    core_dir_config *d = ap_get_core_module_config(r->per_dir_config);
1071    apr_table_setn(r->headers_out, "Accept-Ranges",
1072                  (d->max_ranges == AP_MAXRANGES_NORANGES) ? "none"
1073                                                           : "bytes");
1074}
1075static const char *add_optional_notes(request_rec *r,
1076                                      const char *prefix,
1077                                      const char *key,
1078                                      const char *suffix)
1079{
1080    const char *notes, *result;
1081
1082    if ((notes = apr_table_get(r->notes, key)) == NULL) {
1083        result = apr_pstrcat(r->pool, prefix, suffix, NULL);
1084    }
1085    else {
1086        result = apr_pstrcat(r->pool, prefix, notes, suffix, NULL);
1087    }
1088
1089    return result;
1090}
1091
1092/* construct and return the default error message for a given
1093 * HTTP defined error code
1094 */
1095static const char *get_canned_error_string(int status,
1096                                           request_rec *r,
1097                                           const char *location)
1098{
1099    apr_pool_t *p = r->pool;
1100    const char *error_notes, *h1, *s1;
1101
1102    switch (status) {
1103    case HTTP_MOVED_PERMANENTLY:
1104    case HTTP_MOVED_TEMPORARILY:
1105    case HTTP_TEMPORARY_REDIRECT:
1106    case HTTP_PERMANENT_REDIRECT:
1107        return(apr_pstrcat(p,
1108                           "<p>The document has moved <a href=\"",
1109                           ap_escape_html(r->pool, location),
1110                           "\">here</a>.</p>\n",
1111                           NULL));
1112    case HTTP_SEE_OTHER:
1113        return(apr_pstrcat(p,
1114                           "<p>The answer to your request is located "
1115                           "<a href=\"",
1116                           ap_escape_html(r->pool, location),
1117                           "\">here</a>.</p>\n",
1118                           NULL));
1119    case HTTP_USE_PROXY:
1120        return(apr_pstrcat(p,
1121                           "<p>This resource is only accessible "
1122                           "through the proxy\n",
1123                           ap_escape_html(r->pool, location),
1124                           "<br />\nYou will need to configure "
1125                           "your client to use that proxy.</p>\n",
1126                           NULL));
1127    case HTTP_PROXY_AUTHENTICATION_REQUIRED:
1128    case HTTP_UNAUTHORIZED:
1129        return("<p>This server could not verify that you\n"
1130               "are authorized to access the document\n"
1131               "requested.  Either you supplied the wrong\n"
1132               "credentials (e.g., bad password), or your\n"
1133               "browser doesn't understand how to supply\n"
1134               "the credentials required.</p>\n");
1135    case HTTP_BAD_REQUEST:
1136        return(add_optional_notes(r,
1137                                  "<p>Your browser sent a request that "
1138                                  "this server could not understand.<br />\n",
1139                                  "error-notes",
1140                                  "</p>\n"));
1141    case HTTP_FORBIDDEN:
1142        return(apr_pstrcat(p,
1143                           "<p>You don't have permission to access ",
1144                           ap_escape_html(r->pool, r->uri),
1145                           "\non this server.</p>\n",
1146                           NULL));
1147    case HTTP_NOT_FOUND:
1148        return(apr_pstrcat(p,
1149                           "<p>The requested URL ",
1150                           ap_escape_html(r->pool, r->uri),
1151                           " was not found on this server.</p>\n",
1152                           NULL));
1153    case HTTP_METHOD_NOT_ALLOWED:
1154        return(apr_pstrcat(p,
1155                           "<p>The requested method ",
1156                           ap_escape_html(r->pool, r->method),
1157                           " is not allowed for the URL ",
1158                           ap_escape_html(r->pool, r->uri),
1159                           ".</p>\n",
1160                           NULL));
1161    case HTTP_NOT_ACCEPTABLE:
1162        s1 = apr_pstrcat(p,
1163                         "<p>An appropriate representation of the "
1164                         "requested resource ",
1165                         ap_escape_html(r->pool, r->uri),
1166                         " could not be found on this server.</p>\n",
1167                         NULL);
1168        return(add_optional_notes(r, s1, "variant-list", ""));
1169    case HTTP_MULTIPLE_CHOICES:
1170        return(add_optional_notes(r, "", "variant-list", ""));
1171    case HTTP_LENGTH_REQUIRED:
1172        s1 = apr_pstrcat(p,
1173                         "<p>A request of the requested method ",
1174                         ap_escape_html(r->pool, r->method),
1175                         " requires a valid Content-length.<br />\n",
1176                         NULL);
1177        return(add_optional_notes(r, s1, "error-notes", "</p>\n"));
1178    case HTTP_PRECONDITION_FAILED:
1179        return(apr_pstrcat(p,
1180                           "<p>The precondition on the request "
1181                           "for the URL ",
1182                           ap_escape_html(r->pool, r->uri),
1183                           " evaluated to false.</p>\n",
1184                           NULL));
1185    case HTTP_NOT_IMPLEMENTED:
1186        s1 = apr_pstrcat(p,
1187                         "<p>",
1188                         ap_escape_html(r->pool, r->method), " to ",
1189                         ap_escape_html(r->pool, r->uri),
1190                         " not supported.<br />\n",
1191                         NULL);
1192        return(add_optional_notes(r, s1, "error-notes", "</p>\n"));
1193    case HTTP_BAD_GATEWAY:
1194        s1 = "<p>The proxy server received an invalid" CRLF
1195            "response from an upstream server.<br />" CRLF;
1196        return(add_optional_notes(r, s1, "error-notes", "</p>\n"));
1197    case HTTP_VARIANT_ALSO_VARIES:
1198        return(apr_pstrcat(p,
1199                           "<p>A variant for the requested "
1200                           "resource\n<pre>\n",
1201                           ap_escape_html(r->pool, r->uri),
1202                           "\n</pre>\nis itself a negotiable resource. "
1203                           "This indicates a configuration error.</p>\n",
1204                           NULL));
1205    case HTTP_REQUEST_TIME_OUT:
1206        return("<p>Server timeout waiting for the HTTP request from the client.</p>\n");
1207    case HTTP_GONE:
1208        return(apr_pstrcat(p,
1209                           "<p>The requested resource<br />",
1210                           ap_escape_html(r->pool, r->uri),
1211                           "<br />\nis no longer available on this server "
1212                           "and there is no forwarding address.\n"
1213                           "Please remove all references to this "
1214                           "resource.</p>\n",
1215                           NULL));
1216    case HTTP_REQUEST_ENTITY_TOO_LARGE:
1217        return(apr_pstrcat(p,
1218                           "The requested resource<br />",
1219                           ap_escape_html(r->pool, r->uri), "<br />\n",
1220                           "does not allow request data with ",
1221                           ap_escape_html(r->pool, r->method),
1222                           " requests, or the amount of data provided in\n"
1223                           "the request exceeds the capacity limit.\n",
1224                           NULL));
1225    case HTTP_REQUEST_URI_TOO_LARGE:
1226        s1 = "<p>The requested URL's length exceeds the capacity\n"
1227             "limit for this server.<br />\n";
1228        return(add_optional_notes(r, s1, "error-notes", "</p>\n"));
1229    case HTTP_UNSUPPORTED_MEDIA_TYPE:
1230        return("<p>The supplied request data is not in a format\n"
1231               "acceptable for processing by this resource.</p>\n");
1232    case HTTP_RANGE_NOT_SATISFIABLE:
1233        return("<p>None of the range-specifier values in the Range\n"
1234               "request-header field overlap the current extent\n"
1235               "of the selected resource.</p>\n");
1236    case HTTP_EXPECTATION_FAILED:
1237        s1 = apr_table_get(r->headers_in, "Expect");
1238        if (s1)
1239            s1 = apr_pstrcat(p,
1240                     "<p>The expectation given in the Expect request-header\n"
1241                     "field could not be met by this server.\n"
1242                     "The client sent<pre>\n    Expect: ",
1243                     ap_escape_html(r->pool, s1), "\n</pre>\n",
1244                     NULL);
1245        else
1246            s1 = "<p>No expectation was seen, the Expect request-header \n"
1247                 "field was not presented by the client.\n";
1248        return add_optional_notes(r, s1, "error-notes", "</p>"
1249                   "<p>Only the 100-continue expectation is supported.</p>\n");
1250    case HTTP_UNPROCESSABLE_ENTITY:
1251        return("<p>The server understands the media type of the\n"
1252               "request entity, but was unable to process the\n"
1253               "contained instructions.</p>\n");
1254    case HTTP_LOCKED:
1255        return("<p>The requested resource is currently locked.\n"
1256               "The lock must be released or proper identification\n"
1257               "given before the method can be applied.</p>\n");
1258    case HTTP_FAILED_DEPENDENCY:
1259        return("<p>The method could not be performed on the resource\n"
1260               "because the requested action depended on another\n"
1261               "action and that other action failed.</p>\n");
1262    case HTTP_UPGRADE_REQUIRED:
1263        return("<p>The requested resource can only be retrieved\n"
1264               "using SSL.  The server is willing to upgrade the current\n"
1265               "connection to SSL, but your client doesn't support it.\n"
1266               "Either upgrade your client, or try requesting the page\n"
1267               "using https://\n");
1268    case HTTP_PRECONDITION_REQUIRED:
1269        return("<p>The request is required to be conditional.</p>\n");
1270    case HTTP_TOO_MANY_REQUESTS:
1271        return("<p>The user has sent too many requests\n"
1272               "in a given amount of time.</p>\n");
1273    case HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE:
1274        return("<p>The server refused this request because\n"
1275               "the request header fields are too large.</p>\n");
1276    case HTTP_INSUFFICIENT_STORAGE:
1277        return("<p>The method could not be performed on the resource\n"
1278               "because the server is unable to store the\n"
1279               "representation needed to successfully complete the\n"
1280               "request.  There is insufficient free space left in\n"
1281               "your storage allocation.</p>\n");
1282    case HTTP_SERVICE_UNAVAILABLE:
1283        return("<p>The server is temporarily unable to service your\n"
1284               "request due to maintenance downtime or capacity\n"
1285               "problems. Please try again later.</p>\n");
1286    case HTTP_GATEWAY_TIME_OUT:
1287        return("<p>The gateway did not receive a timely response\n"
1288               "from the upstream server or application.</p>\n");
1289    case HTTP_LOOP_DETECTED:
1290        return("<p>The server terminated an operation because\n"
1291               "it encountered an infinite loop.</p>\n");
1292    case HTTP_NOT_EXTENDED:
1293        return("<p>A mandatory extension policy in the request is not\n"
1294               "accepted by the server for this resource.</p>\n");
1295    case HTTP_NETWORK_AUTHENTICATION_REQUIRED:
1296        return("<p>The client needs to authenticate to gain\n"
1297               "network access.</p>\n");
1298    default:                    /* HTTP_INTERNAL_SERVER_ERROR */
1299        /*
1300         * This comparison to expose error-notes could be modified to
1301         * use a configuration directive and export based on that
1302         * directive.  For now "*" is used to designate an error-notes
1303         * that is totally safe for any user to see (ie lacks paths,
1304         * database passwords, etc.)
1305         */
1306        if (((error_notes = apr_table_get(r->notes,
1307                                          "error-notes")) != NULL)
1308            && (h1 = apr_table_get(r->notes, "verbose-error-to")) != NULL
1309            && (strcmp(h1, "*") == 0)) {
1310            return(apr_pstrcat(p, error_notes, "<p />\n", NULL));
1311        }
1312        else {
1313            return(apr_pstrcat(p,
1314                               "<p>The server encountered an internal "
1315                               "error or\n"
1316                               "misconfiguration and was unable to complete\n"
1317                               "your request.</p>\n"
1318                               "<p>Please contact the server "
1319                               "administrator at \n ",
1320                               ap_escape_html(r->pool,
1321                                              r->server->server_admin),
1322                               " to inform them of the time this "
1323                               "error occurred,\n"
1324                               " and the actions you performed just before "
1325                               "this error.</p>\n"
1326                               "<p>More information about this error "
1327                               "may be available\n"
1328                               "in the server error log.</p>\n",
1329                               NULL));
1330        }
1331        /*
1332         * It would be nice to give the user the information they need to
1333         * fix the problem directly since many users don't have access to
1334         * the error_log (think University sites) even though they can easily
1335         * get this error by misconfiguring an htaccess file.  However, the
1336         * e error notes tend to include the real file pathname in this case,
1337         * which some people consider to be a breach of privacy.  Until we
1338         * can figure out a way to remove the pathname, leave this commented.
1339         *
1340         * if ((error_notes = apr_table_get(r->notes,
1341         *                                  "error-notes")) != NULL) {
1342         *     return(apr_pstrcat(p, error_notes, "<p />\n", NULL);
1343         * }
1344         * else {
1345         *     return "";
1346         * }
1347         */
1348    }
1349}
1350
1351/* We should have named this send_canned_response, since it is used for any
1352 * response that can be generated by the server from the request record.
1353 * This includes all 204 (no content), 3xx (redirect), 4xx (client error),
1354 * and 5xx (server error) messages that have not been redirected to another
1355 * handler via the ErrorDocument feature.
1356 */
1357AP_DECLARE(void) ap_send_error_response(request_rec *r, int recursive_error)
1358{
1359    int status = r->status;
1360    int idx = ap_index_of_response(status);
1361    char *custom_response;
1362    const char *location = apr_table_get(r->headers_out, "Location");
1363
1364    /* At this point, we are starting the response over, so we have to reset
1365     * this value.
1366     */
1367    r->eos_sent = 0;
1368
1369    /* and we need to get rid of any RESOURCE filters that might be lurking
1370     * around, thinking they are in the middle of the original request
1371     */
1372
1373    r->output_filters = r->proto_output_filters;
1374
1375    ap_run_insert_error_filter(r);
1376
1377    /*
1378     * It's possible that the Location field might be in r->err_headers_out
1379     * instead of r->headers_out; use the latter if possible, else the
1380     * former.
1381     */
1382    if (location == NULL) {
1383        location = apr_table_get(r->err_headers_out, "Location");
1384    }
1385    /* We need to special-case the handling of 204 and 304 responses,
1386     * since they have specific HTTP requirements and do not include a
1387     * message body.  Note that being assbackwards here is not an option.
1388     */
1389    if (status == HTTP_NOT_MODIFIED) {
1390        ap_finalize_request_protocol(r);
1391        return;
1392    }
1393
1394    if (status == HTTP_NO_CONTENT) {
1395        ap_finalize_request_protocol(r);
1396        return;
1397    }
1398
1399    if (!r->assbackwards) {
1400        apr_table_t *tmp = r->headers_out;
1401
1402        /* For all HTTP/1.x responses for which we generate the message,
1403         * we need to avoid inheriting the "normal status" header fields
1404         * that may have been set by the request handler before the
1405         * error or redirect, except for Location on external redirects.
1406         */
1407        r->headers_out = r->err_headers_out;
1408        r->err_headers_out = tmp;
1409        apr_table_clear(r->err_headers_out);
1410
1411        if (ap_is_HTTP_REDIRECT(status) || (status == HTTP_CREATED)) {
1412            if ((location != NULL) && *location) {
1413                apr_table_setn(r->headers_out, "Location", location);
1414            }
1415            else {
1416                location = "";   /* avoids coredump when printing, below */
1417            }
1418        }
1419
1420        r->content_languages = NULL;
1421        r->content_encoding = NULL;
1422        r->clength = 0;
1423
1424        if (apr_table_get(r->subprocess_env,
1425                          "suppress-error-charset") != NULL) {
1426            core_request_config *request_conf =
1427                        ap_get_core_module_config(r->request_config);
1428            request_conf->suppress_charset = 1; /* avoid adding default
1429                                                 * charset later
1430                                                 */
1431            ap_set_content_type(r, "text/html");
1432        }
1433        else {
1434            ap_set_content_type(r, "text/html; charset=iso-8859-1");
1435        }
1436
1437        if ((status == HTTP_METHOD_NOT_ALLOWED)
1438            || (status == HTTP_NOT_IMPLEMENTED)) {
1439            apr_table_setn(r->headers_out, "Allow", make_allow(r));
1440        }
1441
1442        if (r->header_only) {
1443            ap_finalize_request_protocol(r);
1444            return;
1445        }
1446    }
1447
1448    if ((custom_response = ap_response_code_string(r, idx))) {
1449        /*
1450         * We have a custom response output. This should only be
1451         * a text-string to write back. But if the ErrorDocument
1452         * was a local redirect and the requested resource failed
1453         * for any reason, the custom_response will still hold the
1454         * redirect URL. We don't really want to output this URL
1455         * as a text message, so first check the custom response
1456         * string to ensure that it is a text-string (using the
1457         * same test used in ap_die(), i.e. does it start with a ").
1458         *
1459         * If it's not a text string, we've got a recursive error or
1460         * an external redirect.  If it's a recursive error, ap_die passes
1461         * us the second error code so we can write both, and has already
1462         * backed up to the original error.  If it's an external redirect,
1463         * it hasn't happened yet; we may never know if it fails.
1464         */
1465        if (custom_response[0] == '\"') {
1466            ap_rputs(custom_response + 1, r);
1467            ap_finalize_request_protocol(r);
1468            return;
1469        }
1470    }
1471    {
1472        const char *title = status_lines[idx];
1473        const char *h1;
1474
1475        /* Accept a status_line set by a module, but only if it begins
1476         * with the correct 3 digit status code
1477         */
1478        if (r->status_line) {
1479            char *end;
1480            int len = strlen(r->status_line);
1481            if (len >= 3
1482                && apr_strtoi64(r->status_line, &end, 10) == r->status
1483                && (end - 3) == r->status_line
1484                && (len < 4 || apr_isspace(r->status_line[3]))
1485                && (len < 5 || apr_isalnum(r->status_line[4]))) {
1486                /* Since we passed the above check, we know that length three
1487                 * is equivalent to only a 3 digit numeric http status.
1488                 * RFC2616 mandates a trailing space, let's add it.
1489                 * If we have an empty reason phrase, we also add "Unknown Reason".
1490                 */
1491                if (len == 3) {
1492                    r->status_line = apr_pstrcat(r->pool, r->status_line, " Unknown Reason", NULL);
1493                } else if (len == 4) {
1494                    r->status_line = apr_pstrcat(r->pool, r->status_line, "Unknown Reason", NULL);
1495                }
1496                title = r->status_line;
1497            }
1498        }
1499
1500        /* folks decided they didn't want the error code in the H1 text */
1501        h1 = &title[4];
1502
1503        /* can't count on a charset filter being in place here,
1504         * so do ebcdic->ascii translation explicitly (if needed)
1505         */
1506
1507        ap_rvputs_proto_in_ascii(r,
1508                  DOCTYPE_HTML_2_0
1509                  "<html><head>\n<title>", title,
1510                  "</title>\n</head><body>\n<h1>", h1, "</h1>\n",
1511                  NULL);
1512
1513        ap_rvputs_proto_in_ascii(r,
1514                                 get_canned_error_string(status, r, location),
1515                                 NULL);
1516
1517        if (recursive_error) {
1518            ap_rvputs_proto_in_ascii(r, "<p>Additionally, a ",
1519                      status_lines[ap_index_of_response(recursive_error)],
1520                      "\nerror was encountered while trying to use an "
1521                      "ErrorDocument to handle the request.</p>\n", NULL);
1522        }
1523        ap_rvputs_proto_in_ascii(r, ap_psignature("<hr>\n", r), NULL);
1524        ap_rvputs_proto_in_ascii(r, "</body></html>\n", NULL);
1525    }
1526    ap_finalize_request_protocol(r);
1527}
1528
1529/*
1530 * Create a new method list with the specified number of preallocated
1531 * extension slots.
1532 */
1533AP_DECLARE(ap_method_list_t *) ap_make_method_list(apr_pool_t *p, int nelts)
1534{
1535    ap_method_list_t *ml;
1536
1537    ml = (ap_method_list_t *) apr_palloc(p, sizeof(ap_method_list_t));
1538    ml->method_mask = 0;
1539    ml->method_list = apr_array_make(p, nelts, sizeof(char *));
1540    return ml;
1541}
1542
1543/*
1544 * Make a copy of a method list (primarily for subrequests that may
1545 * subsequently change it; don't want them changing the parent's, too!).
1546 */
1547AP_DECLARE(void) ap_copy_method_list(ap_method_list_t *dest,
1548                                     ap_method_list_t *src)
1549{
1550    int i;
1551    char **imethods;
1552    char **omethods;
1553
1554    dest->method_mask = src->method_mask;
1555    imethods = (char **) src->method_list->elts;
1556    for (i = 0; i < src->method_list->nelts; ++i) {
1557        omethods = (char **) apr_array_push(dest->method_list);
1558        *omethods = apr_pstrdup(dest->method_list->pool, imethods[i]);
1559    }
1560}
1561
1562/*
1563 * Return true if the specified HTTP method is in the provided
1564 * method list.
1565 */
1566AP_DECLARE(int) ap_method_in_list(ap_method_list_t *l, const char *method)
1567{
1568    int methnum;
1569    int i;
1570    char **methods;
1571
1572    /*
1573     * If it's one of our known methods, use the shortcut and check the
1574     * bitmask.
1575     */
1576    methnum = ap_method_number_of(method);
1577    if (methnum != M_INVALID) {
1578        return !!(l->method_mask & (AP_METHOD_BIT << methnum));
1579    }
1580    /*
1581     * Otherwise, see if the method name is in the array or string names
1582     */
1583    if ((l->method_list == NULL) || (l->method_list->nelts == 0)) {
1584        return 0;
1585    }
1586    methods = (char **)l->method_list->elts;
1587    for (i = 0; i < l->method_list->nelts; ++i) {
1588        if (strcmp(method, methods[i]) == 0) {
1589            return 1;
1590        }
1591    }
1592    return 0;
1593}
1594
1595/*
1596 * Add the specified method to a method list (if it isn't already there).
1597 */
1598AP_DECLARE(void) ap_method_list_add(ap_method_list_t *l, const char *method)
1599{
1600    int methnum;
1601    int i;
1602    const char **xmethod;
1603    char **methods;
1604
1605    /*
1606     * If it's one of our known methods, use the shortcut and use the
1607     * bitmask.
1608     */
1609    methnum = ap_method_number_of(method);
1610    l->method_mask |= (AP_METHOD_BIT << methnum);
1611    if (methnum != M_INVALID) {
1612        return;
1613    }
1614    /*
1615     * Otherwise, see if the method name is in the array of string names.
1616     */
1617    if (l->method_list->nelts != 0) {
1618        methods = (char **)l->method_list->elts;
1619        for (i = 0; i < l->method_list->nelts; ++i) {
1620            if (strcmp(method, methods[i]) == 0) {
1621                return;
1622            }
1623        }
1624    }
1625    xmethod = (const char **) apr_array_push(l->method_list);
1626    *xmethod = method;
1627}
1628
1629/*
1630 * Remove the specified method from a method list.
1631 */
1632AP_DECLARE(void) ap_method_list_remove(ap_method_list_t *l,
1633                                       const char *method)
1634{
1635    int methnum;
1636    char **methods;
1637
1638    /*
1639     * If it's a known methods, either builtin or registered
1640     * by a module, use the bitmask.
1641     */
1642    methnum = ap_method_number_of(method);
1643    l->method_mask |= ~(AP_METHOD_BIT << methnum);
1644    if (methnum != M_INVALID) {
1645        return;
1646    }
1647    /*
1648     * Otherwise, see if the method name is in the array of string names.
1649     */
1650    if (l->method_list->nelts != 0) {
1651        register int i, j, k;
1652        methods = (char **)l->method_list->elts;
1653        for (i = 0; i < l->method_list->nelts; ) {
1654            if (strcmp(method, methods[i]) == 0) {
1655                for (j = i, k = i + 1; k < l->method_list->nelts; ++j, ++k) {
1656                    methods[j] = methods[k];
1657                }
1658                --l->method_list->nelts;
1659            }
1660            else {
1661                ++i;
1662            }
1663        }
1664    }
1665}
1666
1667/*
1668 * Reset a method list to be completely empty.
1669 */
1670AP_DECLARE(void) ap_clear_method_list(ap_method_list_t *l)
1671{
1672    l->method_mask = 0;
1673    l->method_list->nelts = 0;
1674}
1675
1676