PageRenderTime 82ms CodeModel.GetById 51ms RepoModel.GetById 1ms app.codeStats 0ms

/varnish-3.0.2/bin/varnishd/cache_response.c

#
C | 427 lines | 291 code | 64 blank | 72 comment | 70 complexity | debd3850f32acead27b45392e1cb2cf8 MD5 | raw file
  1. /*-
  2. * Copyright (c) 2006 Verdens Gang AS
  3. * Copyright (c) 2006-2011 Varnish Software AS
  4. * All rights reserved.
  5. *
  6. * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  18. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
  21. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27. * SUCH DAMAGE.
  28. */
  29. #include "config.h"
  30. #include <sys/types.h>
  31. #include <sys/time.h>
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include "cache.h"
  35. #include "stevedore.h"
  36. #include "vct.h"
  37. /*--------------------------------------------------------------------*/
  38. static void
  39. res_dorange(const struct sess *sp, const char *r, ssize_t *plow, ssize_t *phigh)
  40. {
  41. ssize_t low, high, has_low;
  42. assert(sp->obj->response == 200);
  43. if (strncmp(r, "bytes=", 6))
  44. return;
  45. r += 6;
  46. /* The low end of range */
  47. has_low = low = 0;
  48. if (!vct_isdigit(*r) && *r != '-')
  49. return;
  50. while (vct_isdigit(*r)) {
  51. has_low = 1;
  52. low *= 10;
  53. low += *r - '0';
  54. r++;
  55. }
  56. if (low >= sp->obj->len)
  57. return;
  58. if (*r != '-')
  59. return;
  60. r++;
  61. /* The high end of range */
  62. if (vct_isdigit(*r)) {
  63. high = 0;
  64. while (vct_isdigit(*r)) {
  65. high *= 10;
  66. high += *r - '0';
  67. r++;
  68. }
  69. if (!has_low) {
  70. low = sp->obj->len - high;
  71. high = sp->obj->len - 1;
  72. }
  73. } else
  74. high = sp->obj->len - 1;
  75. if (*r != '\0')
  76. return;
  77. if (high >= sp->obj->len)
  78. high = sp->obj->len - 1;
  79. if (low > high)
  80. return;
  81. http_PrintfHeader(sp->wrk, sp->fd, sp->wrk->resp,
  82. "Content-Range: bytes %jd-%jd/%jd",
  83. (intmax_t)low, (intmax_t)high, (intmax_t)sp->obj->len);
  84. http_Unset(sp->wrk->resp, H_Content_Length);
  85. assert(sp->wrk->res_mode & RES_LEN);
  86. http_PrintfHeader(sp->wrk, sp->fd, sp->wrk->resp,
  87. "Content-Length: %jd", (intmax_t)(1 + high - low));
  88. http_SetResp(sp->wrk->resp, "HTTP/1.1", 206, "Partial Content");
  89. *plow = low;
  90. *phigh = high;
  91. }
  92. /*--------------------------------------------------------------------*/
  93. void
  94. RES_BuildHttp(const struct sess *sp)
  95. {
  96. char time_str[30];
  97. CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
  98. http_ClrHeader(sp->wrk->resp);
  99. sp->wrk->resp->logtag = HTTP_Tx;
  100. http_CopyResp(sp->wrk->resp, sp->obj->http);
  101. http_FilterFields(sp->wrk, sp->fd, sp->wrk->resp, sp->obj->http,
  102. HTTPH_A_DELIVER);
  103. if (!(sp->wrk->res_mode & RES_LEN)) {
  104. http_Unset(sp->wrk->resp, H_Content_Length);
  105. } else if (params->http_range_support) {
  106. /* We only accept ranges if we know the length */
  107. http_SetHeader(sp->wrk, sp->fd, sp->wrk->resp,
  108. "Accept-Ranges: bytes");
  109. }
  110. if (sp->wrk->res_mode & RES_CHUNKED)
  111. http_PrintfHeader(sp->wrk, sp->fd, sp->wrk->resp,
  112. "Transfer-Encoding: chunked");
  113. TIM_format(TIM_real(), time_str);
  114. http_PrintfHeader(sp->wrk, sp->fd, sp->wrk->resp, "Date: %s", time_str);
  115. if (sp->xid != sp->obj->xid)
  116. http_PrintfHeader(sp->wrk, sp->fd, sp->wrk->resp,
  117. "X-Varnish: %u %u", sp->xid, sp->obj->xid);
  118. else
  119. http_PrintfHeader(sp->wrk, sp->fd, sp->wrk->resp,
  120. "X-Varnish: %u", sp->xid);
  121. http_PrintfHeader(sp->wrk, sp->fd, sp->wrk->resp, "Age: %.0f",
  122. sp->obj->exp.age + sp->t_resp - sp->obj->exp.entered);
  123. http_SetHeader(sp->wrk, sp->fd, sp->wrk->resp, "Via: 1.1 varnish");
  124. http_PrintfHeader(sp->wrk, sp->fd, sp->wrk->resp, "Connection: %s",
  125. sp->doclose ? "close" : "keep-alive");
  126. }
  127. /*--------------------------------------------------------------------
  128. * We have a gzip'ed object and need to ungzip it for a client which
  129. * does not understand gzip.
  130. * XXX: handle invalid gzip data better (how ?)
  131. */
  132. static void
  133. res_WriteGunzipObj(struct sess *sp)
  134. {
  135. struct storage *st;
  136. unsigned u = 0;
  137. struct vgz *vg;
  138. char obuf[params->gzip_stack_buffer];
  139. ssize_t obufl = 0;
  140. int i;
  141. CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
  142. vg = VGZ_NewUngzip(sp, "U D -");
  143. VGZ_Obuf(vg, obuf, sizeof obuf);
  144. VTAILQ_FOREACH(st, &sp->obj->store, list) {
  145. CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
  146. CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC);
  147. u += st->len;
  148. VSC_C_main->n_objwrite++;
  149. i = VGZ_WrwGunzip(sp, vg,
  150. st->ptr, st->len,
  151. obuf, sizeof obuf, &obufl);
  152. /* XXX: error check */
  153. (void)i;
  154. }
  155. if (obufl) {
  156. (void)WRW_Write(sp->wrk, obuf, obufl);
  157. (void)WRW_Flush(sp->wrk);
  158. }
  159. VGZ_Destroy(&vg);
  160. assert(u == sp->obj->len);
  161. }
  162. /*--------------------------------------------------------------------*/
  163. static void
  164. res_WriteDirObj(const struct sess *sp, ssize_t low, ssize_t high)
  165. {
  166. ssize_t u = 0;
  167. size_t ptr, off, len;
  168. struct storage *st;
  169. CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
  170. ptr = 0;
  171. VTAILQ_FOREACH(st, &sp->obj->store, list) {
  172. CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
  173. CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC);
  174. u += st->len;
  175. len = st->len;
  176. off = 0;
  177. if (ptr + len <= low) {
  178. /* This segment is too early */
  179. ptr += len;
  180. continue;
  181. }
  182. if (ptr < low) {
  183. /* Chop front of segment off */
  184. off += (low - ptr);
  185. len -= (low - ptr);
  186. ptr += (low - ptr);
  187. }
  188. if (ptr + len > high)
  189. /* Chop tail of segment off */
  190. len = 1 + high - ptr;
  191. ptr += len;
  192. sp->wrk->acct_tmp.bodybytes += len;
  193. #ifdef SENDFILE_WORKS
  194. /*
  195. * XXX: the overhead of setting up sendfile is not
  196. * XXX: epsilon and maybe not even delta, so avoid
  197. * XXX: engaging sendfile for small objects.
  198. * XXX: Should use getpagesize() ?
  199. */
  200. if (st->fd >= 0 &&
  201. st->len >= params->sendfile_threshold) {
  202. VSC_C_main->n_objsendfile++;
  203. WRW_Sendfile(sp->wrk, st->fd, st->where + off, len);
  204. continue;
  205. }
  206. #endif /* SENDFILE_WORKS */
  207. VSC_C_main->n_objwrite++;
  208. (void)WRW_Write(sp->wrk, st->ptr + off, len);
  209. }
  210. assert(u == sp->obj->len);
  211. }
  212. /*--------------------------------------------------------------------
  213. * Deliver an object.
  214. * Attempt optimizations like 304 and 206 here.
  215. */
  216. void
  217. RES_WriteObj(struct sess *sp)
  218. {
  219. char *r;
  220. ssize_t low, high;
  221. CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
  222. WRW_Reserve(sp->wrk, &sp->fd);
  223. if (sp->obj->response == 200 &&
  224. sp->http->conds &&
  225. RFC2616_Do_Cond(sp)) {
  226. sp->wantbody = 0;
  227. http_SetResp(sp->wrk->resp, "HTTP/1.1", 304, "Not Modified");
  228. http_Unset(sp->wrk->resp, H_Content_Length);
  229. http_Unset(sp->wrk->resp, H_Transfer_Encoding);
  230. }
  231. /*
  232. * If nothing special planned, we can attempt Range support
  233. */
  234. low = 0;
  235. high = sp->obj->len - 1;
  236. if (
  237. sp->wantbody &&
  238. (sp->wrk->res_mode & RES_LEN) &&
  239. !(sp->wrk->res_mode & (RES_ESI|RES_ESI_CHILD|RES_GUNZIP)) &&
  240. params->http_range_support &&
  241. sp->obj->response == 200 &&
  242. http_GetHdr(sp->http, H_Range, &r))
  243. res_dorange(sp, r, &low, &high);
  244. /*
  245. * Always remove C-E if client don't grok it
  246. */
  247. if (sp->wrk->res_mode & RES_GUNZIP)
  248. http_Unset(sp->wrk->resp, H_Content_Encoding);
  249. /*
  250. * Send HTTP protocol header, unless interior ESI object
  251. */
  252. if (!(sp->wrk->res_mode & RES_ESI_CHILD))
  253. sp->wrk->acct_tmp.hdrbytes +=
  254. http_Write(sp->wrk, sp->wrk->resp, 1);
  255. if (!sp->wantbody)
  256. sp->wrk->res_mode &= ~RES_CHUNKED;
  257. if (sp->wrk->res_mode & RES_CHUNKED)
  258. WRW_Chunked(sp->wrk);
  259. if (!sp->wantbody) {
  260. /* This was a HEAD or conditional request */
  261. } else if (sp->obj->len == 0) {
  262. /* Nothing to do here */
  263. } else if (sp->wrk->res_mode & RES_ESI) {
  264. ESI_Deliver(sp);
  265. } else if (sp->wrk->res_mode & RES_ESI_CHILD && sp->wrk->gzip_resp) {
  266. ESI_DeliverChild(sp);
  267. } else if (sp->wrk->res_mode & RES_GUNZIP) {
  268. res_WriteGunzipObj(sp);
  269. } else {
  270. res_WriteDirObj(sp, low, high);
  271. }
  272. if (sp->wrk->res_mode & RES_CHUNKED &&
  273. !(sp->wrk->res_mode & RES_ESI_CHILD))
  274. WRW_EndChunk(sp->wrk);
  275. if (WRW_FlushRelease(sp->wrk))
  276. vca_close_session(sp, "remote closed");
  277. }
  278. /*--------------------------------------------------------------------*/
  279. void
  280. RES_StreamStart(struct sess *sp)
  281. {
  282. struct stream_ctx *sctx;
  283. sctx = sp->wrk->sctx;
  284. CHECK_OBJ_NOTNULL(sctx, STREAM_CTX_MAGIC);
  285. AZ(sp->wrk->res_mode & RES_ESI_CHILD);
  286. AN(sp->wantbody);
  287. WRW_Reserve(sp->wrk, &sp->fd);
  288. /*
  289. * Always remove C-E if client don't grok it
  290. */
  291. if (sp->wrk->res_mode & RES_GUNZIP)
  292. http_Unset(sp->wrk->resp, H_Content_Encoding);
  293. if (!(sp->wrk->res_mode & RES_CHUNKED) &&
  294. sp->wrk->h_content_length != NULL)
  295. http_PrintfHeader(sp->wrk, sp->fd, sp->wrk->resp,
  296. "Content-Length: %s", sp->wrk->h_content_length);
  297. sp->wrk->acct_tmp.hdrbytes +=
  298. http_Write(sp->wrk, sp->wrk->resp, 1);
  299. if (sp->wrk->res_mode & RES_CHUNKED)
  300. WRW_Chunked(sp->wrk);
  301. }
  302. void
  303. RES_StreamPoll(const struct sess *sp)
  304. {
  305. struct stream_ctx *sctx;
  306. struct storage *st;
  307. ssize_t l, l2;
  308. void *ptr;
  309. sctx = sp->wrk->sctx;
  310. CHECK_OBJ_NOTNULL(sctx, STREAM_CTX_MAGIC);
  311. if (sp->obj->len == sctx->stream_next)
  312. return;
  313. assert(sp->obj->len > sctx->stream_next);
  314. l = sctx->stream_front;
  315. VTAILQ_FOREACH(st, &sp->obj->store, list) {
  316. if (st->len + l <= sctx->stream_next) {
  317. l += st->len;
  318. continue;
  319. }
  320. l2 = st->len + l - sctx->stream_next;
  321. ptr = st->ptr + (sctx->stream_next - l);
  322. if (sp->wrk->res_mode & RES_GUNZIP) {
  323. (void)VGZ_WrwGunzip(sp, sctx->vgz, ptr, l2,
  324. sctx->obuf, sctx->obuf_len, &sctx->obuf_ptr);
  325. } else {
  326. (void)WRW_Write(sp->wrk, ptr, l2);
  327. }
  328. l += st->len;
  329. sctx->stream_next += l2;
  330. }
  331. if (!(sp->wrk->res_mode & RES_GUNZIP))
  332. (void)WRW_Flush(sp->wrk);
  333. if (sp->obj->objcore == NULL ||
  334. (sp->obj->objcore->flags & OC_F_PASS)) {
  335. /*
  336. * This is a pass object, release storage as soon as we
  337. * have delivered it.
  338. */
  339. while (1) {
  340. st = VTAILQ_FIRST(&sp->obj->store);
  341. if (st == NULL ||
  342. sctx->stream_front + st->len > sctx->stream_next)
  343. break;
  344. VTAILQ_REMOVE(&sp->obj->store, st, list);
  345. sctx->stream_front += st->len;
  346. STV_free(st);
  347. }
  348. }
  349. }
  350. void
  351. RES_StreamEnd(struct sess *sp)
  352. {
  353. struct stream_ctx *sctx;
  354. sctx = sp->wrk->sctx;
  355. CHECK_OBJ_NOTNULL(sctx, STREAM_CTX_MAGIC);
  356. if (sp->wrk->res_mode & RES_GUNZIP && sctx->obuf_ptr > 0)
  357. (void)WRW_Write(sp->wrk, sctx->obuf, sctx->obuf_ptr);
  358. if (sp->wrk->res_mode & RES_CHUNKED &&
  359. !(sp->wrk->res_mode & RES_ESI_CHILD))
  360. WRW_EndChunk(sp->wrk);
  361. if (WRW_FlushRelease(sp->wrk))
  362. vca_close_session(sp, "remote closed");
  363. }