varnish-cache/bin/varnishd/http1/cache_http1_fsm.c
1
/*-
2
 * Copyright (c) 2006 Verdens Gang AS
3
 * Copyright (c) 2006-2015 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
 * This file contains the two central state machine for pushing HTTP1
30
 * sessions through their states.
31
 *
32
 */
33
34
#include "config.h"
35
36
#include "cache/cache_varnishd.h"
37
38
#include <stdio.h>
39
#include <stdlib.h>
40
41
#include "cache/cache_objhead.h"
42
#include "cache/cache_transport.h"
43
#include "cache_http1.h"
44
45
#include "vtcp.h"
46
47
static const char H1NEWREQ[] = "HTTP1::NewReq";
48
static const char H1PROC[] = "HTTP1::Proc";
49
static const char H1CLEANUP[] = "HTTP1::Cleanup";
50
51
static void HTTP1_Session(struct worker *, struct req *);
52
53
static void
54 68520
http1_setstate(const struct sess *sp, const char *s)
55
{
56
        uintptr_t p;
57
58 68520
        p = (uintptr_t)s;
59 68520
        AZ(SES_Set_proto_priv(sp, &p));
60 68520
}
61
62
static const char *
63 81394
http1_getstate(const struct sess *sp)
64
{
65
        uintptr_t *p;
66
67 81394
        AZ(SES_Get_proto_priv(sp, &p));
68 81392
        return ((const char *)*p);
69
}
70
71
/*--------------------------------------------------------------------
72
 * Call protocol for this request
73
 */
74
75
static void v_matchproto_(task_func_t)
76 13218
http1_req(struct worker *wrk, void *arg)
77
{
78
        struct req *req;
79
80 13218
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
81 13218
        CAST_OBJ_NOTNULL(req, arg, REQ_MAGIC);
82
83 13218
        THR_SetRequest(req);
84 13218
        req->transport = &HTTP1_transport;
85 13218
        AZ(wrk->aws->r);
86 13218
        HTTP1_Session(wrk, req);
87 13218
        AZ(wrk->v1l);
88 13186
        WS_Assert(wrk->aws);
89 13186
        THR_SetRequest(NULL);
90 13186
}
91
92
/*--------------------------------------------------------------------
93
 * Call protocol for this session (new or from waiter)
94
 *
95
 * When sessions are rescheduled from the waiter, a struct pool_task
96
 * is put on the reserved session workspace (for reasons of memory
97
 * conservation).  This reservation is released as the first thing.
98
 * The acceptor and any other code which schedules this function
99
 * must obey this calling convention with a dummy reservation.
100
 */
