client_side.c
上传用户:liugui
上传日期:2007-01-04
资源大小:822k
文件大小:83k
源码类别:

代理服务器

开发平台:

Unix_Linux

  1. /*
  2.  * $Id: client_side.c,v 1.440.2.1 1999/02/12 19:38:25 wessels Exp $
  3.  *
  4.  * DEBUG: section 33    Client-side Routines
  5.  * AUTHOR: Duane Wessels
  6.  *
  7.  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
  8.  * ----------------------------------------------------------
  9.  *
  10.  *  Squid is the result of efforts by numerous individuals from the
  11.  *  Internet community.  Development is led by Duane Wessels of the
  12.  *  National Laboratory for Applied Network Research and funded by the
  13.  *  National Science Foundation.  Squid is Copyrighted (C) 1998 by
  14.  *  Duane Wessels and the University of California San Diego.  Please
  15.  *  see the COPYRIGHT file for full details.  Squid incorporates
  16.  *  software developed and/or copyrighted by other sources.  Please see
  17.  *  the CREDITS file for full details.
  18.  *
  19.  *  This program is free software; you can redistribute it and/or modify
  20.  *  it under the terms of the GNU General Public License as published by
  21.  *  the Free Software Foundation; either version 2 of the License, or
  22.  *  (at your option) any later version.
  23.  *  
  24.  *  This program is distributed in the hope that it will be useful,
  25.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  26.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  27.  *  GNU General Public License for more details.
  28.  *  
  29.  *  You should have received a copy of the GNU General Public License
  30.  *  along with this program; if not, write to the Free Software
  31.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  32.  *
  33.  */
  34. #include "squid.h"
  35. #if IPF_TRANSPARENT
  36. #if HAVE_SYS_IOCTL_H
  37. #include <sys/ioctl.h>
  38. #endif
  39. #include <netinet/tcp.h>
  40. #include <net/if.h>
  41. #include <ip_compat.h>
  42. #include <ip_fil.h>
  43. #include <ip_nat.h>
  44. #endif
  45. #if LINGERING_CLOSE
  46. #define comm_close comm_lingering_close
  47. #endif
  48. static const char *const crlf = "rn";
  49. #define REQUEST_BUF_SIZE 4096
  50. #define FAILURE_MODE_TIME 300
  51. /* Local functions */
  52. static CWCB clientWriteComplete;
  53. static PF clientReadRequest;
  54. static PF connStateFree;
  55. static PF requestTimeout;
  56. static int clientCheckTransferDone(clientHttpRequest *);
  57. static int clientGotNotEnough(clientHttpRequest *);
  58. static void checkFailureRatio(err_type, hier_code);
  59. static void clientProcessMiss(clientHttpRequest *);
  60. static void clientBuildReplyHeader(clientHttpRequest * http, HttpReply * rep);
  61. static clientHttpRequest *parseHttpRequestAbort(ConnStateData * conn, const char *uri);
  62. static clientHttpRequest *parseHttpRequest(ConnStateData *, method_t *, int *, char **, size_t *);
  63. static RH clientRedirectDone;
  64. static STCB clientHandleIMSReply;
  65. static int clientGetsOldEntry(StoreEntry * new, StoreEntry * old, request_t * request);
  66. static int checkAccelOnly(clientHttpRequest *);
  67. #if USE_IDENT
  68. static IDCB clientIdentDone;
  69. #endif
  70. static int clientOnlyIfCached(clientHttpRequest * http);
  71. static STCB clientSendMoreData;
  72. static STCB clientCacheHit;
  73. static void clientSetKeepaliveFlag(clientHttpRequest *);
  74. static void clientInterpretRequestHeaders(clientHttpRequest *);
  75. static void clientProcessRequest(clientHttpRequest *);
  76. static void clientProcessExpired(void *data);
  77. static void clientProcessOnlyIfCachedMiss(clientHttpRequest * http);
  78. static int clientCachable(clientHttpRequest * http);
  79. static int clientHierarchical(clientHttpRequest * http);
  80. static int clientCheckContentLength(request_t * r);
  81. static int httpAcceptDefer(void);
  82. static log_type clientProcessRequest2(clientHttpRequest * http);
  83. static int
  84. checkAccelOnly(clientHttpRequest * http)
  85. {
  86.     /* return TRUE if someone makes a proxy request to us and
  87.      * we are in httpd-accel only mode */
  88.     if (!Config2.Accel.on)
  89. return 0;
  90.     if (Config.onoff.accel_with_proxy)
  91. return 0;
  92.     if (http->request->protocol == PROTO_CACHEOBJ)
  93. return 0;
  94.     if (http->flags.accel)
  95. return 0;
  96.     return 1;
  97. }
  98. #if USE_IDENT
  99. void
  100. clientIdentDone(const char *ident, void *data)
  101. {
  102.     ConnStateData *conn = data;
  103.     if (ident)
  104. xstrncpy(conn->ident, ident, sizeof(conn->ident));
  105.     else
  106. xstrncpy(conn->ident, "-", sizeof(conn->ident));
  107. }
  108. #endif
  109. void
  110. clientAccessCheck(void *data)
  111. {
  112.     clientHttpRequest *http = data;
  113.     ConnStateData *conn = http->conn;
  114.     const char *browser;
  115.     if (checkAccelOnly(http)) {
  116. clientAccessCheckDone(0, http);
  117. return;
  118.     }
  119.     browser = httpHeaderGetStr(&http->request->header, HDR_USER_AGENT);
  120.     http->acl_checklist = aclChecklistCreate(Config.accessList.http,
  121. http->request,
  122. conn->peer.sin_addr,
  123. conn->me.sin_addr,
  124. browser,
  125. conn->ident);
  126. #if USE_IDENT
  127.     /*
  128.      * hack for ident ACL. It needs to get full addresses, and a
  129.      * place to store the ident result on persistent connections...
  130.      */
  131.     http->acl_checklist->conn = conn;
  132.     cbdataLock(http->acl_checklist->conn);
  133. #endif
  134.     aclNBCheck(http->acl_checklist, clientAccessCheckDone, http);
  135. }
  136. /*
  137.  * returns true if client specified that the object must come from the cache
  138.  * witout contacting origin server
  139.  */
  140. static int
  141. clientOnlyIfCached(clientHttpRequest * http)
  142. {
  143.     const request_t *r = http->request;
  144.     assert(r);
  145.     return r->cache_control &&
  146. EBIT_TEST(r->cache_control->mask, CC_ONLY_IF_CACHED);
  147. }
  148. StoreEntry *
  149. clientCreateStoreEntry(clientHttpRequest * h, method_t m, request_flags flags)
  150. {
  151.     StoreEntry *e;
  152.     /*
  153.      * For erroneous requests, we might not have a h->request,
  154.      * so make a fake one.
  155.      */
  156.     if (h->request == NULL)
  157. h->request = requestLink(requestCreate(m, PROTO_NONE, NULL));
  158.     e = storeCreateEntry(h->uri, h->log_uri, flags, m);
  159.     storeClientListAdd(e, h);
  160. #if DELAY_POOLS
  161.     delaySetStoreClient(e, h, delayClient(h->request));
  162. #endif
  163.     storeClientCopy(e, 0, 0, CLIENT_SOCK_SZ,
  164. memAllocate(MEM_CLIENT_SOCK_BUF), clientSendMoreData, h);
  165.     return e;
  166. }
  167. void
  168. clientAccessCheckDone(int answer, void *data)
  169. {
  170.     clientHttpRequest *http = data;
  171.     int page_id = -1;
  172.     http_status status;
  173.     ErrorState *err = NULL;
  174.     debug(33, 5) ("clientAccessCheckDone: '%s' answer=%dn", http->uri, answer);
  175.     http->acl_checklist = NULL;
  176.     if (answer == ACCESS_ALLOWED) {
  177. safe_free(http->uri);
  178. http->uri = xstrdup(urlCanonical(http->request));
  179. assert(http->redirect_state == REDIRECT_NONE);
  180. http->redirect_state = REDIRECT_PENDING;
  181. redirectStart(http, clientRedirectDone, http);
  182.     } else {
  183. debug(33, 5) ("Access Denied: %sn", http->uri);
  184. debug(33, 5) ("AclMatchedName = %sn",
  185.     AclMatchedName ? AclMatchedName : "<null>");
  186. http->log_type = LOG_TCP_DENIED;
  187. http->entry = clientCreateStoreEntry(http, http->request->method,
  188.     null_request_flags);
  189. page_id = aclGetDenyInfoPage(&Config.denyInfoList, AclMatchedName);
  190. if (answer == ACCESS_REQ_PROXY_AUTH || aclIsProxyAuth(AclMatchedName)) {
  191.     if (!http->flags.accel) {
  192. /* Proxy authorisation needed */
  193. status = HTTP_PROXY_AUTHENTICATION_REQUIRED;
  194.     } else {
  195. /* WWW authorisation needed */
  196. status = HTTP_UNAUTHORIZED;
  197.     }
  198.     if (page_id <= 0)
  199. page_id = ERR_CACHE_ACCESS_DENIED;
  200. } else {
  201.     status = HTTP_FORBIDDEN;
  202.     if (page_id <= 0)
  203. page_id = ERR_ACCESS_DENIED;
  204. }
  205. err = errorCon(page_id, status);
  206. err->request = requestLink(http->request);
  207. err->src_addr = http->conn->peer.sin_addr;
  208. errorAppendEntry(http->entry, err);
  209.     }
  210. }
  211. static void
  212. clientRedirectDone(void *data, char *result)
  213. {
  214.     clientHttpRequest *http = data;
  215.     request_t *new_request = NULL;
  216.     request_t *old_request = http->request;
  217.     debug(33, 5) ("clientRedirectDone: '%s' result=%sn", http->uri,
  218. result ? result : "NULL");
  219.     assert(http->redirect_state == REDIRECT_PENDING);
  220.     http->redirect_state = REDIRECT_DONE;
  221.     if (result) {
  222. http_status status = atoi(result);
  223. if (status == 301 || status == 302) {
  224.     char *t = result;
  225.     if ((t = strchr(result, ':')) != NULL) {
  226. http->redirect.status = status;
  227. http->redirect.location = xstrdup(t + 1);
  228.     } else {
  229. debug(33, 1) ("clientRedirectDone: bad input: %sn", result);
  230.     }
  231. }
  232. if (strcmp(result, http->uri))
  233.     new_request = urlParse(old_request->method, result);
  234.     }
  235.     if (new_request) {
  236. safe_free(http->uri);
  237. http->uri = xstrdup(urlCanonical(new_request));
  238. new_request->http_ver = old_request->http_ver;
  239. httpHeaderAppend(&new_request->header, &old_request->header);
  240. new_request->client_addr = old_request->client_addr;
  241. new_request->my_addr = old_request->my_addr;
  242. new_request->flags.redirected = 1;
  243. if (old_request->body) {
  244.     new_request->body = xmalloc(old_request->body_sz);
  245.     xmemcpy(new_request->body, old_request->body, old_request->body_sz);
  246.     new_request->body_sz = old_request->body_sz;
  247. }
  248. requestUnlink(old_request);
  249. http->request = requestLink(new_request);
  250.     }
  251.     clientInterpretRequestHeaders(http);
  252.     fd_note(http->conn->fd, http->uri);
  253.     clientProcessRequest(http);
  254. }
  255. static void
  256. clientProcessExpired(void *data)
  257. {
  258.     clientHttpRequest *http = data;
  259.     char *url = http->uri;
  260.     StoreEntry *entry = NULL;
  261.     debug(33, 3) ("clientProcessExpired: '%s'n", http->uri);
  262.     assert(http->entry->lastmod >= 0);
  263.     /*
  264.      * check if we are allowed to contact other servers
  265.      * @?@: Instead of a 504 (Gateway Timeout) reply, we may want to return 
  266.      *      a stale entry *if* it matches client requirements
  267.      */
  268.     if (clientOnlyIfCached(http)) {
  269. clientProcessOnlyIfCachedMiss(http);
  270. return;
  271.     }
  272.     http->request->flags.refresh = 1;
  273.     http->old_entry = http->entry;
  274.     entry = storeCreateEntry(url,
  275. http->log_uri,
  276. http->request->flags,
  277. http->request->method);
  278.     /* NOTE, don't call storeLockObject(), storeCreateEntry() does it */
  279.     storeClientListAdd(entry, http);
  280.     storeClientListAdd(http->old_entry, http);
  281. #if DELAY_POOLS
  282.     /* delay_id is already set on original store client */
  283.     delaySetStoreClient(entry, http, delayClient(http->request));
  284. #endif
  285.     entry->lastmod = http->old_entry->lastmod;
  286.     debug(33, 5) ("clientProcessExpired: lastmod %dn", (int) entry->lastmod);
  287.     entry->refcount++; /* EXPIRED CASE */
  288.     http->entry = entry;
  289.     http->out.offset = 0;
  290.     fwdStart(http->conn->fd, http->entry, http->request,
  291. http->conn->peer.sin_addr, http->conn->me.sin_addr);
  292.     /* Register with storage manager to receive updates when data comes in. */
  293.     if (EBIT_TEST(entry->flags, ENTRY_ABORTED))
  294. debug(33, 0) ("clientProcessExpired: found ENTRY_ABORTED objectn");
  295.     storeClientCopy(entry,
  296. http->out.offset,
  297. http->out.offset,
  298. CLIENT_SOCK_SZ,
  299. memAllocate(MEM_CLIENT_SOCK_BUF),
  300. clientHandleIMSReply,
  301. http);
  302. }
  303. static int
  304. clientGetsOldEntry(StoreEntry * new_entry, StoreEntry * old_entry, request_t * request)
  305. {
  306.     const http_status status = new_entry->mem_obj->reply->sline.status;
  307.     if (0 == status) {
  308. debug(33, 5) ("clientGetsOldEntry: YES, broken HTTP replyn");
  309. return 1;
  310.     }
  311.     /* If the reply is a failure then send the old object as a last
  312.      * resort */
  313.     if (status >= 500 && status < 600) {
  314. debug(33, 2) ("clientGetsOldEntry: YES, failure reply=%dn", status);
  315. return 1;
  316.     }
  317.     /* If the reply is anything but "Not Modified" then
  318.      * we must forward it to the client */
  319.     if (HTTP_NOT_MODIFIED != status) {
  320. debug(33, 5) ("clientGetsOldEntry: NO, reply=%dn", status);
  321. return 0;
  322.     }
  323.     /* If the client did not send IMS in the request, then it
  324.      * must get the old object, not this "Not Modified" reply */
  325.     if (!request->flags.ims) {
  326. debug(33, 5) ("clientGetsOldEntry: YES, no client IMSn");
  327. return 1;
  328.     }
  329.     /* If the client IMS time is prior to the entry LASTMOD time we
  330.      * need to send the old object */
  331.     if (modifiedSince(old_entry, request)) {
  332. debug(33, 5) ("clientGetsOldEntry: YES, modified since %dn",
  333.     (int) request->ims);
  334. return 1;
  335.     }
  336.     debug(33, 5) ("clientGetsOldEntry: NO, new one is finen");
  337.     return 0;
  338. }
  339. static void
  340. clientHandleIMSReply(void *data, char *buf, ssize_t size)
  341. {
  342.     clientHttpRequest *http = data;
  343.     StoreEntry *entry = http->entry;
  344.     MemObject *mem = entry->mem_obj;
  345.     const char *url = storeUrl(entry);
  346.     int unlink_request = 0;
  347.     StoreEntry *oldentry;
  348.     int recopy = 1;
  349.     const http_status status = mem->reply->sline.status;
  350.     debug(33, 3) ("clientHandleIMSReply: %s, %d bytesn", url, (int) size);
  351.     if (size < 0 && !EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
  352. memFree(buf, MEM_CLIENT_SOCK_BUF);
  353. return;
  354.     }
  355.     if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
  356. debug(33, 3) ("clientHandleIMSReply: ABORTED '%s'n", url);
  357. /* We have an existing entry, but failed to validate it */
  358. /* Its okay to send the old one anyway */
  359. http->log_type = LOG_TCP_REFRESH_FAIL_HIT;
  360. storeUnregister(entry, http);
  361. storeUnlockObject(entry);
  362. entry = http->entry = http->old_entry;
  363. entry->refcount++;
  364.     } else if (STORE_PENDING == entry->store_status && 0 == status) {
  365. debug(33, 3) ("clientHandleIMSReply: Incomplete headers for '%s'n", url);
  366. if (size >= CLIENT_SOCK_SZ) {
  367.     /* will not get any bigger than that */
  368.     debug(33, 3) ("clientHandleIMSReply: Reply is too large '%s', using old entryn", url);
  369.     /* use old entry, this repeats the code abovez */
  370.     http->log_type = LOG_TCP_REFRESH_FAIL_HIT;
  371.     storeUnregister(entry, http);
  372.     storeUnlockObject(entry);
  373.     entry = http->entry = http->old_entry;
  374.     entry->refcount++;
  375.     /* continue */
  376. } else {
  377.     storeClientCopy(entry,
  378. http->out.offset + size,
  379. http->out.offset,
  380. CLIENT_SOCK_SZ,
  381. buf,
  382. clientHandleIMSReply,
  383. http);
  384.     return;
  385. }
  386.     } else if (clientGetsOldEntry(entry, http->old_entry, http->request)) {
  387. /* We initiated the IMS request, the client is not expecting
  388.  * 304, so put the good one back.  First, make sure the old entry
  389.  * headers have been loaded from disk. */
  390. oldentry = http->old_entry;
  391. http->log_type = LOG_TCP_REFRESH_HIT;
  392. if (oldentry->mem_obj->request == NULL) {
  393.     oldentry->mem_obj->request = requestLink(mem->request);
  394.     unlink_request = 1;
  395. }
  396. /* Don't memcpy() the whole reply structure here.  For example,
  397.  * www.thegist.com (Netscape/1.13) returns a content-length for
  398.  * 304's which seems to be the length of the 304 HEADERS!!! and
  399.  * not the body they refer to.  */
  400. httpReplyUpdateOnNotModified(oldentry->mem_obj->reply, mem->reply);
  401. storeTimestampsSet(oldentry);
  402. storeUnregister(entry, http);
  403. storeUnlockObject(entry);
  404. entry = http->entry = oldentry;
  405. entry->timestamp = squid_curtime;
  406. if (unlink_request) {
  407.     requestUnlink(entry->mem_obj->request);
  408.     entry->mem_obj->request = NULL;
  409. }
  410.     } else {
  411. /* the client can handle this reply, whatever it is */
  412. http->log_type = LOG_TCP_REFRESH_MISS;
  413. if (HTTP_NOT_MODIFIED == mem->reply->sline.status) {
  414.     http->old_entry->timestamp = squid_curtime;
  415.     http->old_entry->refcount++;
  416.     http->log_type = LOG_TCP_REFRESH_HIT;
  417. }
  418. storeUnregister(http->old_entry, http);
  419. storeUnlockObject(http->old_entry);
  420. recopy = 0;
  421.     }
  422.     http->old_entry = NULL; /* done with old_entry */
  423.     assert(!EBIT_TEST(entry->flags, ENTRY_ABORTED));
  424.     if (recopy) {
  425. storeClientCopy(entry,
  426.     http->out.offset,
  427.     http->out.offset,
  428.     CLIENT_SOCK_SZ,
  429.     buf,
  430.     clientSendMoreData,
  431.     http);
  432.     } else {
  433. clientSendMoreData(data, buf, size);
  434.     }
  435. }
  436. int
  437. modifiedSince(StoreEntry * entry, request_t * request)
  438. {
  439.     int object_length;
  440.     MemObject *mem = entry->mem_obj;
  441.     time_t mod_time = entry->lastmod;
  442.     debug(33, 3) ("modifiedSince: '%s'n", storeUrl(entry));
  443.     if (mod_time < 0)
  444. mod_time = entry->timestamp;
  445.     debug(33, 3) ("modifiedSince: mod_time = %dn", (int) mod_time);
  446.     if (mod_time < 0)
  447. return 1;
  448.     /* Find size of the object */
  449.     object_length = mem->reply->content_length;
  450.     if (object_length < 0)
  451. object_length = contentLen(entry);
  452.     if (mod_time > request->ims) {
  453. debug(33, 3) ("--> YES: entry newer than clientn");
  454. return 1;
  455.     } else if (mod_time < request->ims) {
  456. debug(33, 3) ("-->  NO: entry older than clientn");
  457. return 0;
  458.     } else if (request->imslen < 0) {
  459. debug(33, 3) ("-->  NO: same LMT, no client lengthn");
  460. return 0;
  461.     } else if (request->imslen == object_length) {
  462. debug(33, 3) ("-->  NO: same LMT, same lengthn");
  463. return 0;
  464.     } else {
  465. debug(33, 3) ("--> YES: same LMT, different lengthn");
  466. return 1;
  467.     }
  468. }
  469. void
  470. clientPurgeRequest(clientHttpRequest * http)
  471. {
  472.     StoreEntry *entry;
  473.     ErrorState *err = NULL;
  474.     HttpReply *r;
  475.     debug(33, 3) ("Config.onoff.enable_purge = %dn", Config.onoff.enable_purge);
  476.     if (!Config.onoff.enable_purge) {
  477. http->log_type = LOG_TCP_DENIED;
  478. err = errorCon(ERR_ACCESS_DENIED, HTTP_FORBIDDEN);
  479. err->request = requestLink(http->request);
  480. err->src_addr = http->conn->peer.sin_addr;
  481. http->entry = clientCreateStoreEntry(http, http->request->method, null_request_flags);
  482. errorAppendEntry(http->entry, err);
  483. return;
  484.     }
  485.     http->log_type = LOG_TCP_MISS;
  486.     if ((entry = storeGetPublic(http->uri, METHOD_GET)) == NULL) {
  487. http->http_code = HTTP_NOT_FOUND;
  488.     } else {
  489. storeRelease(entry);
  490. http->http_code = HTTP_OK;
  491.     }
  492.     debug(33, 4) ("clientPurgeRequest: Not modified '%s'n",
  493. storeUrl(entry));
  494.     /*
  495.      * Make a new entry to hold the reply to be written
  496.      * to the client.
  497.      */
  498.     http->entry = clientCreateStoreEntry(http, http->request->method, null_request_flags);
  499.     httpReplyReset(r = http->entry->mem_obj->reply);
  500.     httpReplySetHeaders(r, 1.0, http->http_code, NULL, NULL, 0, 0, -1);
  501.     httpReplySwapOut(r, http->entry);
  502.     storeComplete(http->entry);
  503. }
  504. int
  505. checkNegativeHit(StoreEntry * e)
  506. {
  507.     if (!EBIT_TEST(e->flags, ENTRY_NEGCACHED))
  508. return 0;
  509.     if (e->expires <= squid_curtime)
  510. return 0;
  511.     if (e->store_status != STORE_OK)
  512. return 0;
  513.     return 1;
  514. }
  515. void
  516. clientUpdateCounters(clientHttpRequest * http)
  517. {
  518.     int svc_time = tvSubMsec(http->start, current_time);
  519.     ping_data *i;
  520.     HierarchyLogEntry *H;
  521.     Counter.client_http.requests++;
  522.     if (isTcpHit(http->log_type))
  523. Counter.client_http.hits++;
  524.     if (http->request->err_type != ERR_NONE)
  525. Counter.client_http.errors++;
  526.     statHistCount(&Counter.client_http.all_svc_time, svc_time);
  527.     /*
  528.      * The idea here is not to be complete, but to get service times
  529.      * for only well-defined types.  For example, we don't include
  530.      * LOG_TCP_REFRESH_FAIL_HIT because its not really a cache hit
  531.      * (we *tried* to validate it, but failed).
  532.      */
  533.     switch (http->log_type) {
  534.     case LOG_TCP_REFRESH_HIT:
  535. statHistCount(&Counter.client_http.nh_svc_time, svc_time);
  536. break;
  537.     case LOG_TCP_IMS_HIT:
  538. statHistCount(&Counter.client_http.nm_svc_time, svc_time);
  539. break;
  540.     case LOG_TCP_HIT:
  541.     case LOG_TCP_MEM_HIT:
  542.     case LOG_TCP_OFFLINE_HIT:
  543. statHistCount(&Counter.client_http.hit_svc_time, svc_time);
  544. break;
  545.     case LOG_TCP_MISS:
  546.     case LOG_TCP_CLIENT_REFRESH_MISS:
  547. statHistCount(&Counter.client_http.miss_svc_time, svc_time);
  548. break;
  549.     default:
  550. /* make compiler warnings go away */
  551. break;
  552.     }
  553.     H = &http->request->hier;
  554.     switch (H->alg) {
  555.     case PEER_SA_DIGEST:
  556. Counter.cd.times_used++;
  557. break;
  558.     case PEER_SA_ICP:
  559. Counter.icp.times_used++;
  560. i = &H->ping;
  561. if (0 != i->stop.tv_sec && 0 != i->start.tv_sec)
  562.     statHistCount(&Counter.icp.query_svc_time,
  563. tvSubUsec(i->start, i->stop));
  564. if (i->timeout)
  565.     Counter.icp.query_timeouts++;
  566. break;
  567.     case PEER_SA_NETDB:
  568. Counter.netdb.times_used++;
  569. break;
  570.     default:
  571. break;
  572.     }
  573. }
  574. static void
  575. httpRequestFree(void *data)
  576. {
  577.     clientHttpRequest *http = data;
  578.     clientHttpRequest **H;
  579.     ConnStateData *conn = http->conn;
  580.     StoreEntry *entry = http->entry;
  581.     request_t *request = http->request;
  582.     MemObject *mem = NULL;
  583.     debug(33, 3) ("httpRequestFree: %sn", storeUrl(entry));
  584.     if (!clientCheckTransferDone(http)) {
  585. if (entry)
  586.     storeUnregister(entry, http);
  587. entry = http->entry; /* reset, IMS might have changed it */
  588. if (entry && entry->ping_status == PING_WAITING)
  589.     storeReleaseRequest(entry);
  590.     }
  591.     assert(http->log_type < LOG_TYPE_MAX);
  592.     if (entry)
  593. mem = entry->mem_obj;
  594.     if (http->out.size || http->log_type) {
  595. http->al.icp.opcode = ICP_INVALID;
  596. http->al.url = http->log_uri;
  597. debug(33, 9) ("httpRequestFree: al.url='%s'n", http->al.url);
  598. if (mem) {
  599.     http->al.http.code = mem->reply->sline.status;
  600.     http->al.http.content_type = strBuf(mem->reply->content_type);
  601. }
  602. http->al.cache.caddr = conn->log_addr;
  603. http->al.cache.size = http->out.size;
  604. http->al.cache.code = http->log_type;
  605. http->al.cache.msec = tvSubMsec(http->start, current_time);
  606. if (request->user_ident[0])
  607.     http->al.cache.ident = request->user_ident;
  608. else
  609.     http->al.cache.ident = conn->ident;
  610. if (request) {
  611.     Packer p;
  612.     MemBuf mb;
  613.     memBufDefInit(&mb);
  614.     packerToMemInit(&p, &mb);
  615.     httpHeaderPackInto(&request->header, &p);
  616.     http->al.http.method = request->method;
  617.     http->al.http.version = request->http_ver;
  618.     http->al.headers.request = xstrdup(mb.buf);
  619.     http->al.hier = request->hier;
  620.     packerClean(&p);
  621.     memBufClean(&mb);
  622. }
  623. accessLogLog(&http->al);
  624. clientUpdateCounters(http);
  625. clientdbUpdate(conn->peer.sin_addr, http->log_type, PROTO_HTTP, http->out.size);
  626.     }
  627.     if (http->acl_checklist)
  628. aclChecklistFree(http->acl_checklist);
  629.     if (request)
  630. checkFailureRatio(request->err_type, http->al.hier.code);
  631.     safe_free(http->uri);
  632.     safe_free(http->log_uri);
  633.     safe_free(http->al.headers.request);
  634.     safe_free(http->al.headers.reply);
  635.     safe_free(http->redirect.location);
  636.     stringClean(&http->range_iter.boundary);
  637.     if (entry) {
  638. http->entry = NULL;
  639. storeUnregister(entry, http);
  640. storeUnlockObject(entry);
  641.     }
  642.     /* old_entry might still be set if we didn't yet get the reply
  643.      * code in clientHandleIMSReply() */
  644.     if (http->old_entry) {
  645. storeUnregister(http->old_entry, http);
  646. storeUnlockObject(http->old_entry);
  647. http->old_entry = NULL;
  648.     }
  649.     requestUnlink(http->request);
  650.     assert(http != http->next);
  651.     assert(http->conn->chr != NULL);
  652.     H = &http->conn->chr;
  653.     while (*H) {
  654. if (*H == http)
  655.     break;
  656. H = &(*H)->next;
  657.     }
  658.     assert(*H != NULL);
  659.     *H = http->next;
  660.     http->next = NULL;
  661.     dlinkDelete(&http->active, &ClientActiveRequests);
  662.     cbdataFree(http);
  663. }
  664. /* This is a handler normally called by comm_close() */
  665. static void
  666. connStateFree(int fd, void *data)
  667. {
  668.     ConnStateData *connState = data;
  669.     clientHttpRequest *http;
  670.     debug(33, 3) ("connStateFree: FD %dn", fd);
  671.     assert(connState != NULL);
  672.     while ((http = connState->chr) != NULL) {
  673. assert(http->conn == connState);
  674. assert(connState->chr != connState->chr->next);
  675. httpRequestFree(http);
  676.     }
  677.     safe_free(connState->in.buf);
  678.     /* XXX account connState->in.buf */
  679.     pconnHistCount(0, connState->nrequests);
  680.     cbdataFree(connState);
  681. #ifdef _SQUID_LINUX_
  682.     /* prevent those nasty RST packets */
  683.     {
  684. char buf[SQUID_TCP_SO_RCVBUF];
  685. while (read(fd, buf, SQUID_TCP_SO_RCVBUF) > 0);
  686.     }
  687. #endif
  688. }
  689. static void
  690. clientInterpretRequestHeaders(clientHttpRequest * http)
  691. {
  692.     request_t *request = http->request;
  693.     const HttpHeader *req_hdr = &request->header;
  694.     int no_cache = 0;
  695. #if USE_USERAGENT_LOG
  696.     const char *str;
  697. #endif
  698.     request->imslen = -1;
  699.     request->ims = httpHeaderGetTime(req_hdr, HDR_IF_MODIFIED_SINCE);
  700.     if (request->ims > 0)
  701. request->flags.ims = 1;
  702.     if (httpHeaderHas(req_hdr, HDR_PRAGMA)) {
  703. String s = httpHeaderGetList(req_hdr, HDR_PRAGMA);
  704. if (strListIsMember(&s, "no-cache", ','))
  705.     no_cache++;
  706. stringClean(&s);
  707.     }
  708.     if (request->cache_control)
  709. if (EBIT_TEST(request->cache_control->mask, CC_NO_CACHE))
  710.     no_cache++;
  711.     if (no_cache) {
  712. #if HTTP_VIOLATIONS
  713. if (Config.onoff.reload_into_ims)
  714.     request->flags.nocache_hack = 1;
  715. else if (refresh_nocache_hack)
  716.     request->flags.nocache_hack = 1;
  717. else
  718. #endif
  719.     request->flags.nocache = 1;
  720.     }
  721.     /* ignore range header in non-GETs */
  722.     if (request->method == METHOD_GET) {
  723. request->range = httpHeaderGetRange(req_hdr);
  724. if (request->range)
  725.     request->flags.range = 1;
  726.     }
  727.     if (httpHeaderHas(req_hdr, HDR_AUTHORIZATION))
  728. request->flags.auth = 1;
  729.     if (request->login[0] != '')
  730. request->flags.auth = 1;
  731.     if (httpHeaderHas(req_hdr, HDR_VIA)) {
  732. String s = httpHeaderGetList(req_hdr, HDR_VIA);
  733. /*
  734.  * ThisCache cannot be a member of Via header, "1.0 ThisCache" can.
  735.  * Note ThisCache2 has a space prepended to the hostname so we don't
  736.  * accidentally match super-domains.
  737.  */
  738. if (strListIsSubstr(&s, ThisCache2, ',')) {
  739.     debugObj(33, 1, "WARNING: Forwarding loop detected for:n",
  740. request, (ObjPackMethod) & httpRequestPack);
  741.     request->flags.loopdetect = 1;
  742. }
  743. #if FORW_VIA_DB
  744. fvdbCountVia(strBuf(s));
  745. #endif
  746. stringClean(&s);
  747.     }
  748. #if USE_USERAGENT_LOG
  749.     if ((str = httpHeaderGetStr(req_hdr, HDR_USER_AGENT)))
  750. logUserAgent(fqdnFromAddr(http->conn->peer.sin_addr), str);
  751. #endif
  752. #if FORW_VIA_DB
  753.     if (httpHeaderHas(req_hdr, HDR_X_FORWARDED_FOR)) {
  754. String s = httpHeaderGetList(req_hdr, HDR_X_FORWARDED_FOR);
  755. fvdbCountForw(strBuf(s));
  756. stringClean(&s);
  757.     }
  758. #endif
  759.     request->cache_control = httpHeaderGetCc(req_hdr);
  760.     if (request->method == METHOD_TRACE) {
  761. request->max_forwards = httpHeaderGetInt(req_hdr, HDR_MAX_FORWARDS);
  762.     }
  763.     if (clientCachable(http))
  764. request->flags.cachable = 1;
  765.     if (clientHierarchical(http))
  766. request->flags.hierarchical = 1;
  767.     debug(33, 5) ("clientInterpretRequestHeaders: REQ_NOCACHE = %sn",
  768. request->flags.nocache ? "SET" : "NOT SET");
  769.     debug(33, 5) ("clientInterpretRequestHeaders: REQ_CACHABLE = %sn",
  770. request->flags.cachable ? "SET" : "NOT SET");
  771.     debug(33, 5) ("clientInterpretRequestHeaders: REQ_HIERARCHICAL = %sn",
  772. request->flags.hierarchical ? "SET" : "NOT SET");
  773. }
  774. /*
  775.  * clientSetKeepaliveFlag() sets request->flags.proxy_keepalive.
  776.  * This is the client-side persistent connection flag.  We need
  777.  * to set this relatively early in the request processing
  778.  * to handle hacks for broken servers and clients.
  779.  */
  780. static void
  781. clientSetKeepaliveFlag(clientHttpRequest * http)
  782. {
  783.     request_t *request = http->request;
  784.     const HttpHeader *req_hdr = &request->header;
  785.     debug(33, 3) ("clientSetKeepaliveFlag: http_ver = %3.1fn",
  786. request->http_ver);
  787.     debug(33, 3) ("clientSetKeepaliveFlag: method = %sn",
  788. RequestMethodStr[request->method]);
  789.     if (httpMsgIsPersistent(request->http_ver, req_hdr))
  790. request->flags.proxy_keepalive = 1;
  791. }
  792. static int
  793. clientCheckContentLength(request_t * r)
  794. {
  795.     /* We only require a content-length for "upload" methods */
  796.     if (!pumpMethod(r->method))
  797. return 1;
  798.     if (httpHeaderGetInt(&r->header, HDR_CONTENT_LENGTH) < 0)
  799. return 0;
  800.     return 1;
  801. }
  802. static int
  803. clientCachable(clientHttpRequest * http)
  804. {
  805.     const char *url = http->uri;
  806.     request_t *req = http->request;
  807.     method_t method = req->method;
  808.     aclCheck_t ch;
  809.     memset(&ch, '', sizeof(ch));
  810.     /*
  811.      * Hopefully, nobody really wants 'no_cache' by client's IP
  812.      * address, but if they do, this should work if they use IP
  813.      * addresses in their ACLs, or if the client's address is in
  814.      * the FQDN cache.
  815.      *
  816.      * This may not work yet for 'dst' and 'dst_domain' ACLs.
  817.      */
  818.     ch.src_addr = http->conn->peer.sin_addr;
  819.     ch.my_addr = http->conn->me.sin_addr;
  820.     ch.request = http->request;
  821.     /*
  822.      * aclCheckFast returns 1 for ALLOW and 0 for DENY.  The default
  823.      * is ALLOW, so we require 'no_cache DENY foo' in squid.conf
  824.      * to indicate uncachable objects.
  825.      */
  826.     if (!aclCheckFast(Config.accessList.noCache, &ch))
  827. return 0;
  828.     if (req->protocol == PROTO_HTTP)
  829. return httpCachable(method);
  830.     /* FTP is always cachable */
  831.     if (req->protocol == PROTO_GOPHER)
  832. return gopherCachable(url);
  833.     if (req->protocol == PROTO_WAIS)
  834. return 0;
  835.     if (method == METHOD_CONNECT)
  836. return 0;
  837.     if (method == METHOD_TRACE)
  838. return 0;
  839.     if (req->protocol == PROTO_CACHEOBJ)
  840. return 0;
  841.     return 1;
  842. }
  843. /* Return true if we can query our neighbors for this object */
  844. static int
  845. clientHierarchical(clientHttpRequest * http)
  846. {
  847.     const char *url = http->uri;
  848.     request_t *request = http->request;
  849.     method_t method = request->method;
  850.     const wordlist *p = NULL;
  851.     /* IMS needs a private key, so we can use the hierarchy for IMS only
  852.      * if our neighbors support private keys */
  853.     if (request->flags.ims && !neighbors_do_private_keys)
  854. return 0;
  855.     if (request->flags.auth)
  856. return 0;
  857.     if (method == METHOD_TRACE)
  858. return 1;
  859.     if (method != METHOD_GET)
  860. return 0;
  861.     /* scan hierarchy_stoplist */
  862.     for (p = Config.hierarchy_stoplist; p; p = p->next)
  863. if (strstr(url, p->key))
  864.     return 0;
  865.     if (request->flags.loopdetect)
  866. return 0;
  867.     if (request->protocol == PROTO_HTTP)
  868. return httpCachable(method);
  869.     if (request->protocol == PROTO_GOPHER)
  870. return gopherCachable(url);
  871.     if (request->protocol == PROTO_WAIS)
  872. return 0;
  873.     if (request->protocol == PROTO_CACHEOBJ)
  874. return 0;
  875.     return 1;
  876. }
  877. int
  878. isTcpHit(log_type code)
  879. {
  880.     /* this should be a bitmap for better optimization */
  881.     if (code == LOG_TCP_HIT)
  882. return 1;
  883.     if (code == LOG_TCP_IMS_HIT)
  884. return 1;
  885.     if (code == LOG_TCP_REFRESH_FAIL_HIT)
  886. return 1;
  887.     if (code == LOG_TCP_REFRESH_HIT)
  888. return 1;
  889.     if (code == LOG_TCP_NEGATIVE_HIT)
  890. return 1;
  891.     if (code == LOG_TCP_MEM_HIT)
  892. return 1;
  893.     if (code == LOG_TCP_OFFLINE_HIT)
  894. return 1;
  895.     return 0;
  896. }
  897. /*
  898.  * returns true if If-Range specs match reply, false otherwise
  899.  */
  900. static int
  901. clientIfRangeMatch(clientHttpRequest * http, HttpReply * rep)
  902. {
  903.     const TimeOrTag spec = httpHeaderGetTimeOrTag(&http->request->header, HDR_IF_RANGE);
  904.     /* check for parsing falure */
  905.     if (!spec.valid)
  906. return 0;
  907.     /* got an ETag? */
  908.     if (spec.tag.str) {
  909. ETag rep_tag = httpHeaderGetETag(&rep->header, HDR_ETAG);
  910. debug(33, 3) ("clientIfRangeMatch: ETags: %s and %sn",
  911.     spec.tag.str, rep_tag.str ? rep_tag.str : "<none>");
  912. if (!rep_tag.str)
  913.     return 0; /* entity has no etag to compare with! */
  914. if (spec.tag.weak || rep_tag.weak) {
  915.     debug(33, 1) ("clientIfRangeMatch: Weak ETags are not allowed in If-Range: %s ? %sn",
  916. spec.tag.str, rep_tag.str);
  917.     return 0; /* must use strong validator for sub-range requests */
  918. }
  919. return etagIsEqual(&rep_tag, &spec.tag);
  920.     }
  921.     /* got modification time? */
  922.     if (spec.time >= 0) {
  923. return http->entry->lastmod <= spec.time;
  924.     }
  925.     assert(0); /* should not happen */
  926.     return 0;
  927. }
  928. /* adds appropriate Range headers if needed */
  929. static void
  930. clientBuildRangeHeader(clientHttpRequest * http, HttpReply * rep)
  931. {
  932.     HttpHeader *hdr = rep ? &rep->header : 0;
  933.     const char *range_err = NULL;
  934.     assert(http->request->range);
  935.     /* check if we still want to do ranges */
  936.     if (!rep)
  937. range_err = "no [parse-able] reply";
  938.     else if (rep->sline.status != HTTP_OK)
  939. range_err = "wrong status code";
  940.     else if (httpHeaderHas(hdr, HDR_CONTENT_RANGE))
  941. range_err = "origin server does ranges";
  942.     else if (rep->content_length < 0)
  943. range_err = "unknown length";
  944.     else if (rep->content_length != http->entry->mem_obj->reply->content_length)
  945. range_err = "INCONSISTENT length"; /* a bug? */
  946.     else if (httpHeaderHas(&http->request->header, HDR_IF_RANGE) && !clientIfRangeMatch(http, rep))
  947. range_err = "If-Range match failed";
  948.     else if (!httpHdrRangeCanonize(http->request->range, rep->content_length))
  949. range_err = "canonization failed";
  950.     else if (httpHdrRangeIsComplex(http->request->range))
  951. range_err = "too complex range header";
  952.     /* get rid of our range specs on error */
  953.     if (range_err) {
  954. debug(33, 2) ("clientBuildRangeHeader: will not do ranges: %s.n", range_err);
  955. httpHdrRangeDestroy(http->request->range);
  956. http->request->range = NULL;
  957.     } else {
  958. const int spec_count = http->request->range->specs.count;
  959. debug(33, 2) ("clientBuildRangeHeader: range spec count: %d clen: %dn",
  960.     spec_count, rep->content_length);
  961. assert(spec_count > 0);
  962. /* ETags should not be returned with Partial Content replies? */
  963. httpHeaderDelById(hdr, HDR_ETAG);
  964. /* append appropriate header(s) */
  965. if (spec_count == 1) {
  966.     HttpHdrRangePos pos = HttpHdrRangeInitPos;
  967.     const HttpHdrRangeSpec *spec = httpHdrRangeGetSpec(http->request->range, &pos);
  968.     assert(spec);
  969.     /* append Content-Range */
  970.     httpHeaderAddContRange(hdr, *spec, rep->content_length);
  971.     /* set new Content-Length to the actual number of OCTETs
  972.      * transmitted in the message-body */
  973.     httpHeaderDelById(hdr, HDR_CONTENT_LENGTH);
  974.     httpHeaderPutInt(hdr, HDR_CONTENT_LENGTH, spec->length);
  975.     debug(33, 2) ("clientBuildRangeHeader: actual content length: %dn", spec->length);
  976. } else {
  977.     /* multipart! */
  978.     /* generate boundary string */
  979.     http->range_iter.boundary = httpHdrRangeBoundaryStr(http);
  980.     /* delete old Content-Type, add ours */
  981.     httpHeaderDelById(hdr, HDR_CONTENT_TYPE);
  982.     httpHeaderPutStrf(hdr, HDR_CONTENT_TYPE,
  983. "multipart/byteranges; boundary="%s"",
  984. strBuf(http->range_iter.boundary));
  985.     /* no need for Content-Length in multipart responses */
  986.     /* but we must delete the original one if we cannot (yet)
  987.      * calculate the actual length */
  988.     httpHeaderDelById(hdr, HDR_CONTENT_LENGTH);
  989. }
  990.     }
  991. }
  992. /* filters out unwanted entries from original reply header
  993.  * adds extra entries if we have more info than origin server
  994.  * adds Squid specific entries */
  995. static void
  996. clientBuildReplyHeader(clientHttpRequest * http, HttpReply * rep)
  997. {
  998.     HttpHeader *hdr = &rep->header;
  999.     int is_hit = isTcpHit(http->log_type);
  1000.     request_t *request = http->request;
  1001. #if DONT_FILTER_THESE
  1002.     /* but you might want to if you run Squid as an HTTP accelerator */
  1003.     /* httpHeaderDelById(hdr, HDR_ACCEPT_RANGES); */
  1004.     httpHeaderDelById(hdr, HDR_ETAG);
  1005. #endif
  1006.     httpHeaderDelById(hdr, HDR_PROXY_CONNECTION);
  1007.     /* here: Keep-Alive is a field-name, not a connection directive! */
  1008.     httpHeaderDelByName(hdr, "Keep-Alive");
  1009.     /* remove Set-Cookie if a hit */
  1010.     if (is_hit)
  1011. httpHeaderDelById(hdr, HDR_SET_COOKIE);
  1012.     /* handle Connection header */
  1013.     if (httpHeaderHas(hdr, HDR_CONNECTION)) {
  1014. /* anything that matches Connection list member will be deleted */
  1015. String strConnection = httpHeaderGetList(hdr, HDR_CONNECTION);
  1016. const HttpHeaderEntry *e;
  1017. HttpHeaderPos pos = HttpHeaderInitPos;
  1018. /*
  1019.  * think: on-average-best nesting of the two loops (hdrEntry
  1020.  * and strListItem) @?@
  1021.  */
  1022. /*
  1023.  * maybe we should delete standard stuff ("keep-alive","close")
  1024.  * from strConnection first?
  1025.  */
  1026. while ((e = httpHeaderGetEntry(hdr, &pos))) {
  1027.     if (strListIsMember(&strConnection, strBuf(e->name), ','))
  1028. httpHeaderDelAt(hdr, pos);
  1029. }
  1030. httpHeaderDelById(hdr, HDR_CONNECTION);
  1031. stringClean(&strConnection);
  1032.     }
  1033.     /* Handle Ranges */
  1034.     if (request->range)
  1035. clientBuildRangeHeader(http, rep);
  1036.     /*
  1037.      * Add Age header, not that our header must replace Age headers
  1038.      * from other caches if any
  1039.      */
  1040.     if (http->entry->timestamp > 0) {
  1041. httpHeaderDelById(hdr, HDR_AGE);
  1042. /*
  1043.  * we do not follow HTTP/1.1 precisely here becuase we rely
  1044.  * on Date header when computing entry->timestamp; we should
  1045.  * be using _request_ time if Date header is not available
  1046.  * or if it is out of sync
  1047.  */
  1048. httpHeaderPutInt(hdr, HDR_AGE,
  1049.     http->entry->timestamp <= squid_curtime ?
  1050.     squid_curtime - http->entry->timestamp : 0);
  1051.     }
  1052.     /* Append X-Cache */
  1053.     httpHeaderPutStrf(hdr, HDR_X_CACHE, "%s from %s",
  1054. is_hit ? "HIT" : "MISS", getMyHostname());
  1055. #if USE_CACHE_DIGESTS
  1056.     /* Append X-Cache-Lookup: -- temporary hack, to be removed @?@ @?@ */
  1057.     httpHeaderPutStrf(hdr, HDR_X_CACHE_LOOKUP, "%s from %s:%d",
  1058. http->lookup_type ? http->lookup_type : "NONE",
  1059. getMyHostname(), Config.Port.http->i);
  1060. #endif
  1061.     /*
  1062.      * Clear keepalive for NON-HEAD requests with invalid content length
  1063.      */
  1064.     if (request->method != METHOD_HEAD)
  1065. if (http->entry->mem_obj->reply->content_length < 0)
  1066.     request->flags.proxy_keepalive = 0;
  1067.     /* Signal keep-alive if needed */
  1068.     httpHeaderPutStr(hdr,
  1069. http->flags.accel ? HDR_CONNECTION : HDR_PROXY_CONNECTION,
  1070. request->flags.proxy_keepalive ? "keep-alive" : "close");
  1071. #if ADD_X_REQUEST_URI
  1072.     /*
  1073.      * Knowing the URI of the request is useful when debugging persistent
  1074.      * connections in a client; we cannot guarantee the order of http headers,
  1075.      * but X-Request-URI is likely to be the very last header to ease use from a
  1076.      * debugger [hdr->entries.count-1].
  1077.      */
  1078.     httpHeaderPutStr(hdr, HDR_X_REQUEST_URI,
  1079. http->entry->mem_obj->url ? http->entry->mem_obj->url : http->uri);
  1080. #endif
  1081. }
  1082. static HttpReply *
  1083. clientBuildReply(clientHttpRequest * http, const char *buf, size_t size)
  1084. {
  1085.     HttpReply *rep = httpReplyCreate();
  1086.     if (httpReplyParse(rep, buf)) {
  1087. /* enforce 1.0 reply version */
  1088. rep->sline.version = 1.0;
  1089. /* do header conversions */
  1090. clientBuildReplyHeader(http, rep);
  1091. /* if we do ranges, change status to "Partial Content" */
  1092. if (http->request->range)
  1093.     httpStatusLineSet(&rep->sline, rep->sline.version, HTTP_PARTIAL_CONTENT, NULL);
  1094.     } else {
  1095. /* parsing failure, get rid of the invalid reply */
  1096. httpReplyDestroy(rep);
  1097. rep = NULL;
  1098. /* if we were going to do ranges, backoff */
  1099. if (http->request->range)
  1100.     clientBuildRangeHeader(http, rep); /* will fail and destroy request->range */
  1101.     }
  1102.     return rep;
  1103. }
  1104. /*
  1105.  * clientCacheHit should only be called until the HTTP reply headers
  1106.  * have been parsed.  Normally this should be a single call, but
  1107.  * it might take more than one.  As soon as we have the headers,
  1108.  * we hand off to clientSendMoreData, clientProcessExpired, or
  1109.  * clientProcessMiss.
  1110.  */
  1111. static void
  1112. clientCacheHit(void *data, char *buf, ssize_t size)
  1113. {
  1114.     clientHttpRequest *http = data;
  1115.     StoreEntry *e = http->entry;
  1116.     MemObject *mem;
  1117.     request_t *r = http->request;
  1118.     debug(33, 3) ("clientCacheHit: %s, %d bytesn", http->uri, (int) size);
  1119.     if (http->entry == NULL) {
  1120. memFree(buf, MEM_CLIENT_SOCK_BUF);
  1121. debug(33, 3) ("clientCacheHit: request abortedn");
  1122. return;
  1123.     } else if (size < 0) {
  1124. /* swap in failure */
  1125. memFree(buf, MEM_CLIENT_SOCK_BUF);
  1126. debug(33, 3) ("clientCacheHit: swapin failure for %sn", http->uri);
  1127. http->log_type = LOG_TCP_SWAPFAIL_MISS;
  1128. if ((e = http->entry)) {
  1129.     http->entry = NULL;
  1130.     storeUnregister(e, http);
  1131.     storeUnlockObject(e);
  1132. }
  1133. clientProcessMiss(http);
  1134. return;
  1135.     }
  1136.     assert(size > 0);
  1137.     mem = e->mem_obj;
  1138.     assert(!EBIT_TEST(e->flags, ENTRY_ABORTED));
  1139.     if (mem->reply->sline.status == 0) {
  1140. /*
  1141.  * we don't have full reply headers yet; either wait for more or
  1142.  * punt to clientProcessMiss.
  1143.  */
  1144. if (e->mem_status == IN_MEMORY || e->store_status == STORE_OK) {
  1145.     memFree(buf, MEM_CLIENT_SOCK_BUF);
  1146.     clientProcessMiss(http);
  1147. } else if (size == CLIENT_SOCK_SZ && http->out.offset == 0) {
  1148.     memFree(buf, MEM_CLIENT_SOCK_BUF);
  1149.     clientProcessMiss(http);
  1150. } else {
  1151.     debug(33, 3) ("clientCacheHit: waiting for HTTP reply headersn");
  1152.     storeClientCopy(e,
  1153. http->out.offset + size,
  1154. http->out.offset,
  1155. CLIENT_SOCK_SZ,
  1156. buf,
  1157. clientCacheHit,
  1158. http);
  1159. }
  1160. return;
  1161.     }
  1162.     /*
  1163.      * Got the headers, now grok them
  1164.      */
  1165.     assert(http->log_type == LOG_TCP_HIT);
  1166.     if (checkNegativeHit(e)) {
  1167. http->log_type = LOG_TCP_NEGATIVE_HIT;
  1168. clientSendMoreData(data, buf, size);
  1169.     } else if (r->method == METHOD_HEAD) {
  1170. /*
  1171.  * RFC 2068 seems to indicate there is no "conditional HEAD"
  1172.  * request.  We cannot validate a cached object for a HEAD
  1173.  * request, nor can we return 304.
  1174.  */
  1175. if (e->mem_status == IN_MEMORY)
  1176.     http->log_type = LOG_TCP_MEM_HIT;
  1177. clientSendMoreData(data, buf, size);
  1178.     } else if (refreshCheckHTTP(e, r) && !http->flags.internal) {
  1179. debug(33, 5) ("clientCacheHit: in refreshCheck() blockn");
  1180. /*
  1181.  * We hold a stale copy; it needs to be validated
  1182.  */
  1183. /*
  1184.  * The 'need_validation' flag is used to prevent forwarding
  1185.  * loops between siblings.  If our copy of the object is stale,
  1186.  * then we should probably only use parents for the validation
  1187.  * request.  Otherwise two siblings could generate a loop if
  1188.  * both have a stale version of the object.
  1189.  */
  1190. r->flags.need_validation = 1;
  1191. if (e->lastmod < 0) {
  1192.     /*
  1193.      * Previous reply didn't have a Last-Modified header,
  1194.      * we cannot revalidate it.
  1195.      */
  1196.     http->log_type = LOG_TCP_MISS;
  1197.     clientProcessMiss(http);
  1198. } else if (r->flags.nocache) {
  1199.     /*
  1200.      * This did not match a refresh pattern that overrides no-cache
  1201.      * we should honour the client no-cache header.
  1202.      */
  1203.     http->log_type = LOG_TCP_CLIENT_REFRESH_MISS;
  1204.     clientProcessMiss(http);
  1205. } else if (r->protocol == PROTO_HTTP) {
  1206.     /*
  1207.      * Object needs to be revalidated
  1208.      * XXX This could apply to FTP as well, if Last-Modified is known.
  1209.      */
  1210.     http->log_type = LOG_TCP_REFRESH_MISS;
  1211.     clientProcessExpired(http);
  1212. } else {
  1213.     /*
  1214.      * We don't know how to re-validate other protocols. Handle
  1215.      * them as if the object has expired.
  1216.      */
  1217.     http->log_type = LOG_TCP_MISS;
  1218.     clientProcessMiss(http);
  1219. }
  1220. memFree(buf, MEM_CLIENT_SOCK_BUF);
  1221.     } else if (r->flags.ims) {
  1222. /*
  1223.  * Handle If-Modified-Since requests from the client
  1224.  */
  1225. if (mem->reply->sline.status != HTTP_OK) {
  1226.     debug(33, 4) ("clientCacheHit: Reply code %d != 200n",
  1227. mem->reply->sline.status);
  1228.     memFree(buf, MEM_CLIENT_SOCK_BUF);
  1229.     clientProcessMiss(http);
  1230. } else if (modifiedSince(e, http->request)) {
  1231.     http->log_type = LOG_TCP_IMS_HIT;
  1232.     clientSendMoreData(data, buf, size);
  1233. } else {
  1234.     MemBuf mb = httpPacked304Reply(e->mem_obj->reply);
  1235.     http->log_type = LOG_TCP_IMS_HIT;
  1236.     memFree(buf, MEM_CLIENT_SOCK_BUF);
  1237.     storeUnregister(e, http);
  1238.     storeUnlockObject(e);
  1239.     e = clientCreateStoreEntry(http, http->request->method, null_request_flags);
  1240.     http->entry = e;
  1241.     httpReplyParse(e->mem_obj->reply, mb.buf);
  1242.     storeAppend(e, mb.buf, mb.size);
  1243.     memBufClean(&mb);
  1244.     storeComplete(e);
  1245. }
  1246.     } else {
  1247. /*
  1248.  * plain ol' cache hit
  1249.  */
  1250. if (e->mem_status == IN_MEMORY)
  1251.     http->log_type = LOG_TCP_MEM_HIT;
  1252. else if (Config.onoff.offline)
  1253.     http->log_type = LOG_TCP_OFFLINE_HIT;
  1254. clientSendMoreData(data, buf, size);
  1255.     }
  1256. }
  1257. /* extracts a "range" from *buf and appends them to mb, updating all offsets and such */
  1258. static void
  1259. clientPackRange(clientHttpRequest * http, HttpHdrRangeIter * i, const char **buf, ssize_t * size, MemBuf * mb)
  1260. {
  1261.     const size_t copy_sz = i->debt_size <= *size ? i->debt_size : *size;
  1262.     off_t body_off = http->out.offset - i->prefix_size;
  1263.     assert(*size > 0);
  1264.     assert(i->spec);
  1265.     /* intersection of "have" and "need" ranges must not be empty */
  1266.     assert(body_off < i->spec->offset + i->spec->length);
  1267.     assert(body_off + *size > i->spec->offset);
  1268.     /* put boundary and headers at the beginning of range in a multi-range */
  1269.     if (http->request->range->specs.count > 1 && i->debt_size == i->spec->length) {
  1270. HttpReply *rep = http->entry->mem_obj ? /* original reply */
  1271. http->entry->mem_obj->reply : NULL;
  1272. HttpHeader hdr;
  1273. Packer p;
  1274. assert(rep);
  1275. /* put boundary */
  1276. debug(33, 5) ("clientPackRange: appending boundary: %sn", strBuf(i->boundary));
  1277. /* rfc2046 requires to _prepend_ boundary with <crlf>! */
  1278. memBufPrintf(mb, "rn--%srn", strBuf(i->boundary));
  1279. httpHeaderInit(&hdr, hoReply);
  1280. if (httpHeaderHas(&rep->header, HDR_CONTENT_TYPE))
  1281.     httpHeaderPutStr(&hdr, HDR_CONTENT_TYPE, httpHeaderGetStr(&rep->header, HDR_CONTENT_TYPE));
  1282. httpHeaderAddContRange(&hdr, *i->spec, rep->content_length);
  1283. packerToMemInit(&p, mb);
  1284. httpHeaderPackInto(&hdr, &p);
  1285. packerClean(&p);
  1286. httpHeaderClean(&hdr);
  1287. /* append <crlf> (we packed a header, not a reply */
  1288. memBufPrintf(mb, crlf);
  1289.     }
  1290.     /* append */
  1291.     debug(33, 3) ("clientPackRange: appending %d bytesn", copy_sz);
  1292.     memBufAppend(mb, *buf, copy_sz);
  1293.     /* update offsets */
  1294.     *size -= copy_sz;
  1295.     i->debt_size -= copy_sz;
  1296.     body_off += copy_sz;
  1297.     *buf += copy_sz;
  1298.     http->out.offset = body_off + i->prefix_size; /* sync */
  1299.     /* paranoid check */
  1300.     assert(*size >= 0 && i->debt_size >= 0);
  1301. }
  1302. /* returns true if there is still data available to pack more ranges
  1303.  * increments iterator "i"
  1304.  * used by clientPackMoreRanges */
  1305. static int
  1306. clientCanPackMoreRanges(const clientHttpRequest * http, HttpHdrRangeIter * i, ssize_t size)
  1307. {
  1308.     /* first update "i" if needed */
  1309.     if (!i->debt_size) {
  1310. if ((i->spec = httpHdrRangeGetSpec(http->request->range, &i->pos)))
  1311.     i->debt_size = i->spec->length;
  1312.     }
  1313.     assert(!i->debt_size == !i->spec); /* paranoid sync condition */
  1314.     /* continue condition: need_more_data && have_more_data */
  1315.     return i->spec && size > 0;
  1316. }
  1317. /* extracts "ranges" from buf and appends them to mb, updating all offsets and such */
  1318. /* returns true if we need more data */
  1319. static int
  1320. clientPackMoreRanges(clientHttpRequest * http, const char *buf, ssize_t size, MemBuf * mb)
  1321. {
  1322.     HttpHdrRangeIter *i = &http->range_iter;
  1323.     /* offset in range specs does not count the prefix of an http msg */
  1324.     off_t body_off = http->out.offset - i->prefix_size;
  1325.     assert(size >= 0);
  1326.     /* check: reply was parsed and range iterator was initialized */
  1327.     assert(i->prefix_size > 0);
  1328.     /* filter out data according to range specs */
  1329.     while (clientCanPackMoreRanges(http, i, size)) {
  1330. off_t start; /* offset of still missing data */
  1331. assert(i->spec);
  1332. start = i->spec->offset + i->spec->length - i->debt_size;
  1333. debug(33, 2) ("clientPackMoreRanges: in:  offset: %d size: %dn",
  1334.     (int) body_off, size);
  1335. debug(33, 2) ("clientPackMoreRanges: out: start: %d spec[%d]: [%d, %d), len: %d debt: %dn",
  1336.     (int) start, (int) i->pos, i->spec->offset, (int) (i->spec->offset + i->spec->length), i->spec->length, i->debt_size);
  1337. assert(body_off <= start); /* we did not miss it */
  1338. /* skip up to start */
  1339. if (body_off + size > start) {
  1340.     const size_t skip_size = start - body_off;
  1341.     body_off = start;
  1342.     size -= skip_size;
  1343.     buf += skip_size;
  1344. } else {
  1345.     /* has not reached start yet */
  1346.     body_off += size;
  1347.     size = 0;
  1348.     buf = NULL;
  1349. }
  1350. /* put next chunk if any */
  1351. if (size) {
  1352.     http->out.offset = body_off + i->prefix_size; /* sync */
  1353.     clientPackRange(http, i, &buf, &size, mb);
  1354.     body_off = http->out.offset - i->prefix_size; /* sync */
  1355. }
  1356.     }
  1357.     assert(!i->debt_size == !i->spec); /* paranoid sync condition */
  1358.     debug(33, 2) ("clientPackMoreRanges: buf exhausted: in:  offset: %d size: %d need_more: %dn",
  1359. (int) body_off, size, i->debt_size);
  1360.     if (i->debt_size) {
  1361. debug(33, 2) ("clientPackMoreRanges: need more: spec[%d]: [%d, %d), len: %dn",
  1362.     (int) i->pos, i->spec->offset, (int) (i->spec->offset + i->spec->length), i->spec->length);
  1363. /* skip the data we do not need if possible */
  1364. if (i->debt_size == i->spec->length) /* at the start of the cur. spec */
  1365.     body_off = i->spec->offset;
  1366. else
  1367.     assert(body_off == i->spec->offset + i->spec->length - i->debt_size);
  1368.     } else if (http->request->range->specs.count > 1) {
  1369. /* put terminating boundary for multiparts */
  1370. memBufPrintf(mb, "rn--%s--rn", strBuf(i->boundary));
  1371.     }
  1372.     http->out.offset = body_off + i->prefix_size; /* sync */
  1373.     return i->debt_size > 0;
  1374. }
  1375. /*
  1376.  * accepts chunk of a http message in buf, parses prefix, filters headers and
  1377.  * such, writes processed message to the client's socket
  1378.  */
  1379. static void
  1380. clientSendMoreData(void *data, char *buf, ssize_t size)
  1381. {
  1382.     clientHttpRequest *http = data;
  1383.     StoreEntry *entry = http->entry;
  1384.     ConnStateData *conn = http->conn;
  1385.     int fd = conn->fd;
  1386.     HttpReply *rep = NULL;
  1387.     const char *body_buf = buf;
  1388.     ssize_t body_size = size;
  1389.     MemBuf mb;
  1390.     ssize_t check_size = 0;
  1391.     debug(33, 5) ("clientSendMoreData: %s, %d bytesn", http->uri, (int) size);
  1392.     assert(size <= CLIENT_SOCK_SZ);
  1393.     assert(http->request != NULL);
  1394.     dlinkDelete(&http->active, &ClientActiveRequests);
  1395.     dlinkAdd(http, &http->active, &ClientActiveRequests);
  1396.     debug(33, 5) ("clientSendMoreData: FD %d '%s', out.offset=%d n",
  1397. fd, storeUrl(entry), (int) http->out.offset);
  1398.     if (conn->chr != http) {
  1399. /* there is another object in progress, defer this one */
  1400. debug(33, 1) ("clientSendMoreData: Deferring %sn", storeUrl(entry));
  1401. memFree(buf, MEM_CLIENT_SOCK_BUF);
  1402. return;
  1403.     } else if (entry && EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
  1404. /* call clientWriteComplete so the client socket gets closed */
  1405. clientWriteComplete(fd, NULL, 0, COMM_OK, http);
  1406. memFree(buf, MEM_CLIENT_SOCK_BUF);
  1407. return;
  1408.     } else if (size < 0) {
  1409. /* call clientWriteComplete so the client socket gets closed */
  1410. clientWriteComplete(fd, NULL, 0, COMM_OK, http);
  1411. memFree(buf, MEM_CLIENT_SOCK_BUF);
  1412. return;
  1413.     } else if (size == 0) {
  1414. /* call clientWriteComplete so the client socket gets closed */
  1415. clientWriteComplete(fd, NULL, 0, COMM_OK, http);
  1416. memFree(buf, MEM_CLIENT_SOCK_BUF);
  1417. return;
  1418.     }
  1419.     if (http->out.offset == 0) {
  1420. if (Config.onoff.log_mime_hdrs) {
  1421.     size_t k;
  1422.     if ((k = headersEnd(buf, size))) {
  1423. safe_free(http->al.headers.reply);
  1424. http->al.headers.reply = xcalloc(k + 1, 1);
  1425. xstrncpy(http->al.headers.reply, buf, k);
  1426.     }
  1427. }
  1428. rep = clientBuildReply(http, buf, size);
  1429. if (rep) {
  1430.     body_size = size - rep->hdr_sz;
  1431.     assert(body_size >= 0);
  1432.     body_buf = buf + rep->hdr_sz;
  1433.     http->range_iter.prefix_size = rep->hdr_sz;
  1434.     debug(33, 3) ("clientSendMoreData: Appending %d bytes after %d bytes of headersn",
  1435. body_size, rep->hdr_sz);
  1436. } else if (size < CLIENT_SOCK_SZ && entry->store_status == STORE_PENDING) {
  1437.     /* wait for more to arrive */
  1438.     storeClientCopy(entry,
  1439. http->out.offset + size,
  1440. http->out.offset,
  1441. CLIENT_SOCK_SZ,
  1442. buf,
  1443. clientSendMoreData,
  1444. http);
  1445.     return;
  1446. }
  1447. /* reset range iterator */
  1448. http->range_iter.pos = HttpHdrRangeInitPos;
  1449.     }
  1450.     if (http->request->method == METHOD_HEAD) {
  1451. if (rep) {
  1452.     /* do not forward body for HEAD replies */
  1453.     body_size = 0;
  1454.     http->flags.done_copying = 1;
  1455. } else {
  1456.     /*
  1457.      * If we are here, then store_status == STORE_OK and it
  1458.      * seems we have a HEAD repsponse which is missing the
  1459.      * empty end-of-headers line (home.mira.net, phttpd/0.99.72
  1460.      * does this).  Because clientBuildReply() fails we just
  1461.      * call this reply a body, set the done_copying flag and
  1462.      * continue...
  1463.      */
  1464.     http->flags.done_copying = 1;
  1465. }
  1466.     }
  1467.     /* write headers and/or body if any */
  1468.     assert(rep || (body_buf && body_size));
  1469.     /* init mb; put status line and headers if any */
  1470.     if (rep) {
  1471. mb = httpReplyPack(rep);
  1472. http->out.offset += rep->hdr_sz;
  1473. check_size += rep->hdr_sz;
  1474. httpReplyDestroy(rep);
  1475. rep = NULL;
  1476.     } else {
  1477. memBufDefInit(&mb);
  1478.     }
  1479.     /* append body if any */
  1480.     if (http->request->range) {
  1481. /* Only GET requests should have ranges */
  1482. assert(http->request->method == METHOD_GET);
  1483. /* clientPackMoreRanges() updates http->out.offset */
  1484. /* force the end of the transfer if we are done */
  1485. if (!clientPackMoreRanges(http, body_buf, body_size, &mb))
  1486.     http->flags.done_copying = 1;
  1487.     } else if (body_buf && body_size) {
  1488. http->out.offset += body_size;
  1489. check_size += body_size;
  1490. memBufAppend(&mb, body_buf, body_size);
  1491.     }
  1492.     if (!http->request->range && http->request->method == METHOD_GET)
  1493. assert(check_size == size);
  1494.     /* write */
  1495.     comm_write_mbuf(fd, mb, clientWriteComplete, http);
  1496.     /* if we don't do it, who will? */
  1497.     memFree(buf, MEM_CLIENT_SOCK_BUF);
  1498. }
  1499. static void
  1500. clientKeepaliveNextRequest(clientHttpRequest * http)
  1501. {
  1502.     ConnStateData *conn = http->conn;
  1503.     StoreEntry *entry;
  1504.     debug(33, 3) ("clientKeepaliveNextRequest: FD %dn", conn->fd);
  1505.     conn->defer.until = 0; /* Kick it to read a new request */
  1506.     httpRequestFree(http);
  1507.     if ((http = conn->chr) == NULL) {
  1508. debug(33, 5) ("clientKeepaliveNextRequest: FD %d reading next reqn",
  1509.     conn->fd);
  1510. fd_note(conn->fd, "Reading next request");
  1511. /*
  1512.  * Set the timeout BEFORE calling clientReadRequest().
  1513.  */
  1514. commSetTimeout(conn->fd, 15, requestTimeout, conn);
  1515. clientReadRequest(conn->fd, conn); /* Read next request */
  1516. /*
  1517.  * Note, the FD may be closed at this point.
  1518.  */
  1519.     } else if ((entry = http->entry) == NULL) {
  1520. /*
  1521.  * this request is in progress, maybe doing an ACL or a redirect,
  1522.  * execution will resume after the operation completes.
  1523.  */
  1524.     } else {
  1525. debug(33, 1) ("clientKeepaliveNextRequest: FD %d Sending nextn",
  1526.     conn->fd);
  1527. assert(entry);
  1528. if (0 == storeClientCopyPending(entry, http)) {
  1529.     if (EBIT_TEST(entry->flags, ENTRY_ABORTED))
  1530. debug(33, 0) ("clientKeepaliveNextRequest: ENTRY_ABORTEDn");
  1531.     storeClientCopy(entry,
  1532. http->out.offset,
  1533. http->out.offset,
  1534. CLIENT_SOCK_SZ,
  1535. memAllocate(MEM_CLIENT_SOCK_BUF),
  1536. clientSendMoreData,
  1537. http);
  1538. }
  1539.     }
  1540. }
  1541. static void
  1542. clientWriteComplete(int fd, char *bufnotused, size_t size, int errflag, void *data)
  1543. {
  1544.     clientHttpRequest *http = data;
  1545.     StoreEntry *entry = http->entry;
  1546.     int done;
  1547.     http->out.size += size;
  1548.     debug(33, 5) ("clientWriteComplete: FD %d, sz %d, err %d, off %d, len %dn",
  1549. fd, size, errflag, (int) http->out.offset, entry ? objectLen(entry) : 0);
  1550.     if (size > 0) {
  1551. kb_incr(&Counter.client_http.kbytes_out, size);
  1552. if (isTcpHit(http->log_type))
  1553.     kb_incr(&Counter.client_http.hit_kbytes_out, size);
  1554.     }
  1555.     if (errflag) {
  1556. /*
  1557.  * just close the socket, httpRequestFree will abort if needed
  1558.  */
  1559. comm_close(fd);
  1560.     } else if (NULL == entry) {
  1561. comm_close(fd); /* yuk */
  1562.     } else if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
  1563. comm_close(fd);
  1564.     } else if ((done = clientCheckTransferDone(http)) != 0 || size == 0) {
  1565. debug(33, 5) ("clientWriteComplete: FD %d transfer is DONEn", fd);
  1566. /* We're finished case */
  1567. if (http->entry->mem_obj->reply->content_length < 0) {
  1568.     debug(33, 5) ("clientWriteComplete: closing, content_length < 0n");
  1569.     comm_close(fd);
  1570. } else if (!done) {
  1571.     debug(33, 5) ("clientWriteComplete: closing, !donen");
  1572.     comm_close(fd);
  1573. } else if (clientGotNotEnough(http)) {
  1574.     debug(33, 5) ("clientWriteComplete: client didn't get all it expectedn");
  1575.     comm_close(fd);
  1576. } else if (http->request->flags.proxy_keepalive) {
  1577.     debug(33, 5) ("clientWriteComplete: FD %d Keeping Aliven", fd);
  1578.     clientKeepaliveNextRequest(http);
  1579. } else {
  1580.     comm_close(fd);
  1581. }
  1582.     } else {
  1583. /* More data will be coming from primary server; register with 
  1584.  * storage manager. */
  1585. if (EBIT_TEST(entry->flags, ENTRY_ABORTED))
  1586.     debug(33, 0) ("clientWriteComplete 2: ENTRY_ABORTEDn");
  1587. storeClientCopy(entry,
  1588.     http->out.offset,
  1589.     http->out.offset,
  1590.     CLIENT_SOCK_SZ,
  1591.     memAllocate(MEM_CLIENT_SOCK_BUF),
  1592.     clientSendMoreData,
  1593.     http);
  1594.     }
  1595. }
  1596. /*
  1597.  * client issued a request with an only-if-cached cache-control directive;
  1598.  * we did not find a cached object that can be returned without
  1599.  *     contacting other servers;
  1600.  * respond with a 504 (Gateway Timeout) as suggested in [RFC 2068]
  1601.  */
  1602. static void
  1603. clientProcessOnlyIfCachedMiss(clientHttpRequest * http)
  1604. {
  1605.     char *url = http->uri;
  1606.     request_t *r = http->request;
  1607.     ErrorState *err = NULL;
  1608.     debug(33, 4) ("clientProcessOnlyIfCachedMiss: '%s %s'n",
  1609. RequestMethodStr[r->method], url);
  1610.     http->al.http.code = HTTP_GATEWAY_TIMEOUT;
  1611.     err = errorCon(ERR_ONLY_IF_CACHED_MISS, HTTP_GATEWAY_TIMEOUT);
  1612.     err->request = requestLink(r);
  1613.     err->src_addr = http->conn->peer.sin_addr;
  1614.     if (http->entry) {
  1615. storeUnregister(http->entry, http);
  1616. storeUnlockObject(http->entry);
  1617.     }
  1618.     http->entry = clientCreateStoreEntry(http, r->method, null_request_flags);
  1619.     errorAppendEntry(http->entry, err);
  1620. }
  1621. static log_type
  1622. clientProcessRequest2(clientHttpRequest * http)
  1623. {
  1624.     request_t *r = http->request;
  1625.     StoreEntry *e;
  1626.     e = http->entry = storeGetPublic(http->uri, r->method);
  1627.     if (r->method == METHOD_HEAD && e == NULL) {
  1628. /* We can generate a HEAD reply from a cached GET object */
  1629. e = http->entry = storeGetPublic(http->uri, METHOD_GET);
  1630.     }
  1631. #if USE_CACHE_DIGESTS
  1632.     http->lookup_type = e ? "HIT" : "MISS";
  1633. #endif
  1634.     if (NULL == e) {
  1635. /* this object isn't in the cache */
  1636. debug(33, 3) ("clientProcessRequest2: storeGet() MISSn");
  1637. return LOG_TCP_MISS;
  1638.     }
  1639.     if (Config.onoff.offline) {
  1640. debug(33, 3) ("clientProcessRequest2: offline HITn");
  1641. http->entry = e;
  1642. return LOG_TCP_HIT;
  1643.     }
  1644.     if (!storeEntryValidToSend(e)) {
  1645. debug(33, 3) ("clientProcessRequest2: !storeEntryValidToSend MISSn");
  1646. http->entry = NULL;
  1647. return LOG_TCP_MISS;
  1648.     }
  1649.     if (EBIT_TEST(e->flags, ENTRY_SPECIAL)) {
  1650. /* Special entries are always hits, no matter what the client says */
  1651. debug(33, 3) ("clientProcessRequest2: ENTRY_SPECIAL HITn");
  1652. http->entry = e;
  1653. return LOG_TCP_HIT;
  1654.     }
  1655. #if HTTP_VIOLATIONS
  1656.     if (r->flags.nocache_hack) {
  1657. /* if nocache_hack is set, nocache should always be clear, right? */
  1658. assert(!r->flags.nocache);
  1659. ipcacheReleaseInvalid(r->host);
  1660. /* continue! */
  1661.     }
  1662.     if (e->store_status == STORE_PENDING) {
  1663. if (r->flags.nocache || r->flags.nocache_hack) {
  1664.     debug(33, 3) ("Clearing no-cache for STORE_PENDING requestnt%sn",
  1665. storeUrl(e));
  1666.     r->flags.nocache = 0;
  1667.     r->flags.nocache_hack = 0;
  1668. }
  1669.     }
  1670. #endif
  1671.     if (r->flags.nocache) {
  1672. debug(33, 3) ("clientProcessRequest2: no-cache REFRESH MISSn");
  1673. http->entry = NULL;
  1674. ipcacheReleaseInvalid(r->host);
  1675. return LOG_TCP_CLIENT_REFRESH_MISS;
  1676.     }
  1677.     if (r->range && httpHdrRangeWillBeComplex(r->range)) {
  1678. /*
  1679.  * Some clients break if we return "200 OK" for a Range
  1680.  * request.  We would have to return "200 OK" for a _complex_
  1681.  * Range request that is also a HIT. Thus, let's prevent HITs
  1682.  * on complex Range requests
  1683.  */
  1684. debug(33, 3) ("clientProcessRequest2: complex range MISSn");
  1685. http->entry = NULL;
  1686. return LOG_TCP_MISS;
  1687.     }
  1688.     debug(33, 3) ("clientProcessRequest2: default HITn");
  1689.     http->entry = e;
  1690.     return LOG_TCP_HIT;
  1691. }
  1692. static void
  1693. clientProcessRequest(clientHttpRequest * http)
  1694. {
  1695.     char *url = http->uri;
  1696.     request_t *r = http->request;
  1697.     int fd = http->conn->fd;
  1698.     HttpReply *rep;
  1699.     debug(33, 4) ("clientProcessRequest: %s '%s'n",
  1700. RequestMethodStr[r->method],
  1701. url);
  1702.     if (r->method == METHOD_CONNECT) {
  1703. http->log_type = LOG_TCP_MISS;
  1704. sslStart(fd, url, r, &http->out.size);
  1705. return;
  1706.     } else if (r->method == METHOD_PURGE) {
  1707. clientPurgeRequest(http);
  1708. return;
  1709.     } else if (r->method == METHOD_TRACE) {
  1710. if (r->max_forwards == 0) {
  1711.     http->entry = clientCreateStoreEntry(http, r->method, null_request_flags);
  1712.     storeReleaseRequest(http->entry);
  1713.     storeBuffer(http->entry);
  1714.     rep = httpReplyCreate();
  1715.     httpReplySetHeaders(rep, 1.0, HTTP_OK, NULL, "text/plain",
  1716. httpRequestPrefixLen(r), 0, squid_curtime);
  1717.     httpReplySwapOut(rep, http->entry);
  1718.     httpReplyDestroy(rep);
  1719.     httpRequestSwapOut(r, http->entry);
  1720.     storeComplete(http->entry);
  1721.     return;
  1722. }
  1723. /* yes, continue */
  1724. http->log_type = LOG_TCP_MISS;
  1725.     } else if (pumpMethod(r->method)) {
  1726. http->log_type = LOG_TCP_MISS;
  1727. /* XXX oof, POST can be cached! */
  1728. pumpInit(fd, r, http->uri);
  1729.     } else {
  1730. http->log_type = clientProcessRequest2(http);
  1731.     }
  1732.     debug(33, 4) ("clientProcessRequest: %s for '%s'n",
  1733. log_tags[http->log_type],
  1734. http->uri);
  1735.     http->out.offset = 0;
  1736.     if (NULL != http->entry) {
  1737. storeLockObject(http->entry);
  1738. storeCreateMemObject(http->entry, http->uri, http->log_uri);
  1739. storeClientListAdd(http->entry, http);
  1740. #if DELAY_POOLS
  1741. delaySetStoreClient(http->entry, http, delayClient(r));
  1742. #endif
  1743. http->entry->refcount++;
  1744. storeClientCopy(http->entry,
  1745.     http->out.offset,
  1746.     http->out.offset,
  1747.     CLIENT_SOCK_SZ,
  1748.     memAllocate(MEM_CLIENT_SOCK_BUF),
  1749.     clientCacheHit,
  1750.     http);
  1751.     } else {
  1752. /* MISS CASE */
  1753. http->log_type = LOG_TCP_MISS;
  1754. clientProcessMiss(http);
  1755.     }
  1756. }
  1757. /*
  1758.  * Prepare to fetch the object as it's a cache miss of some kind.
  1759.  */
  1760. static void
  1761. clientProcessMiss(clientHttpRequest * http)
  1762. {
  1763.     char *url = http->uri;
  1764.     request_t *r = http->request;
  1765.     ErrorState *err = NULL;
  1766.     debug(33, 4) ("clientProcessMiss: '%s %s'n",
  1767. RequestMethodStr[r->method], url);
  1768.     /*
  1769.      * We might have a left-over StoreEntry from a failed cache hit
  1770.      * or IMS request.
  1771.      */
  1772.     if (http->entry) {
  1773. if (EBIT_TEST(http->entry->flags, ENTRY_SPECIAL))
  1774.     debug(33, 0) ("clientProcessMiss: miss on a special object (%s).n", url);
  1775. storeUnregister(http->entry, http);
  1776. storeUnlockObject(http->entry);
  1777. http->entry = NULL;
  1778.     }
  1779.     if (clientOnlyIfCached(http)) {
  1780. clientProcessOnlyIfCachedMiss(http);
  1781. return;
  1782.     }
  1783.     /*
  1784.      * Deny loops when running in accelerator/transproxy mode.
  1785.      */
  1786.     if (http->flags.accel && r->flags.loopdetect) {
  1787. http->al.http.code = HTTP_FORBIDDEN;
  1788. err = errorCon(ERR_ACCESS_DENIED, HTTP_FORBIDDEN);
  1789. err->request = requestLink(r);
  1790. err->src_addr = http->conn->peer.sin_addr;
  1791. http->entry = clientCreateStoreEntry(http, r->method, null_request_flags);
  1792. errorAppendEntry(http->entry, err);
  1793. return;
  1794.     }
  1795.     assert(http->out.offset == 0);
  1796.     http->entry = clientCreateStoreEntry(http, r->method, r->flags);
  1797.     http->entry->refcount++;
  1798.     if (http->redirect.status) {
  1799. HttpReply *rep = httpReplyCreate();
  1800. storeReleaseRequest(http->entry);
  1801. httpRedirectReply(rep, http->redirect.status, http->redirect.location);
  1802. httpReplySwapOut(rep, http->entry);
  1803. httpReplyDestroy(rep);
  1804. storeComplete(http->entry);
  1805. return;
  1806.     }
  1807.     if (http->flags.internal)
  1808. r->protocol = PROTO_INTERNAL;
  1809.     fwdStart(http->conn->fd, http->entry, r,
  1810. http->conn->peer.sin_addr, http->conn->me.sin_addr);
  1811. }
  1812. static clientHttpRequest *
  1813. parseHttpRequestAbort(ConnStateData * conn, const char *uri)
  1814. {
  1815.     clientHttpRequest *http = xcalloc(1, sizeof(clientHttpRequest));
  1816.     cbdataAdd(http, cbdataXfree, 0);
  1817.     http->conn = conn;
  1818.     http->start = current_time;
  1819.     http->req_sz = conn->in.offset;
  1820.     http->uri = xstrdup(uri);
  1821.     http->log_uri = xstrndup(uri, MAX_URL);
  1822.     http->range_iter.boundary = StringNull;
  1823.     dlinkAdd(http, &http->active, &ClientActiveRequests);
  1824.     return http;
  1825. }
  1826. /*
  1827.  *  parseHttpRequest()
  1828.  * 
  1829.  *  Returns
  1830.  *   NULL on error or incomplete request
  1831.  *    a clientHttpRequest structure on success
  1832.  */
  1833. static clientHttpRequest *
  1834. parseHttpRequest(ConnStateData * conn, method_t * method_p, int *status,
  1835.     char **prefix_p, size_t * req_line_sz_p)
  1836. {
  1837.     char *inbuf = NULL;
  1838.     char *mstr = NULL;
  1839.     char *url = NULL;
  1840.     char *req_hdr = NULL;
  1841.     float http_ver;
  1842.     char *token = NULL;
  1843.     char *t = NULL;
  1844.     char *end;
  1845.     int free_request = 0;
  1846.     size_t header_sz; /* size of headers, not including first line */
  1847.     size_t prefix_sz; /* size of whole request (req-line + headers) */
  1848.     size_t url_sz;
  1849.     size_t req_sz;
  1850.     method_t method;
  1851.     clientHttpRequest *http = NULL;
  1852. #if IPF_TRANSPARENT
  1853.     struct natlookup natLookup;
  1854.     static int natfd = -1;
  1855. #endif
  1856.     if ((req_sz = headersEnd(conn->in.buf, conn->in.offset)) == 0) {
  1857. debug(33, 5) ("Incomplete request, waiting for end of headersn");
  1858. *status = 0;
  1859. *prefix_p = NULL;
  1860. *method_p = METHOD_NONE;
  1861. return NULL;
  1862.     }
  1863.     assert(req_sz <= conn->in.offset);
  1864.     /* Use memcpy, not strdup! */
  1865.     inbuf = xmalloc(req_sz + 1);
  1866.     xmemcpy(inbuf, conn->in.buf, req_sz);
  1867.     *(inbuf + req_sz) = '';
  1868.     /* pre-set these values to make aborting simpler */
  1869.     *prefix_p = inbuf;
  1870.     *method_p = METHOD_NONE;
  1871.     *status = -1;
  1872.     /* Barf on NULL characters in the headers */
  1873.     if (strlen(inbuf) != req_sz) {
  1874. debug(33, 1) ("parseHttpRequest: Requestheader contains NULL charactersn");
  1875. return parseHttpRequestAbort(conn, "error:invalid-request");
  1876.     }
  1877.     /* Look for request method */
  1878.     if ((mstr = strtok(inbuf, "t ")) == NULL) {
  1879. debug(33, 1) ("parseHttpRequest: Can't get request methodn");
  1880. return parseHttpRequestAbort(conn, "error:invalid-request-method");
  1881.     }
  1882.     method = urlParseMethod(mstr);
  1883.     if (method == METHOD_NONE) {
  1884. debug(33, 1) ("parseHttpRequest: Unsupported method '%s'n", mstr);
  1885. return parseHttpRequestAbort(conn, "error:unsupported-request-method");
  1886.     }
  1887.     debug(33, 5) ("parseHttpRequest: Method is '%s'n", mstr);
  1888.     *method_p = method;
  1889.     /* look for URL+HTTP/x.x */
  1890.     if ((url = strtok(NULL, "n")) == NULL) {
  1891. debug(33, 1) ("parseHttpRequest: Missing URLn");
  1892. return parseHttpRequestAbort(conn, "error:missing-url");
  1893.     }
  1894.     while (xisspace(*url))
  1895. url++;
  1896.     t = url + strlen(url);
  1897.     assert(*t == '');
  1898.     token = NULL;
  1899.     while (t > url) {
  1900. t--;
  1901. if (xisspace(*t) && !strncmp(t + 1, "HTTP/", 5)) {
  1902.     token = t + 1;
  1903.     break;
  1904. }
  1905.     }
  1906.     while (t > url && xisspace(*t))
  1907. *(t--) = '';
  1908.     debug(33, 5) ("parseHttpRequest: URI is '%s'n", url);
  1909.     if (token == NULL) {
  1910. debug(33, 3) ("parseHttpRequest: Missing HTTP identifiern");
  1911. #if RELAXED_HTTP_PARSER
  1912. http_ver = (float) 0.9; /* wild guess */
  1913. #else
  1914. return parseHttpRequestAbort(conn, "error:missing-http-ident");
  1915. #endif
  1916.     } else {
  1917. http_ver = (float) atof(token + 5);
  1918.     }
  1919.     /*
  1920.      * Process headers after request line
  1921.      */
  1922.     req_hdr = strtok(NULL, null_string);
  1923.     header_sz = req_sz - (req_hdr - inbuf);
  1924.     if (0 == header_sz) {
  1925. debug(33, 3) ("parseHttpRequest: header_sz == 0n");
  1926. *status = 0;
  1927. return NULL;
  1928.     }
  1929.     assert(header_sz > 0);
  1930.     debug(33, 3) ("parseHttpRequest: req_hdr = {%s}n", req_hdr);
  1931.     end = req_hdr + header_sz;
  1932.     debug(33, 3) ("parseHttpRequest: end = {%s}n", end);
  1933.     prefix_sz = end - inbuf;
  1934.     *req_line_sz_p = req_hdr - inbuf;
  1935.     debug(33, 3) ("parseHttpRequest: prefix_sz = %d, req_line_sz = %dn",
  1936. (int) prefix_sz, (int) *req_line_sz_p);
  1937.     assert(prefix_sz <= conn->in.offset);
  1938.     /* Ok, all headers are received */
  1939.     http = xcalloc(1, sizeof(clientHttpRequest));
  1940.     cbdataAdd(http, cbdataXfree, 0);
  1941.     http->http_ver = http_ver;
  1942.     http->conn = conn;
  1943.     http->start = current_time;
  1944.     http->req_sz = prefix_sz;
  1945.     http->range_iter.boundary = StringNull;
  1946.     *prefix_p = xmalloc(prefix_sz + 1);
  1947.     xmemcpy(*prefix_p, conn->in.buf, prefix_sz);
  1948.     *(*prefix_p + prefix_sz) = '';
  1949.     dlinkAdd(http, &http->active, &ClientActiveRequests);
  1950.     debug(33, 5) ("parseHttpRequest: Request Header isn%sn", (*prefix_p) + *req_line_sz_p);
  1951.     if ((t = strchr(url, '#'))) /* remove HTML anchors */
  1952. *t = '';
  1953.     /* handle internal objects */
  1954.     if (internalCheck(url)) {
  1955. /* prepend our name & port */
  1956. http->uri = xstrdup(internalLocalUri(NULL, url));
  1957. http->flags.internal = 1;
  1958. http->flags.accel = 1;
  1959.     }
  1960.     /* see if we running in Config2.Accel.on, if so got to convert it to URL */
  1961.     else if (Config2.Accel.on && *url == '/') {
  1962. /* prepend the accel prefix */
  1963. if (opt_accel_uses_host && (t = mime_get_header(req_hdr, "Host"))) {
  1964.     /* If a Host: header was specified, use it to build the URL 
  1965.      * instead of the one in the Config file. */
  1966.     /*
  1967.      * XXX Use of the Host: header here opens a potential
  1968.      * security hole.  There are no checks that the Host: value
  1969.      * corresponds to one of your servers.  It might, for example,
  1970.      * refer to www.playboy.com.  The 'dst' and/or 'dst_domain' ACL 
  1971.      * types should be used to prevent httpd-accelerators 
  1972.      * handling requests for non-local servers */
  1973.     strtok(t, " :/;@");
  1974.     url_sz = strlen(url) + 32 + Config.appendDomainLen +
  1975. strlen(t);
  1976.     http->uri = xcalloc(url_sz, 1);
  1977.     snprintf(http->uri, url_sz, "http://%s:%d%s",
  1978. t, (int) Config.Accel.port, url);
  1979. } else if (vhost_mode) {
  1980.     /* Put the local socket IP address as the hostname */
  1981.     url_sz = strlen(url) + 32 + Config.appendDomainLen;
  1982.     http->uri = xcalloc(url_sz, 1);
  1983. #if IPF_TRANSPARENT
  1984.     natLookup.nl_inport = http->conn->me.sin_port;
  1985.     natLookup.nl_outport = http->conn->peer.sin_port;
  1986.     natLookup.nl_inip = http->conn->me.sin_addr;
  1987.     natLookup.nl_outip = http->conn->peer.sin_addr;
  1988.     natLookup.nl_flags = IPN_TCP;
  1989.     if (natfd < 0)
  1990. natfd = open(IPL_NAT, O_RDONLY, 0);
  1991.     if (natfd < 0) {
  1992. debug(50, 1) ("parseHttpRequest: NAT open failed: %sn",
  1993.     xstrerror());
  1994. return parseHttpRequestAbort(conn, "error:nat-open-failed");
  1995.     }
  1996.     if (ioctl(natfd, SIOCGNATL, &natLookup) < 0) {
  1997. if (errno != ESRCH) {
  1998.     debug(50, 1) ("parseHttpRequest: NAT lookup failed: ioctl(SIOCGNATL)n");
  1999.     close(natfd);
  2000.     natfd = -1;
  2001.     return parseHttpRequestAbort(conn, "error:nat-lookup-failed");
  2002. } else
  2003.     snprintf(http->uri, url_sz, "http://%s:%d%s",
  2004. inet_ntoa(http->conn->me.sin_addr),
  2005. (int) Config.Accel.port,
  2006. url);
  2007.     } else
  2008. snprintf(http->uri, url_sz, "http://%s:%d%s",
  2009.     inet_ntoa(natLookup.nl_realip),
  2010.     (int) Config.Accel.port,
  2011.     url);
  2012. #else
  2013.     snprintf(http->uri, url_sz, "http://%s:%d%s",
  2014. inet_ntoa(http->conn->me.sin_addr),
  2015. (int) Config.Accel.port,
  2016. url);
  2017. #endif
  2018.     debug(33, 5) ("VHOST REWRITE: '%s'n", http->uri);
  2019. } else {
  2020.     url_sz = strlen(Config2.Accel.prefix) + strlen(url) +
  2021. Config.appendDomainLen + 1;
  2022.     http->uri = xcalloc(url_sz, 1);
  2023.     snprintf(http->uri, url_sz, "%s%s", Config2.Accel.prefix, url);
  2024. }
  2025. http->flags.accel = 1;
  2026.     } else {
  2027. /* URL may be rewritten later, so make extra room */
  2028. url_sz = strlen(url) + Config.appendDomainLen + 5;
  2029. http->uri = xcalloc(url_sz, 1);
  2030. strcpy(http->uri, url);
  2031. http->flags.accel = 0;
  2032.     }
  2033.     if (!stringHasWhitespace(http->uri))
  2034. http->log_uri = xstrndup(http->uri, MAX_URL);
  2035.     else
  2036. http->log_uri = xstrndup(rfc1738_escape(http->uri), MAX_URL);
  2037.     debug(33, 5) ("parseHttpRequest: Complete request receivedn");
  2038.     if (free_request)
  2039. safe_free(url);
  2040.     xfree(inbuf);
  2041.     *status = 1;
  2042.     return http;
  2043. }
  2044. static int
  2045. clientReadDefer(int fdnotused, void *data)
  2046. {
  2047.     ConnStateData *conn = data;
  2048.     return conn->defer.until > squid_curtime;
  2049. }
  2050. static void
  2051. clientReadRequest(int fd, void *data)
  2052. {
  2053.     ConnStateData *conn = data;
  2054.     int parser_return_code = 0;
  2055.     int k;
  2056.     request_t *request = NULL;
  2057.     int size;
  2058.     method_t method;
  2059.     clientHttpRequest *http = NULL;
  2060.     clientHttpRequest **H = NULL;
  2061.     char *prefix = NULL;
  2062.     ErrorState *err = NULL;
  2063.     fde *F = &fd_table[fd];
  2064.     int len = conn->in.size - conn->in.offset - 1;
  2065.     debug(33, 4) ("clientReadRequest: FD %d: reading request...n", fd);
  2066.     Counter.syscalls.sock.reads++;
  2067.     size = read(fd, conn->in.buf + conn->in.offset, len);
  2068.     if (size > 0) {
  2069. fd_bytes(fd, size, FD_READ);
  2070. kb_incr(&Counter.client_http.kbytes_in, size);
  2071.     }
  2072.     /*
  2073.      * Don't reset the timeout value here.  The timeout value will be
  2074.      * set to Config.Timeout.request by httpAccept() and
  2075.      * clientWriteComplete(), and should apply to the request as a
  2076.      * whole, not individual read() calls.  Plus, it breaks our
  2077.      * lame half-close detection
  2078.      */
  2079.     commSetSelect(fd, COMM_SELECT_READ, clientReadRequest, conn, 0);
  2080.     if (size == 0) {
  2081. if (conn->chr == NULL) {
  2082.     /* no current or pending requests */
  2083.     comm_close(fd);
  2084.     return;
  2085. } else if (!Config.onoff.half_closed_clients) {
  2086.     /* admin doesn't want to support half-closed client sockets */
  2087.     comm_close(fd);
  2088.     return;
  2089. }
  2090. /* It might be half-closed, we can't tell */
  2091. debug(33, 5) ("clientReadRequest: FD %d closed?n", fd);
  2092. F->flags.socket_eof = 1;
  2093. conn->defer.until = squid_curtime + 1;
  2094. conn->defer.n++;
  2095. fd_note(fd, "half-closed");
  2096. return;
  2097.     } else if (size < 0) {
  2098. if (!ignoreErrno(errno)) {
  2099.     debug(50, 2) ("clientReadRequest: FD %d: %sn", fd, xstrerror());
  2100.     comm_close(fd);
  2101.     return;
  2102. } else if (conn->in.offset == 0) {
  2103.     debug(50, 2) ("clientReadRequest: FD %d: no data to process (%s)n", fd, xstrerror());
  2104.     return;
  2105. }
  2106. /* Continue to process previously read data */
  2107. size = 0;
  2108.     }
  2109.     conn->in.offset += size;
  2110.     /* Skip leading (and trailing) whitespace */
  2111.     while (conn->in.offset > 0) {
  2112. int nrequests;
  2113. size_t req_line_sz;
  2114. while (conn->in.offset > 0 && xisspace(conn->in.buf[0])) {
  2115.     xmemmove(conn->in.buf, conn->in.buf + 1, conn->in.offset - 1);
  2116.     conn->in.offset--;
  2117. }
  2118. conn->in.buf[conn->in.offset] = ''; /* Terminate the string */
  2119. if (conn->in.offset == 0)
  2120.     break;
  2121. /* Limit the number of concurrent requests to 2 */
  2122. for (H = &conn->chr, nrequests = 0; *H; H = &(*H)->next, nrequests++);
  2123. if (nrequests >= 2) {
  2124.     debug(33, 2) ("clientReadRequest: FD %d max concurrent requests reachedn", fd);
  2125.     debug(33, 5) ("clientReadRequest: FD %d defering new request until one is donen", fd);
  2126.     conn->defer.until = squid_curtime + 100; /* Reset when a request is complete */
  2127.     break;
  2128. }
  2129. /* Process request */
  2130. http = parseHttpRequest(conn,
  2131.     &method,
  2132.     &parser_return_code,
  2133.     &prefix,
  2134.     &req_line_sz);
  2135. if (!http)
  2136.     safe_free(prefix);
  2137. if (http) {
  2138.     assert(http->req_sz > 0);
  2139.     conn->in.offset -= http->req_sz;
  2140.     assert(conn->in.offset >= 0);
  2141.     debug(33, 5) ("conn->in.offset = %dn", (int) conn->in.offset);
  2142.     /*
  2143.      * If we read past the end of this request, move the remaining
  2144.      * data to the beginning
  2145.      */
  2146.     if (conn->in.offset > 0)
  2147. xmemmove(conn->in.buf, conn->in.buf + http->req_sz, conn->in.offset);
  2148.     /* add to the client request queue */
  2149.     for (H = &conn->chr; *H; H = &(*H)->next);
  2150.     *H = http;
  2151.     conn->nrequests++;
  2152.     commSetTimeout(fd, Config.Timeout.lifetime, NULL, NULL);
  2153.     if (parser_return_code < 0) {
  2154. debug(33, 1) ("clientReadRequest: FD %d Invalid Requestn", fd);
  2155. err = errorCon(ERR_INVALID_REQ, HTTP_BAD_REQUEST);
  2156. err->request_hdrs = xstrdup(conn->in.buf);
  2157. http->entry = clientCreateStoreEntry(http, method, null_request_flags);
  2158. errorAppendEntry(http->entry, err);
  2159. safe_free(prefix);
  2160. break;
  2161.     }
  2162.     if ((request = urlParse(method, http->uri)) == NULL) {
  2163. debug(33, 5) ("Invalid URL: %sn", http->uri);
  2164. err = errorCon(ERR_INVALID_URL, HTTP_BAD_REQUEST);
  2165. err->src_addr = conn->peer.sin_addr;
  2166. err->url = xstrdup(http->uri);
  2167. http->al.http.code = err->http_status;
  2168. http->entry = clientCreateStoreEntry(http, method, null_request_flags);
  2169. errorAppendEntry(http->entry, err);
  2170. safe_free(prefix);
  2171. break;
  2172.     } else {
  2173. /* compile headers */
  2174. /* we should skip request line! */
  2175. if (!httpRequestParseHeader(request, prefix + req_line_sz))
  2176.     debug(33, 1) ("Failed to parse request headers: %sn%sn",
  2177. http->uri, prefix);
  2178. /* continue anyway? */
  2179.     }
  2180.     request->flags.accelerated = http->flags.accel;
  2181.     if (!http->flags.internal) {
  2182. if (internalCheck(strBuf(request->urlpath))) {
  2183.     if (0 == strcasecmp(request->host, internalHostname())) {
  2184. if (request->port == Config.Port.http->i)
  2185.     http->flags.internal = 1;
  2186.     } else if (internalStaticCheck(strBuf(request->urlpath))) {
  2187. xstrncpy(request->host, internalHostname(), SQUIDHOSTNAMELEN);
  2188. request->port = Config.Port.http->i;
  2189. http->flags.internal = 1;
  2190.     }
  2191. }
  2192.     }
  2193.     request->flags.internal = http->flags.internal;
  2194.     safe_free(prefix);
  2195.     safe_free(http->log_uri);
  2196.     http->log_uri = xstrdup(urlCanonicalClean(request));
  2197.     request->client_addr = conn->peer.sin_addr;
  2198.     request->my_addr = conn->me.sin_addr;
  2199.     request->http_ver = http->http_ver;
  2200.     if (!urlCheckRequest(request)) {
  2201. err = errorCon(ERR_UNSUP_REQ, HTTP_NOT_IMPLEMENTED);
  2202. err->src_addr = conn->peer.sin_addr;
  2203. err->request = requestLink(request);
  2204. http->al.http.code = err->http_status;
  2205. http->entry = clientCreateStoreEntry(http, request->method, null_request_flags);
  2206. errorAppendEntry(http->entry, err);
  2207. break;
  2208.     }
  2209.     if (0 == clientCheckContentLength(request)) {
  2210. err = errorCon(ERR_INVALID_REQ, HTTP_LENGTH_REQUIRED);
  2211. err->src_addr = conn->peer.sin_addr;
  2212. err->request = requestLink(request);
  2213. http->al.http.code = err->http_status;
  2214. http->entry = clientCreateStoreEntry(http, request->method, null_request_flags);
  2215. errorAppendEntry(http->entry, err);
  2216. break;
  2217.     }
  2218.     http->request = requestLink(request);
  2219.     /*
  2220.      * We need to set the keepalive flag before doing some
  2221.      * hacks for POST/PUT requests below.  Maybe we could
  2222.      * set keepalive flag even earlier.
  2223.      */
  2224.     clientSetKeepaliveFlag(http);
  2225.     /*
  2226.      * break here for NON-GET because most likely there is a
  2227.      * reqeust body following and we don't want to parse it
  2228.      * as though it was new request
  2229.      */
  2230.     if (request->method != METHOD_GET) {
  2231. int cont_len = httpHeaderGetInt(&request->header, HDR_CONTENT_LENGTH);
  2232. int copy_len = XMIN(conn->in.offset, cont_len);
  2233. if (copy_len > 0) {
  2234.     assert(conn->in.offset >= copy_len);
  2235.     request->body_sz = copy_len;
  2236.     request->body = xmalloc(request->body_sz);
  2237.     xmemcpy(request->body, conn->in.buf, request->body_sz);
  2238.     conn->in.offset -= copy_len;
  2239.     if (conn->in.offset)
  2240. xmemmove(conn->in.buf, conn->in.buf + copy_len, conn->in.offset);
  2241. }
  2242. /*
  2243.  * if we didn't get the full body now, then more will
  2244.  * be arriving on the client socket.  Lets cancel
  2245.  * the read handler until this request gets forwarded.
  2246.  */
  2247. if (request->body_sz < cont_len)
  2248.     commSetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0);
  2249.     }
  2250.     clientAccessCheck(http);
  2251.     continue; /* while offset > 0 */
  2252. } else if (parser_return_code == 0) {
  2253.     /*
  2254.      *    Partial request received; reschedule until parseHttpRequest()
  2255.      *    is happy with the input
  2256.      */
  2257.     k = conn->in.size - 1 - conn->in.offset;
  2258.     if (k == 0) {
  2259. if (conn->in.offset >= Config.maxRequestSize) {
  2260.     /* The request is too large to handle */
  2261.     debug(33, 0) ("Request won't fit in buffer.n");
  2262.     debug(33, 0) ("Config 'request_size'= %d bytes.n",
  2263. Config.maxRequestSize);
  2264.     debug(33, 0) ("This request = %d bytes.n",
  2265. (int) conn->in.offset);
  2266.     err = errorCon(ERR_INVALID_REQ, HTTP_REQUEST_ENTITY_TOO_LARGE);
  2267.     http = parseHttpRequestAbort(conn, "error:request-too-large");
  2268.     /* add to the client request queue */
  2269.     for (H = &conn->chr; *H; H = &(*H)->next);
  2270.     *H = http;
  2271.     http->entry = clientCreateStoreEntry(http, METHOD_NONE, null_request_flags);
  2272.     errorAppendEntry(http->entry, err);
  2273.     return;
  2274. }
  2275. /* Grow the request memory area to accomodate for a large request */
  2276. conn->in.size += REQUEST_BUF_SIZE;
  2277. conn->in.buf = xrealloc(conn->in.buf, conn->in.size);
  2278. /* XXX account conn->in.buf */
  2279. debug(33, 2) ("Handling a large request, offset=%d inbufsize=%dn",
  2280.     (int) conn->in.offset, conn->in.size);
  2281. k = conn->in.size - 1 - conn->in.offset;
  2282.     }
  2283.     break;
  2284. }
  2285.     }
  2286. }
  2287. /* general lifetime handler for HTTP requests */
  2288. static void
  2289. requestTimeout(int fd, void *data)
  2290. {
  2291.     ConnStateData *conn = data;
  2292.     ErrorState *err;
  2293.     debug(33, 2) ("requestTimeout: FD %d: lifetime is expired.n", fd);
  2294.     if (fd_table[fd].rwstate) {
  2295. /*
  2296.  * Some data has been sent to the client, just close the FD
  2297.  */
  2298. comm_close(fd);
  2299.     } else if (conn->nrequests) {
  2300. /*
  2301.  * assume its a persistent connection; just close it
  2302.  */
  2303. comm_close(fd);
  2304.     } else {
  2305. /*
  2306.  * Generate an error
  2307.  */
  2308. err = errorCon(ERR_LIFETIME_EXP, HTTP_REQUEST_TIMEOUT);
  2309. err->url = xstrdup("N/A");
  2310. /*
  2311.  * Normally we shouldn't call errorSend() in client_side.c, but
  2312.  * it should be okay in this case.  Presumably if we get here
  2313.  * this is the first request for the connection, and no data
  2314.  * has been written yet
  2315.  */
  2316. assert(conn->chr == NULL);
  2317. errorSend(fd, err);
  2318. /*
  2319.  * if we don't close() here, we still need a timeout handler!
  2320.  */
  2321. commSetTimeout(fd, 30, requestTimeout, conn);
  2322.     }
  2323. }
  2324. static int
  2325. httpAcceptDefer(void)
  2326. {
  2327.     static time_t last_warn = 0;
  2328.     if (fdNFree() >= RESERVED_FD)
  2329. return 0;
  2330.     if (last_warn + 15 < squid_curtime) {
  2331. debug(33, 0) ("WARNING! Your cache is running out of filedescriptorsn");
  2332. last_warn = squid_curtime;
  2333.     }
  2334.     return 1;
  2335. }
  2336. /* Handle a new connection on HTTP socket. */
  2337. void
  2338. httpAccept(int sock, void *data)
  2339. {
  2340.     int *N = data;
  2341.     int fd = -1;
  2342.     ConnStateData *connState = NULL;
  2343.     struct sockaddr_in peer;
  2344.     struct sockaddr_in me;
  2345.     int max = INCOMING_HTTP_MAX;
  2346. #if USE_IDENT
  2347.     static aclCheck_t identChecklist;
  2348. #endif
  2349.     commSetSelect(sock, COMM_SELECT_READ, httpAccept, NULL, 0);
  2350.     while (max-- && !httpAcceptDefer()) {
  2351. memset(&peer, '', sizeof(struct sockaddr_in));
  2352. memset(&me, '', sizeof(struct sockaddr_in));
  2353. if ((fd = comm_accept(sock, &peer, &me)) < 0) {
  2354.     if (!ignoreErrno(errno))
  2355. debug(50, 1) ("httpAccept: FD %d: accept failure: %sn",
  2356.     sock, xstrerror());
  2357.     break;
  2358. }
  2359. debug(33, 4) ("httpAccept: FD %d: acceptedn", fd);
  2360. connState = xcalloc(1, sizeof(ConnStateData));
  2361. connState->peer = peer;
  2362. connState->log_addr = peer.sin_addr;
  2363. connState->log_addr.s_addr &= Config.Addrs.client_netmask.s_addr;
  2364. connState->me = me;
  2365. connState->fd = fd;
  2366. connState->in.size = REQUEST_BUF_SIZE;
  2367. connState->in.buf = xcalloc(connState->in.size, 1);
  2368. cbdataAdd(connState, cbdataXfree, 0);
  2369. /* XXX account connState->in.buf */
  2370. comm_add_close_handler(fd, connStateFree, connState);
  2371. if (Config.onoff.log_fqdn)
  2372.     fqdncache_gethostbyaddr(peer.sin_addr, FQDN_LOOKUP_IF_MISS);
  2373. commSetTimeout(fd, Config.Timeout.request, requestTimeout, connState);
  2374. #if USE_IDENT
  2375. identChecklist.src_addr = peer.sin_addr;
  2376. if (aclCheckFast(Config.accessList.identLookup, &identChecklist))
  2377.     identStart(&me, &peer, clientIdentDone, connState);
  2378. #endif
  2379. commSetSelect(fd, COMM_SELECT_READ, clientReadRequest, connState, 0);
  2380. commSetDefer(fd, clientReadDefer, connState);
  2381. (*N)++;
  2382.     }
  2383. }
  2384. #define SENDING_BODY 0
  2385. #define SENDING_HDRSONLY 1
  2386. static int
  2387. clientCheckTransferDone(clientHttpRequest * http)
  2388. {
  2389.     int sending = SENDING_BODY;
  2390.     StoreEntry *entry = http->entry;
  2391.     MemObject *mem;
  2392.     http_reply *reply;
  2393.     int sendlen;
  2394.     if (entry == NULL)
  2395. return 0;
  2396.     /*
  2397.      * For now, 'done_copying' is used for special cases like
  2398.      * Range and HEAD requests.
  2399.      */
  2400.     if (http->flags.done_copying)
  2401. return 1;
  2402.     /*
  2403.      * Handle STORE_OK objects.
  2404.      * objectLen(entry) will be set proprely.
  2405.      */
  2406.     if (entry->store_status == STORE_OK) {
  2407. if (http->out.offset >= objectLen(entry))
  2408.     return 1;
  2409. else
  2410.     return 0;
  2411.     }
  2412.     /*
  2413.      * Now, handle STORE_PENDING objects
  2414.      */
  2415.     mem = entry->mem_obj;
  2416.     assert(mem != NULL);
  2417.     assert(http->request != NULL);
  2418.     reply = mem->reply;
  2419.     if (reply->hdr_sz == 0)
  2420. return 0; /* haven't found end of headers yet */
  2421.     else if (reply->sline.status == HTTP_OK)
  2422. sending = SENDING_BODY;
  2423.     else if (reply->sline.status == HTTP_NO_CONTENT)
  2424. sending = SENDING_HDRSONLY;
  2425.     else if (reply->sline.status == HTTP_NOT_MODIFIED)
  2426. sending = SENDING_HDRSONLY;
  2427.     else if (reply->sline.status < HTTP_OK)
  2428. sending = SENDING_HDRSONLY;
  2429.     else if (http->request->method == METHOD_HEAD)
  2430. sending = SENDING_HDRSONLY;
  2431.     else
  2432. sending = SENDING_BODY;
  2433.     /*
  2434.      * Figure out how much data we are supposed to send.
  2435.      * If we are sending a body and we don't have a content-length,
  2436.      * then we must wait for the object to become STORE_OK.
  2437.      */
  2438.     if (sending == SENDING_HDRSONLY)
  2439. sendlen = reply->hdr_sz;
  2440.     else if (reply->content_length < 0)
  2441. return 0;
  2442.     else
  2443. sendlen = reply->content_length + reply->hdr_sz;
  2444.     /*
  2445.      * Now that we have the expected length, did we send it all?
  2446.      */
  2447.     if (http->out.offset < sendlen)
  2448. return 0;
  2449.     else
  2450. return 1;
  2451. }
  2452. static int
  2453. clientGotNotEnough(clientHttpRequest * http)
  2454. {
  2455.     int cl = http->entry->mem_obj->reply->content_length;
  2456.     int hs = http->entry->mem_obj->reply->hdr_sz;
  2457.     assert(cl >= 0);
  2458.     if (http->out.offset < cl + hs)
  2459. return 1;
  2460.     return 0;
  2461. }
  2462. /*
  2463.  * This function is designed to serve a fairly specific purpose.
  2464.  * Occasionally our vBNS-connected caches can talk to each other, but not
  2465.  * the rest of the world.  Here we try to detect frequent failures which
  2466.  * make the cache unusable (e.g. DNS lookup and connect() failures).  If
  2467.  * the failure:success ratio goes above 1.0 then we go into "hit only"
  2468.  * mode where we only return UDP_HIT or UDP_MISS_NOFETCH.  Neighbors
  2469.  * will only fetch HITs from us if they are using the ICP protocol.  We
  2470.  * stay in this mode for 5 minutes.
  2471.  * 
  2472.  * Duane W., Sept 16, 1996
  2473.  */
  2474. static void
  2475. checkFailureRatio(err_type etype, hier_code hcode)
  2476. {
  2477.     static double magic_factor = 100.0;
  2478.     double n_good;
  2479.     double n_bad;
  2480.     if (hcode == HIER_NONE)
  2481. return;
  2482.     n_good = magic_factor / (1.0 + request_failure_ratio);
  2483.     n_bad = magic_factor - n_good;
  2484.     switch (etype) {
  2485.     case ERR_DNS_FAIL:
  2486.     case ERR_CONNECT_FAIL:
  2487.     case ERR_READ_ERROR:
  2488. n_bad++;
  2489. break;
  2490.     default:
  2491. n_good++;
  2492.     }
  2493.     request_failure_ratio = n_bad / n_good;
  2494.     if (hit_only_mode_until > squid_curtime)
  2495. return;
  2496.     if (request_failure_ratio < 1.0)
  2497. return;
  2498.     debug(33, 0) ("Failure Ratio at %4.2fn", request_failure_ratio);
  2499.     debug(33, 0) ("Going into hit-only-mode for %d minutes...n",
  2500. FAILURE_MODE_TIME / 60);
  2501.     hit_only_mode_until = squid_curtime + FAILURE_MODE_TIME;
  2502.     request_failure_ratio = 0.8; /* reset to something less than 1.0 */
  2503. }
  2504. void
  2505. clientHttpConnectionsOpen(void)
  2506. {
  2507.     ushortlist *u;
  2508.     int fd;
  2509.     for (u = Config.Port.http; u; u = u->next) {
  2510. enter_suid();
  2511. fd = comm_open(SOCK_STREAM,
  2512.     0,
  2513.     Config.Addrs.tcp_incoming,
  2514.     u->i,
  2515.     COMM_NONBLOCKING,
  2516.     "HTTP Socket");
  2517. leave_suid();
  2518. if (fd < 0)
  2519.     continue;
  2520. comm_listen(fd);
  2521. commSetSelect(fd, COMM_SELECT_READ, httpAccept, NULL, 0);
  2522. /*commSetDefer(fd, httpAcceptDefer, NULL); */
  2523. debug(1, 1) ("Accepting HTTP connections on port %d, FD %d.n",
  2524.     (int) u->i, fd);
  2525. HttpSockets[NHttpSockets++] = fd;
  2526.     }
  2527.     if (NHttpSockets < 1)
  2528. fatal("Cannot open HTTP Port");
  2529. }
  2530. void
  2531. clientHttpConnectionsClose(void)
  2532. {
  2533.     int i;
  2534.     for (i = 0; i < NHttpSockets; i++) {
  2535. if (HttpSockets[i] >= 0) {
  2536.     debug(1, 1) ("FD %d Closing HTTP connectionn", HttpSockets[i]);
  2537.     comm_close(HttpSockets[i]);
  2538.     HttpSockets[i] = -1;
  2539. }
  2540.     }
  2541.     NHttpSockets = 0;
  2542. }