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