101
102
static void v_matchproto_(task_func_t)
103 11938
http1_new_session(struct worker *wrk, void *arg)
104
{
105
        struct sess *sp;
106
        struct req *req;
107
        uintptr_t *u;
108
109 11938
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
110 11944
        CAST_OBJ_NOTNULL(req, arg, REQ_MAGIC);
111 11944
        sp = req->sp;
112 11944
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
113
114 11944
        HTC_RxInit(req->htc, req->ws);
115 11944
        SES_Reserve_proto_priv(sp, &u);
116 11944
        http1_setstate(sp, H1NEWREQ);
117 11944
        wrk->task.func = http1_req;
118 11944
        wrk->task.priv = req;
119 11944
}
120
121
static void v_matchproto_(task_func_t)
122 1024
http1_unwait(struct worker *wrk, void *arg)
123
{
124
        struct sess *sp;
125
        struct req *req;
126
127 1024
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
128 1024
        CAST_OBJ_NOTNULL(sp, arg, SESS_MAGIC);
129 1024
        WS_Release(sp->ws, 0);
130 1024
        req = Req_New(wrk, sp);
131 1024
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
132 1024
        req->htc->rfd = &sp->fd;
133 1024
        HTC_RxInit(req->htc, req->ws);
134 1024
        http1_setstate(sp, H1NEWREQ);
135 1024
        wrk->task.func = http1_req;
136 1024
        wrk->task.priv = req;
137 1024
}
138
139
static void v_matchproto_(vtr_req_body_t)
140 352
http1_req_body(struct req *req)
141
{
142
143 352
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
144 352
        switch (req->htc->body_status) {
145
        case BS_EOF:
146
        case BS_LENGTH:
147
        case BS_CHUNKED:
148 352
                if (V1F_Setup_Fetch(req->vfc, req->htc) != 0)
149 0
                        req->req_body_status = REQ_BODY_FAIL;
150 352
                break;
151
        default:
152 0
                break;
153
        }
154 352
}
155
156
static void
157 32
http1_sess_panic(struct vsb *vsb, const struct sess *sp)
158
{
159
160 32
        VSB_printf(vsb, "state = %s\n", http1_getstate(sp));
161 32
}
162
163
static void
164 24
http1_req_panic(struct vsb *vsb, const struct req *req)
165
{
166
167 24
        VSB_printf(vsb, "state = %s\n", http1_getstate(req->sp));
168 24
}
169
170
static void v_matchproto_(vtr_req_fail_f)
171 136
http1_req_fail(struct req *req, enum sess_close reason)
172
{
173 136
        assert(reason > 0);
174 136
        assert(req->sp->fd != 0);
175 136
        if (req->sp->fd > 0)
176 128
                SES_Close(req->sp, reason);
177 136
}
178
179
static int v_matchproto_(vtr_minimal_response_f)
180 288
http1_minimal_response(struct req *req, uint16_t status)
181
{
182
        ssize_t wl, l;
183
        char buf[80];
184
        const char *reason;
185
186 288
        assert(status >= 100);
187 288
        assert(status < 1000);
188
189 288
        reason = http_Status2Reason(status, NULL);
190
191 576
        l = snprintf(buf, sizeof(buf),
192 288
            "HTTP/1.1 %03d %s\r\n\r\n", status, reason);
193 288
        assert (l < sizeof(buf));
194
195 288
        VSLb(req->vsl, SLT_RespProtocol, "HTTP/1.1");
196 288
        VSLb(req->vsl, SLT_RespStatus, "%03d", status);
197 288
        VSLb(req->vsl, SLT_RespReason, "%s", reason);
198
199 288
        if (status >= 400)
200 248
                req->err_code = status;
201 288
        wl = write(req->sp->fd, buf, l);
202
203 288
        if (wl > 0)
204 288
                req->acct.resp_hdrbytes += wl;
205 288
        if (wl != l) {
206 0
                if (wl < 0)
207 0
                        VTCP_Assert(1);
208 0
                if (!req->doclose)
209 0
                        req->doclose = SC_REM_CLOSE;
210 0
                return (-1);
211
        }
212 288
        return (0);
213 288
}
214
215
struct transport HTTP1_transport = {
216
        .name =                 "HTTP/1",
217
        .proto_ident =          "HTTP",
218
        .magic =                TRANSPORT_MAGIC,
219
        .deliver =              V1D_Deliver,
220
        .minimal_response =     http1_minimal_response,
221
        .new_session =          http1_new_session,
222
        .req_body =             http1_req_body,
223
        .req_fail =             http1_req_fail,
224
        .req_panic =            http1_req_panic,
225
        .sess_panic =           http1_sess_panic,
226
        .unwait =               http1_unwait,
227
};
228
229
/*----------------------------------------------------------------------
230
 */
