]> git.ipfire.org Git - thirdparty/squid.git/blob - src/http.cc
Updated copyright
[thirdparty/squid.git] / src / http.cc
1
2 /*
3 * $Id: http.cc,v 1.377 2001/01/12 00:37:18 wessels Exp $
4 *
5 * DEBUG: section 11 Hypertext Transfer Protocol (HTTP)
6 * AUTHOR: Harvest Derived
7 *
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
10 *
11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 *
34 */
35
36 /*
37 * Anonymizing patch by lutz@as-node.jena.thur.de
38 * have a look into http-anon.c to get more informations.
39 */
40
41 #include "squid.h"
42
43 static const char *const crlf = "\r\n";
44
45 static CWCB httpSendComplete;
46 static CWCB httpSendRequestEntry;
47
48 static PF httpReadReply;
49 static void httpSendRequest(HttpStateData *);
50 static PF httpStateFree;
51 static PF httpTimeout;
52 static void httpCacheNegatively(StoreEntry *);
53 static void httpMakePrivate(StoreEntry *);
54 static void httpMakePublic(StoreEntry *);
55 static int httpCachableReply(HttpStateData *);
56 static void httpMaybeRemovePublic(StoreEntry *, http_status);
57
58 static void
59 httpStateFree(int fd, void *data)
60 {
61 HttpStateData *httpState = data;
62 #if DELAY_POOLS
63 delayClearNoDelay(fd);
64 #endif
65 if (httpState == NULL)
66 return;
67 storeUnlockObject(httpState->entry);
68 if (httpState->reply_hdr) {
69 memFree(httpState->reply_hdr, MEM_8K_BUF);
70 httpState->reply_hdr = NULL;
71 }
72 requestUnlink(httpState->request);
73 requestUnlink(httpState->orig_request);
74 httpState->request = NULL;
75 httpState->orig_request = NULL;
76 cbdataFree(httpState);
77 }
78
79 int
80 httpCachable(method_t method)
81 {
82 /* GET and HEAD are cachable. Others are not. */
83 if (method != METHOD_GET && method != METHOD_HEAD)
84 return 0;
85 /* else cachable */
86 return 1;
87 }
88
89 static void
90 httpTimeout(int fd, void *data)
91 {
92 HttpStateData *httpState = data;
93 StoreEntry *entry = httpState->entry;
94 debug(11, 4) ("httpTimeout: FD %d: '%s'\n", fd, storeUrl(entry));
95 if (entry->store_status == STORE_PENDING) {
96 if (entry->mem_obj->inmem_hi == 0) {
97 fwdFail(httpState->fwd,
98 errorCon(ERR_READ_TIMEOUT, HTTP_GATEWAY_TIMEOUT));
99 }
100 }
101 comm_close(fd);
102 }
103
104 /* This object can be cached for a long time */
105 static void
106 httpMakePublic(StoreEntry * entry)
107 {
108 if (EBIT_TEST(entry->flags, ENTRY_CACHABLE))
109 storeSetPublicKey(entry);
110 }
111
112 /* This object should never be cached at all */
113 static void
114 httpMakePrivate(StoreEntry * entry)
115 {
116 storeExpireNow(entry);
117 storeReleaseRequest(entry); /* delete object when not used */
118 /* storeReleaseRequest clears ENTRY_CACHABLE flag */
119 }
120
121 /* This object may be negatively cached */
122 static void
123 httpCacheNegatively(StoreEntry * entry)
124 {
125 storeNegativeCache(entry);
126 if (EBIT_TEST(entry->flags, ENTRY_CACHABLE))
127 storeSetPublicKey(entry);
128 }
129
130 static void
131 httpMaybeRemovePublic(StoreEntry * e, http_status status)
132 {
133 int remove = 0;
134 int forbidden = 0;
135 StoreEntry *pe;
136 if (!EBIT_TEST(e->flags, KEY_PRIVATE))
137 return;
138 switch (status) {
139 case HTTP_OK:
140 case HTTP_NON_AUTHORITATIVE_INFORMATION:
141 case HTTP_MULTIPLE_CHOICES:
142 case HTTP_MOVED_PERMANENTLY:
143 case HTTP_MOVED_TEMPORARILY:
144 case HTTP_GONE:
145 case HTTP_NOT_FOUND:
146 remove = 1;
147 break;
148 case HTTP_FORBIDDEN:
149 case HTTP_METHOD_NOT_ALLOWED:
150 forbidden = 1;
151 break;
152 #if WORK_IN_PROGRESS
153 case HTTP_UNAUTHORIZED:
154 forbidden = 1;
155 break;
156 #endif
157 default:
158 #if QUESTIONABLE
159 /*
160 * Any 2xx response should eject previously cached entities...
161 */
162 if (status >= 200 && status < 300)
163 remove = 1;
164 #endif
165 break;
166 }
167 if (!remove && !forbidden)
168 return;
169 assert(e->mem_obj);
170 if ((pe = storeGetPublic(e->mem_obj->url, e->mem_obj->method)) != NULL) {
171 assert(e != pe);
172 storeRelease(pe);
173 }
174 /*
175 * Also remove any cached HEAD response in case the object has
176 * changed.
177 */
178 if ((pe = storeGetPublic(e->mem_obj->url, METHOD_HEAD)) != NULL) {
179 assert(e != pe);
180 storeRelease(pe);
181 }
182 if (forbidden)
183 return;
184 switch (e->mem_obj->method) {
185 case METHOD_PUT:
186 case METHOD_DELETE:
187 case METHOD_PROPPATCH:
188 case METHOD_MKCOL:
189 case METHOD_MOVE:
190 case METHOD_BMOVE:
191 case METHOD_BDELETE:
192 /*
193 * Remove any cached GET object if it is beleived that the
194 * object may have changed as a result of other methods
195 */
196 if ((pe = storeGetPublic(e->mem_obj->url, METHOD_GET)) != NULL) {
197 assert(e != pe);
198 storeRelease(pe);
199 }
200 break;
201 }
202 }
203
204 static int
205 httpCachableReply(HttpStateData * httpState)
206 {
207 HttpReply *rep = httpState->entry->mem_obj->reply;
208 HttpHeader *hdr = &rep->header;
209 const int cc_mask = (rep->cache_control) ? rep->cache_control->mask : 0;
210 const char *v;
211 if (EBIT_TEST(cc_mask, CC_PRIVATE))
212 return 0;
213 if (EBIT_TEST(cc_mask, CC_NO_CACHE))
214 return 0;
215 if (EBIT_TEST(cc_mask, CC_NO_STORE))
216 return 0;
217 if (httpState->request->flags.auth) {
218 /*
219 * Responses to requests with authorization may be cached
220 * only if a Cache-Control: public reply header is present.
221 * RFC 2068, sec 14.9.4
222 */
223 if (!EBIT_TEST(cc_mask, CC_PUBLIC))
224 return 0;
225 }
226 /*
227 * We don't properly deal with Vary features yet, so we can't
228 * cache these
229 */
230 if (httpHeaderHas(hdr, HDR_VARY))
231 return 0;
232 /* Pragma: no-cache in _replies_ is not documented in HTTP,
233 * but servers like "Active Imaging Webcast/2.0" sure do use it */
234 if (httpHeaderHas(hdr, HDR_PRAGMA)) {
235 String s = httpHeaderGetList(hdr, HDR_PRAGMA);
236 const int no_cache = strListIsMember(&s, "no-cache", ',');
237 stringClean(&s);
238 if (no_cache)
239 return 0;
240 }
241 /*
242 * The "multipart/x-mixed-replace" content type is used for
243 * continuous push replies. These are generally dynamic and
244 * probably should not be cachable
245 */
246 if ((v = httpHeaderGetStr(hdr, HDR_CONTENT_TYPE)))
247 if (!strncasecmp(v, "multipart/x-mixed-replace", 25))
248 return 0;
249 switch (httpState->entry->mem_obj->reply->sline.status) {
250 /* Responses that are cacheable */
251 case HTTP_OK:
252 case HTTP_NON_AUTHORITATIVE_INFORMATION:
253 case HTTP_MULTIPLE_CHOICES:
254 case HTTP_MOVED_PERMANENTLY:
255 case HTTP_GONE:
256 /*
257 * Don't cache objects that need to be refreshed on next request,
258 * unless we know how to refresh it.
259 */
260 if (!refreshIsCachable(httpState->entry))
261 return 0;
262 /* don't cache objects from peers w/o LMT, Date, or Expires */
263 /* check that is it enough to check headers @?@ */
264 if (rep->date > -1)
265 return 1;
266 else if (rep->last_modified > -1)
267 return 1;
268 else if (!httpState->peer)
269 return 1;
270 /* @?@ (here and 302): invalid expires header compiles to squid_curtime */
271 else if (rep->expires > -1)
272 return 1;
273 else
274 return 0;
275 /* NOTREACHED */
276 break;
277 /* Responses that only are cacheable if the server says so */
278 case HTTP_MOVED_TEMPORARILY:
279 if (rep->expires > -1)
280 return 1;
281 else
282 return 0;
283 /* NOTREACHED */
284 break;
285 /* Errors can be negatively cached */
286 case HTTP_NO_CONTENT:
287 case HTTP_USE_PROXY:
288 case HTTP_BAD_REQUEST:
289 case HTTP_FORBIDDEN:
290 case HTTP_NOT_FOUND:
291 case HTTP_METHOD_NOT_ALLOWED:
292 case HTTP_REQUEST_URI_TOO_LARGE:
293 case HTTP_INTERNAL_SERVER_ERROR:
294 case HTTP_NOT_IMPLEMENTED:
295 case HTTP_BAD_GATEWAY:
296 case HTTP_SERVICE_UNAVAILABLE:
297 case HTTP_GATEWAY_TIMEOUT:
298 return -1;
299 /* NOTREACHED */
300 break;
301 /* Some responses can never be cached */
302 case HTTP_PARTIAL_CONTENT: /* Not yet supported */
303 case HTTP_SEE_OTHER:
304 case HTTP_NOT_MODIFIED:
305 case HTTP_UNAUTHORIZED:
306 case HTTP_PROXY_AUTHENTICATION_REQUIRED:
307 case HTTP_INVALID_HEADER: /* Squid header parsing error */
308 default: /* Unknown status code */
309 return 0;
310 /* NOTREACHED */
311 break;
312 }
313 /* NOTREACHED */
314 }
315
316 /* rewrite this later using new interfaces @?@ */
317 void
318 httpProcessReplyHeader(HttpStateData * httpState, const char *buf, int size)
319 {
320 char *t = NULL;
321 StoreEntry *entry = httpState->entry;
322 int room;
323 size_t hdr_len;
324 HttpReply *reply = entry->mem_obj->reply;
325 Ctx ctx;
326 debug(11, 3) ("httpProcessReplyHeader: key '%s'\n",
327 storeKeyText(entry->hash.key));
328 if (httpState->reply_hdr == NULL)
329 httpState->reply_hdr = memAllocate(MEM_8K_BUF);
330 assert(httpState->reply_hdr_state == 0);
331 hdr_len = httpState->reply_hdr_size;
332 room = 8191 - hdr_len;
333 xmemcpy(httpState->reply_hdr + hdr_len, buf, room < size ? room : size);
334 hdr_len += room < size ? room : size;
335 httpState->reply_hdr[hdr_len] = '\0';
336 httpState->reply_hdr_size = hdr_len;
337 if (hdr_len > 4 && strncmp(httpState->reply_hdr, "HTTP/", 5)) {
338 debug(11, 3) ("httpProcessReplyHeader: Non-HTTP-compliant header: '%s'\n", httpState->reply_hdr);
339 httpState->reply_hdr_state += 2;
340 reply->sline.status = HTTP_INVALID_HEADER;
341 return;
342 }
343 t = httpState->reply_hdr + hdr_len;
344 /* headers can be incomplete only if object still arriving */
345 if (!httpState->eof) {
346 size_t k = headersEnd(httpState->reply_hdr, 8192);
347 if (0 == k)
348 return; /* headers not complete */
349 t = httpState->reply_hdr + k;
350 }
351 *t = '\0';
352 httpState->reply_hdr_state++;
353 assert(httpState->reply_hdr_state == 1);
354 ctx = ctx_enter(entry->mem_obj->url);
355 httpState->reply_hdr_state++;
356 debug(11, 9) ("GOT HTTP REPLY HDR:\n---------\n%s\n----------\n",
357 httpState->reply_hdr);
358 /* Parse headers into reply structure */
359 /* what happens if we fail to parse here? */
360 httpReplyParse(reply, httpState->reply_hdr, hdr_len);
361 storeTimestampsSet(entry);
362 /* Check if object is cacheable or not based on reply code */
363 debug(11, 3) ("httpProcessReplyHeader: HTTP CODE: %d\n", reply->sline.status);
364 if (neighbors_do_private_keys)
365 httpMaybeRemovePublic(entry, reply->sline.status);
366 switch (httpCachableReply(httpState)) {
367 case 1:
368 httpMakePublic(entry);
369 break;
370 case 0:
371 httpMakePrivate(entry);
372 break;
373 case -1:
374 httpCacheNegatively(entry);
375 break;
376 default:
377 assert(0);
378 break;
379 }
380 if (reply->cache_control) {
381 if (EBIT_TEST(reply->cache_control->mask, CC_PROXY_REVALIDATE))
382 EBIT_SET(entry->flags, ENTRY_REVALIDATE);
383 else if (EBIT_TEST(reply->cache_control->mask, CC_MUST_REVALIDATE))
384 EBIT_SET(entry->flags, ENTRY_REVALIDATE);
385 }
386 if (httpState->flags.keepalive)
387 if (httpState->peer)
388 httpState->peer->stats.n_keepalives_sent++;
389 if (reply->keep_alive)
390 if (httpState->peer)
391 httpState->peer->stats.n_keepalives_recv++;
392 if (reply->date > -1 && !httpState->peer) {
393 int skew = abs(reply->date - squid_curtime);
394 if (skew > 86400)
395 debug(11, 3) ("%s's clock is skewed by %d seconds!\n",
396 httpState->request->host, skew);
397 }
398 ctx_exit(ctx);
399 #if HEADERS_LOG
400 headersLog(1, 0, httpState->request->method, reply);
401 #endif
402 }
403
404 static int
405 httpPconnTransferDone(HttpStateData * httpState)
406 {
407 /* return 1 if we got the last of the data on a persistent connection */
408 MemObject *mem = httpState->entry->mem_obj;
409 HttpReply *reply = mem->reply;
410 int clen;
411 debug(11, 3) ("httpPconnTransferDone: FD %d\n", httpState->fd);
412 /*
413 * If we didn't send a keep-alive request header, then this
414 * can not be a persistent connection.
415 */
416 if (!httpState->flags.keepalive)
417 return 0;
418 /*
419 * What does the reply have to say about keep-alive?
420 */
421 /*
422 * XXX BUG?
423 * If the origin server (HTTP/1.0) does not send a keep-alive
424 * header, but keeps the connection open anyway, what happens?
425 * We'll return here and http.c waits for an EOF before changing
426 * store_status to STORE_OK. Combine this with ENTRY_FWD_HDR_WAIT
427 * and an error status code, and we might have to wait until
428 * the server times out the socket.
429 */
430 if (!reply->keep_alive)
431 return 0;
432 debug(11, 5) ("httpPconnTransferDone: content_length=%d\n",
433 reply->content_length);
434 /* If we haven't seen the end of reply headers, we are not done */
435 if (httpState->reply_hdr_state < 2)
436 return 0;
437 clen = httpReplyBodySize(httpState->request->method, reply);
438 /* If there is no message body, we can be persistent */
439 if (0 == clen)
440 return 1;
441 /* If the body size is unknown we must wait for EOF */
442 if (clen < 0)
443 return 0;
444 /* If the body size is known, we must wait until we've gotten all of it. */
445 if (mem->inmem_hi < reply->content_length + reply->hdr_sz)
446 return 0;
447 /* We got it all */
448 return 1;
449 }
450
451 /* This will be called when data is ready to be read from fd. Read until
452 * error or connection closed. */
453 /* XXX this function is too long! */
454 static void
455 httpReadReply(int fd, void *data)
456 {
457 HttpStateData *httpState = data;
458 LOCAL_ARRAY(char, buf, SQUID_TCP_SO_RCVBUF);
459 StoreEntry *entry = httpState->entry;
460 const request_t *request = httpState->request;
461 int len;
462 int bin;
463 int clen;
464 size_t read_sz;
465 #if DELAY_POOLS
466 delay_id delay_id;
467
468 /* special "if" only for http (for nodelay proxy conns) */
469 if (delayIsNoDelay(fd))
470 delay_id = 0;
471 else
472 delay_id = delayMostBytesAllowed(entry->mem_obj);
473 #endif
474 if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
475 comm_close(fd);
476 return;
477 }
478 /* check if we want to defer reading */
479 errno = 0;
480 read_sz = SQUID_TCP_SO_RCVBUF;
481 #if DELAY_POOLS
482 read_sz = delayBytesWanted(delay_id, 1, read_sz);
483 #endif
484 statCounter.syscalls.sock.reads++;
485 len = read(fd, buf, read_sz);
486 debug(11, 5) ("httpReadReply: FD %d: len %d.\n", fd, len);
487 if (len > 0) {
488 fd_bytes(fd, len, FD_READ);
489 #if DELAY_POOLS
490 delayBytesIn(delay_id, len);
491 #endif
492 kb_incr(&statCounter.server.all.kbytes_in, len);
493 kb_incr(&statCounter.server.http.kbytes_in, len);
494 commSetTimeout(fd, Config.Timeout.read, NULL, NULL);
495 IOStats.Http.reads++;
496 for (clen = len - 1, bin = 0; clen; bin++)
497 clen >>= 1;
498 IOStats.Http.read_hist[bin]++;
499 }
500 if (!httpState->reply_hdr && len > 0) {
501 /* Skip whitespace */
502 while (len > 0 && xisspace(*buf))
503 xmemmove(buf, buf + 1, len--);
504 if (len == 0) {
505 /* Continue to read... */
506 commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0);
507 return;
508 }
509 }
510 if (len < 0) {
511 debug(50, 2) ("httpReadReply: FD %d: read failure: %s.\n",
512 fd, xstrerror());
513 if (ignoreErrno(errno)) {
514 commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0);
515 } else if (entry->mem_obj->inmem_hi == 0) {
516 ErrorState *err;
517 err = errorCon(ERR_READ_ERROR, HTTP_INTERNAL_SERVER_ERROR);
518 err->xerrno = errno;
519 fwdFail(httpState->fwd, err);
520 comm_close(fd);
521 } else {
522 comm_close(fd);
523 }
524 } else if (len == 0 && entry->mem_obj->inmem_hi == 0) {
525 ErrorState *err;
526 err = errorCon(ERR_ZERO_SIZE_OBJECT, HTTP_SERVICE_UNAVAILABLE);
527 err->xerrno = errno;
528 fwdFail(httpState->fwd, err);
529 httpState->eof = 1;
530 comm_close(fd);
531 } else if (len == 0) {
532 /* Connection closed; retrieval done. */
533 httpState->eof = 1;
534 if (httpState->reply_hdr_state < 2)
535 /*
536 * Yes Henrik, there is a point to doing this. When we
537 * called httpProcessReplyHeader() before, we didn't find
538 * the end of headers, but now we are definately at EOF, so
539 * we want to process the reply headers.
540 */
541 httpProcessReplyHeader(httpState, buf, len);
542 fwdComplete(httpState->fwd);
543 comm_close(fd);
544 } else {
545 if (httpState->reply_hdr_state < 2) {
546 httpProcessReplyHeader(httpState, buf, len);
547 if (httpState->reply_hdr_state == 2) {
548 http_status s = entry->mem_obj->reply->sline.status;
549 #if WIP_FWD_LOG
550 fwdStatus(httpState->fwd, s);
551 #endif
552 /*
553 * If its not a reply that we will re-forward, then
554 * allow the client to get it.
555 */
556 if (!fwdReforwardableStatus(s))
557 EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
558 }
559 }
560 storeAppend(entry, buf, len);
561 if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
562 /*
563 * the above storeAppend() call could ABORT this entry,
564 * in that case, the server FD should already be closed.
565 * there's nothing for us to do.
566 */
567 (void) 0;
568 } else if (httpPconnTransferDone(httpState)) {
569 /* yes we have to clear all these! */
570 commSetDefer(fd, NULL, NULL);
571 commSetTimeout(fd, -1, NULL, NULL);
572 commSetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0);
573 #if DELAY_POOLS
574 delayClearNoDelay(fd);
575 #endif
576 comm_remove_close_handler(fd, httpStateFree, httpState);
577 fwdUnregister(fd, httpState->fwd);
578 pconnPush(fd, request->host, request->port);
579 fwdComplete(httpState->fwd);
580 httpState->fd = -1;
581 httpStateFree(fd, httpState);
582 } else {
583 /* Wait for EOF condition */
584 commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0);
585 }
586 }
587 }
588
589 /* This will be called when request write is complete. Schedule read of
590 * reply. */
591 static void
592 httpSendComplete(int fd, char *bufnotused, size_t size, int errflag, void *data)
593 {
594 HttpStateData *httpState = data;
595 StoreEntry *entry = httpState->entry;
596 ErrorState *err;
597 debug(11, 5) ("httpSendComplete: FD %d: size %d: errflag %d.\n",
598 fd, size, errflag);
599 #if URL_CHECKSUM_DEBUG
600 assert(entry->mem_obj->chksum == url_checksum(entry->mem_obj->url));
601 #endif
602 if (size > 0) {
603 fd_bytes(fd, size, FD_WRITE);
604 kb_incr(&statCounter.server.all.kbytes_out, size);
605 kb_incr(&statCounter.server.http.kbytes_out, size);
606 }
607 if (errflag == COMM_ERR_CLOSING)
608 return;
609 if (errflag) {
610 err = errorCon(ERR_WRITE_ERROR, HTTP_INTERNAL_SERVER_ERROR);
611 err->xerrno = errno;
612 err->request = requestLink(httpState->orig_request);
613 errorAppendEntry(entry, err);
614 comm_close(fd);
615 return;
616 } else {
617 /* Schedule read reply. */
618 commSetSelect(fd, COMM_SELECT_READ, httpReadReply, httpState, 0);
619 /*
620 * Set the read timeout here because it hasn't been set yet.
621 * We only set the read timeout after the request has been
622 * fully written to the server-side. If we start the timeout
623 * after connection establishment, then we are likely to hit
624 * the timeout for POST/PUT requests that have very large
625 * request bodies.
626 */
627 commSetTimeout(fd, Config.Timeout.read, httpTimeout, httpState);
628 commSetDefer(fd, fwdCheckDeferRead, entry);
629 }
630 }
631
632 /*
633 * build request headers and append them to a given MemBuf
634 * used by httpBuildRequestPrefix()
635 * note: calls httpHeaderInit(), the caller is responsible for Clean()-ing
636 */
637 void
638 httpBuildRequestHeader(request_t * request,
639 request_t * orig_request,
640 StoreEntry * entry,
641 HttpHeader * hdr_out,
642 int cfd,
643 http_state_flags flags)
644 {
645 /* building buffer for complex strings */
646 #define BBUF_SZ (MAX_URL+32)
647 LOCAL_ARRAY(char, bbuf, BBUF_SZ);
648 String strConnection = StringNull;
649 const HttpHeader *hdr_in = &orig_request->header;
650 int we_do_ranges;
651 const HttpHeaderEntry *e;
652 String strVia;
653 String strFwd;
654 HttpHeaderPos pos = HttpHeaderInitPos;
655 httpHeaderInit(hdr_out, hoRequest);
656 /* append our IMS header */
657 if (request->lastmod > -1 && request->method == METHOD_GET)
658 httpHeaderPutTime(hdr_out, HDR_IF_MODIFIED_SINCE, request->lastmod);
659
660 /* decide if we want to do Ranges ourselves
661 * (and fetch the whole object now)
662 * We want to handle Ranges ourselves iff
663 * - we can actually parse client Range specs
664 * - the specs are expected to be simple enough (e.g. no out-of-order ranges)
665 * - reply will be cachable
666 * (If the reply will be uncachable we have to throw it away after
667 * serving this request, so it is better to forward ranges to
668 * the server and fetch only the requested content)
669 */
670 if (NULL == orig_request->range)
671 we_do_ranges = 0;
672 else if (!orig_request->flags.cachable)
673 we_do_ranges = 0;
674 else if (httpHdrRangeOffsetLimit(orig_request->range))
675 we_do_ranges = 0;
676 else
677 we_do_ranges = 1;
678 debug(11, 8) ("httpBuildRequestHeader: range specs: %p, cachable: %d; we_do_ranges: %d\n",
679 orig_request->range, orig_request->flags.cachable, we_do_ranges);
680
681 strConnection = httpHeaderGetList(hdr_in, HDR_CONNECTION);
682 while ((e = httpHeaderGetEntry(hdr_in, &pos))) {
683 debug(11, 5) ("httpBuildRequestHeader: %s: %s\n",
684 strBuf(e->name), strBuf(e->value));
685 if (!httpRequestHdrAllowed(e, &strConnection)) {
686 debug(11, 2) ("'%s' header denied by anonymize_headers configuration\n",
687 strBuf(e->name));
688 continue;
689 }
690 switch (e->id) {
691 case HDR_PROXY_AUTHORIZATION:
692 /* Only pass on proxy authentication to peers for which
693 * authentication forwarding is explicitly enabled
694 */
695 if (request->flags.proxying && orig_request->peer_login &&
696 strcmp(orig_request->peer_login, "PASS") == 0) {
697 httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
698 }
699 break;
700 case HDR_AUTHORIZATION:
701 /* Pass on WWW authentication even if used locally. If this is
702 * not wanted in an accelerator then the header can be removed
703 * using the anonymization functions
704 */
705 httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
706 /* XXX Some accelerators might want to strip the header
707 * and regard the reply as cacheable, but authentication
708 * is not normally enabled for accelerators without reading
709 * the code, so there is not much use in adding logics here
710 * without first defining the concept of having authentication
711 * in the accelerator...
712 */
713 break;
714 case HDR_HOST:
715 /*
716 * Normally Squid does not copy the Host: header from
717 * a client request into the forwarded request headers.
718 * However, there is one case when we do: If the URL
719 * went through our redirector and the admin configured
720 * 'redir_rewrites_host' to be off.
721 */
722 if (request->flags.redirected)
723 if (!Config.onoff.redir_rewrites_host)
724 httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
725 break;
726 case HDR_IF_MODIFIED_SINCE:
727 /* append unless we added our own;
728 * note: at most one client's ims header can pass through */
729 if (!httpHeaderHas(hdr_out, HDR_IF_MODIFIED_SINCE))
730 httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
731 break;
732 case HDR_MAX_FORWARDS:
733 if (orig_request->method == METHOD_TRACE) {
734 /* sacrificing efficiency over clarity, etc. */
735 const int hops = httpHeaderGetInt(hdr_in, HDR_MAX_FORWARDS);
736 if (hops > 0)
737 httpHeaderPutInt(hdr_out, HDR_MAX_FORWARDS, hops - 1);
738 }
739 break;
740 case HDR_RANGE:
741 case HDR_IF_RANGE:
742 case HDR_REQUEST_RANGE:
743 if (!we_do_ranges)
744 httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
745 break;
746 case HDR_PROXY_CONNECTION:
747 case HDR_CONNECTION:
748 case HDR_VIA:
749 case HDR_X_FORWARDED_FOR:
750 case HDR_CACHE_CONTROL:
751 /* append these after the loop if needed */
752 break;
753 default:
754 /* pass on all other header fields */
755 httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
756 }
757 }
758
759 /* append Via */
760 strVia = httpHeaderGetList(hdr_in, HDR_VIA);
761 snprintf(bbuf, BBUF_SZ, "%d.%d %s",
762 orig_request->http_ver.major,
763 orig_request->http_ver.minor, ThisCache);
764 strListAdd(&strVia, bbuf, ',');
765 httpHeaderPutStr(hdr_out, HDR_VIA, strBuf(strVia));
766 stringClean(&strVia);
767
768 /* append X-Forwarded-For */
769 strFwd = httpHeaderGetList(hdr_in, HDR_X_FORWARDED_FOR);
770 strListAdd(&strFwd, (cfd < 0 ? "unknown" : fd_table[cfd].ipaddr), ',');
771 httpHeaderPutStr(hdr_out, HDR_X_FORWARDED_FOR, strBuf(strFwd));
772 stringClean(&strFwd);
773
774 /* append Host if not there already */
775 if (!httpHeaderHas(hdr_out, HDR_HOST)) {
776 /* use port# only if not default */
777 if (orig_request->port == urlDefaultPort(orig_request->protocol)) {
778 httpHeaderPutStr(hdr_out, HDR_HOST, orig_request->host);
779 } else {
780 httpHeaderPutStrf(hdr_out, HDR_HOST, "%s:%d",
781 orig_request->host, (int) orig_request->port);
782 }
783 }
784 /* append Authorization if known in URL, not in header and going direct */
785 if (!httpHeaderHas(hdr_out, HDR_AUTHORIZATION)) {
786 if (!request->flags.proxying && *request->login) {
787 httpHeaderPutStrf(hdr_out, HDR_AUTHORIZATION, "Basic %s",
788 base64_encode(request->login));
789 }
790 }
791 /* append Proxy-Authorization if configured for peer, and proxying */
792 if (request->flags.proxying && orig_request->peer_login &&
793 !httpHeaderHas(hdr_out, HDR_PROXY_AUTHORIZATION) &&
794 strcmp(orig_request->peer_login, "PASS") != 0) {
795 if (*orig_request->peer_login == '*') {
796 /* Special mode, to pass the username to the upstream cache */
797 char loginbuf[256];
798 char *username = "-";
799 if (orig_request->auth_user_request)
800 username = authenticateUserRequestUsername(orig_request->auth_user_request);
801 snprintf(loginbuf, sizeof(loginbuf), "%s%s", username, orig_request->peer_login + 1);
802 httpHeaderPutStrf(hdr_out, HDR_PROXY_AUTHORIZATION, "Basic %s",
803 base64_encode(loginbuf));
804 } else {
805 httpHeaderPutStrf(hdr_out, HDR_PROXY_AUTHORIZATION, "Basic %s",
806 base64_encode(orig_request->peer_login));
807 }
808 }
809 /* append Cache-Control, add max-age if not there already */
810 {
811 HttpHdrCc *cc = httpHeaderGetCc(hdr_in);
812 if (!cc)
813 cc = httpHdrCcCreate();
814 if (!EBIT_TEST(cc->mask, CC_MAX_AGE)) {
815 const char *url = entry ? storeUrl(entry) : urlCanonical(orig_request);
816 httpHdrCcSetMaxAge(cc, getMaxAge(url));
817 if (strLen(request->urlpath))
818 assert(strstr(url, strBuf(request->urlpath)));
819 }
820 if (flags.only_if_cached)
821 EBIT_SET(cc->mask, CC_ONLY_IF_CACHED);
822 httpHeaderPutCc(hdr_out, cc);
823 httpHdrCcDestroy(cc);
824 }
825 /* maybe append Connection: keep-alive */
826 if (flags.keepalive) {
827 if (flags.proxying) {
828 httpHeaderPutStr(hdr_out, HDR_PROXY_CONNECTION, "keep-alive");
829 } else {
830 httpHeaderPutStr(hdr_out, HDR_CONNECTION, "keep-alive");
831 }
832 }
833 /* Now mangle the headers. */
834 httpHdrMangleList(hdr_out, request);
835 stringClean(&strConnection);
836 }
837
838 /* build request prefix and append it to a given MemBuf;
839 * return the length of the prefix */
840 mb_size_t
841 httpBuildRequestPrefix(request_t * request,
842 request_t * orig_request,
843 StoreEntry * entry,
844 MemBuf * mb,
845 int cfd,
846 http_state_flags flags)
847 {
848 const int offset = mb->size;
849 memBufPrintf(mb, "%s %s HTTP/1.0\r\n",
850 RequestMethodStr[request->method],
851 strLen(request->urlpath) ? strBuf(request->urlpath) : "/");
852 /* build and pack headers */
853 {
854 HttpHeader hdr;
855 Packer p;
856 httpBuildRequestHeader(request, orig_request, entry, &hdr, cfd, flags);
857 packerToMemInit(&p, mb);
858 httpHeaderPackInto(&hdr, &p);
859 httpHeaderClean(&hdr);
860 packerClean(&p);
861 }
862 /* append header terminator */
863 memBufAppend(mb, crlf, 2);
864 return mb->size - offset;
865 }
866 /* This will be called when connect completes. Write request. */
867 static void
868 httpSendRequest(HttpStateData * httpState)
869 {
870 MemBuf mb;
871 request_t *req = httpState->request;
872 StoreEntry *entry = httpState->entry;
873 int cfd;
874 peer *p = httpState->peer;
875 CWCB *sendHeaderDone;
876
877 debug(11, 5) ("httpSendRequest: FD %d: httpState %p.\n", httpState->fd, httpState);
878
879 if (httpState->orig_request->body_connection)
880 sendHeaderDone = httpSendRequestEntry;
881 else
882 sendHeaderDone = httpSendComplete;
883
884 if (!opt_forwarded_for)
885 cfd = -1;
886 else if (entry->mem_obj == NULL)
887 cfd = -1;
888 else
889 cfd = entry->mem_obj->fd;
890 assert(-1 == cfd || FD_SOCKET == fd_table[cfd].type);
891 if (p != NULL)
892 httpState->flags.proxying = 1;
893 else
894 httpState->flags.proxying = 0;
895 /*
896 * Is keep-alive okay for all request methods?
897 */
898 if (!Config.onoff.server_pconns)
899 httpState->flags.keepalive = 0;
900 else if (p == NULL)
901 httpState->flags.keepalive = 1;
902 else if (p->stats.n_keepalives_sent < 10)
903 httpState->flags.keepalive = 1;
904 else if ((double) p->stats.n_keepalives_recv / (double) p->stats.n_keepalives_sent > 0.50)
905 httpState->flags.keepalive = 1;
906 if (httpState->peer)
907 if (neighborType(httpState->peer, httpState->request) == PEER_SIBLING &&
908 !httpState->peer->options.allow_miss)
909 httpState->flags.only_if_cached = 1;
910 memBufDefInit(&mb);
911 httpBuildRequestPrefix(req,
912 httpState->orig_request,
913 entry,
914 &mb,
915 cfd,
916 httpState->flags);
917 debug(11, 6) ("httpSendRequest: FD %d:\n%s\n", httpState->fd, mb.buf);
918 comm_write_mbuf(httpState->fd, mb, sendHeaderDone, httpState);
919 }
920
921 void
922 httpStart(FwdState * fwd)
923 {
924 int fd = fwd->server_fd;
925 HttpStateData *httpState;
926 request_t *proxy_req;
927 request_t *orig_req = fwd->request;
928 debug(11, 3) ("httpStart: \"%s %s\"\n",
929 RequestMethodStr[orig_req->method],
930 storeUrl(fwd->entry));
931 httpState = CBDATA_ALLOC(HttpStateData, NULL);
932 storeLockObject(fwd->entry);
933 httpState->fwd = fwd;
934 httpState->entry = fwd->entry;
935 httpState->fd = fd;
936 if (fwd->servers)
937 httpState->peer = fwd->servers->peer; /* might be NULL */
938 if (httpState->peer) {
939 proxy_req = requestCreate(orig_req->method,
940 PROTO_NONE, storeUrl(httpState->entry));
941 xstrncpy(proxy_req->host, httpState->peer->host, SQUIDHOSTNAMELEN);
942 proxy_req->port = httpState->peer->http_port;
943 proxy_req->flags = orig_req->flags;
944 proxy_req->lastmod = orig_req->lastmod;
945 httpState->request = requestLink(proxy_req);
946 httpState->orig_request = requestLink(orig_req);
947 proxy_req->flags.proxying = 1;
948 /*
949 * This NEIGHBOR_PROXY_ONLY check probably shouldn't be here.
950 * We might end up getting the object from somewhere else if,
951 * for example, the request to this neighbor fails.
952 */
953 if (httpState->peer->options.proxy_only)
954 storeReleaseRequest(httpState->entry);
955 #if DELAY_POOLS
956 assert(delayIsNoDelay(fd) == 0);
957 if (httpState->peer->options.no_delay)
958 delaySetNoDelay(fd);
959 #endif
960 } else {
961 httpState->request = requestLink(orig_req);
962 httpState->orig_request = requestLink(orig_req);
963 }
964 /*
965 * register the handler to free HTTP state data when the FD closes
966 */
967 comm_add_close_handler(fd, httpStateFree, httpState);
968 statCounter.server.all.requests++;
969 statCounter.server.http.requests++;
970 httpSendRequest(httpState);
971 /*
972 * We used to set the read timeout here, but not any more.
973 * Now its set in httpSendComplete() after the full request,
974 * including request body, has been written to the server.
975 */
976 }
977
978 static void
979 httpSendRequestEntryDone(int fd, void *data)
980 {
981 HttpStateData *httpState = data;
982 aclCheck_t ch;
983 debug(11, 5) ("httpSendRequestEntryDone: FD %d\n",
984 fd);
985 memset(&ch, '\0', sizeof(ch));
986 ch.request = httpState->request;
987 if (!Config.accessList.brokenPosts) {
988 debug(11, 5) ("httpSendRequestEntryDone: No brokenPosts list\n");
989 httpSendComplete(fd, NULL, 0, 0, data);
990 } else if (!aclCheckFast(Config.accessList.brokenPosts, &ch)) {
991 debug(11, 5) ("httpSendRequestEntryDone: didn't match brokenPosts\n");
992 httpSendComplete(fd, NULL, 0, 0, data);
993 } else {
994 debug(11, 2) ("httpSendRequestEntryDone: matched brokenPosts\n");
995 comm_write(fd, "\r\n", 2, httpSendComplete, data, NULL);
996 }
997 }
998
999 static void
1000 httpRequestBodyHandler(char *buf, size_t size, void *data)
1001 {
1002 HttpStateData *httpState = (HttpStateData *) data;
1003 if (size > 0) {
1004 comm_write(httpState->fd, buf, size, httpSendRequestEntry, data, memFree8K);
1005 } else if (size == 0) {
1006 /* End of body */
1007 memFree8K(buf);
1008 httpSendRequestEntryDone(httpState->fd, data);
1009 } else {
1010 /* Failed to get whole body, probably aborted */
1011 memFree8K(buf);
1012 httpSendComplete(httpState->fd, NULL, 0, COMM_ERR_CLOSING, data);
1013 }
1014 }
1015
1016 static void
1017 httpSendRequestEntry(int fd, char *bufnotused, size_t size, int errflag, void *data)
1018 {
1019 HttpStateData *httpState = data;
1020 StoreEntry *entry = httpState->entry;
1021 ErrorState *err;
1022 debug(11, 5) ("httpSendRequestEntry: FD %d: size %d: errflag %d.\n",
1023 fd, size, errflag);
1024 if (size > 0) {
1025 fd_bytes(fd, size, FD_WRITE);
1026 kb_incr(&statCounter.server.all.kbytes_out, size);
1027 kb_incr(&statCounter.server.http.kbytes_out, size);
1028 }
1029 if (errflag == COMM_ERR_CLOSING)
1030 return;
1031 if (errflag) {
1032 err = errorCon(ERR_WRITE_ERROR, HTTP_INTERNAL_SERVER_ERROR);
1033 err->xerrno = errno;
1034 err->request = requestLink(httpState->orig_request);
1035 errorAppendEntry(entry, err);
1036 comm_close(fd);
1037 return;
1038 }
1039 if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
1040 comm_close(fd);
1041 return;
1042 }
1043 clientReadBody(httpState->orig_request, memAllocate(MEM_8K_BUF), 8192, httpRequestBodyHandler, httpState);
1044 }
1045
1046 void
1047 httpBuildVersion(http_version_t * version, unsigned int major, unsigned int minor)
1048 {
1049 version->major = major;
1050 version->minor = minor;
1051 }