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

代理服务器

开发平台:

Unix_Linux

  1. /*
  2.  * $Id: HttpReply.c,v 1.35 1999/01/22 19:07:00 glenn Exp $
  3.  *
  4.  * DEBUG: section 58    HTTP Reply (Response)
  5.  * AUTHOR: Alex Rousskov
  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. /* local constants */
  36. /* these entity-headers must be ignored if a bogus server sends them in 304 */
  37. static HttpHeaderMask Denied304HeadersMask;
  38. static http_hdr_type Denied304HeadersArr[] =
  39. {
  40.     HDR_ALLOW, HDR_CONTENT_ENCODING, HDR_CONTENT_LANGUAGE, HDR_CONTENT_LENGTH,
  41.     HDR_CONTENT_LOCATION, HDR_CONTENT_RANGE, HDR_LAST_MODIFIED, HDR_LINK,
  42.     HDR_OTHER
  43. };
  44. /* local routines */
  45. static void httpReplyInit(HttpReply * rep);
  46. static void httpReplyClean(HttpReply * rep);
  47. static void httpReplyDoDestroy(HttpReply * rep);
  48. static void httpReplyHdrCacheInit(HttpReply * rep);
  49. static void httpReplyHdrCacheClean(HttpReply * rep);
  50. static int httpReplyParseStep(HttpReply * rep, const char *parse_start, int atEnd);
  51. static int httpReplyParseError(HttpReply * rep);
  52. static int httpReplyIsolateStart(const char **parse_start, const char **blk_start, const char **blk_end);
  53. /* module initialization */
  54. void
  55. httpReplyInitModule()
  56. {
  57.     httpHeaderMaskInit(&Denied304HeadersMask, 0);
  58.     httpHeaderCalcMask(&Denied304HeadersMask, (const int *) Denied304HeadersArr, countof(Denied304HeadersArr));
  59. }
  60. HttpReply *
  61. httpReplyCreate()
  62. {
  63.     HttpReply *rep = memAllocate(MEM_HTTP_REPLY);
  64.     debug(58, 7) ("creating rep: %pn", rep);
  65.     httpReplyInit(rep);
  66.     return rep;
  67. }
  68. static void
  69. httpReplyInit(HttpReply * rep)
  70. {
  71.     assert(rep);
  72.     rep->hdr_sz = 0;
  73.     rep->pstate = psReadyToParseStartLine;
  74.     httpBodyInit(&rep->body);
  75.     httpHeaderInit(&rep->header, hoReply);
  76.     httpReplyHdrCacheInit(rep);
  77.     httpStatusLineInit(&rep->sline);
  78. }
  79. static void
  80. httpReplyClean(HttpReply * rep)
  81. {
  82.     assert(rep);
  83.     httpBodyClean(&rep->body);
  84.     httpReplyHdrCacheClean(rep);
  85.     httpHeaderClean(&rep->header);
  86.     httpStatusLineClean(&rep->sline);
  87. }
  88. void
  89. httpReplyDestroy(HttpReply * rep)
  90. {
  91.     assert(rep);
  92.     debug(58, 7) ("destroying rep: %pn", rep);
  93.     httpReplyClean(rep);
  94.     httpReplyDoDestroy(rep);
  95. }
  96. void
  97. httpReplyReset(HttpReply * rep)
  98. {
  99.     httpReplyClean(rep);
  100.     httpReplyInit(rep);
  101. }
  102. /* absorb: copy the contents of a new reply to the old one, destroy new one */
  103. void
  104. httpReplyAbsorb(HttpReply * rep, HttpReply * new_rep)
  105. {
  106.     assert(rep && new_rep);
  107.     httpReplyClean(rep);
  108.     *rep = *new_rep;
  109.     /* cannot use Clean() on new reply now! */
  110.     httpReplyDoDestroy(new_rep);
  111. }
  112. /* parses a 4K buffer that may not be 0-terminated; returns true on success */
  113. int
  114. httpReplyParse(HttpReply * rep, const char *buf)
  115. {
  116.     /*
  117.      * this extra buffer/copy will be eliminated when headers become meta-data
  118.      * in store. Currently we have to xstrncpy the buffer becuase store.c may
  119.      * feed a non 0-terminated buffer to us.
  120.      */
  121.     char *headers = memAllocate(MEM_4K_BUF);
  122.     int success;
  123.     /* reset current state, because we are not used in incremental fashion */
  124.     httpReplyReset(rep);
  125.     /* put a 0-terminator */
  126.     xstrncpy(headers, buf, 4096);
  127.     success = httpReplyParseStep(rep, headers, 0);
  128.     memFree(headers, MEM_4K_BUF);
  129.     return success == 1;
  130. }
  131. void
  132. httpReplyPackInto(const HttpReply * rep, Packer * p)
  133. {
  134.     assert(rep);
  135.     httpStatusLinePackInto(&rep->sline, p);
  136.     httpHeaderPackInto(&rep->header, p);
  137.     packerAppend(p, "rn", 2);
  138.     httpBodyPackInto(&rep->body, p);
  139. }
  140. /* create memBuf, create mem-based packer,  pack, destroy packer, return MemBuf */
  141. MemBuf
  142. httpReplyPack(const HttpReply * rep)
  143. {
  144.     MemBuf mb;
  145.     Packer p;
  146.     assert(rep);
  147.     memBufDefInit(&mb);
  148.     packerToMemInit(&p, &mb);
  149.     httpReplyPackInto(rep, &p);
  150.     packerClean(&p);
  151.     return mb;
  152. }
  153. /* swap: create swap-based packer, pack, destroy packer */
  154. void
  155. httpReplySwapOut(const HttpReply * rep, StoreEntry * e)
  156. {
  157.     Packer p;
  158.     assert(rep && e);
  159.     packerToStoreInit(&p, e);
  160.     httpReplyPackInto(rep, &p);
  161.     packerClean(&p);
  162. }
  163. MemBuf
  164. httpPackedReply(double ver, http_status status, const char *ctype,
  165.     int clen, time_t lmt, time_t expires)
  166. {
  167.     HttpReply *rep = httpReplyCreate();
  168.     MemBuf mb;
  169.     httpReplySetHeaders(rep, ver, status, ctype, NULL, clen, lmt, expires);
  170.     mb = httpReplyPack(rep);
  171.     httpReplyDestroy(rep);
  172.     return mb;
  173. }
  174. MemBuf
  175. httpPacked304Reply(const HttpReply * rep)
  176. {
  177.     static const http_hdr_type ImsEntries[] =
  178.     {HDR_DATE, HDR_CONTENT_LENGTH, HDR_CONTENT_TYPE, HDR_EXPIRES, HDR_LAST_MODIFIED, /* eof */ HDR_OTHER};
  179.     int t;
  180.     MemBuf mb;
  181.     Packer p;
  182.     HttpHeaderEntry *e;
  183.     assert(rep);
  184.     memBufDefInit(&mb);
  185.     packerToMemInit(&p, &mb);
  186.     memBufPrintf(&mb, "%s", "HTTP/1.0 304 Not Modifiedrn");
  187.     for (t = 0; ImsEntries[t] != HDR_OTHER; ++t)
  188. if ((e = httpHeaderFindEntry(&rep->header, ImsEntries[t])))
  189.     httpHeaderEntryPackInto(e, &p);
  190.     memBufAppend(&mb, "rn", 2);
  191.     packerClean(&p);
  192.     return mb;
  193. }
  194. void
  195. httpReplySetHeaders(HttpReply * reply, double ver, http_status status, const char *reason,
  196.     const char *ctype, int clen, time_t lmt, time_t expires)
  197. {
  198.     HttpHeader *hdr;
  199.     assert(reply);
  200.     httpStatusLineSet(&reply->sline, ver, status, reason);
  201.     hdr = &reply->header;
  202.     httpHeaderPutStr(hdr, HDR_SERVER, full_appname_string);
  203.     httpHeaderPutStr(hdr, HDR_MIME_VERSION, "1.0");
  204.     httpHeaderPutTime(hdr, HDR_DATE, squid_curtime);
  205.     if (ctype) {
  206. httpHeaderPutStr(hdr, HDR_CONTENT_TYPE, ctype);
  207. stringInit(&reply->content_type, ctype);
  208.     } else
  209. reply->content_type = StringNull;
  210.     if (clen >= 0)
  211. httpHeaderPutInt(hdr, HDR_CONTENT_LENGTH, clen);
  212.     if (expires >= 0)
  213. httpHeaderPutTime(hdr, HDR_EXPIRES, expires);
  214.     if (lmt > 0) /* this used to be lmt != 0 @?@ */
  215. httpHeaderPutTime(hdr, HDR_LAST_MODIFIED, lmt);
  216.     reply->date = squid_curtime;
  217.     reply->content_length = clen;
  218.     reply->expires = expires;
  219.     reply->last_modified = lmt;
  220. }
  221. void
  222. httpRedirectReply(HttpReply * reply, http_status status, const char *loc)
  223. {
  224.     HttpHeader *hdr;
  225.     assert(reply);
  226.     httpStatusLineSet(&reply->sline, 1.0, status, httpStatusString(status));
  227.     hdr = &reply->header;
  228.     httpHeaderPutStr(hdr, HDR_SERVER, full_appname_string);
  229.     httpHeaderPutTime(hdr, HDR_DATE, squid_curtime);
  230.     httpHeaderPutInt(hdr, HDR_CONTENT_LENGTH, 0);
  231.     httpHeaderPutStr(hdr, HDR_LOCATION, loc);
  232.     reply->date = squid_curtime;
  233.     reply->content_length = 0;
  234. }
  235. void
  236. httpReplyUpdateOnNotModified(HttpReply * rep, HttpReply * freshRep)
  237. {
  238.     assert(rep && freshRep);
  239.     /* clean cache */
  240.     httpReplyHdrCacheClean(rep);
  241.     /* update raw headers */
  242.     httpHeaderUpdate(&rep->header, &freshRep->header,
  243. (const HttpHeaderMask *) &Denied304HeadersMask);
  244.     /* init cache */
  245.     httpReplyHdrCacheInit(rep);
  246. }
  247. /* internal routines */
  248. /* internal function used by Destroy and Absorb */
  249. static void
  250. httpReplyDoDestroy(HttpReply * rep)
  251. {
  252.     memFree(rep, MEM_HTTP_REPLY);
  253. }
  254. /* sync this routine when you update HttpReply struct */
  255. static void
  256. httpReplyHdrCacheInit(HttpReply * rep)
  257. {
  258.     const HttpHeader *hdr = &rep->header;
  259.     const char *str;
  260.     rep->content_length = httpHeaderGetInt(hdr, HDR_CONTENT_LENGTH);
  261.     rep->date = httpHeaderGetTime(hdr, HDR_DATE);
  262.     rep->last_modified = httpHeaderGetTime(hdr, HDR_LAST_MODIFIED);
  263.     rep->expires = httpHeaderGetTime(hdr, HDR_EXPIRES);
  264.     str = httpHeaderGetStr(hdr, HDR_CONTENT_TYPE);
  265.     if (str)
  266. stringLimitInit(&rep->content_type, str, strcspn(str, ";t "));
  267.     else
  268. rep->content_type = StringNull;
  269.     rep->cache_control = httpHeaderGetCc(hdr);
  270.     rep->content_range = httpHeaderGetContRange(hdr);
  271.     rep->keep_alive = httpMsgIsPersistent(rep->sline.version, &rep->header);
  272.     /* final adjustments */
  273.     /* The max-age directive takes priority over Expires, check it first */
  274.     if (rep->cache_control && rep->cache_control->max_age >= 0)
  275. rep->expires = squid_curtime + rep->cache_control->max_age;
  276.     else
  277. /*
  278.  * The HTTP/1.0 specs says that robust implementations should consider bad
  279.  * or malformed Expires header as equivalent to "expires immediately."
  280.  */
  281.     if (rep->expires < 0 && httpHeaderHas(hdr, HDR_EXPIRES))
  282. rep->expires = squid_curtime;
  283. }
  284. /* sync this routine when you update HttpReply struct */
  285. static void
  286. httpReplyHdrCacheClean(HttpReply * rep)
  287. {
  288.     stringClean(&rep->content_type);
  289.     if (rep->cache_control)
  290. httpHdrCcDestroy(rep->cache_control);
  291.     if (rep->content_range)
  292. httpHdrContRangeDestroy(rep->content_range);
  293. }
  294. /*
  295.  * parses a 0-terminating buffer into HttpReply. 
  296.  * Returns:
  297.  *      +1 -- success 
  298.  *       0 -- need more data (partial parse)
  299.  *      -1 -- parse error
  300.  */
  301. static int
  302. httpReplyParseStep(HttpReply * rep, const char *buf, int atEnd)
  303. {
  304.     const char *parse_start = buf;
  305.     const char *blk_start, *blk_end;
  306.     const char **parse_end_ptr = &blk_end;
  307.     assert(rep);
  308.     assert(parse_start);
  309.     assert(rep->pstate < psParsed);
  310.     *parse_end_ptr = parse_start;
  311.     if (rep->pstate == psReadyToParseStartLine) {
  312. if (!httpReplyIsolateStart(&parse_start, &blk_start, &blk_end))
  313.     return 0;
  314. if (!httpStatusLineParse(&rep->sline, blk_start, blk_end))
  315.     return httpReplyParseError(rep);
  316. *parse_end_ptr = parse_start;
  317. rep->hdr_sz = *parse_end_ptr - buf;
  318. rep->pstate++;
  319.     }
  320.     if (rep->pstate == psReadyToParseHeaders) {
  321. if (!httpMsgIsolateHeaders(&parse_start, &blk_start, &blk_end)) {
  322.     if (atEnd)
  323. blk_start = parse_start, blk_end = blk_start + strlen(blk_start);
  324.     else
  325. return 0;
  326. }
  327. if (!httpHeaderParse(&rep->header, blk_start, blk_end))
  328.     return httpReplyParseError(rep);
  329. httpReplyHdrCacheInit(rep);
  330. *parse_end_ptr = parse_start;
  331. rep->hdr_sz = *parse_end_ptr - buf;
  332. rep->pstate++;
  333.     }
  334.     return 1;
  335. }
  336. /* handy: resets and returns -1 */
  337. static int
  338. httpReplyParseError(HttpReply * rep)
  339. {
  340.     assert(rep);
  341.     /* reset */
  342.     httpReplyReset(rep);
  343.     /* indicate an error */
  344.     rep->sline.status = HTTP_INVALID_HEADER;
  345.     return -1;
  346. }
  347. /* find first CRLF */
  348. static int
  349. httpReplyIsolateStart(const char **parse_start, const char **blk_start, const char **blk_end)
  350. {
  351.     int slen = strcspn(*parse_start, "rn");
  352.     if (!(*parse_start)[slen]) /* no CRLF found */
  353. return 0;
  354.     *blk_start = *parse_start;
  355.     *blk_end = *blk_start + slen;
  356.     while (**blk_end == 'r') /* CR */
  357. (*blk_end)++;
  358.     if (**blk_end == 'n') /* LF */
  359. (*blk_end)++;
  360.     *parse_start = *blk_end;
  361.     return 1;
  362. }