231
232
static inline void
233 224
http1_abort(struct req *req, uint16_t status)
234
{
235 224
        AN(req->doclose);
236 224
        assert(status >= 400);
237 224
        (void)http1_minimal_response(req, status);
238 224
}
239
240
static int
241 19135
http1_dissect(struct worker *wrk, struct req *req)
242
{
243
244 19135
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
245 19136
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
246 19136
        CHECK_OBJ_NOTNULL(req->transport, TRANSPORT_MAGIC);
247
248
        /* Allocate a new vxid now that we know we'll need it. */
249 19136
        AZ(req->vsl->wid);
250 19136
        req->vsl->wid = VXID_Get(wrk, VSL_CLIENTMARKER);
251
252 19136
        VSLb(req->vsl, SLT_Begin, "req %u rxreq", VXID(req->sp->vxid));
253 19136
        VSL(SLT_Link, req->sp->vxid, "req %u rxreq", VXID(req->vsl->wid));
254 19136
        AZ(isnan(req->t_first)); /* First byte timestamp set by http1_wait */
255 19136
        AZ(isnan(req->t_req));   /* Complete req rcvd set by http1_wait */
256 19136
        req->t_prev = req->t_first;
257 19136
        VSLb_ts_req(req, "Start", req->t_first);
258 19136
        VSLb_ts_req(req, "Req", req->t_req);
259
260 19136
        HTTP_Setup(req->http, req->ws, req->vsl, SLT_ReqMethod);
261 19136
        req->err_code = HTTP1_DissectRequest(req->htc, req->http);
262
263
        /* If we could not even parse the request, just close */
264 19136
        if (req->err_code != 0) {
265 448
                VSLb(req->vsl, SLT_HttpGarbage, "%.*s",
266 224
                    (int)(req->htc->rxbuf_e - req->htc->rxbuf_b),
267 224
                    req->htc->rxbuf_b);
268 224
                wrk->stats->client_req_400++;
269 224
                req->doclose = SC_RX_JUNK;
270 224
                http1_abort(req, 400);
271 224
                return (-1);
272
        }
273
274 18912
        assert (req->req_body_status == REQ_BODY_INIT);
275
276 18912
        switch (req->htc->body_status) {
277
        case BS_CHUNKED:
278 48
                req->req_body_status = REQ_BODY_WITHOUT_LEN;
279 48
                break;
280
        case BS_LENGTH:
281 312
                req->req_body_status = REQ_BODY_WITH_LEN;
282 312
                break;
283
        case BS_NONE:
284 18552
                req->req_body_status = REQ_BODY_NONE;
285 18552
                break;
286
        case BS_EOF:
287 0
                req->req_body_status = REQ_BODY_WITHOUT_LEN;
288 0
                break;
289
        default:
290 0
                WRONG("Unknown req_body_status situation");
291 0
        }
292 18912
        return (0);
293 19136
}
294
295
/*----------------------------------------------------------------------
296
 */
