~ubuntu-branches/ubuntu/feisty/apache2/feisty

« back to all changes in this revision

Viewing changes to modules/http/http_protocol.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Barth
  • Date: 2006-12-09 21:05:45 UTC
  • mfrom: (0.6.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20061209210545-h70s0xaqc2v8vqr2
Tags: 2.2.3-3.2
* Non-maintainer upload.
* 043_ajp_connection_reuse: Patch from upstream Bugzilla, fixing a critical
  issue with regard to connection reuse in mod_proxy_ajp.
  Closes: #396265

Show diffs side-by-side

added added

removed removed

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