source: bin/varnishd/cache_fetch.c @ 28d4a2d

Revision 28d4a2d, 6.2 KB checked in by Poul-Henning Kamp <phk@…>, 8 years ago (diff)

304's don't have a body

git-svn-id:  http://www.varnish-cache.org/svn/trunk/varnish-cache@246 d4fa192b-c00b-0410-8231-f00ffab90ce4

  • Property mode set to 100644
Line 
1/*
2 * $Id$
3 */
4
5#include <assert.h>
6#include <stdio.h>
7#include <ctype.h>
8#include <inttypes.h>
9#include <unistd.h>
10#include <string.h>
11#include <stdlib.h>
12#include <fcntl.h>
13#include <pthread.h>
14#include <sys/queue.h>
15#include <sys/types.h>
16#include <sys/socket.h>
17#include <netdb.h>
18#include <sbuf.h>
19#include <event.h>
20
21#include "libvarnish.h"
22#include "shmlog.h"
23#include "cache.h"
24
25/*
26 * Chunked encoding is a hack.  We prefer to have a single or a few
27 * large storage objects, and a terribly long list of small ones.
28 * If our stevedore can trim, we alloc big chunks and trim the last one
29 * at the end know the result.
30 *
31 * Good testcase: http://www.washingtonpost.com/
32 */
33#define CHUNK_PREALLOC          (128 * 1024)
34
35/*--------------------------------------------------------------------*/
36static int
37fetch_straight(struct worker *w, struct sess *sp, int fd, struct http *hp, char *b)
38{
39        int i;
40        char *e;
41        unsigned char *p;
42        off_t   cl;
43        struct storage *st;
44
45        cl = strtoumax(b, NULL, 0);
46
47        st = stevedore->alloc(stevedore, cl);
48        TAILQ_INSERT_TAIL(&sp->obj->store, st, list);
49        st->len = cl;
50        sp->obj->len = cl;
51        p = st->ptr;
52
53        i = fcntl(fd, F_GETFL);         /* XXX ? */
54        i &= ~O_NONBLOCK;
55        i = fcntl(fd, F_SETFL, i);
56
57        if (http_GetTail(hp, cl, &b, &e)) {
58                i = e - b;
59                memcpy(p, b, i);
60                p += i;
61                cl -= i;
62        }
63
64        while (cl != 0) {
65                i = read(fd, p, cl);
66                assert(i > 0);
67                p += i;
68                cl -= i;
69        }
70        return (0);
71}
72
73/*--------------------------------------------------------------------*/
74/* XXX: Cleanup.  It must be possible somehow :-( */
75
76static int
77fetch_chunked(struct worker *w, struct sess *sp, int fd, struct http *hp)
78{
79        int i;
80        char *b, *q, *e;
81        unsigned char *p;
82        struct storage *st;
83        unsigned u, v;
84        char buf[20];
85        char *bp, *be;
86
87        i = fcntl(fd, F_GETFL);         /* XXX ? */
88        i &= ~O_NONBLOCK;
89        i = fcntl(fd, F_SETFL, i);
90
91        be = buf + sizeof buf;
92        bp = buf;
93        st = NULL;
94        while (1) {
95                if (http_GetTail(hp, be - bp, &b, &e)) {
96                        memcpy(bp, b, e - b);
97                        bp += e - b;
98                        *bp = '\0';
99                } else {
100                        i = read(fd, bp, be - bp);
101                        assert(i >= 0);
102                        bp += i;
103                        *bp = '\0';
104                }
105                u = strtoul(buf, &q, 16);
106                if (q == NULL || q == buf)
107                        continue;
108                assert(isspace(*q));
109                while (*q == '\t' || *q == ' ')
110                        q++;
111                if (*q == '\r')
112                        q++;
113                assert(*q == '\n');
114                q++;
115                if (u == 0)
116                        break;
117                sp->obj->len += u;
118
119                while (u > 0) {
120                        if (st != NULL && st->len < st->space) {
121                                p = st->ptr + st->len;
122                        } else {
123                                st = stevedore->alloc(stevedore,
124                                    stevedore->trim == NULL ? u : CHUNK_PREALLOC);
125                                TAILQ_INSERT_TAIL(&sp->obj->store, st, list);
126                                p = st->ptr;
127                        }
128                        v = st->space - st->len;
129                        if (v > u)
130                                v = u;
131
132                        i = bp - q;
133                        if (i == 0) {
134                        } else if (v > i) {
135                                assert(i > 0);
136                                memcpy(p, q, i);
137                                p += i;
138                                st->len += i;
139                                u -= i;
140                                v -= i;
141                                q = bp = buf;
142                        } else if (i >= v) {
143                                memcpy(p, q, v);
144                                p += v;
145                                st->len += i;
146                                q += v;
147                                u -= v;
148                                v -= v;
149                                if (u == 0 && bp > q) {
150                                        memcpy(buf, q, bp - q);
151                                        q = bp = buf + (bp - q);
152                                }
153                        }
154                        if (u == 0)
155                                break;
156                        if (v == 0)
157                                continue;
158                        if (http_GetTail(hp, v, &b, &e)) {
159                                memcpy(p, b, e - b);
160                                p += e - b;
161                                st->len += e - b;
162                                v -= e - b;
163                                u -= e - b;
164                        }
165                        while (v > 0) {
166                                i = read(fd, p, v);
167                                assert(i > 0);
168                                st->len += i;
169                                v -= i;
170                                u -= i;
171                                p += i;
172                        }
173                }
174        }
175
176        if (st != NULL && stevedore->trim != NULL)
177                stevedore->trim(st, st->len);
178        return (0);
179}
180
181
182/*--------------------------------------------------------------------*/
183
184#include <errno.h>
185
186static int
187fetch_eof(struct worker *w, struct sess *sp, int fd, struct http *hp)
188{
189        int i;
190        char *b, *e;
191        unsigned char *p;
192        struct storage *st;
193        unsigned v;
194
195        i = fcntl(fd, F_GETFL);         /* XXX ? */
196        i &= ~O_NONBLOCK;
197        i = fcntl(fd, F_SETFL, i);
198
199        p = NULL;
200        v = 0;
201        while (1) {
202                if (v == 0) {
203                        st = stevedore->alloc(stevedore, CHUNK_PREALLOC);
204                        TAILQ_INSERT_TAIL(&sp->obj->store, st, list);
205                        p = st->ptr + st->len;
206                        v = st->space - st->len;
207                }
208                if (http_GetTail(hp, v, &b, &e)) {
209                        memcpy(p, b, e - b);
210                        p += e - b;
211                        v -= e - b;
212                        st->len += e - b;
213                        *p = '\0';
214                }
215                i = read(fd, p, v);
216                assert(i >= 0);
217                if (i == 0)
218                     break;
219                p += i;
220                v -= i;
221                st->len += i;
222        }
223
224        if (st != NULL && stevedore->trim != NULL)
225                stevedore->trim(st, st->len);
226
227        return (1);
228}
229
230/*--------------------------------------------------------------------*/
231int
232FetchSession(struct worker *w, struct sess *sp)
233{
234        int fd, i, cls;
235        void *fd_token;
236        struct http *hp;
237        char *b;
238        time_t t_req, t_resp;
239        int body;
240
241        fd = VBE_GetFd(sp->backend, &fd_token);
242        assert(fd != -1);
243        VSL(SLT_Backend, sp->fd, "%d %s", fd, sp->backend->vcl_name);
244
245        hp = http_New();
246        http_BuildSbuf(1, w->sb, sp->http);
247        i = write(fd, sbuf_data(w->sb), sbuf_len(w->sb));
248        assert(i == sbuf_len(w->sb));
249        time(&t_req);
250
251        /* XXX: copy any contents */
252
253        /*
254         * XXX: It might be cheaper to avoid the event_engine and simply
255         * XXX: read(2) the header
256         */
257        http_RecvHead(hp, fd, w->eb, NULL, NULL);
258        event_base_loop(w->eb, 0);
259        time(&t_resp);
260        http_Dissect(hp, fd, 2);
261
262        switch (http_GetStatus(hp)) {
263        case 200:
264        case 301:
265                http_BuildSbuf(3, w->sb, hp);
266                /* XXX: fill in object from headers */
267                sp->obj->valid = 1;
268                sp->obj->cacheable = 1;
269                sp->obj->header = strdup(sbuf_data(w->sb));
270                body = 1;
271                break;
272        case 304:
273                http_BuildSbuf(3, w->sb, hp);
274                /* XXX: fill in object from headers */
275                sp->obj->valid = 1;
276                sp->obj->cacheable = 1;
277                sp->obj->header = strdup(sbuf_data(w->sb));
278                body = 0;
279                break;
280        case 391:
281                sp->obj->valid = 0;
282                sp->obj->cacheable = 0;
283                break;
284        default:
285                break;
286        }
287
288        sp->obj->ttl = RFC2616_Ttl(hp, t_req, t_resp);
289        if (sp->obj->ttl == 0) {
290                sp->obj->cacheable = 0;
291        }
292
293        VCL_fetch_method(sp);
294
295        if (sp->obj->cacheable)
296                EXP_Insert(sp->obj);
297
298        if (body) {
299                if (http_GetHdr(hp, "Content-Length", &b))
300                        cls = fetch_straight(w, sp, fd, hp, b);
301                else if (http_HdrIs(hp, "Transfer-Encoding", "chunked"))
302                        cls = fetch_chunked(w, sp, fd, hp);
303                else 
304                        cls = fetch_eof(w, sp, fd, hp);
305        } else
306                cls = 0;
307
308        http_BuildSbuf(2, w->sb, hp);
309
310        vca_write_obj(sp, w->sb);
311
312        if (http_GetHdr(hp, "Connection", &b) && !strcasecmp(b, "close"))
313                cls = 1;
314
315        if (cls)
316                VBE_ClosedFd(fd_token);
317        else
318                VBE_RecycleFd(fd_token);
319
320        HSH_Unbusy(sp->obj);
321        if (!sp->obj->cacheable)
322                HSH_Deref(sp->obj);
323
324        return (1);
325}
Note: See TracBrowser for help on using the repository browser.