297
298
static void
299 13201
HTTP1_Session(struct worker *wrk, struct req *req)
300
{
301
        enum htc_status_e hs;
302
        struct sess *sp;
303
        const char *st;
304
        int i;
305
306 13201
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
307 13217
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
308 13218
        sp = req->sp;
309 13218
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
310
311
        /*
312
         * Whenever we come in from the acceptor or waiter, we need to set
313
         * blocking mode.  It would be simpler to do this in the acceptor
314
         * or waiter, but we'd rather do the syscall in the worker thread.
315
         */
316 13218
        if (http1_getstate(sp) == H1NEWREQ)
317 12968
                VTCP_blocking(sp->fd);
318
319 13218
        req->transport = &HTTP1_transport;
320
321 67882
        while (1) {
322 68121
                st = http1_getstate(sp);
323 68121
                if (st == H1NEWREQ) {
324 29936
                        CHECK_OBJ_NOTNULL(req->transport, TRANSPORT_MAGIC);
325 29936
                        assert(isnan(req->t_prev));
326 29936
                        assert(isnan(req->t_req));
327 29936
                        AZ(req->vcl);
328 29936
                        AZ(req->esi_level);
329 29936
                        AN(req->htc->ws->r);
330
331 59872
                        hs = HTC_RxStuff(req->htc, HTTP1_Complete,
332 29936
                            &req->t_first, &req->t_req,
333 29936
                            sp->t_idle + cache_param->timeout_linger,
334 29936
                            sp->t_idle + SESS_TMO(sp, timeout_idle),
335
                            NAN,
336 29936
                            cache_param->http_req_size);
337 29936
                        AZ(req->htc->ws->r);
338 29934
                        if (hs < HTC_S_EMPTY) {
339 8945
                                req->acct.req_hdrbytes +=
340 8945
                                    req->htc->rxbuf_e - req->htc->rxbuf_b;
341 8945
                                Req_AcctLogCharge(wrk->stats, req);
342 8945
                                Req_Release(req);
343 8945
                                switch (hs) {
344
                                case HTC_S_CLOSE:
345 0
                                        SES_Delete(sp, SC_REM_CLOSE, NAN);
346 0
                                        return;
347
                                case HTC_S_TIMEOUT:
348 0
                                        SES_Delete(sp, SC_RX_TIMEOUT, NAN);
349 0
                                        return;
350
                                case HTC_S_OVERFLOW:
351 16
                                        SES_Delete(sp, SC_RX_OVERFLOW, NAN);
352 16
                                        return;
353
                                case HTC_S_EOF:
354 8930
                                        SES_Delete(sp, SC_REM_CLOSE, NAN);
355 8930
                                        return;
356
                                default:
357 0
                                        WRONG("htc_status (bad)");
358 0
                                }
359 0
                        }
360 20989
                        if (hs == HTC_S_IDLE) {
361 1237
                                wrk->stats->sess_herd++;
362 1237
                                Req_Release(req);
363 1237
                                SES_Wait(sp, &HTTP1_transport);
364 1237
                                return;
365
                        }
366 19752
                        if (hs != HTC_S_COMPLETE)
367 0
                                WRONG("htc_status (nonbad)");
368
369 19752
                        if (H2_prism_complete(req->htc) == HTC_S_COMPLETE) {
370 616
                                if (!FEATURE(FEATURE_HTTP2)) {
371 16
                                        SES_Close(req->sp, SC_REQ_HTTP20);
372 16
                                        AZ(req->ws->r);
373 16
                                        AZ(wrk->aws->r);
374 16
                                        http1_setstate(sp, H1CLEANUP);
375 16
                                        continue;
376
                                }
377 600
                                http1_setstate(sp, NULL);
378 600
                                H2_PU_Sess(wrk, sp, req);
379 600
                                return;
380
                        }
381
382 19135
                        i = http1_dissect(wrk, req);
383 19135
                        req->acct.req_hdrbytes +=
384 19135
                            req->htc->rxbuf_e - req->htc->rxbuf_b;
385 19135
                        if (i) {
386 224
                                assert(req->doclose > 0);
387 224
                                SES_Close(req->sp, req->doclose);
388 224
                                AZ(req->ws->r);
389 224
                                AZ(wrk->aws->r);
390 224
                                http1_setstate(sp, H1CLEANUP);
391 224
                                continue;
392
                        }
393 18912
                        if (http_HdrIs(req->http, H_Upgrade, "h2c")) {
394 64
                                if (!FEATURE(FEATURE_HTTP2)) {
395 8
                                        VSLb(req->vsl, SLT_Debug,
396
                                            "H2 upgrade attempt");
397 64
                                } else if (req->htc->body_status != BS_NONE) {
398 8
                                        VSLb(req->vsl, SLT_Debug,
399
                                            "H2 upgrade attempt has body");
400 8
                                } else {
401 48
                                        http1_setstate(sp, NULL);
402 48
                                        req->err_code = 2;
403 48
                                        H2_OU_Sess(wrk, sp, req);
404 48
                                        return;
405
                                }
406 16
                        }
407 18864
                        req->req_step = R_STP_TRANSPORT;
408 18864
                        http1_setstate(sp, H1PROC);
409 57050
                } else if (st == H1PROC) {
410 19114
                        req->task.func = http1_req;
411 19114
                        req->task.priv = req;
412 19114
                        wrk->stats->client_req++;
413 19114
                        CNT_Embark(wrk, req);
414 19114
                        if (req->req_step == R_STP_TRANSPORT)
415 18864
                                VCL_TaskEnter(req->vcl, req->privs);
416 19114
                        if (CNT_Request(req) == REQ_FSM_DISEMBARK)
417 250
                                return;
418 18832
                        AZ(req->vcl0);
419 18832
                        req->task.func = NULL;
420 18832
                        req->task.priv = NULL;
421 18832
                        AZ(req->ws->r);
422 18832
                        AZ(wrk->aws->r);
423 18832
                        http1_setstate(sp, H1CLEANUP);
424 37904
                } else if (st == H1CLEANUP) {
425
426 19072
                        AZ(wrk->aws->r);
427 19072
                        AZ(req->ws->r);
428
429 19072
                        if (sp->fd >= 0 && req->doclose != SC_NULL)
430 1616
                                SES_Close(sp, req->doclose);
431
432 19072
                        if (sp->fd < 0) {
433 2104
                                wrk->stats->sess_closed++;
434 2104
                                Req_Cleanup(sp, wrk, req);
435 2104
                                Req_Release(req);
436 2104
                                SES_Delete(sp, SC_NULL, NAN);
437 2104
                                return;
438
                        }
439
440 16968
                        Req_Cleanup(sp, wrk, req);
441 16968
                        HTC_RxInit(req->htc, req->ws);
442 16968
                        if (req->htc->rxbuf_e != req->htc->rxbuf_b)
443 118
                                wrk->stats->sess_readahead++;
444 16968
                        http1_setstate(sp, H1NEWREQ);
445 16968
                } else {
446 0
                        WRONG("Wrong H1 session state");
447
                }
448
        }
449 13186
}