1 /** $MirOS: src/usr.sbin/httpd/src/main/http_protocol.c,v 1.13 2010/09/21 21:24:40 tg Exp $ */
2 /* $OpenBSD: http_protocol.c,v 1.32 2008/01/24 11:56:29 krw Exp $ */
3 /* ====================================================================
4 * The Apache Software License, Version 1.1
5 *
6 * Copyright (c) 2000-2003 The Apache Software Foundation. All rights
7 * reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
19 * distribution.
20 *
21 * 3. The end-user documentation included with the redistribution,
22 * if any, must include the following acknowledgment:
23 * "This product includes software developed by the
24 * Apache Software Foundation (http://www.apache.org/)."
25 * Alternately, this acknowledgment may appear in the software itself,
26 * if and wherever such third-party acknowledgments normally appear.
27 *
28 * 4. The names "Apache" and "Apache Software Foundation" must
29 * not be used to endorse or promote products derived from this
30 * software without prior written permission. For written
31 * permission, please contact apache@apache.org.
32 *
33 * 5. Products derived from this software may not be called "Apache",
34 * nor may "Apache" appear in their name, without prior written
35 * permission of the Apache Software Foundation.
36 *
37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
41 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48 * SUCH DAMAGE.
49 * ====================================================================
50 *
51 * This software consists of voluntary contributions made by many
52 * individuals on behalf of the Apache Software Foundation. For more
53 * information on the Apache Software Foundation, please see
54 * <http://www.apache.org/>.
55 *
56 * Portions of this software are based upon public domain software
57 * originally written at the National Center for Supercomputing Applications,
58 * University of Illinois, Urbana-Champaign.
59 */
60
61 /*
62 * http_protocol.c --- routines which directly communicate with the client.
63 *
64 * Code originally by Rob McCool; much redone by Robert S. Thau
65 * and the Apache Group.
66 */
67
68 #define CORE_PRIVATE
69 #include "httpd.h"
70 #include "http_config.h"
71 #include "http_core.h"
72 #include "http_protocol.h"
73 #include "http_main.h"
74 #include "http_request.h"
75 #include "http_vhost.h"
76 #include "http_log.h" /* For errors detected in basic auth common
77 * support code... */
78 #include "util_date.h" /* For parseHTTPdate and BAD_DATE */
79 #include <stdarg.h>
80 #include "http_conf_globals.h"
81 #include "util_md5.h" /* For digestAuth */
82 #include "ap_sha1.h"
83
84 __RCSID("$MirOS: src/usr.sbin/httpd/src/main/http_protocol.c,v 1.13 2010/09/21 21:24:40 tg Exp $");
85
86 #define SET_BYTES_SENT(r) \
87 do { if (r->sent_bodyct) \
88 ap_bgetopt (r->connection->client, BO_BYTECT, &r->bytes_sent); \
89 } while (0)
90
91 /*
92 * Builds the content-type that should be sent to the client from the
93 * content-type specified. The following rules are followed:
94 * - if type is NULL, type is set to ap_default_type(r)
95 * - if charset adding is disabled, stop processing and return type.
96 * - then, if there are no parameters on type, add the default charset
97 * - return type
98 */
make_content_type(request_rec * r,const char * type)99 static const char *make_content_type(request_rec *r, const char *type) {
100 char *needcset[] = {
101 "text/plain",
102 "text/html",
103 NULL };
104 char **pcset;
105 core_dir_config *conf;
106
107 conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
108 &core_module);
109 if (!type) {
110 type = ap_default_type(r);
111 }
112 if (conf->add_default_charset != ADD_DEFAULT_CHARSET_ON) {
113 return type;
114 }
115
116 if (ap_strcasestr(type, "charset=") != NULL) {
117 /* already has parameter, do nothing */
118 /* XXX we don't check the validity */
119 ;
120 }
121 else {
122 /* see if it makes sense to add the charset. At present,
123 * we only add it if the Content-type is one of needcset[]
124 */
125 for (pcset = needcset; *pcset ; pcset++) {
126 if (ap_strcasestr(type, *pcset) != NULL) {
127 type = ap_pstrcat(r->pool, type, "; charset=",
128 conf->add_default_charset_name, NULL);
129 break;
130 }
131 }
132 }
133 return type;
134 }
135
136 enum byterange_token {
137 BYTERANGE_OK,
138 BYTERANGE_EMPTY,
139 BYTERANGE_BADSYNTAX,
140 BYTERANGE_UNSATISFIABLE
141 };
142
143 static enum byterange_token
parse_byterange(request_rec * r,long * start,long * end)144 parse_byterange(request_rec *r, long *start, long *end)
145 {
146 /* parsing first, semantics later */
147
148 while (ap_isspace(*r->range))
149 ++r->range;
150
151 /* check for an empty range, which is OK */
152 if (*r->range == '\0') {
153 return BYTERANGE_EMPTY;
154 }
155 else if (*r->range == ',') {
156 ++r->range;
157 return BYTERANGE_EMPTY;
158 }
159
160 if (isdigit((unsigned char)*r->range))
161 *start = ap_strtol(r->range, (char **)&r->range, 10);
162 else
163 *start = -1;
164
165 while (ap_isspace(*r->range))
166 ++r->range;
167
168 if (*r->range != '-')
169 return BYTERANGE_BADSYNTAX;
170 ++r->range;
171
172 while (ap_isspace(*r->range))
173 ++r->range;
174
175 if (isdigit((unsigned char)*r->range))
176 *end = ap_strtol(r->range, (char **)&r->range, 10);
177 else
178 *end = -1;
179
180 while (ap_isspace(*r->range))
181 ++r->range;
182
183 /* check the end of the range */
184 if (*r->range == ',') {
185 ++r->range;
186 }
187 else if (*r->range != '\0') {
188 return BYTERANGE_BADSYNTAX;
189 }
190
191 /* parsing done; now check the numbers */
192
193 if (*start < 0) { /* suffix-byte-range-spec */
194 if (*end < 0) /* no numbers */
195 return BYTERANGE_BADSYNTAX;
196 *start = r->clength - *end;
197 if (*start < 0)
198 *start = 0;
199 *end = r->clength - 1;
200 }
201 else {
202 if (*end >= 0 && *start > *end) /* out-of-order range */
203 return BYTERANGE_BADSYNTAX;
204 if (*end < 0 || *end >= r->clength)
205 *end = r->clength - 1;
206 }
207 /* RFC 2616 is somewhat unclear about what we should do if the end
208 * is missing and the start is after the clength. The robustness
209 * principle says we should accept it as an unsatisfiable range.
210 * We accept suffix-byte-range-specs like -0 for the same reason.
211 */
212 if (*start >= r->clength)
213 return BYTERANGE_UNSATISFIABLE;
214
215 return BYTERANGE_OK;
216 }
217
218 /* If this function is called with output=1, it will spit out the
219 * correct headers for a byterange chunk. If output=0 it will not
220 * output anything but just return the number of bytes it would have
221 * output. If start or end are less than 0 then it will do a byterange
222 * chunk trailer instead of a header.
223 */
byterange_boundary(request_rec * r,long start,long end,int output)224 static int byterange_boundary(request_rec *r, long start, long end, int output)
225 {
226 int length = 0;
227
228 if (start < 0 || end < 0) {
229 if (output)
230 ap_rvputs(r, CRLF "--", r->boundary, "--" CRLF, NULL);
231 else
232 length = 4 + strlen(r->boundary) + 4;
233 }
234 else {
235 const char *ct = make_content_type(r, r->content_type);
236 char ts[MAX_STRING_LEN];
237
238 snprintf(ts, sizeof(ts), "%ld-%ld/%ld", start, end, r->clength);
239 if (output)
240 ap_rvputs(r, CRLF "--", r->boundary, CRLF "Content-type: ",
241 ct, CRLF "Content-range: bytes ", ts, CRLF CRLF,
242 NULL);
243 else
244 length = 4 + strlen(r->boundary) + 16
245 + strlen(ct) + 23 + strlen(ts) + 4;
246 }
247
248 return length;
249 }
250
ap_set_byterange(request_rec * r)251 API_EXPORT(int) ap_set_byterange(request_rec *r)
252 {
253 const char *range, *if_range, *match;
254 char *bbuf, *b;
255 u_int32_t rbuf[12]; /* 48 bytes yields 64 base64 chars */
256 long length, start, end, one_start = 0, one_end = 0;
257 size_t u;
258 int ranges, empty;
259
260 if (!r->clength || r->assbackwards)
261 return 0;
262
263 /* Check for Range request-header (HTTP/1.1) or Request-Range for
264 * backwards-compatibility with second-draft Luotonen/Franks
265 * byte-ranges (e.g. Netscape Navigator 2-3).
266 *
267 * We support this form, with Request-Range, and (farther down) we
268 * send multipart/x-byteranges instead of multipart/byteranges for
269 * Request-Range based requests to work around a bug in Netscape
270 * Navigator 2-3 and MSIE 3.
271 */
272
273 if (!(range = ap_table_get(r->headers_in, "Range")))
274 range = ap_table_get(r->headers_in, "Request-Range");
275
276 if (!range || strncasecmp(range, "bytes=", 6)) {
277 return 0;
278 }
279 range += 6;
280
281 /* Check the If-Range header for Etag or Date.
282 * Note that this check will return false (as required) if either
283 * of the two etags are weak.
284 */
285 if ((if_range = ap_table_get(r->headers_in, "If-Range"))) {
286 if (if_range[0] == '"') {
287 if (!(match = ap_table_get(r->headers_out, "Etag")) ||
288 (strcmp(if_range, match) != 0))
289 return 0;
290 }
291 else if (!(match = ap_table_get(r->headers_out, "Last-Modified")) ||
292 (strcmp(if_range, match) != 0))
293 return 0;
294 }
295
296 /*
297 * Parse the byteranges, counting how many of them there are and
298 * the total number of bytes we will send to the client. This is a
299 * dummy run for the while(ap_each_byterange()) loop that the
300 * caller will perform if we return 1.
301 */
302 r->range = range;
303 arc4random_buf(rbuf, sizeof(rbuf));
304 bbuf = ap_palloc(r->pool, ap_base64encode_len(sizeof(rbuf)));
305 ap_base64encode(bbuf, (const unsigned char *)rbuf, sizeof(rbuf));
306 for (b = bbuf; *b != '\0'; b++) {
307 if (((b - bbuf) + 1) % 7 == 0)
308 *b = '-';
309 else if (!isalnum(*b))
310 *b = 'a';
311 }
312
313 r->boundary = bbuf;
314
315 length = 0;
316 ranges = 0;
317 empty = 1;
318 do {
319 switch (parse_byterange(r, &start, &end)) {
320 case BYTERANGE_UNSATISFIABLE:
321 empty = 0;
322 break;
323 default:
324 /* be more defensive here? */
325 case BYTERANGE_BADSYNTAX:
326 r->boundary = NULL;
327 r->range = NULL;
328 return 0;
329 case BYTERANGE_EMPTY:
330 break;
331 case BYTERANGE_OK:
332 ++ranges;
333 length += byterange_boundary(r, start, end, 0)
334 + end - start + 1;
335 /* save in case of unsatisfiable ranges */
336 one_start = start;
337 one_end = end;
338 break;
339 }
340 } while (*r->range != '\0');
341
342 if (ranges == 0) {
343 /* no ranges or only unsatisfiable ranges */
344 if (empty || if_range) {
345 r->boundary = NULL;
346 r->range = NULL;
347 return 0;
348 }
349 else {
350 ap_table_setn(r->headers_out, "Content-Range",
351 ap_psprintf(r->pool, "bytes */%ld", r->clength));
352 ap_set_content_length(r, 0);
353 r->boundary = NULL;
354 r->range = range;
355 r->header_only = 1;
356 r->status = HTTP_RANGE_NOT_SATISFIABLE;
357 return 1;
358 }
359 }
360 else if (ranges == 1) {
361 /* simple handling of a single range -- no boundaries */
362 ap_table_setn(r->headers_out, "Content-Range",
363 ap_psprintf(r->pool, "bytes %ld-%ld/%ld",
364 one_start, one_end, r->clength));
365 ap_table_setn(r->headers_out, "Content-Length",
366 ap_psprintf(r->pool, "%ld", one_end - one_start + 1));
367 r->boundary = NULL;
368 r->byterange = 1;
369 r->range = range;
370 r->status = PARTIAL_CONTENT;
371 return 1;
372 }
373 else {
374 /* multiple ranges */
375 length += byterange_boundary(r, -1, -1, 0);
376 ap_table_setn(r->headers_out, "Content-Length",
377 ap_psprintf(r->pool, "%ld", length));
378 r->byterange = 2;
379 r->range = range;
380 r->status = PARTIAL_CONTENT;
381 return 1;
382 }
383 }
384
ap_each_byterange(request_rec * r,long * offset,long * length)385 API_EXPORT(int) ap_each_byterange(request_rec *r, long *offset, long *length)
386 {
387 long start, end;
388
389 do {
390 if (parse_byterange(r, &start, &end) == BYTERANGE_OK) {
391 if (r->byterange > 1)
392 byterange_boundary(r, start, end, 1);
393 *offset = start;
394 *length = end - start + 1;
395 return 1;
396 }
397 } while (*r->range != '\0');
398 if (r->byterange > 1)
399 byterange_boundary(r, -1, -1, 1);
400 return 0;
401 }
402
ap_set_content_length(request_rec * r,long clength)403 API_EXPORT(int) ap_set_content_length(request_rec *r, long clength)
404 {
405 r->clength = clength;
406 ap_table_setn(r->headers_out, "Content-Length", ap_psprintf(r->pool, "%ld", clength));
407 return 0;
408 }
409
ap_set_keepalive(request_rec * r)410 API_EXPORT(int) ap_set_keepalive(request_rec *r)
411 {
412 int ka_sent = 0;
413 int wimpy = ap_find_token(r->pool,
414 ap_table_get(r->headers_out, "Connection"), "close");
415 const char *conn = ap_table_get(r->headers_in, "Connection");
416
417 /* The following convoluted conditional determines whether or not
418 * the current connection should remain persistent after this response
419 * (a.k.a. HTTP Keep-Alive) and whether or not the output message
420 * body should use the HTTP/1.1 chunked transfer-coding. In English,
421 *
422 * IF we have not marked this connection as errored;
423 * and the response body has a defined length due to the status code
424 * being 304 or 204, the request method being HEAD, already
425 * having defined Content-Length or Transfer-Encoding: chunked, or
426 * the request version being HTTP/1.1 and thus capable of being set
427 * as chunked [we know the (r->chunked = 1) side-effect is ugly];
428 * and the server configuration enables keep-alive;
429 * and the server configuration has a reasonable inter-request timeout;
430 * and there is no maximum # requests or the max hasn't been reached;
431 * and the response status does not require a close;
432 * and the response generator has not already indicated close;
433 * and the client did not request non-persistence (Connection: close);
434 * and we haven't been configured to ignore the buggy twit
435 * or they're a buggy twit coming through a HTTP/1.1 proxy
436 * and the client is requesting an HTTP/1.0-style keep-alive
437 * or the client claims to be HTTP/1.1 compliant (perhaps a proxy);
438 * THEN we can be persistent, which requires more headers be output.
439 *
440 * Note that the condition evaluation order is extremely important.
441 */
442 if ((r->connection->keepalive != -1) &&
443 ((r->status == HTTP_NOT_MODIFIED) ||
444 (r->status == HTTP_NO_CONTENT) ||
445 r->header_only ||
446 ap_table_get(r->headers_out, "Content-Length") ||
447 ap_find_last_token(r->pool,
448 ap_table_get(r->headers_out, "Transfer-Encoding"),
449 "chunked") ||
450 ((r->proto_num >= HTTP_VERSION(1,1)) &&
451 (r->chunked = 1))) && /* THIS CODE IS CORRECT, see comment above. */
452 r->server->keep_alive &&
453 (r->server->keep_alive_timeout > 0) &&
454 ((r->server->keep_alive_max == 0) ||
455 (r->server->keep_alive_max > r->connection->keepalives)) &&
456 !ap_status_drops_connection(r->status) &&
457 !wimpy &&
458 !ap_find_token(r->pool, conn, "close") &&
459 (!ap_table_get(r->subprocess_env, "nokeepalive") ||
460 ap_table_get(r->headers_in, "Via")) &&
461 ((ka_sent = ap_find_token(r->pool, conn, "keep-alive")) ||
462 (r->proto_num >= HTTP_VERSION(1,1)))
463 ) {
464 int left = r->server->keep_alive_max - r->connection->keepalives;
465
466 r->connection->keepalive = 1;
467 r->connection->keepalives++;
468
469 /* If they sent a Keep-Alive token, send one back */
470 if (ka_sent) {
471 if (r->server->keep_alive_max)
472 ap_table_setn(r->headers_out, "Keep-Alive",
473 ap_psprintf(r->pool, "timeout=%d, max=%d",
474 r->server->keep_alive_timeout, left));
475 else
476 ap_table_setn(r->headers_out, "Keep-Alive",
477 ap_psprintf(r->pool, "timeout=%d",
478 r->server->keep_alive_timeout));
479 ap_table_mergen(r->headers_out, "Connection", "Keep-Alive");
480 }
481
482 return 1;
483 }
484
485 /* Otherwise, we need to indicate that we will be closing this
486 * connection immediately after the current response.
487 *
488 * We only really need to send "close" to HTTP/1.1 clients, but we
489 * always send it anyway, because a broken proxy may identify itself
490 * as HTTP/1.0, but pass our request along with our HTTP/1.1 tag
491 * to a HTTP/1.1 client. Better safe than sorry.
492 */
493 if (!wimpy)
494 ap_table_mergen(r->headers_out, "Connection", "close");
495
496 r->connection->keepalive = 0;
497
498 return 0;
499 }
500
501 /*
502 * Return the latest rational time from a request/mtime (modification time)
503 * pair. We return the mtime unless it's in the future, in which case we
504 * return the current time. We use the request time as a reference in order
505 * to limit the number of calls to time(). We don't check for futurosity
506 * unless the mtime is at least as new as the reference.
507 */
ap_rationalize_mtime(request_rec * r,time_t mtime)508 API_EXPORT(time_t) ap_rationalize_mtime(request_rec *r, time_t mtime)
509 {
510 time_t now;
511
512 /* For all static responses, it's almost certain that the file was
513 * last modified before the beginning of the request. So there's
514 * no reason to call time(NULL) again. But if the response has been
515 * created on demand, then it might be newer than the time the request
516 * started. In this event we really have to call time(NULL) again
517 * so that we can give the clients the most accurate Last-Modified. If we
518 * were given a time in the future, we return the current time - the
519 * Last-Modified can't be in the future.
520 */
521 now = (mtime < r->request_time) ? r->request_time : time(NULL);
522 return (mtime > now) ? now : mtime;
523 }
524
ap_meets_conditions(request_rec * r)525 API_EXPORT(int) ap_meets_conditions(request_rec *r)
526 {
527 const char *etag = ap_table_get(r->headers_out, "ETag");
528 const char *if_match, *if_modified_since, *if_unmodified, *if_nonematch;
529 time_t mtime;
530
531 /* Check for conditional requests --- note that we only want to do
532 * this if we are successful so far and we are not processing a
533 * subrequest or an ErrorDocument.
534 *
535 * The order of the checks is important, since ETag checks are supposed
536 * to be more accurate than checks relative to the modification time.
537 * However, not all documents are guaranteed to *have* ETags, and some
538 * might have Last-Modified values w/o ETags, so this gets a little
539 * complicated.
540 */
541
542 if (!ap_is_HTTP_SUCCESS(r->status) || r->no_local_copy) {
543 return OK;
544 }
545
546 mtime = (r->mtime != 0) ? r->mtime : time(NULL);
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 if ((if_match = ap_table_get(r->headers_in, "If-Match")) != NULL) {
554 if (if_match[0] != '*' &&
555 (etag == NULL || etag[0] == 'W' ||
556 !ap_find_list_item(r->pool, if_match, etag))) {
557 return HTTP_PRECONDITION_FAILED;
558 }
559 }
560 else {
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 if_unmodified = ap_table_get(r->headers_in, "If-Unmodified-Since");
567 if (if_unmodified != NULL) {
568 time_t ius = ap_parseHTTPdate(if_unmodified);
569
570 if ((ius != BAD_DATE) && (mtime > ius)) {
571 return HTTP_PRECONDITION_FAILED;
572 }
573 }
574 }
575
576 /* If an If-None-Match request-header field was given
577 * AND the field value is "*" (meaning match anything)
578 * OR our ETag matches any of the entity tags in that field, fail.
579 *
580 * If the request method was GET or HEAD, failure means the server
581 * SHOULD respond with a 304 (Not Modified) response.
582 * For all other request methods, failure means the server MUST
583 * respond with a status of 412 (Precondition Failed).
584 *
585 * GET or HEAD allow weak etag comparison, all other methods require
586 * strong comparison. We can only use weak if it's not a range request.
587 */
588 if_nonematch = ap_table_get(r->headers_in, "If-None-Match");
589 if (if_nonematch != NULL) {
590 if (r->method_number == M_GET) {
591 if (if_nonematch[0] == '*')
592 return HTTP_NOT_MODIFIED;
593 if (etag != NULL) {
594 if (ap_table_get(r->headers_in, "Range")) {
595 if (etag[0] != 'W' &&
596 ap_find_list_item(r->pool, if_nonematch, etag)) {
597 return HTTP_NOT_MODIFIED;
598 }
599 }
600 else if (strstr(if_nonematch, etag)) {
601 return HTTP_NOT_MODIFIED;
602 }
603 }
604 }
605 else if (if_nonematch[0] == '*' ||
606 (etag != NULL &&
607 ap_find_list_item(r->pool, if_nonematch, etag))) {
608 return HTTP_PRECONDITION_FAILED;
609 }
610 }
611 /* Else if a valid If-Modified-Since request-header field was given
612 * AND it is a GET or HEAD request
613 * AND the requested resource has not been modified since the time
614 * specified in this field, then the server MUST
615 * respond with a status of 304 (Not Modified).
616 * A date later than the server's current request time is invalid.
617 */
618 else if ((r->method_number == M_GET)
619 && ((if_modified_since =
620 ap_table_get(r->headers_in, "If-Modified-Since")) != NULL)) {
621 time_t ims = ap_parseHTTPdate(if_modified_since);
622
623 if ((ims >= mtime) && (ims <= r->request_time)) {
624 return HTTP_NOT_MODIFIED;
625 }
626 }
627 return OK;
628 }
629
630 /*
631 * Construct an entity tag (ETag) from resource information. If it's a real
632 * file, build in some of the file characteristics. If the modification time
633 * is newer than (request-time minus 1 second), mark the ETag as weak - it
634 * could be modified again in as short an interval. We rationalize the
635 * modification time we're given to keep it from being in the future.
636 */
ap_make_etag_orig(request_rec * r,int force_weak)637 API_EXPORT(char *) ap_make_etag_orig(request_rec *r, int force_weak)
638 {
639 char *etag;
640 char *weak;
641 core_dir_config *cfg;
642 etag_components_t etag_bits;
643
644 cfg = (core_dir_config *)ap_get_module_config(r->per_dir_config,
645 &core_module);
646 etag_bits = (cfg->etag_bits & (~ cfg->etag_remove)) | cfg->etag_add;
647 if (etag_bits == ETAG_UNSET) {
648 etag_bits = ETAG_BACKWARD;
649 }
650 /*
651 * Make an ETag header out of various pieces of information. We use
652 * the last-modified date and, if we have a real file, the
653 * length and inode number - note that this doesn't have to match
654 * the content-length (i.e. includes), it just has to be unique
655 * for the file.
656 *
657 * If the request was made within a second of the last-modified date,
658 * we send a weak tag instead of a strong one, since it could
659 * be modified again later in the second, and the validation
660 * would be incorrect.
661 */
662
663 weak = ((r->request_time - r->mtime > 1) && !force_weak) ? "" : "W/";
664
665 if (r->finfo.st_mode != 0) {
666 char **ent;
667 array_header *components;
668 int i;
669
670 /*
671 * If it's a file (or we wouldn't be here) and no ETags
672 * should be set for files, return an empty string and
673 * note it for ap_send_header_field() to ignore.
674 */
675 if (etag_bits & ETAG_NONE) {
676 ap_table_setn(r->notes, "no-etag", "omit");
677 return "";
678 }
679
680 components = ap_make_array(r->pool, 4, sizeof(char *));
681 if (etag_bits & ETAG_INODE) {
682 ent = (char **) ap_push_array(components);
683 *ent = ap_psprintf(r->pool, "%lx",
684 (unsigned long) r->finfo.st_ino);
685 }
686 if (etag_bits & ETAG_SIZE) {
687 ent = (char **) ap_push_array(components);
688 *ent = ap_psprintf(r->pool, "%lx",
689 (unsigned long) r->finfo.st_size);
690 }
691 if (etag_bits & ETAG_MTIME) {
692 ent = (char **) ap_push_array(components);
693 *ent = ap_psprintf(r->pool, "%lx", (unsigned long) r->mtime);
694 }
695 ent = (char **) components->elts;
696 etag = ap_pstrcat(r->pool, weak, "\"", NULL);
697 for (i = 0; i < components->nelts; ++i) {
698 etag = ap_psprintf(r->pool, "%s%s%s", etag,
699 (i == 0 ? "" : "-"),
700 ent[i]);
701 }
702 etag = ap_pstrcat(r->pool, etag, "\"", NULL);
703 }
704 else {
705 etag = ap_psprintf(r->pool, "%s\"%lx\"", weak,
706 (unsigned long) r->mtime);
707 }
708
709 return etag;
710 }
711
ap_set_etag(request_rec * r)712 API_EXPORT(void) ap_set_etag(request_rec *r)
713 {
714 char *etag;
715 char *variant_etag, *vlv;
716 int vlv_weak;
717
718 if (!r->vlist_validator) {
719 etag = ap_make_etag(r, 0);
720
721 /* If we get a blank etag back, don't set the header. */
722 if (!etag[0]) {
723 return;
724 }
725 }
726 else {
727 /* If we have a variant list validator (vlv) due to the
728 * response being negotiated, then we create a structured
729 * entity tag which merges the variant etag with the variant
730 * list validator (vlv). This merging makes revalidation
731 * somewhat safer, ensures that caches which can deal with
732 * Vary will (eventually) be updated if the set of variants is
733 * changed, and is also a protocol requirement for transparent
734 * content negotiation.
735 */
736
737 /* if the variant list validator is weak, we make the whole
738 * structured etag weak. If we would not, then clients could
739 * have problems merging range responses if we have different
740 * variants with the same non-globally-unique strong etag.
741 */
742
743 vlv = r->vlist_validator;
744 vlv_weak = (vlv[0] == 'W');
745
746 variant_etag = ap_make_etag(r, vlv_weak);
747
748 /* If we get a blank etag back, don't append vlv and stop now. */
749 if (!variant_etag[0]) {
750 return;
751 }
752
753 /* merge variant_etag and vlv into a structured etag */
754 variant_etag[strlen(variant_etag) - 1] = '\0';
755 if (vlv_weak)
756 vlv += 3;
757 else
758 vlv++;
759 etag = ap_pstrcat(r->pool, variant_etag, ";", vlv, NULL);
760 }
761
762 ap_table_setn(r->headers_out, "ETag", etag);
763 }
764
765 /*
766 * This function sets the Last-Modified output header field to the value
767 * of the mtime field in the request structure - rationalized to keep it from
768 * being in the future.
769 */
ap_set_last_modified(request_rec * r)770 API_EXPORT(void) ap_set_last_modified(request_rec *r)
771 {
772 time_t mod_time = ap_rationalize_mtime(r, r->mtime);
773
774 ap_table_setn(r->headers_out, "Last-Modified",
775 ap_gm_timestr_822(r->pool, mod_time));
776 }
777
778 /* Get the method number associated with the given string, assumed to
779 * contain an HTTP method. Returns M_INVALID if not recognized.
780 *
781 * This is the first step toward placing method names in a configurable
782 * list. Hopefully it (and other routines) can eventually be moved to
783 * something like a mod_http_methods.c, complete with config stuff.
784 */
ap_method_number_of(const char * method)785 API_EXPORT(int) ap_method_number_of(const char *method)
786 {
787 switch (*method) {
788 case 'H':
789 if (strcmp(method, "HEAD") == 0)
790 return M_GET; /* see header_only in request_rec */
791 break;
792 case 'G':
793 if (strcmp(method, "GET") == 0)
794 return M_GET;
795 break;
796 case 'P':
797 if (strcmp(method, "POST") == 0)
798 return M_POST;
799 if (strcmp(method, "PUT") == 0)
800 return M_PUT;
801 if (strcmp(method, "PATCH") == 0)
802 return M_PATCH;
803 if (strcmp(method, "PROPFIND") == 0)
804 return M_PROPFIND;
805 if (strcmp(method, "PROPPATCH") == 0)
806 return M_PROPPATCH;
807 break;
808 case 'D':
809 if (strcmp(method, "DELETE") == 0)
810 return M_DELETE;
811 break;
812 case 'C':
813 if (strcmp(method, "CONNECT") == 0)
814 return M_CONNECT;
815 if (strcmp(method, "COPY") == 0)
816 return M_COPY;
817 break;
818 case 'M':
819 if (strcmp(method, "MKCOL") == 0)
820 return M_MKCOL;
821 if (strcmp(method, "MOVE") == 0)
822 return M_MOVE;
823 break;
824 case 'O':
825 if (strcmp(method, "OPTIONS") == 0)
826 return M_OPTIONS;
827 break;
828 case 'L':
829 if (strcmp(method, "LOCK") == 0)
830 return M_LOCK;
831 break;
832 case 'U':
833 if (strcmp(method, "UNLOCK") == 0)
834 return M_UNLOCK;
835 break;
836 }
837 return M_INVALID;
838 }
839
840 /* Get a line of protocol input, including any continuation lines
841 * caused by MIME folding (or broken clients) if fold != 0, and place it
842 * in the buffer s, of size n bytes, without the ending newline.
843 *
844 * Returns -1 on error, or the length of s.
845 *
846 * Note: Because bgets uses 1 char for newline and 1 char for NUL,
847 * the most we can get is (n - 2) actual characters if it
848 * was ended by a newline, or (n - 1) characters if the line
849 * length exceeded (n - 1). So, if the result == (n - 1),
850 * then the actual input line exceeded the buffer length,
851 * and it would be a good idea for the caller to puke 400 or 414.
852 */
ap_getline(char * s,int n,BUFF * in,int fold)853 API_EXPORT(int) ap_getline(char *s, int n, BUFF *in, int fold)
854 {
855 char *pos, next;
856 int retval;
857 int total = 0;
858
859 pos = s;
860
861 do {
862 retval = ap_bgets(pos, n, in); /* retval == -1 if error, 0 if EOF */
863
864 if (retval <= 0) {
865 total = ((retval < 0) && (total == 0)) ? -1 : total;
866 break;
867 }
868
869 /* retval is the number of characters read, not including NUL */
870
871 n -= retval; /* Keep track of how much of s is full */
872 pos += (retval - 1); /* and where s ends */
873 total += retval; /* and how long s has become */
874
875 if (*pos == '\n') { /* Did we get a full line of input? */
876 /*
877 * Trim any extra trailing spaces or tabs except for the first
878 * space or tab at the beginning of a blank string. This makes
879 * it much easier to check field values for exact matches, and
880 * saves memory as well. Terminate string at end of line.
881 */
882 while (pos > (s + 1) && (*(pos - 1) == ' ' || *(pos - 1) == '\t')) {
883 --pos; /* trim extra trailing spaces or tabs */
884 --total; /* but not one at the beginning of line */
885 ++n;
886 }
887 *pos = '\0';
888 --total;
889 ++n;
890 }
891 else
892 break; /* if not, input line exceeded buffer size */
893
894 /* Continue appending if line folding is desired and
895 * the last line was not empty and we have room in the buffer and
896 * the next line begins with a continuation character.
897 */
898 } while (fold && (retval != 1) && (n > 1)
899 && (ap_blookc(&next, in) == 1)
900 && ((next == ' ') || (next == '\t')));
901
902 return total;
903 }
904
905 /* parse_uri: break apart the uri
906 * Side Effects:
907 * - sets r->args to rest after '?' (or NULL if no '?')
908 * - sets r->uri to request uri (without r->args part)
909 * - sets r->hostname (if not set already) from request (scheme://host:port)
910 */
ap_parse_uri(request_rec * r,const char * uri)911 CORE_EXPORT(void) ap_parse_uri(request_rec *r, const char *uri)
912 {
913 int status = HTTP_OK;
914
915 r->unparsed_uri = ap_pstrdup(r->pool, uri);
916
917 if (r->method_number == M_CONNECT) {
918 status = ap_parse_hostinfo_components(r->pool, uri, &r->parsed_uri);
919 } else {
920 /* Simple syntax Errors in URLs are trapped by parse_uri_components(). */
921 status = ap_parse_uri_components(r->pool, uri, &r->parsed_uri);
922 }
923
924 if (ap_is_HTTP_SUCCESS(status)) {
925 /* if it has a scheme we may need to do absoluteURI vhost stuff */
926 if (r->parsed_uri.scheme
927 && !strcasecmp(r->parsed_uri.scheme, ap_http_method(r))) {
928 r->hostname = r->parsed_uri.hostname;
929 } else if (r->method_number == M_CONNECT) {
930 r->hostname = r->parsed_uri.hostname;
931 }
932 r->args = r->parsed_uri.query;
933 r->uri = r->parsed_uri.path ? r->parsed_uri.path
934 : ap_pstrdup(r->pool, "/");
935 }
936 else {
937 r->args = NULL;
938 r->hostname = NULL;
939 r->status = status; /* set error status */
940 r->uri = ap_pstrdup(r->pool, uri);
941 }
942 }
943
read_request_line(request_rec * r)944 static int read_request_line(request_rec *r)
945 {
946 char l[DEFAULT_LIMIT_REQUEST_LINE + 2]; /* ap_getline's two extra for \n\0 */
947 const char *ll = l;
948 const char *uri;
949 conn_rec *conn = r->connection;
950 unsigned int major = 1, minor = 0; /* Assume HTTP/1.0 if non-"HTTP" protocol */
951 int len = 0;
952 int valid_protocol = 1;
953
954 /* Read past empty lines until we get a real request line,
955 * a read error, the connection closes (EOF), or we timeout.
956 *
957 * We skip empty lines because browsers have to tack a CRLF on to the end
958 * of POSTs to support old CERN webservers. But note that we may not
959 * have flushed any previous response completely to the client yet.
960 * We delay the flush as long as possible so that we can improve
961 * performance for clients that are pipelining requests. If a request
962 * is pipelined then we won't block during the (implicit) read() below.
963 * If the requests aren't pipelined, then the client is still waiting
964 * for the final buffer flush from us, and we will block in the implicit
965 * read(). B_SAFEREAD ensures that the BUFF layer flushes if it will
966 * have to block during a read.
967 */
968 ap_bsetflag(conn->client, B_SAFEREAD, 1);
969 while ((len = ap_getline(l, sizeof(l), conn->client, 0)) <= 0) {
970 if ((len < 0) || ap_bgetflag(conn->client, B_EOF)) {
971 ap_bsetflag(conn->client, B_SAFEREAD, 0);
972 /* this is a hack to make sure that request time is set,
973 * it's not perfect, but it's better than nothing
974 */
975 r->request_time = time(0);
976 return 0;
977 }
978 }
979 /* we've probably got something to do, ignore graceful restart requests */
980 signal(SIGUSR1, SIG_IGN);
981
982 ap_bsetflag(conn->client, B_SAFEREAD, 0);
983
984 r->request_time = time(NULL);
985 r->the_request = ap_pstrdup(r->pool, l);
986 r->method = ap_getword_white(r->pool, &ll);
987 uri = ap_getword_white(r->pool, &ll);
988
989 /* Provide quick information about the request method as soon as known */
990
991 r->method_number = ap_method_number_of(r->method);
992 if (r->method_number == M_GET && r->method[0] == 'H') {
993 r->header_only = 1;
994 }
995
996 ap_parse_uri(r, uri);
997
998 /* ap_getline returns (size of max buffer - 1) if it fills up the
999 * buffer before finding the end-of-line. This is only going to
1000 * happen if it exceeds the configured limit for a request-line.
1001 */
1002 if (len > r->server->limit_req_line) {
1003 r->status = HTTP_REQUEST_URI_TOO_LARGE;
1004 r->proto_num = HTTP_VERSION(1,0);
1005 r->protocol = ap_pstrdup(r->pool, "HTTP/1.0");
1006 return 0;
1007 }
1008
1009 r->assbackwards = (ll[0] == '\0');
1010 r->protocol = ap_pstrdup(r->pool, ll[0] ? ll : "HTTP/0.9");
1011
1012 /* Avoid sscanf in the common case */
1013 if (strlen(r->protocol) == 8
1014 && r->protocol[0] == 'H' && r->protocol[1] == 'T'
1015 && r->protocol[2] == 'T' && r->protocol[3] == 'P'
1016 && r->protocol[4] == '/' && isdigit((unsigned char)r->protocol[5])
1017 && r->protocol[6] == '.' && isdigit((unsigned char)r->protocol[7])) {
1018 r->proto_num = HTTP_VERSION(r->protocol[5] - '0', r->protocol[7] - '0');
1019 }
1020 else {
1021 char lint[2];
1022 char http[5];
1023 if (3 == sscanf(r->protocol, "%4s/%u.%u%1s", http, &major, &minor, lint)
1024 && (strcasecmp("http", http) == 0)
1025 && (minor < HTTP_VERSION(1,0)) ) /* don't allow HTTP/0.1000 */
1026 r->proto_num = HTTP_VERSION(major, minor);
1027 else {
1028 r->proto_num = HTTP_VERSION(1,0);
1029 valid_protocol = 0;
1030 }
1031 }
1032
1033 /* Check for a valid protocol, and disallow everything but whitespace
1034 * after the protocol string. A protocol string of nothing but
1035 * whitespace is considered valid */
1036 if (ap_protocol_req_check && !valid_protocol) {
1037 int n = 0;
1038 while (ap_isspace(r->protocol[n]))
1039 ++n;
1040 if (r->protocol[n] != '\0') {
1041 r->status = HTTP_BAD_REQUEST;
1042 r->proto_num = HTTP_VERSION(1,0);
1043 r->protocol = ap_pstrdup(r->pool, "HTTP/1.0");
1044 ap_table_setn(r->notes, "error-notes",
1045 "The request line contained invalid characters "
1046 "following the protocol string.<P>\n");
1047 return 0;
1048 }
1049 }
1050
1051 return 1;
1052 }
1053
get_mime_headers(request_rec * r)1054 static void get_mime_headers(request_rec *r)
1055 {
1056 char field[DEFAULT_LIMIT_REQUEST_FIELDSIZE + 2]; /* ap_getline's two extra */
1057 conn_rec *c = r->connection;
1058 char *value;
1059 char *copy;
1060 int len;
1061 int fields_read = 0;
1062 table *tmp_headers;
1063
1064 /* We'll use ap_overlap_tables later to merge these into r->headers_in. */
1065 tmp_headers = ap_make_table(r->pool, 50);
1066
1067 /*
1068 * Read header lines until we get the empty separator line, a read error,
1069 * the connection closes (EOF), reach the server limit, or we timeout.
1070 */
1071 while ((len = ap_getline(field, sizeof(field), c->client, 1)) > 0) {
1072
1073 if (r->server->limit_req_fields &&
1074 (++fields_read > r->server->limit_req_fields)) {
1075 r->status = HTTP_BAD_REQUEST;
1076 ap_table_setn(r->notes, "error-notes",
1077 "The number of request header fields exceeds "
1078 "this server's limit.<P>\n");
1079 return;
1080 }
1081 /* ap_getline returns (size of max buffer - 1) if it fills up the
1082 * buffer before finding the end-of-line. This is only going to
1083 * happen if it exceeds the configured limit for a field size.
1084 */
1085 if (len > r->server->limit_req_fieldsize) {
1086 r->status = HTTP_BAD_REQUEST;
1087 ap_table_setn(r->notes, "error-notes", ap_pstrcat(r->pool,
1088 "Size of a request header field exceeds server limit.<P>\n"
1089 "<PRE>\n", ap_escape_html(r->pool, field), "</PRE>\n", NULL));
1090 return;
1091 }
1092 copy = ap_palloc(r->pool, len + 1);
1093 memcpy(copy, field, len + 1);
1094
1095 if (!(value = strchr(copy, ':'))) { /* Find the colon separator */
1096 r->status = HTTP_BAD_REQUEST; /* or abort the bad request */
1097 ap_table_setn(r->notes, "error-notes", ap_pstrcat(r->pool,
1098 "Request header field is missing colon separator.<P>\n"
1099 "<PRE>\n", ap_escape_html(r->pool, copy), "</PRE>\n", NULL));
1100 return;
1101 }
1102
1103 *value = '\0';
1104 ++value;
1105 while (*value == ' ' || *value == '\t')
1106 ++value; /* Skip to start of value */
1107
1108 ap_table_addn(tmp_headers, copy, value);
1109 }
1110
1111 ap_overlap_tables(r->headers_in, tmp_headers, AP_OVERLAP_TABLES_MERGE);
1112 }
1113
ap_read_request(conn_rec * conn)1114 API_EXPORT(request_rec *) ap_read_request(conn_rec *conn)
1115 {
1116 request_rec *r;
1117 pool *p;
1118 const char *expect;
1119 int access_status;
1120
1121 p = ap_make_sub_pool(conn->pool);
1122 r = ap_pcalloc(p, sizeof(request_rec));
1123 r->pool = p;
1124 r->connection = conn;
1125 conn->server = conn->base_server;
1126 r->server = conn->server;
1127
1128 conn->keptalive = conn->keepalive == 1;
1129 conn->keepalive = 0;
1130
1131 conn->user = NULL;
1132 conn->ap_auth_type = NULL;
1133
1134 r->headers_in = ap_make_table(r->pool, 50);
1135 r->subprocess_env = ap_make_table(r->pool, 50);
1136 r->headers_out = ap_make_table(r->pool, 12);
1137 r->err_headers_out = ap_make_table(r->pool, 5);
1138 r->notes = ap_make_table(r->pool, 5);
1139
1140 r->request_config = ap_create_request_config(r->pool);
1141 r->per_dir_config = r->server->lookup_defaults;
1142
1143 r->sent_bodyct = 0; /* bytect isn't for body */
1144
1145 r->read_length = 0;
1146 r->read_body = REQUEST_NO_BODY;
1147
1148 r->status = HTTP_REQUEST_TIME_OUT; /* Until we get a request */
1149 r->the_request = NULL;
1150
1151 r->ctx = ap_ctx_new(r->pool);
1152
1153 switch (conn->remote_addr.ss_family) {
1154 case AF_INET:
1155 ap_table_setn(r->notes, "address-family", "IPv4");
1156 break;
1157 #ifdef INET6
1158 case AF_INET6:
1159 ap_table_setn(r->notes, "address-family", "IPv6");
1160 break;
1161 #endif
1162 }
1163
1164 /* Get the request... */
1165
1166 ap_keepalive_timeout("read request line", r);
1167 if (!read_request_line(r)) {
1168 ap_kill_timeout(r);
1169 if (r->status == HTTP_REQUEST_URI_TOO_LARGE) {
1170
1171 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
1172 "request failed: URI too long");
1173 ap_send_error_response(r, 0);
1174 ap_log_transaction(r);
1175 return r;
1176 }
1177 else if (r->status == HTTP_BAD_REQUEST) {
1178 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
1179 "request failed: erroneous characters after protocol string: %s",
1180 ap_escape_logitem(r->pool, r->the_request));
1181 ap_send_error_response(r, 0);
1182 ap_log_transaction(r);
1183 return r;
1184 }
1185 return NULL;
1186 }
1187 if (!r->assbackwards) {
1188 ap_hard_timeout("read request headers", r);
1189 get_mime_headers(r);
1190 ap_kill_timeout(r);
1191 if (r->status != HTTP_REQUEST_TIME_OUT) {
1192 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
1193 "request failed: error reading the headers");
1194 ap_send_error_response(r, 0);
1195 ap_log_transaction(r);
1196 return r;
1197 }
1198 }
1199 else {
1200 ap_kill_timeout(r);
1201
1202 if (r->header_only) {
1203 /*
1204 * Client asked for headers only with HTTP/0.9, which doesn't send
1205 * headers! Have to dink things just to make sure the error message
1206 * comes through...
1207 */
1208 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
1209 "client sent invalid HTTP/0.9 request: HEAD %s",
1210 r->uri);
1211 r->header_only = 0;
1212 r->status = HTTP_BAD_REQUEST;
1213 ap_send_error_response(r, 0);
1214 ap_log_transaction(r);
1215 return r;
1216 }
1217 }
1218
1219 r->status = HTTP_OK; /* Until further notice. */
1220
1221 /* update what we think the virtual host is based on the headers we've
1222 * now read. may update status.
1223 */
1224 ap_update_vhost_from_headers(r);
1225
1226 /* we may have switched to another server */
1227 r->per_dir_config = r->server->lookup_defaults;
1228
1229 conn->keptalive = 0; /* We now have a request to play with */
1230
1231 if ((!r->hostname && (r->proto_num >= HTTP_VERSION(1,1))) ||
1232 ((r->proto_num == HTTP_VERSION(1,1)) &&
1233 !ap_table_get(r->headers_in, "Host"))) {
1234 /*
1235 * Client sent us an HTTP/1.1 or later request without telling us the
1236 * hostname, either with a full URL or a Host: header. We therefore
1237 * need to (as per the 1.1 spec) send an error. As a special case,
1238 * HTTP/1.1 mentions twice (S9, S14.23) that a request MUST contain
1239 * a Host: header, and the server MUST respond with 400 if it doesn't.
1240 */
1241 r->status = HTTP_BAD_REQUEST;
1242 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
1243 "client sent HTTP/1.1 request without hostname "
1244 "(see RFC2616 section 14.23): %s", r->uri);
1245 }
1246 if (r->status != HTTP_OK) {
1247 ap_send_error_response(r, 0);
1248 ap_log_transaction(r);
1249 return r;
1250 }
1251
1252 if ((access_status = ap_run_post_read_request(r))) {
1253 ap_die(access_status, r);
1254 ap_log_transaction(r);
1255 return NULL;
1256 }
1257
1258 if (((expect = ap_table_get(r->headers_in, "Expect")) != NULL) &&
1259 (expect[0] != '\0')) {
1260 /*
1261 * The Expect header field was added to HTTP/1.1 after RFC 2068
1262 * as a means to signal when a 100 response is desired and,
1263 * unfortunately, to signal a poor man's mandatory extension that
1264 * the server must understand or return 417 Expectation Failed.
1265 */
1266 if (strcasecmp(expect, "100-continue") == 0) {
1267 r->expecting_100 = 1;
1268 }
1269 else {
1270 r->status = HTTP_EXPECTATION_FAILED;
1271 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, r,
1272 "client sent an unrecognized expectation value of "
1273 "Expect: %s", expect);
1274 ap_send_error_response(r, 0);
1275 (void) ap_discard_request_body(r);
1276 ap_log_transaction(r);
1277 return r;
1278 }
1279 }
1280
1281 return r;
1282 }
1283
1284 /*
1285 * A couple of other functions which initialize some of the fields of
1286 * a request structure, as appropriate for adjuncts of one kind or another
1287 * to a request in progress. Best here, rather than elsewhere, since
1288 * *someone* has to set the protocol-specific fields...
1289 */
1290
ap_set_sub_req_protocol(request_rec * rnew,const request_rec * r)1291 API_EXPORT(void) ap_set_sub_req_protocol(request_rec *rnew, const request_rec *r)
1292 {
1293 const char *ccp;
1294
1295 rnew->the_request = r->the_request; /* Keep original request-line */
1296
1297 rnew->assbackwards = 1; /* Don't send headers from this. */
1298 rnew->no_local_copy = 1; /* Don't try to send USE_LOCAL_COPY for a
1299 * fragment. */
1300 rnew->method = "GET";
1301 rnew->method_number = M_GET;
1302 rnew->protocol = "INCLUDED";
1303
1304 rnew->status = HTTP_OK;
1305
1306 rnew->headers_in = r->headers_in;
1307 rnew->subprocess_env = ap_copy_table(rnew->pool, r->subprocess_env);
1308 rnew->headers_out = ap_make_table(rnew->pool, 5);
1309 rnew->err_headers_out = ap_make_table(rnew->pool, 5);
1310 rnew->notes = ap_make_table(rnew->pool, 5);
1311
1312 rnew->expecting_100 = r->expecting_100;
1313 rnew->read_length = r->read_length;
1314 rnew->read_body = REQUEST_NO_BODY;
1315
1316 rnew->main = (request_rec *) r;
1317
1318 if ((ccp = ap_table_get(r->notes, "address-family")) != NULL)
1319 ap_table_setn(rnew->notes, "address-family", ccp);
1320
1321 rnew->ctx = r->ctx;
1322
1323 }
1324
ap_finalize_sub_req_protocol(request_rec * sub)1325 API_EXPORT(void) ap_finalize_sub_req_protocol(request_rec *sub)
1326 {
1327 SET_BYTES_SENT(sub->main);
1328 }
1329
1330 /*
1331 * Support for the Basic authentication protocol, and a bit for Digest.
1332 */
1333
ap_note_auth_failure(request_rec * r)1334 API_EXPORT(void) ap_note_auth_failure(request_rec *r)
1335 {
1336 if (!strcasecmp(ap_auth_type(r), "Basic"))
1337 ap_note_basic_auth_failure(r);
1338 else if (!strcasecmp(ap_auth_type(r), "Digest"))
1339 ap_note_digest_auth_failure(r);
1340 }
1341
ap_note_basic_auth_failure(request_rec * r)1342 API_EXPORT(void) ap_note_basic_auth_failure(request_rec *r)
1343 {
1344 if (strcasecmp(ap_auth_type(r), "Basic"))
1345 ap_note_auth_failure(r);
1346 else
1347 ap_table_setn(r->err_headers_out,
1348 r->proxyreq == STD_PROXY ? "Proxy-Authenticate"
1349 : "WWW-Authenticate",
1350 ap_pstrcat(r->pool, "Basic realm=\"", ap_auth_name(r), "\"",
1351 NULL));
1352 }
1353
ap_note_digest_auth_failure(request_rec * r)1354 API_EXPORT(void) ap_note_digest_auth_failure(request_rec *r)
1355 {
1356 /* We need to create a nonce which:
1357 * a) changes all the time (see r->request_time)
1358 * below and
1359 * b) of which we can verify that it is our own
1360 * fairly easily when it comes to veryfing
1361 * the digest coming back in the response.
1362 * c) and which as a whole should not
1363 * be unlikely to be in use anywhere else.
1364 */
1365 char * nonce_prefix = ap_md5(r->pool,
1366 (unsigned char *)
1367 ap_psprintf(r->pool, "%s%qu",
1368 ap_auth_nonce(r), (int64_t)r->request_time));
1369
1370 ap_table_setn(r->err_headers_out,
1371 r->proxyreq == STD_PROXY ? "Proxy-Authenticate"
1372 : "WWW-Authenticate",
1373 ap_psprintf(r->pool, "Digest realm=\"%s\", nonce=\"%s%qu\"",
1374 ap_auth_name(r), nonce_prefix, (int64_t)r->request_time));
1375 }
1376
ap_get_basic_auth_pw(request_rec * r,const char ** pw)1377 API_EXPORT(int) ap_get_basic_auth_pw(request_rec *r, const char **pw)
1378 {
1379 const char *auth_line = ap_table_get(r->headers_in,
1380 r->proxyreq == STD_PROXY
1381 ? "Proxy-Authorization"
1382 : "Authorization");
1383 const char *t;
1384
1385 if (!(t = ap_auth_type(r)) || strcasecmp(t, "Basic"))
1386 return DECLINED;
1387
1388 if (!ap_auth_name(r)) {
1389 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR,
1390 r, "need AuthName: %s", r->uri);
1391 return SERVER_ERROR;
1392 }
1393
1394 if (!auth_line) {
1395 ap_note_basic_auth_failure(r);
1396 return AUTH_REQUIRED;
1397 }
1398
1399 if (strcasecmp(ap_getword(r->pool, &auth_line, ' '), "Basic")) {
1400 /* Client tried to authenticate using wrong auth scheme */
1401 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
1402 "client used wrong authentication scheme: %s", r->uri);
1403 ap_note_basic_auth_failure(r);
1404 return AUTH_REQUIRED;
1405 }
1406
1407 while (*auth_line== ' ' || *auth_line== '\t')
1408 auth_line++;
1409
1410 t = ap_pbase64decode(r->pool, auth_line);
1411 /* Note that this allocation has to be made from r->connection->pool
1412 * because it has the lifetime of the connection. The other allocations
1413 * are temporary and can be tossed away any time.
1414 */
1415 r->connection->user = ap_getword_nulls (r->connection->pool, &t, ':');
1416 r->connection->ap_auth_type = "Basic";
1417
1418 *pw = t;
1419
1420 return OK;
1421 }
1422
1423 /* New Apache routine to map status codes into array indicies
1424 * e.g. 100 -> 0, 101 -> 1, 200 -> 2 ...
1425 * The number of status lines must equal the value of RESPONSE_CODES (httpd.h)
1426 * and must be listed in order.
1427 */
1428
1429 static const char * const status_lines[RESPONSE_CODES] =
1430 {
1431 "100 Continue",
1432 "101 Switching Protocols",
1433 "102 Processing",
1434 #define LEVEL_200 3
1435 "200 OK",
1436 "201 Created",
1437 "202 Accepted",
1438 "203 Non-Authoritative Information",
1439 "204 No Content",
1440 "205 Reset Content",
1441 "206 Partial Content",
1442 "207 Multi-Status",
1443 #define LEVEL_300 11
1444 "300 Multiple Choices",
1445 "301 Moved Permanently",
1446 "302 Found",
1447 "303 See Other",
1448 "304 Not Modified",
1449 "305 Use Proxy",
1450 "306 unused",
1451 "307 Temporary Redirect",
1452 #define LEVEL_400 19
1453 "400 Bad Request",
1454 "401 Authorization Required",
1455 "402 Payment Required",
1456 "403 Forbidden",
1457 "404 Not Found",
1458 "405 Method Not Allowed",
1459 "406 Not Acceptable",
1460 "407 Proxy Authentication Required",
1461 "408 Request Time-out",
1462 "409 Conflict",
1463 "410 Gone",
1464 "411 Length Required",
1465 "412 Precondition Failed",
1466 "413 Request Entity Too Large",
1467 "414 Request-URI Too Large",
1468 "415 Unsupported Media Type",
1469 "416 Requested Range Not Satisfiable",
1470 "417 Expectation Failed",
1471 "418 unused",
1472 "419 unused",
1473 "420 unused",
1474 "421 unused",
1475 "422 Unprocessable Entity",
1476 "423 Locked",
1477 "424 Failed Dependency",
1478 #define LEVEL_500 44
1479 "500 Internal Server Error",
1480 "501 Method Not Implemented",
1481 "502 Bad Gateway",
1482 "503 Service Temporarily Unavailable",
1483 "504 Gateway Time-out",
1484 "505 HTTP Version Not Supported",
1485 "506 Variant Also Negotiates",
1486 "507 Insufficient Storage",
1487 "508 unused",
1488 "509 unused",
1489 "510 Not Extended"
1490 };
1491
1492 /* The index is found by its offset from the x00 code of each level.
1493 * Although this is fast, it will need to be replaced if some nutcase
1494 * decides to define a high-numbered code before the lower numbers.
1495 * If that sad event occurs, replace the code below with a linear search
1496 * from status_lines[shortcut[i]] to status_lines[shortcut[i+1]-1];
1497 */
ap_index_of_response(int status)1498 API_EXPORT(int) ap_index_of_response(int status)
1499 {
1500 static int shortcut[6] = {0, LEVEL_200, LEVEL_300, LEVEL_400,
1501 LEVEL_500, RESPONSE_CODES};
1502 int i, pos;
1503
1504 if (status < 100) /* Below 100 is illegal for HTTP status */
1505 return LEVEL_500;
1506
1507 for (i = 0; i < 5; i++) {
1508 status -= 100;
1509 if (status < 100) {
1510 pos = (status + shortcut[i]);
1511 if (pos < shortcut[i + 1])
1512 return pos;
1513 else
1514 return LEVEL_500; /* status unknown (falls in gap) */
1515 }
1516 }
1517 return LEVEL_500; /* 600 or above is also illegal */
1518 }
1519
1520 /* Send a single HTTP header field to the client. Note that this function
1521 * is used in calls to table_do(), so their interfaces are co-dependent.
1522 * In other words, don't change this one without checking table_do in alloc.c.
1523 * It returns true unless there was a write error of some kind.
1524 */
ap_send_header_field(request_rec * r,const char * fieldname,const char * fieldval)1525 API_EXPORT_NONSTD(int) ap_send_header_field(request_rec *r,
1526 const char *fieldname,
1527 const char *fieldval)
1528 {
1529 if (strcasecmp(fieldname, "ETag") == 0) {
1530 if (ap_table_get(r->notes, "no-etag") != NULL) {
1531 return 1;
1532 }
1533 }
1534 return (0 < ap_rvputs(r, fieldname, ": ", fieldval, CRLF, NULL));
1535 }
1536
ap_basic_http_header(request_rec * r)1537 API_EXPORT(void) ap_basic_http_header(request_rec *r)
1538 {
1539 char *protocol;
1540
1541 if (r->assbackwards)
1542 return;
1543
1544 if (!r->status_line)
1545 r->status_line = status_lines[ap_index_of_response(r->status)];
1546
1547 /* kluge around broken browsers when indicated by force-response-1.0
1548 */
1549 if (r->proto_num == HTTP_VERSION(1,0)
1550 && ap_table_get(r->subprocess_env, "force-response-1.0")) {
1551
1552 protocol = "HTTP/1.0";
1553 r->connection->keepalive = -1;
1554 }
1555 else
1556 protocol = SERVER_PROTOCOL;
1557
1558 /* output the HTTP/1.x Status-Line */
1559 ap_rvputs(r, protocol, " ", r->status_line, CRLF, NULL);
1560
1561 /* output the date header */
1562 ap_send_header_field(r, "Date", ap_gm_timestr_822(r->pool, r->request_time));
1563
1564 /* keep the set-by-proxy server header, otherwise
1565 * generate a new server header */
1566 if (r->proxyreq) {
1567 const char *server = ap_table_get(r->headers_out, "Server");
1568 if (server) {
1569 ap_send_header_field(r, "Server", server);
1570 }
1571 }
1572 else {
1573 ap_send_header_field(r, "Server", ap_get_server_version());
1574 }
1575
1576 /* unset so we don't send them again */
1577 ap_table_unset(r->headers_out, "Date"); /* Avoid bogosity */
1578 ap_table_unset(r->headers_out, "Server");
1579 }
1580
1581 /* Navigator versions 2.x, 3.x and 4.0 betas up to and including 4.0b2
1582 * have a header parsing bug. If the terminating \r\n occur starting
1583 * at offset 256, 257 or 258 of output then it will not properly parse
1584 * the headers. Curiously it doesn't exhibit this problem at 512, 513.
1585 * We are guessing that this is because their initial read of a new request
1586 * uses a 256 byte buffer, and subsequent reads use a larger buffer.
1587 * So the problem might exist at different offsets as well.
1588 *
1589 * This should also work on keepalive connections assuming they use the
1590 * same small buffer for the first read of each new request.
1591 *
1592 * At any rate, we check the bytes written so far and, if we are about to
1593 * tickle the bug, we instead insert a bogus padding header. Since the bug
1594 * manifests as a broken image in Navigator, users blame the server. :(
1595 * It is more expensive to check the User-Agent than it is to just add the
1596 * bytes, so we haven't used the BrowserMatch feature here.
1597 */
terminate_header(BUFF * client)1598 static void terminate_header(BUFF *client)
1599 {
1600 long int bs;
1601
1602 ap_bgetopt(client, BO_BYTECT, &bs);
1603 if (bs >= 255 && bs <= 257)
1604 ap_bputs("X-Pad: avoid browser bug" CRLF, client);
1605
1606 ap_bputs(CRLF, client); /* Send the terminating empty line */
1607 }
1608
1609 /* Build the Allow field-value from the request handler method mask.
1610 * Note that we always allow TRACE, since it is handled below.
1611 */
make_allow(request_rec * r)1612 static char *make_allow(request_rec *r)
1613 {
1614 return 2 + ap_pstrcat(r->pool,
1615 (r->allowed & (1 << M_GET)) ? ", GET, HEAD" : "",
1616 (r->allowed & (1 << M_POST)) ? ", POST" : "",
1617 (r->allowed & (1 << M_PUT)) ? ", PUT" : "",
1618 (r->allowed & (1 << M_DELETE)) ? ", DELETE" : "",
1619 (r->allowed & (1 << M_CONNECT)) ? ", CONNECT" : "",
1620 (r->allowed & (1 << M_OPTIONS)) ? ", OPTIONS" : "",
1621 (r->allowed & (1 << M_PATCH)) ? ", PATCH" : "",
1622 (r->allowed & (1 << M_PROPFIND)) ? ", PROPFIND" : "",
1623 (r->allowed & (1 << M_PROPPATCH)) ? ", PROPPATCH" : "",
1624 (r->allowed & (1 << M_MKCOL)) ? ", MKCOL" : "",
1625 (r->allowed & (1 << M_COPY)) ? ", COPY" : "",
1626 (r->allowed & (1 << M_MOVE)) ? ", MOVE" : "",
1627 (r->allowed & (1 << M_LOCK)) ? ", LOCK" : "",
1628 (r->allowed & (1 << M_UNLOCK)) ? ", UNLOCK" : "",
1629 ", TRACE",
1630 NULL);
1631 }
1632
ap_send_http_trace(request_rec * r)1633 API_EXPORT(int) ap_send_http_trace(request_rec *r)
1634 {
1635 int rv;
1636
1637 /* Get the original request */
1638 while (r->prev)
1639 r = r->prev;
1640
1641 if ((rv = ap_setup_client_block(r, REQUEST_NO_BODY)))
1642 return rv;
1643
1644 ap_hard_timeout("send TRACE", r);
1645
1646 r->content_type = "message/http";
1647 ap_send_http_header(r);
1648
1649 /* Now we recreate the request, and echo it back */
1650
1651 ap_rvputs(r, r->the_request, CRLF, NULL);
1652
1653 ap_table_do((int (*) (void *, const char *, const char *))
1654 ap_send_header_field, (void *) r, r->headers_in, NULL);
1655 ap_rputs(CRLF, r);
1656
1657 ap_kill_timeout(r);
1658 return OK;
1659 }
1660
ap_send_http_options(request_rec * r)1661 API_EXPORT(int) ap_send_http_options(request_rec *r)
1662 {
1663 const long int zero = 0L;
1664
1665 if (r->assbackwards)
1666 return DECLINED;
1667
1668 ap_hard_timeout("send OPTIONS", r);
1669
1670 ap_basic_http_header(r);
1671
1672 ap_table_setn(r->headers_out, "Content-Length", "0");
1673 ap_table_setn(r->headers_out, "Allow", make_allow(r));
1674 ap_set_keepalive(r);
1675
1676 ap_table_do((int (*) (void *, const char *, const char *)) ap_send_header_field,
1677 (void *) r, r->headers_out, NULL);
1678
1679 terminate_header(r->connection->client);
1680
1681 ap_kill_timeout(r);
1682 ap_bsetopt(r->connection->client, BO_BYTECT, &zero);
1683
1684 return OK;
1685 }
1686
1687 /*
1688 * Here we try to be compatible with clients that want multipart/x-byteranges
1689 * instead of multipart/byteranges (also see above), as per HTTP/1.1. We
1690 * look for the Request-Range header (e.g. Netscape 2 and 3) as an indication
1691 * that the browser supports an older protocol. We also check User-Agent
1692 * for Microsoft Internet Explorer 3, which needs this as well.
1693 */
use_range_x(request_rec * r)1694 static int use_range_x(request_rec *r)
1695 {
1696 const char *ua;
1697 return (ap_table_get(r->headers_in, "Request-Range") ||
1698 ((ua = ap_table_get(r->headers_in, "User-Agent"))
1699 && strstr(ua, "MSIE 3")));
1700 }
1701
1702 /* This routine is called by ap_table_do and merges all instances of
1703 * the passed field values into a single array that will be further
1704 * processed by some later routine. Originally intended to help split
1705 * and recombine multiple Vary fields, though it is generic to any field
1706 * consisting of comma/space-separated tokens.
1707 */
uniq_field_values(void * d,const char * key,const char * val)1708 static int uniq_field_values(void *d, const char *key, const char *val)
1709 {
1710 array_header *values;
1711 char *start;
1712 char *e;
1713 char **strpp;
1714 int i;
1715
1716 values = (array_header *)d;
1717
1718 e = ap_pstrdup(values->pool, val);
1719
1720 do {
1721 /* Find a non-empty fieldname */
1722
1723 while (*e == ',' || ap_isspace(*e)) {
1724 ++e;
1725 }
1726 if (*e == '\0') {
1727 break;
1728 }
1729 start = e;
1730 while (*e != '\0' && *e != ',' && !ap_isspace(*e)) {
1731 ++e;
1732 }
1733 if (*e != '\0') {
1734 *e++ = '\0';
1735 }
1736
1737 /* Now add it to values if it isn't already represented.
1738 * Could be replaced by a ap_array_strcasecmp() if we had one.
1739 */
1740 for (i = 0, strpp = (char **) values->elts; i < values->nelts;
1741 ++i, ++strpp) {
1742 if (*strpp && strcasecmp(*strpp, start) == 0) {
1743 break;
1744 }
1745 }
1746 if (i == values->nelts) { /* if not found */
1747 *(char **)ap_push_array(values) = start;
1748 }
1749 } while (*e != '\0');
1750
1751 return 1;
1752 }
1753
1754 /*
1755 * Since some clients choke violently on multiple Vary fields, or
1756 * Vary fields with duplicate tokens, combine any multiples and remove
1757 * any duplicates.
1758 */
fixup_vary(request_rec * r)1759 static void fixup_vary(request_rec *r)
1760 {
1761 array_header *varies;
1762
1763 varies = ap_make_array(r->pool, 5, sizeof(char *));
1764
1765 /* Extract all Vary fields from the headers_out, separate each into
1766 * its comma-separated fieldname values, and then add them to varies
1767 * if not already present in the array.
1768 */
1769 ap_table_do((int (*)(void *, const char *, const char *))uniq_field_values,
1770 (void *) varies, r->headers_out, "Vary", NULL);
1771
1772 /* If we found any, replace old Vary fields with unique-ified value */
1773
1774 if (varies->nelts > 0) {
1775 ap_table_setn(r->headers_out, "Vary",
1776 ap_array_pstrcat(r->pool, varies, ','));
1777 }
1778 }
1779
ap_send_http_header(request_rec * r)1780 API_EXPORT(void) ap_send_http_header(request_rec *r)
1781 {
1782 int i;
1783 const long int zero = 0L;
1784
1785 if (r->assbackwards) {
1786 if (!r->main)
1787 ap_bsetopt(r->connection->client, BO_BYTECT, &zero);
1788 r->sent_bodyct = 1;
1789 return;
1790 }
1791
1792 /*
1793 * Now that we are ready to send a response, we need to combine the two
1794 * header field tables into a single table. If we don't do this, our
1795 * later attempts to set or unset a given fieldname might be bypassed.
1796 */
1797 if (!ap_is_empty_table(r->err_headers_out))
1798 r->headers_out = ap_overlay_tables(r->pool, r->err_headers_out,
1799 r->headers_out);
1800
1801 /*
1802 * Remove the 'Vary' header field if the client can't handle it.
1803 * Since this will have nasty effects on HTTP/1.1 caches, force
1804 * the response into HTTP/1.0 mode.
1805 */
1806 if (ap_table_get(r->subprocess_env, "force-no-vary") != NULL) {
1807 ap_table_unset(r->headers_out, "Vary");
1808 r->proto_num = HTTP_VERSION(1,0);
1809 ap_table_set(r->subprocess_env, "force-response-1.0", "1");
1810 }
1811 else {
1812 fixup_vary(r);
1813 }
1814
1815 ap_hard_timeout("send headers", r);
1816
1817 ap_basic_http_header(r);
1818
1819 ap_set_keepalive(r);
1820
1821 if (r->chunked) {
1822 ap_table_mergen(r->headers_out, "Transfer-Encoding", "chunked");
1823 ap_table_unset(r->headers_out, "Content-Length");
1824 }
1825
1826 if (r->byterange > 1)
1827 ap_table_setn(r->headers_out, "Content-Type",
1828 ap_pstrcat(r->pool, "multipart", use_range_x(r) ? "/x-" : "/",
1829 "byteranges; boundary=", r->boundary, NULL));
1830 else ap_table_setn(r->headers_out, "Content-Type", make_content_type(r,
1831 r->content_type));
1832
1833 if (r->content_encoding)
1834 ap_table_setn(r->headers_out, "Content-Encoding", r->content_encoding);
1835
1836 if (r->content_languages && r->content_languages->nelts) {
1837 for (i = 0; i < r->content_languages->nelts; ++i) {
1838 ap_table_mergen(r->headers_out, "Content-Language",
1839 ((char **) (r->content_languages->elts))[i]);
1840 }
1841 }
1842 else if (r->content_language)
1843 ap_table_setn(r->headers_out, "Content-Language", r->content_language);
1844
1845 /*
1846 * Control cachability for non-cachable responses if not already set by
1847 * some other part of the server configuration.
1848 */
1849 if (r->no_cache && !ap_table_get(r->headers_out, "Expires"))
1850 ap_table_addn(r->headers_out, "Expires",
1851 ap_gm_timestr_822(r->pool, r->request_time));
1852
1853 /* Send the entire table of header fields, terminated by an empty line. */
1854
1855 ap_table_do((int (*) (void *, const char *, const char *)) ap_send_header_field,
1856 (void *) r, r->headers_out, NULL);
1857
1858 terminate_header(r->connection->client);
1859
1860 ap_kill_timeout(r);
1861
1862 ap_bsetopt(r->connection->client, BO_BYTECT, &zero);
1863 r->sent_bodyct = 1; /* Whatever follows is real body stuff... */
1864
1865 /* Set buffer flags for the body */
1866 if (r->chunked)
1867 ap_bsetflag(r->connection->client, B_CHUNK, 1);
1868 }
1869
1870 /* finalize_request_protocol is called at completion of sending the
1871 * response. It's sole purpose is to send the terminating protocol
1872 * information for any wrappers around the response message body
1873 * (i.e., transfer encodings). It should have been named finalize_response.
1874 */
ap_finalize_request_protocol(request_rec * r)1875 API_EXPORT(void) ap_finalize_request_protocol(request_rec *r)
1876 {
1877 if (r->chunked && !r->connection->aborted) {
1878 /*
1879 * Turn off chunked encoding --- we can only do this once.
1880 */
1881 r->chunked = 0;
1882 ap_bsetflag(r->connection->client, B_CHUNK, 0);
1883
1884 ap_soft_timeout("send ending chunk", r);
1885 ap_rputs("0" CRLF, r);
1886 /* If we had footer "headers", we'd send them now */
1887 ap_rputs(CRLF, r);
1888 ap_kill_timeout(r);
1889
1890 }
1891 }
1892
1893 /* Here we deal with getting the request message body from the client.
1894 * Whether or not the request contains a body is signaled by the presence
1895 * of a non-zero Content-Length or by a Transfer-Encoding: chunked.
1896 *
1897 * Note that this is more complicated than it was in Apache 1.1 and prior
1898 * versions, because chunked support means that the module does less.
1899 *
1900 * The proper procedure is this:
1901 *
1902 * 1. Call setup_client_block() near the beginning of the request
1903 * handler. This will set up all the necessary properties, and will
1904 * return either OK, or an error code. If the latter, the module should
1905 * return that error code. The second parameter selects the policy to
1906 * apply if the request message indicates a body, and how a chunked
1907 * transfer-coding should be interpreted. Choose one of
1908 *
1909 * REQUEST_NO_BODY Send 413 error if message has any body
1910 * REQUEST_CHUNKED_ERROR Send 411 error if body without Content-Length
1911 * REQUEST_CHUNKED_DECHUNK If chunked, remove the chunks for me.
1912 * REQUEST_CHUNKED_PASS Pass the chunks to me without removal.
1913 *
1914 * In order to use the last two options, the caller MUST provide a buffer
1915 * large enough to hold a chunk-size line, including any extensions.
1916 *
1917 * 2. When you are ready to read a body (if any), call should_client_block().
1918 * This will tell the module whether or not to read input. If it is 0,
1919 * the module should assume that there is no message body to read.
1920 * This step also sends a 100 Continue response to HTTP/1.1 clients,
1921 * so should not be called until the module is *definitely* ready to
1922 * read content. (otherwise, the point of the 100 response is defeated).
1923 * Never call this function more than once.
1924 *
1925 * 3. Finally, call get_client_block in a loop. Pass it a buffer and its size.
1926 * It will put data into the buffer (not necessarily a full buffer), and
1927 * return the length of the input block. When it is done reading, it will
1928 * return 0 if EOF, or -1 if there was an error.
1929 * If an error occurs on input, we force an end to keepalive.
1930 */
1931
ap_setup_client_block(request_rec * r,int read_policy)1932 API_EXPORT(int) ap_setup_client_block(request_rec *r, int read_policy)
1933 {
1934 const char *tenc = ap_table_get(r->headers_in, "Transfer-Encoding");
1935 const char *lenp = ap_table_get(r->headers_in, "Content-Length");
1936 unsigned long max_body;
1937
1938 r->read_body = read_policy;
1939 r->read_chunked = 0;
1940 r->remaining = 0;
1941
1942 if (tenc) {
1943 if (strcasecmp(tenc, "chunked")) {
1944 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
1945 "Unknown Transfer-Encoding %s", tenc);
1946 return HTTP_NOT_IMPLEMENTED;
1947 }
1948 if (r->read_body == REQUEST_CHUNKED_ERROR) {
1949 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
1950 "chunked Transfer-Encoding forbidden: %s", r->uri);
1951 return (lenp) ? HTTP_BAD_REQUEST : HTTP_LENGTH_REQUIRED;
1952 }
1953
1954 r->read_chunked = 1;
1955 }
1956 else if (lenp) {
1957 const char *pos = lenp;
1958 int conversion_error = 0;
1959
1960 while (ap_isspace(*pos))
1961 ++pos;
1962
1963 if (*pos == '\0') {
1964 /* special case test - a C-L field NULL or all blanks is
1965 * assumed OK and defaults to 0. Otherwise, we do a
1966 * strict check of the field */
1967 r->remaining = 0;
1968 }
1969 else {
1970 char *endstr;
1971 errno = 0;
1972 r->remaining = ap_strtol(lenp, &endstr, 10);
1973 if (errno || (endstr && *endstr) || (r->remaining < 0)) {
1974 conversion_error = 1;
1975 }
1976 }
1977
1978 if (conversion_error) {
1979 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
1980 "Invalid Content-Length");
1981 return HTTP_BAD_REQUEST;
1982 }
1983 }
1984
1985 if ((r->read_body == REQUEST_NO_BODY) &&
1986 (r->read_chunked || (r->remaining > 0))) {
1987 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
1988 "%s with body is not allowed for %s", r->method, r->uri);
1989 return HTTP_REQUEST_ENTITY_TOO_LARGE;
1990 }
1991
1992 max_body = ap_get_limit_req_body(r);
1993 if (max_body && ((unsigned long)r->remaining > max_body)
1994 && (r->remaining >= 0)) {
1995 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
1996 "Request content-length of %s is larger than the configured "
1997 "limit of %lu", lenp, max_body);
1998 return HTTP_REQUEST_ENTITY_TOO_LARGE;
1999 }
2000
2001 return OK;
2002 }
2003
ap_should_client_block(request_rec * r)2004 API_EXPORT(int) ap_should_client_block(request_rec *r)
2005 {
2006 /* First check if we have already read the request body */
2007
2008 if (r->read_length || (!r->read_chunked && (r->remaining <= 0)))
2009 return 0;
2010
2011 if (r->expecting_100 && r->proto_num >= HTTP_VERSION(1,1)) {
2012 /* sending 100 Continue interim response */
2013 ap_rvputs(r, SERVER_PROTOCOL, " ", status_lines[0], CRLF CRLF,
2014 NULL);
2015 ap_rflush(r);
2016 }
2017
2018 return 1;
2019 }
2020
2021 /**
2022 * Parse a chunk extension, detect overflow.
2023 * There are two error cases:
2024 * 1) If the conversion would require too many bits, a -1 is returned.
2025 * 2) If the conversion used the correct number of bits, but an overflow
2026 * caused only the sign bit to flip, then that negative number is
2027 * returned.
2028 * In general, any negative number can be considered an overflow error.
2029 */
ap_get_chunk_size(char * b)2030 API_EXPORT(long) ap_get_chunk_size(char *b)
2031 {
2032 long chunksize = 0;
2033 long chunkbits = sizeof(long) * 8;
2034
2035 /* Skip leading zeros */
2036 while (*b == '0') {
2037 ++b;
2038 }
2039
2040 while (ap_isxdigit(*b) && (chunkbits > 0)) {
2041 int xvalue = 0;
2042
2043 if (*b >= '0' && *b <= '9') {
2044 xvalue = *b - '0';
2045 }
2046 else if (*b >= 'A' && *b <= 'F') {
2047 xvalue = *b - 'A' + 0xa;
2048 }
2049 else if (*b >= 'a' && *b <= 'f') {
2050 xvalue = *b - 'a' + 0xa;
2051 }
2052
2053 chunksize = (chunksize << 4) | xvalue;
2054 chunkbits -= 4;
2055 ++b;
2056 }
2057 if (ap_isxdigit(*b) && (chunkbits <= 0)) {
2058 /* overflow */
2059 return -1;
2060 }
2061
2062 return chunksize;
2063 }
2064
2065 /* get_client_block is called in a loop to get the request message body.
2066 * This is quite simple if the client includes a content-length
2067 * (the normal case), but gets messy if the body is chunked. Note that
2068 * r->remaining is used to maintain state across calls and that
2069 * r->read_length is the total number of bytes given to the caller
2070 * across all invocations. It is messy because we have to be careful not
2071 * to read past the data provided by the client, since these reads block.
2072 * Returns 0 on End-of-body, -1 on error or premature chunk end.
2073 *
2074 * Reading the chunked encoding requires a buffer size large enough to
2075 * hold a chunk-size line, including any extensions. For now, we'll leave
2076 * that to the caller, at least until we can come up with a better solution.
2077 */
ap_get_client_block(request_rec * r,char * buffer,int bufsiz)2078 API_EXPORT(long) ap_get_client_block(request_rec *r, char *buffer, int bufsiz)
2079 {
2080 int c;
2081 long len_read, len_to_read;
2082 long chunk_start = 0;
2083 unsigned long max_body;
2084
2085 if (!r->read_chunked) { /* Content-length read */
2086 len_to_read = (r->remaining > bufsiz) ? bufsiz : r->remaining;
2087 len_read = ap_bread(r->connection->client, buffer, len_to_read);
2088 if (len_read <= 0) {
2089 if (len_read < 0)
2090 r->connection->keepalive = -1;
2091 return len_read;
2092 }
2093 r->read_length += len_read;
2094 r->remaining -= len_read;
2095 return len_read;
2096 }
2097
2098 /*
2099 * Handle chunked reading Note: we are careful to shorten the input
2100 * bufsiz so that there will always be enough space for us to add a CRLF
2101 * (if necessary).
2102 */
2103 if (r->read_body == REQUEST_CHUNKED_PASS)
2104 bufsiz -= 2;
2105 if (bufsiz <= 0)
2106 return -1; /* Cannot read chunked with a small buffer */
2107
2108 /* Check to see if we have already read too much request data.
2109 * For efficiency reasons, we only check this at the top of each
2110 * caller read pass, since the limit exists just to stop infinite
2111 * length requests and nobody cares if it goes over by one buffer.
2112 */
2113 max_body = ap_get_limit_req_body(r);
2114 if (max_body && ((unsigned long) r->read_length > max_body)
2115 && (r->read_length >= 0)) {
2116 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
2117 "Chunked request body is larger than the configured limit of %lu",
2118 max_body);
2119 r->connection->keepalive = -1;
2120 return -1;
2121 }
2122
2123 if (r->remaining == 0) { /* Start of new chunk */
2124
2125 chunk_start = ap_getline(buffer, bufsiz, r->connection->client, 0);
2126 if ((chunk_start <= 0) || (chunk_start >= (bufsiz - 1))
2127 || !ap_isxdigit(*buffer)) {
2128 r->connection->keepalive = -1;
2129 return -1;
2130 }
2131
2132 len_to_read = ap_get_chunk_size(buffer);
2133
2134 if (len_to_read == 0) { /* Last chunk indicated, get footers */
2135 if (r->read_body == REQUEST_CHUNKED_DECHUNK) {
2136 get_mime_headers(r);
2137 snprintf(buffer, bufsiz, "%ld", r->read_length);
2138 ap_table_unset(r->headers_in, "Transfer-Encoding");
2139 ap_table_setn(r->headers_in, "Content-Length",
2140 ap_pstrdup(r->pool, buffer));
2141 return 0;
2142 }
2143 r->remaining = -1; /* Indicate footers in-progress */
2144 }
2145 else if (len_to_read < 0) {
2146 r->connection->keepalive = -1;
2147 return -1;
2148 }
2149 else {
2150 r->remaining = len_to_read;
2151 }
2152 if (r->read_body == REQUEST_CHUNKED_PASS) {
2153 buffer[chunk_start++] = CR; /* Restore chunk-size line end */
2154 buffer[chunk_start++] = LF;
2155 buffer += chunk_start; /* and pass line on to caller */
2156 bufsiz -= chunk_start;
2157 }
2158 else {
2159 /* REQUEST_CHUNKED_DECHUNK -- do not include the length of the
2160 * header in the return value
2161 */
2162 chunk_start = 0;
2163 }
2164 }
2165 /* When REQUEST_CHUNKED_PASS, we are */
2166 if (r->remaining == -1) { /* reading footers until empty line */
2167 len_read = chunk_start;
2168
2169 while ((bufsiz > 1) && ((len_read =
2170 ap_getline(buffer, bufsiz, r->connection->client, 1)) > 0)) {
2171
2172 if (len_read != (bufsiz - 1)) {
2173 buffer[len_read++] = CR; /* Restore footer line end */
2174 buffer[len_read++] = LF;
2175 }
2176 chunk_start += len_read;
2177 buffer += len_read;
2178 bufsiz -= len_read;
2179 }
2180 if (len_read < 0) {
2181 r->connection->keepalive = -1;
2182 return -1;
2183 }
2184
2185 if (len_read == 0) { /* Indicates an empty line */
2186 buffer[0] = CR;
2187 buffer[1] = LF;
2188 chunk_start += 2;
2189 r->remaining = -2;
2190 }
2191 r->read_length += chunk_start;
2192 return chunk_start;
2193 }
2194 /* When REQUEST_CHUNKED_PASS, we */
2195 if (r->remaining == -2) { /* finished footers when last called */
2196 r->remaining = 0; /* so now we must signal EOF */
2197 return 0;
2198 }
2199
2200 /* Otherwise, we are in the midst of reading a chunk of data */
2201
2202 len_to_read = (r->remaining > bufsiz) ? bufsiz : r->remaining;
2203
2204 len_read = ap_bread(r->connection->client, buffer, len_to_read);
2205 if (len_read <= 0) {
2206 r->connection->keepalive = -1;
2207 return -1;
2208 }
2209
2210 r->remaining -= len_read;
2211
2212 if (r->remaining == 0) { /* End of chunk, get trailing CRLF */
2213
2214 if ((c = ap_bgetc(r->connection->client)) == CR) {
2215 c = ap_bgetc(r->connection->client);
2216 }
2217
2218 if (c != LF) {
2219 r->connection->keepalive = -1;
2220 return -1;
2221 }
2222 if (r->read_body == REQUEST_CHUNKED_PASS) {
2223 buffer[len_read++] = CR;
2224 buffer[len_read++] = LF;
2225 }
2226 }
2227 r->read_length += (chunk_start + len_read);
2228
2229 return (chunk_start + len_read);
2230 }
2231
2232 /* In HTTP/1.1, any method can have a body. However, most GET handlers
2233 * wouldn't know what to do with a request body if they received one.
2234 * This helper routine tests for and reads any message body in the request,
2235 * simply discarding whatever it receives. We need to do this because
2236 * failing to read the request body would cause it to be interpreted
2237 * as the next request on a persistent connection.
2238 *
2239 * Since we return an error status if the request is malformed, this
2240 * routine should be called at the beginning of a no-body handler, e.g.,
2241 *
2242 * if ((retval = ap_discard_request_body(r)) != OK)
2243 * return retval;
2244 */
ap_discard_request_body(request_rec * r)2245 API_EXPORT(int) ap_discard_request_body(request_rec *r)
2246 {
2247 int rv;
2248
2249 if ((rv = ap_setup_client_block(r, REQUEST_CHUNKED_PASS)))
2250 return rv;
2251
2252 /* In order to avoid sending 100 Continue when we already know the
2253 * final response status, and yet not kill the connection if there is
2254 * no request body to be read, we need to duplicate the test from
2255 * ap_should_client_block() here negated rather than call it directly.
2256 */
2257 if ((r->read_length == 0) && (r->read_chunked || (r->remaining > 0))) {
2258 char dumpbuf[HUGE_STRING_LEN];
2259
2260 if (r->expecting_100) {
2261 r->connection->keepalive = -1;
2262 return OK;
2263 }
2264 ap_hard_timeout("reading request body", r);
2265 while ((rv = ap_get_client_block(r, dumpbuf, HUGE_STRING_LEN)) > 0)
2266 continue;
2267 ap_kill_timeout(r);
2268
2269 if (rv < 0)
2270 return HTTP_BAD_REQUEST;
2271 }
2272 return OK;
2273 }
2274
2275 /*
2276 * Send the body of a response to the client.
2277 */
ap_send_fd(FILE * f,request_rec * r)2278 API_EXPORT(long) ap_send_fd(FILE *f, request_rec *r)
2279 {
2280 return ap_send_fd_length(f, r, -1);
2281 }
2282
ap_send_fd_length(FILE * f,request_rec * r,long length)2283 API_EXPORT(long) ap_send_fd_length(FILE *f, request_rec *r, long length)
2284 {
2285 char buf[IOBUFSIZE];
2286 long total_bytes_sent = 0;
2287 register int n, w, o, len;
2288
2289 if (length == 0)
2290 return 0;
2291
2292 ap_soft_timeout("send body", r);
2293
2294 while (!r->connection->aborted) {
2295 if ((length > 0) && (total_bytes_sent + IOBUFSIZE) > length)
2296 len = length - total_bytes_sent;
2297 else
2298 len = IOBUFSIZE;
2299
2300 while ((n = fread(buf, sizeof(char), len, f)) < 1
2301 && ferror(f) && errno == EINTR && !r->connection->aborted)
2302 continue;
2303
2304 if (n < 1) {
2305 break;
2306 }
2307 o = 0;
2308
2309 while (n && !r->connection->aborted) {
2310 w = ap_bwrite(r->connection->client, &buf[o], n);
2311 if (w > 0) {
2312 ap_reset_timeout(r); /* reset timeout after successful write */
2313 total_bytes_sent += w;
2314 n -= w;
2315 o += w;
2316 }
2317 else if (w < 0) {
2318 if (!r->connection->aborted) {
2319 ap_log_rerror(APLOG_MARK, APLOG_INFO, r,
2320 "client stopped connection before send body completed");
2321 ap_bsetflag(r->connection->client, B_EOUT, 1);
2322 r->connection->aborted = 1;
2323 }
2324 break;
2325 }
2326 }
2327 }
2328
2329 ap_kill_timeout(r);
2330 SET_BYTES_SENT(r);
2331 return total_bytes_sent;
2332 }
2333
2334 /*
2335 * Send the body of a response to the client.
2336 */
ap_send_fb(BUFF * fb,request_rec * r)2337 API_EXPORT(long) ap_send_fb(BUFF *fb, request_rec *r)
2338 {
2339 return ap_send_fb_length(fb, r, -1);
2340 }
2341
ap_send_fb_length(BUFF * fb,request_rec * r,long length)2342 API_EXPORT(long) ap_send_fb_length(BUFF *fb, request_rec *r, long length)
2343 {
2344 char buf[IOBUFSIZE];
2345 long total_bytes_sent = 0;
2346 register int n, w, o, len, fd;
2347 fd_set fds;
2348
2349 if (length == 0)
2350 return 0;
2351
2352 /* Make fb unbuffered and non-blocking */
2353 ap_bsetflag(fb, B_RD, 0);
2354 ap_bnonblock(fb, B_RD);
2355 fd = ap_bfileno(fb, B_RD);
2356 if (fd >= FD_SETSIZE) {
2357 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, NULL,
2358 "send body: filedescriptor (%u) larger than FD_SETSIZE (%u) "
2359 "found, you probably need to rebuild Apache with a "
2360 "larger FD_SETSIZE", fd, FD_SETSIZE);
2361 return 0;
2362 }
2363
2364 ap_soft_timeout("send body", r);
2365
2366 FD_ZERO(&fds);
2367 while (!r->connection->aborted) {
2368 if ((length > 0) && (total_bytes_sent + IOBUFSIZE) > length)
2369 len = length - total_bytes_sent;
2370 else
2371 len = IOBUFSIZE;
2372
2373 do {
2374 n = ap_bread(fb, buf, len);
2375 if (n >= 0)
2376 break;
2377 if (r->connection->aborted)
2378 break;
2379 if (n < 0 && errno != EAGAIN)
2380 break;
2381
2382 /* we need to block, so flush the output first */
2383 if (ap_bflush(r->connection->client) < 0) {
2384 ap_log_rerror(APLOG_MARK, APLOG_INFO, r,
2385 "client stopped connection before send body completed");
2386 ap_bsetflag(r->connection->client, B_EOUT, 1);
2387 r->connection->aborted = 1;
2388 break;
2389 }
2390 FD_SET(fd, &fds);
2391 /*
2392 * we don't care what select says, we might as well loop back
2393 * around and try another read
2394 */
2395 ap_select(fd + 1, &fds, NULL, NULL, NULL);
2396 } while (!r->connection->aborted);
2397
2398 if (n < 1 || r->connection->aborted) {
2399 break;
2400 }
2401 o = 0;
2402
2403 while (n && !r->connection->aborted) {
2404 w = ap_bwrite(r->connection->client, &buf[o], n);
2405 if (w > 0) {
2406 ap_reset_timeout(r); /* reset timeout after successful write */
2407 total_bytes_sent += w;
2408 n -= w;
2409 o += w;
2410 }
2411 else if (w < 0) {
2412 if (!r->connection->aborted) {
2413 ap_log_rerror(APLOG_MARK, APLOG_INFO, r,
2414 "client stopped connection before send body completed");
2415 ap_bsetflag(r->connection->client, B_EOUT, 1);
2416 r->connection->aborted = 1;
2417 }
2418 break;
2419 }
2420 }
2421 }
2422
2423 ap_kill_timeout(r);
2424 SET_BYTES_SENT(r);
2425 return total_bytes_sent;
2426 }
2427
2428
2429
2430 /* The code writes MMAP_SEGMENT_SIZE bytes at a time. This is due to Apache's
2431 * timeout model, which is a timeout per-write rather than a time for the
2432 * entire transaction to complete. Essentially this should be small enough
2433 * so that in one Timeout period, your slowest clients should be reasonably
2434 * able to receive this many bytes.
2435 *
2436 * To take advantage of zero-copy TCP under Solaris 2.6 this should be a
2437 * multiple of 16k. (And you need a SunATM2.0 network card.)
2438 */
2439 #ifndef MMAP_SEGMENT_SIZE
2440 #define MMAP_SEGMENT_SIZE 32768
2441 #endif
2442
2443 /* send data from an in-memory buffer */
ap_send_mmap(void * mm,request_rec * r,size_t offset,size_t length)2444 API_EXPORT(size_t) ap_send_mmap(void *mm, request_rec *r, size_t offset,
2445 size_t length)
2446 {
2447 size_t total_bytes_sent = 0;
2448 int n, w;
2449
2450 if (length == 0)
2451 return 0;
2452
2453 ap_soft_timeout("send mmap", r);
2454
2455 length += offset;
2456 while (!r->connection->aborted && offset < length) {
2457 if (length - offset > MMAP_SEGMENT_SIZE) {
2458 n = MMAP_SEGMENT_SIZE;
2459 }
2460 else {
2461 n = length - offset;
2462 }
2463
2464 while (n && !r->connection->aborted) {
2465 w = ap_bwrite(r->connection->client, (char *) mm + offset, n);
2466 if (w > 0) {
2467 ap_reset_timeout(r); /* reset timeout after successful write */
2468 total_bytes_sent += w;
2469 n -= w;
2470 offset += w;
2471 }
2472 else if (w < 0) {
2473 if (!r->connection->aborted) {
2474 ap_log_rerror(APLOG_MARK, APLOG_INFO, r,
2475 "client stopped connection before send mmap completed");
2476 ap_bsetflag(r->connection->client, B_EOUT, 1);
2477 r->connection->aborted = 1;
2478 }
2479 break;
2480 }
2481 }
2482 }
2483
2484 ap_kill_timeout(r);
2485 SET_BYTES_SENT(r);
2486 return total_bytes_sent;
2487 }
2488
ap_rputc(int c,request_rec * r)2489 API_EXPORT(int) ap_rputc(int c, request_rec *r)
2490 {
2491 if (r->connection->aborted)
2492 return EOF;
2493
2494 if (ap_bputc(c, r->connection->client) < 0) {
2495 if (!r->connection->aborted) {
2496 ap_log_rerror(APLOG_MARK, APLOG_INFO, r,
2497 "client stopped connection before rputc completed");
2498 ap_bsetflag(r->connection->client, B_EOUT, 1);
2499 r->connection->aborted = 1;
2500 }
2501 return EOF;
2502 }
2503 SET_BYTES_SENT(r);
2504 return c;
2505 }
2506
ap_rputs(const char * str,request_rec * r)2507 API_EXPORT(int) ap_rputs(const char *str, request_rec *r)
2508 {
2509 int rcode;
2510
2511 if (r->connection->aborted)
2512 return EOF;
2513
2514 rcode = ap_bputs(str, r->connection->client);
2515 if (rcode < 0) {
2516 if (!r->connection->aborted) {
2517 ap_log_rerror(APLOG_MARK, APLOG_INFO, r,
2518 "client stopped connection before rputs completed");
2519 ap_bsetflag(r->connection->client, B_EOUT, 1);
2520 r->connection->aborted = 1;
2521 }
2522 return EOF;
2523 }
2524 SET_BYTES_SENT(r);
2525 return rcode;
2526 }
2527
ap_rwrite(const void * buf,int nbyte,request_rec * r)2528 API_EXPORT(int) ap_rwrite(const void *buf, int nbyte, request_rec *r)
2529 {
2530 int n;
2531
2532 if (r->connection->aborted)
2533 return -1;
2534
2535 n = ap_bwrite(r->connection->client, buf, nbyte);
2536 if (n < 0) {
2537 if (!r->connection->aborted) {
2538 ap_log_rerror(APLOG_MARK, APLOG_INFO, r,
2539 "client stopped connection before rwrite completed");
2540 ap_bsetflag(r->connection->client, B_EOUT, 1);
2541 r->connection->aborted = 1;
2542 }
2543 return -1;
2544 }
2545 SET_BYTES_SENT(r);
2546 return n;
2547 }
2548
ap_vrprintf(request_rec * r,const char * fmt,va_list ap)2549 API_EXPORT(int) ap_vrprintf(request_rec *r, const char *fmt, va_list ap)
2550 {
2551 int n;
2552
2553 if (r->connection->aborted)
2554 return -1;
2555
2556 n = ap_vbprintf(r->connection->client, fmt, ap);
2557
2558 if (n < 0) {
2559 if (!r->connection->aborted) {
2560 ap_log_rerror(APLOG_MARK, APLOG_INFO, r,
2561 "client stopped connection before vrprintf completed");
2562 ap_bsetflag(r->connection->client, B_EOUT, 1);
2563 r->connection->aborted = 1;
2564 }
2565 return -1;
2566 }
2567 SET_BYTES_SENT(r);
2568 return n;
2569 }
2570
ap_rprintf(request_rec * r,const char * fmt,...)2571 API_EXPORT_NONSTD(int) ap_rprintf(request_rec *r, const char *fmt,...)
2572 {
2573 va_list vlist;
2574 int n;
2575
2576 if (r->connection->aborted)
2577 return -1;
2578
2579 va_start(vlist, fmt);
2580 n = ap_vbprintf(r->connection->client, fmt, vlist);
2581 va_end(vlist);
2582
2583 if (n < 0) {
2584 if (!r->connection->aborted) {
2585 ap_log_rerror(APLOG_MARK, APLOG_INFO, r,
2586 "client stopped connection before rprintf completed");
2587 ap_bsetflag(r->connection->client, B_EOUT, 1);
2588 r->connection->aborted = 1;
2589 }
2590 return -1;
2591 }
2592 SET_BYTES_SENT(r);
2593 return n;
2594 }
2595
ap_rvputs(request_rec * r,...)2596 API_EXPORT_NONSTD(int) ap_rvputs(request_rec *r,...)
2597 {
2598 va_list args;
2599 int i, j, k;
2600 const char *x;
2601 BUFF *fb = r->connection->client;
2602
2603 if (r->connection->aborted)
2604 return EOF;
2605
2606 va_start(args, r);
2607 for (k = 0;;) {
2608 x = va_arg(args, const char *);
2609 if (x == NULL)
2610 break;
2611 j = strlen(x);
2612 i = ap_bwrite(fb, x, j);
2613 if (i != j) {
2614 va_end(args);
2615 if (!r->connection->aborted) {
2616 ap_log_rerror(APLOG_MARK, APLOG_INFO, r,
2617 "client stopped connection before rvputs completed");
2618 ap_bsetflag(r->connection->client, B_EOUT, 1);
2619 r->connection->aborted = 1;
2620 }
2621 return EOF;
2622 }
2623 k += i;
2624 }
2625 va_end(args);
2626
2627 SET_BYTES_SENT(r);
2628 return k;
2629 }
2630
ap_rflush(request_rec * r)2631 API_EXPORT(int) ap_rflush(request_rec *r)
2632 {
2633 if (ap_bflush(r->connection->client) < 0) {
2634 if (!r->connection->aborted) {
2635 ap_log_rerror(APLOG_MARK, APLOG_INFO, r,
2636 "client stopped connection before rflush completed");
2637 ap_bsetflag(r->connection->client, B_EOUT, 1);
2638 r->connection->aborted = 1;
2639 }
2640 return EOF;
2641 }
2642 return 0;
2643 }
2644
2645 /* We should have named this send_canned_response, since it is used for any
2646 * response that can be generated by the server from the request record.
2647 * This includes all 204 (no content), 3xx (redirect), 4xx (client error),
2648 * and 5xx (server error) messages that have not been redirected to another
2649 * handler via the ErrorDocument feature.
2650 */
ap_send_error_response(request_rec * r,int recursive_error)2651 API_EXPORT(void) ap_send_error_response(request_rec *r, int recursive_error)
2652 {
2653 int status = r->status;
2654 int idx = ap_index_of_response(status);
2655 char *custom_response;
2656 const char *location = ap_table_get(r->headers_out, "Location");
2657
2658 /*
2659 * It's possible that the Location field might be in r->err_headers_out
2660 * instead of r->headers_out; use the latter if possible, else the
2661 * former.
2662 */
2663 if (location == NULL) {
2664 location = ap_table_get(r->err_headers_out, "Location");
2665 }
2666 /* We need to special-case the handling of 204 and 304 responses,
2667 * since they have specific HTTP requirements and do not include a
2668 * message body. Note that being assbackwards here is not an option.
2669 */
2670 if (status == HTTP_NOT_MODIFIED) {
2671 if (!ap_is_empty_table(r->err_headers_out))
2672 r->headers_out = ap_overlay_tables(r->pool, r->err_headers_out,
2673 r->headers_out);
2674 ap_hard_timeout("send 304", r);
2675
2676 ap_basic_http_header(r);
2677 ap_set_keepalive(r);
2678
2679 ap_table_do((int (*)(void *, const char *, const char *)) ap_send_header_field,
2680 (void *) r, r->headers_out,
2681 "Connection",
2682 "Keep-Alive",
2683 "ETag",
2684 "Content-Location",
2685 "Expires",
2686 "Cache-Control",
2687 "Vary",
2688 "Warning",
2689 "WWW-Authenticate",
2690 "Proxy-Authenticate",
2691 NULL);
2692
2693 terminate_header(r->connection->client);
2694
2695 ap_kill_timeout(r);
2696 return;
2697 }
2698
2699 if (status == HTTP_NO_CONTENT) {
2700 ap_send_http_header(r);
2701 ap_finalize_request_protocol(r);
2702 return;
2703 }
2704
2705 if (!r->assbackwards) {
2706 table *tmp = r->headers_out;
2707
2708 /* For all HTTP/1.x responses for which we generate the message,
2709 * we need to avoid inheriting the "normal status" header fields
2710 * that may have been set by the request handler before the
2711 * error or redirect, except for Location on external redirects.
2712 */
2713 r->headers_out = r->err_headers_out;
2714 r->err_headers_out = tmp;
2715 ap_clear_table(r->err_headers_out);
2716
2717 if (ap_is_HTTP_REDIRECT(status) || (status == HTTP_CREATED)) {
2718 if ((location != NULL) && *location) {
2719 ap_table_setn(r->headers_out, "Location", location);
2720 }
2721 else {
2722 location = ""; /* avoids coredump when printing, below */
2723 }
2724 }
2725
2726 r->content_language = NULL;
2727 r->content_languages = NULL;
2728 r->content_encoding = NULL;
2729 r->clength = 0;
2730 if (ap_table_get(r->subprocess_env,
2731 "suppress-error-charset") != NULL) {
2732 r->content_type = "text/html";
2733 }
2734 else {
2735 r->content_type = "text/html; charset=iso-8859-1";
2736 }
2737
2738 if ((status == METHOD_NOT_ALLOWED) || (status == NOT_IMPLEMENTED))
2739 ap_table_setn(r->headers_out, "Allow", make_allow(r));
2740
2741 ap_send_http_header(r);
2742
2743 if (r->header_only) {
2744 ap_finalize_request_protocol(r);
2745 ap_rflush(r);
2746 return;
2747 }
2748 }
2749
2750 ap_hard_timeout("send error body", r);
2751
2752 if ((custom_response = ap_response_code_string(r, idx))) {
2753 /*
2754 * We have a custom response output. This should only be
2755 * a text-string to write back. But if the ErrorDocument
2756 * was a local redirect and the requested resource failed
2757 * for any reason, the custom_response will still hold the
2758 * redirect URL. We don't really want to output this URL
2759 * as a text message, so first check the custom response
2760 * string to ensure that it is a text-string (using the
2761 * same test used in ap_die(), i.e. does it start with a ").
2762 * If it doesn't, we've got a recursive error, so find
2763 * the original error and output that as well.
2764 */
2765 if (custom_response[0] == '\"') {
2766 ap_rputs(custom_response + 1, r);
2767 ap_kill_timeout(r);
2768 ap_finalize_request_protocol(r);
2769 ap_rflush(r);
2770 return;
2771 }
2772 /*
2773 * Redirect failed, so get back the original error
2774 */
2775 while (r->prev && (r->prev->status != HTTP_OK))
2776 r = r->prev;
2777 }
2778 {
2779 const char *title = status_lines[idx];
2780 const char *h1;
2781 const char *error_notes;
2782
2783 /* Accept a status_line set by a module, but only if it begins
2784 * with the 3 digit status code
2785 */
2786 if (r->status_line != NULL
2787 && strlen(r->status_line) > 4 /* long enough */
2788 && isdigit((unsigned char)r->status_line[0])
2789 && isdigit((unsigned char)r->status_line[1])
2790 && isdigit((unsigned char)r->status_line[2])
2791 && ap_isspace(r->status_line[3])
2792 && ap_isalnum(r->status_line[4])) {
2793 title = r->status_line;
2794 }
2795
2796 /* folks decided they didn't want the error code in the H1 text */
2797 h1 = &title[4];
2798
2799 ap_rvputs(r,
2800 DOCTYPE_HTML_2_0
2801 "<HTML><HEAD>\n<TITLE>", title,
2802 "</TITLE>\n</HEAD><BODY>\n<H1>", h1, "</H1>\n",
2803 NULL);
2804
2805 switch (status) {
2806 case HTTP_MOVED_PERMANENTLY:
2807 case HTTP_MOVED_TEMPORARILY:
2808 case HTTP_TEMPORARY_REDIRECT:
2809 ap_rvputs(r, "The document has moved <A HREF=\"",
2810 ap_escape_html(r->pool, location), "\">here</A>.<P>\n",
2811 NULL);
2812 break;
2813 case HTTP_SEE_OTHER:
2814 ap_rvputs(r, "The answer to your request is located <A HREF=\"",
2815 ap_escape_html(r->pool, location), "\">here</A>.<P>\n",
2816 NULL);
2817 break;
2818 case HTTP_USE_PROXY:
2819 ap_rvputs(r, "This resource is only accessible "
2820 "through the proxy\n",
2821 ap_escape_html(r->pool, location),
2822 "<BR>\nYou will need to ",
2823 "configure your client to use that proxy.<P>\n", NULL);
2824 break;
2825 case HTTP_PROXY_AUTHENTICATION_REQUIRED:
2826 case AUTH_REQUIRED:
2827 ap_rputs("This server could not verify that you\n"
2828 "are authorized to access the document\n"
2829 "requested. Either you supplied the wrong\n"
2830 "credentials (e.g., bad password), or your\n"
2831 "browser doesn't understand how to supply\n"
2832 "the credentials required.<P>\n", r);
2833 break;
2834 case BAD_REQUEST:
2835 ap_rputs("Your browser sent a request that "
2836 "this server could not understand.<P>\n", r);
2837 if ((error_notes = ap_table_get(r->notes, "error-notes")) != NULL) {
2838 ap_rvputs(r, error_notes, "<P>\n", NULL);
2839 }
2840 break;
2841 case HTTP_FORBIDDEN:
2842 ap_rvputs(r, "You don't have permission to access ",
2843 ap_escape_html(r->pool, r->uri),
2844 "\non this server.<P>\n", NULL);
2845 break;
2846 case NOT_FOUND:
2847 ap_rvputs(r, "The requested URL ",
2848 ap_escape_html(r->pool, r->uri),
2849 " was not found on this server.<P>\n", NULL);
2850 break;
2851 case METHOD_NOT_ALLOWED:
2852 ap_rvputs(r, "The requested method ", r->method,
2853 " is not allowed "
2854 "for the URL ", ap_escape_html(r->pool, r->uri),
2855 ".<P>\n", NULL);
2856 break;
2857 case NOT_ACCEPTABLE:
2858 ap_rvputs(r,
2859 "An appropriate representation of the "
2860 "requested resource ",
2861 ap_escape_html(r->pool, r->uri),
2862 " could not be found on this server.<P>\n", NULL);
2863 /* fall through */
2864 case MULTIPLE_CHOICES:
2865 {
2866 const char *list;
2867 if ((list = ap_table_get(r->notes, "variant-list")))
2868 ap_rputs(list, r);
2869 }
2870 break;
2871 case LENGTH_REQUIRED:
2872 ap_rvputs(r, "A request of the requested method ", r->method,
2873 " requires a valid Content-length.<P>\n", NULL);
2874 if ((error_notes = ap_table_get(r->notes, "error-notes")) != NULL) {
2875 ap_rvputs(r, error_notes, "<P>\n", NULL);
2876 }
2877 break;
2878 case PRECONDITION_FAILED:
2879 ap_rvputs(r, "The precondition on the request for the URL ",
2880 ap_escape_html(r->pool, r->uri),
2881 " evaluated to false.<P>\n", NULL);
2882 break;
2883 case HTTP_NOT_IMPLEMENTED:
2884 ap_rvputs(r, ap_escape_html(r->pool, r->method), " to ",
2885 ap_escape_html(r->pool, r->uri),
2886 " not supported.<P>\n", NULL);
2887 if ((error_notes = ap_table_get(r->notes, "error-notes")) != NULL) {
2888 ap_rvputs(r, error_notes, "<P>\n", NULL);
2889 }
2890 break;
2891 case BAD_GATEWAY:
2892 ap_rputs("The proxy server received an invalid" CRLF
2893 "response from an upstream server.<P>" CRLF, r);
2894 if ((error_notes = ap_table_get(r->notes, "error-notes")) != NULL) {
2895 ap_rvputs(r, error_notes, "<P>\n", NULL);
2896 }
2897 break;
2898 case VARIANT_ALSO_VARIES:
2899 ap_rvputs(r, "A variant for the requested resource\n<PRE>\n",
2900 ap_escape_html(r->pool, r->uri),
2901 "\n</PRE>\nis itself a negotiable resource. "
2902 "This indicates a configuration error.<P>\n", NULL);
2903 break;
2904 case HTTP_REQUEST_TIME_OUT:
2905 ap_rputs("Server timeout waiting for the HTTP request from the client.\n", r);
2906 break;
2907 case HTTP_GONE:
2908 ap_rvputs(r, "The requested resource<BR>",
2909 ap_escape_html(r->pool, r->uri),
2910 "<BR>\nis no longer available on this server ",
2911 "and there is no forwarding address.\n",
2912 "Please remove all references to this resource.\n",
2913 NULL);
2914 break;
2915 case HTTP_REQUEST_ENTITY_TOO_LARGE:
2916 ap_rvputs(r, "The requested resource<BR>",
2917 ap_escape_html(r->pool, r->uri), "<BR>\n",
2918 "does not allow request data with ", r->method,
2919 " requests, or the amount of data provided in\n",
2920 "the request exceeds the capacity limit.\n", NULL);
2921 break;
2922 case HTTP_REQUEST_URI_TOO_LARGE:
2923 ap_rputs("The requested URL's length exceeds the capacity\n"
2924 "limit for this server.<P>\n", r);
2925 if ((error_notes = ap_table_get(r->notes, "error-notes")) != NULL) {
2926 ap_rvputs(r, error_notes, "<P>\n", NULL);
2927 }
2928 break;
2929 case HTTP_UNSUPPORTED_MEDIA_TYPE:
2930 ap_rputs("The supplied request data is not in a format\n"
2931 "acceptable for processing by this resource.\n", r);
2932 break;
2933 case HTTP_RANGE_NOT_SATISFIABLE:
2934 ap_rputs("None of the range-specifier values in the Range\n"
2935 "request-header field overlap the current extent\n"
2936 "of the selected resource.\n", r);
2937 break;
2938 case HTTP_EXPECTATION_FAILED:
2939 ap_rvputs(r, "The expectation given in the Expect request-header"
2940 "\nfield could not be met by this server.<P>\n"
2941 "The client sent<PRE>\n Expect: ",
2942 ap_escape_html(r->pool, ap_table_get(r->headers_in,
2943 "Expect")), "\n</PRE>\n"
2944 "but we only allow the 100-continue expectation.\n",
2945 NULL);
2946 break;
2947 case HTTP_UNPROCESSABLE_ENTITY:
2948 ap_rputs("The server understands the media type of the\n"
2949 "request entity, but was unable to process the\n"
2950 "contained instructions.\n", r);
2951 break;
2952 case HTTP_LOCKED:
2953 ap_rputs("The requested resource is currently locked.\n"
2954 "The lock must be released or proper identification\n"
2955 "given before the method can be applied.\n", r);
2956 break;
2957 case HTTP_FAILED_DEPENDENCY:
2958 ap_rputs("The method could not be performed on the resource\n"
2959 "because the requested action depended on another\n"
2960 "action and that other action failed.\n", r);
2961 break;
2962 case HTTP_INSUFFICIENT_STORAGE:
2963 ap_rputs("The method could not be performed on the resource\n"
2964 "because the server is unable to store the\n"
2965 "representation needed to successfully complete the\n"
2966 "request. There is insufficient free space left in\n"
2967 "your storage allocation.\n", r);
2968 break;
2969 case HTTP_SERVICE_UNAVAILABLE:
2970 ap_rputs("The server is temporarily unable to service your\n"
2971 "request due to maintenance downtime or capacity\n"
2972 "problems. Please try again later.\n", r);
2973 break;
2974 case HTTP_GATEWAY_TIME_OUT:
2975 ap_rputs("The proxy server did not receive a timely response\n"
2976 "from the upstream server.\n", r);
2977 break;
2978 case HTTP_NOT_EXTENDED:
2979 ap_rputs("A mandatory extension policy in the request is not\n"
2980 "accepted by the server for this resource.\n", r);
2981 break;
2982 default: /* HTTP_INTERNAL_SERVER_ERROR */
2983 /*
2984 * This comparison to expose error-notes could be modified to
2985 * use a configuration directive and export based on that
2986 * directive. For now "*" is used to designate an error-notes
2987 * that is totally safe for any user to see (ie lacks paths,
2988 * database passwords, etc.)
2989 */
2990 if (((error_notes = ap_table_get(r->notes, "error-notes")) != NULL)
2991 && (h1 = ap_table_get(r->notes, "verbose-error-to")) != NULL
2992 && (strcmp(h1, "*") == 0)) {
2993 ap_rvputs(r, error_notes, "<P>\n", NULL);
2994 }
2995 else {
2996 ap_rvputs(r, "The server encountered an internal error or\n"
2997 "misconfiguration and was unable to complete\n"
2998 "your request.<P>\n"
2999 "Please contact the server administrator,\n ",
3000 ap_escape_html(r->pool, r->server->server_admin),
3001 " and inform them of the time the error occurred,\n"
3002 "and anything you might have done that may have\n"
3003 "caused the error.<P>\n"
3004 "More information about this error may be available\n"
3005 "in the server error log.<P>\n", NULL);
3006 }
3007 /*
3008 * It would be nice to give the user the information they need to
3009 * fix the problem directly since many users don't have access to
3010 * the error_log (think University sites) even though they can easily
3011 * get this error by misconfiguring an htaccess file. However, the
3012 * error notes tend to include the real file pathname in this case,
3013 * which some people consider to be a breach of privacy. Until we
3014 * can figure out a way to remove the pathname, leave this commented.
3015 *
3016 * if ((error_notes = ap_table_get(r->notes, "error-notes")) != NULL) {
3017 * ap_rvputs(r, error_notes, "<P>\n", NULL);
3018 * }
3019 */
3020 break;
3021 }
3022
3023 if (recursive_error) {
3024 ap_rvputs(r, "<P>Additionally, a ",
3025 status_lines[ap_index_of_response(recursive_error)],
3026 "\nerror was encountered while trying to use an "
3027 "ErrorDocument to handle the request.\n", NULL);
3028 }
3029 ap_rputs(ap_psignature("<HR>\n", r), r);
3030 ap_rputs("</BODY></HTML>\n", r);
3031 }
3032 ap_kill_timeout(r);
3033 ap_finalize_request_protocol(r);
3034 ap_rflush(r);
3035 }
3036
3037 /*
3038 * The shared hash context, copies of which are used by all children for
3039 * etag generation. ap_init_etag() must be called once before all the
3040 * children are created. We use a secret hash initialization value
3041 * so that people can't brute-force inode numbers.
3042 */
3043 static AP_SHA1_CTX baseCtx;
3044
ap_create_etag_state(pool * pconf)3045 int ap_create_etag_state(pool *pconf)
3046 {
3047 unsigned int u;
3048 int fd;
3049 char *filename;
3050 unsigned char rnd[16];
3051
3052 filename = ap_server_root_relative(pconf, "logs/etag-state");
3053 ap_server_strip_chroot(filename, 0);
3054
3055 if ((fd = open(filename, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW, 0640)) ==
3056 -1) {
3057 ap_log_error(APLOG_MARK, APLOG_CRIT, NULL,
3058 "could not create %s", filename);
3059 exit(-1);
3060 }
3061
3062 if (fchown(fd, -1, ap_group_id) == -1) {
3063 ap_log_error(APLOG_MARK, APLOG_CRIT, NULL,
3064 "could not chown %s", filename);
3065 exit(-1);
3066 }
3067
3068 /* generate random bytes and write them */
3069 arc4random_buf(rnd, sizeof(rnd));
3070 if (write(fd, &rnd, sizeof(rnd)) != 16) {
3071 ap_log_error(APLOG_MARK, APLOG_CRIT, NULL,
3072 "could not write to %s", filename);
3073 exit(-1);
3074 }
3075
3076 close (fd);
3077 return (0);
3078 }
3079
ap_read_etag_state(pool * pconf)3080 int ap_read_etag_state(pool *pconf)
3081 {
3082 struct stat st;
3083 unsigned int u;
3084 int fd;
3085 char *filename;
3086 unsigned char rnd[16];
3087
3088 ap_SHA1Init(&baseCtx);
3089
3090 filename = ap_server_root_relative(pconf, "logs/etag-state");
3091 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, NULL,
3092 "Initializing etag from %s", filename);
3093
3094 ap_server_strip_chroot(filename, 0);
3095
3096 if ((fd = open(filename, O_RDONLY|O_NOFOLLOW, 0640)) == -1)
3097 return (-1);
3098
3099 fchmod(fd, S_IRUSR|S_IWUSR|S_IRGRP);
3100 fchown(fd, -1, ap_group_id);
3101
3102 if (fstat(fd, &st) == -1) {
3103 ap_log_error(APLOG_MARK, APLOG_CRIT, NULL,
3104 "could not fstat %s", filename);
3105 exit(-1);
3106 }
3107
3108 if (st.st_size != sizeof(rnd)) {
3109 return (-1);
3110 }
3111
3112 /* read 4 random 32-bit uints from file and update the hash context */
3113 if (read(fd, &rnd, sizeof(rnd)) != sizeof(rnd))
3114 return (-1);
3115
3116 ap_SHA1Update_binary(&baseCtx, (const unsigned char *)&rnd,
3117 sizeof(rnd));
3118
3119 if (close(fd) == -1) {
3120 ap_log_error(APLOG_MARK, APLOG_CRIT, NULL,
3121 "could not properly close %s", filename);
3122 exit(-1);
3123 }
3124 return (0);
3125 }
3126
ap_init_etag(pool * pconf)3127 API_EXPORT(void) ap_init_etag(pool *pconf)
3128 {
3129 if (ap_read_etag_state(pconf) == -1) {
3130 ap_create_etag_state(pconf);
3131 if (ap_read_etag_state(pconf) == -1) {
3132 ap_log_error(APLOG_MARK, APLOG_CRIT, NULL,
3133 "could not initialize etag state");
3134 exit(-1);
3135 }
3136 }
3137 }
3138
ap_make_etag(request_rec * r,int force_weak)3139 API_EXPORT(char *) ap_make_etag(request_rec *r, int force_weak)
3140 {
3141 AP_SHA1_CTX hashCtx;
3142 core_dir_config *cfg;
3143 etag_components_t etag_bits;
3144 int weak;
3145 unsigned char md[SHA_DIGESTSIZE];
3146
3147 memcpy(&hashCtx, &baseCtx, sizeof(hashCtx));
3148
3149 cfg = (core_dir_config *)ap_get_module_config(r->per_dir_config,
3150 &core_module);
3151 etag_bits = (cfg->etag_bits & (~ cfg->etag_remove)) | cfg->etag_add;
3152 if (etag_bits == ETAG_UNSET)
3153 etag_bits = ETAG_BACKWARD;
3154
3155 weak = ((r->request_time - r->mtime <= 1) || force_weak);
3156
3157 if (r->finfo.st_mode != 0) {
3158 if (etag_bits & ETAG_NONE) {
3159 ap_table_setn(r->notes, "no-etag", "omit");
3160 return "";
3161 }
3162 if (etag_bits & ETAG_INODE) {
3163 ap_SHA1Update_binary(&hashCtx,
3164 (const unsigned char *)&r->finfo.st_dev,
3165 sizeof(r->finfo.st_dev));
3166 ap_SHA1Update_binary(&hashCtx,
3167 (const unsigned char *)&r->finfo.st_ino,
3168 sizeof(r->finfo.st_ino));
3169 }
3170 if (etag_bits & ETAG_SIZE)
3171 ap_SHA1Update_binary(&hashCtx,
3172 (const unsigned char *)&r->finfo.st_size,
3173 sizeof(r->finfo.st_size));
3174 if (etag_bits & ETAG_MTIME)
3175 ap_SHA1Update_binary(&hashCtx,
3176 (const unsigned char *)&r->mtime,
3177 sizeof(r->mtime));
3178 }
3179 else {
3180 weak = 1;
3181 ap_SHA1Update_binary(&hashCtx, (const unsigned char *)&r->mtime,
3182 sizeof(r->mtime));
3183 }
3184 ap_SHA1Final(md, &hashCtx);
3185 return ap_psprintf(r->pool, "%s\""
3186 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
3187 "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
3188 "\"", weak ? "W/" : "",
3189 md[0], md[1], md[2], md[3], md[4], md[5], md[6], md[7],
3190 md[8], md[9], md[10], md[11], md[12], md[13], md[14], md[15],
3191 md[16], md[17], md[18], md[19]);
3192 }
3193