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
 * SPDX-License-Identifier: BSD-2-Clause
9
 *
10
 * Redistribution and use in source and binary forms, with or without
11
 * modification, are permitted provided that the following conditions
12
 * are met:
13
 * 1. Redistributions of source code must retain the above copyright
14
 *    notice, this list of conditions and the following disclaimer.
15
 * 2. Redistributions in binary form must reproduce the above copyright
16
 *    notice, this list of conditions and the following disclaimer in the
17
 *    documentation and/or other materials provided with the distribution.
18
 *
19
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
23
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
 * SUCH DAMAGE.
30
 *
31
 * This file contains the two central state machine for pushing HTTP1
32
 * sessions through their states.
33
 *
34
 */
35
36
#include "config.h"
37
38
#include "cache/cache_varnishd.h"
39
40
#include <stdio.h>
41
#include <stdlib.h>
42
43
#include "cache/cache_objhead.h"
44
#include "cache/cache_transport.h"
45
#include "cache_http1.h"
46
47
#include "vtcp.h"
48
49
static const char H1NEWREQ[] = "HTTP1::NewReq";
50
static const char H1PROC[] = "HTTP1::Proc";
51
static const char H1CLEANUP[] = "HTTP1::Cleanup";
52
53
static void HTTP1_Session(struct worker *, struct req *);
54
55
static void
56 9521
http1_setstate(const struct sess *sp, const char *s)
57
{
58
        uintptr_t p;
59
60 9521
        p = (uintptr_t)s;
61 9521
        AZ(SES_Set_proto_priv(sp, &p));
62 9521
}
63
64
static const char *
65 11321
http1_getstate(const struct sess *sp)
66
{
67
        uintptr_t *p;
68
69 11321
        AZ(SES_Get_proto_priv(sp, &p));
70 11323
        return ((const char *)*p);
71
}
72
73
/*--------------------------------------------------------------------
74
 * Call protocol for this request
75
 */
76
77
static void v_matchproto_(task_func_t)
78 1841
http1_req(struct worker *wrk, void *arg)
79
{
80
        struct req *req;
81
82 1841
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
83 1841
        CAST_OBJ_NOTNULL(req, arg, REQ_MAGIC);
84
85 1841
        THR_SetRequest(req);
86 1841
        req->transport = &HTTP1_transport;
87 1841
        AZ(wrk->aws->r);
88 1841
        HTTP1_Session(wrk, req);
89 1841
        AZ(wrk->v1l);
90 1837
        WS_Assert(wrk->aws);
91 1837
        THR_SetRequest(NULL);
92 1837
}
93
94
/*--------------------------------------------------------------------
95
 * Call protocol for this session (new or from waiter)
96
 *
97
 * When sessions are rescheduled from the waiter, a struct pool_task
98
 * is put on the reserved session workspace (for reasons of memory
99
 * conservation).  This reservation is released as the first thing.
100
 * The acceptor and any other code which schedules this function
101
 * must obey this calling convention with a dummy reservation.
102
 */
103
104
static void v_matchproto_(task_func_t)
105 1675
http1_new_session(struct worker *wrk, void *arg)
106
{
107
        struct sess *sp;
108
        struct req *req;
109
        uintptr_t *u;
110
111 1675
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
112 1677
        CAST_OBJ_NOTNULL(req, arg, REQ_MAGIC);
113 1677
        sp = req->sp;
114 1677
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
115
116 1677
        HTC_RxInit(req->htc, req->ws);
117 1677
        if (!SES_Reserve_proto_priv(sp, &u)) {
118
                /* Out of session workspace. Free the req, close the sess,
119
                 * and do not set a new task func, which will exit the
120
                 * worker thread. */
121 0
                VSL(SLT_Error, req->sp->vxid, "insufficient workspace");
122 0
                Req_Release(req);
123 0
                SES_Delete(sp, SC_RX_JUNK, NAN);
124 0
                return;
125
        }
126 1677
        http1_setstate(sp, H1NEWREQ);
127 1677
        wrk->task->func = http1_req;
128 1677
        wrk->task->priv = req;
129 1677
}
130
131
static void v_matchproto_(task_func_t)
132 130
http1_unwait(struct worker *wrk, void *arg)
133
{
134
        struct sess *sp;
135
        struct req *req;
136
137 130
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
138 130
        CAST_OBJ_NOTNULL(sp, arg, SESS_MAGIC);
139 130
        WS_Release(sp->ws, 0);
140 130
        req = Req_New(wrk, sp);
141 130
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
142 130
        req->htc->rfd = &sp->fd;
143 130
        HTC_RxInit(req->htc, req->ws);
144 130
        http1_setstate(sp, H1NEWREQ);
145 130
        wrk->task->func = http1_req;
146 130
        wrk->task->priv = req;
147 130
}
148
149
static void v_matchproto_(vtr_req_body_t)
150 45
http1_req_body(struct req *req)
151
{
152
153 45
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
154 45
        if (V1F_Setup_Fetch(req->vfc, req->htc) != 0)
155 0
                req->req_body_status = BS_ERROR;
156 45
}
157
158
static void
159 4
http1_sess_panic(struct vsb *vsb, const struct sess *sp)
160
{
161
162 4
        VSB_printf(vsb, "state = %s\n", http1_getstate(sp));
163 4
}
164
165
static void
166 3
http1_req_panic(struct vsb *vsb, const struct req *req)
167
{
168
169 3
        VSB_printf(vsb, "state = %s\n", http1_getstate(req->sp));
170 3
}
171
172
static void v_matchproto_(vtr_req_fail_f)
173 20
http1_req_fail(struct req *req, enum sess_close reason)
174
{
175 20
        assert(reason > 0);
176 20
        assert(req->sp->fd != 0);
177 20
        if (req->sp->fd > 0)
178 19
                SES_Close(req->sp, reason);
179 20
}
180
181
static int v_matchproto_(vtr_minimal_response_f)
182 36
http1_minimal_response(struct req *req, uint16_t status)
183
{
184
        ssize_t wl, l;
185
        char buf[80];
186
        const char *reason;
187
188 36
        assert(status >= 100);
189 36
        assert(status < 1000);
190
191 36
        reason = http_Status2Reason(status, NULL);
192
193 36
        bprintf(buf, "HTTP/1.1 %03d %s\r\n\r\n", status, reason);
194 36
        l = strlen(buf);
195
196 36
        VSLb(req->vsl, SLT_RespProtocol, "HTTP/1.1");
197 36
        VSLb(req->vsl, SLT_RespStatus, "%03d", status);
198 36
        VSLb(req->vsl, SLT_RespReason, "%s", reason);
199
200 36
        if (status >= 400)
201 31
                req->err_code = status;
202 36
        wl = write(req->sp->fd, buf, l);
203
204 36
        if (wl > 0)
205 36
                req->acct.resp_hdrbytes += wl;
206 36
        if (wl != l) {
207 0
                if (wl < 0)
208 0
                        VTCP_Assert(1);
209 0
                if (!req->doclose)
210 0
                        req->doclose = SC_REM_CLOSE;
211 0
                return (-1);
212
        }
213 36
        return (0);
214 36
}
215
216
struct transport HTTP1_transport = {
217
        .name =                 "HTTP/1",
218
        .proto_ident =          "HTTP",
219
        .magic =                TRANSPORT_MAGIC,
220
        .deliver =              V1D_Deliver,
221
        .minimal_response =     http1_minimal_response,
222
        .new_session =          http1_new_session,
223
        .req_body =             http1_req_body,
224
        .req_fail =             http1_req_fail,
225
        .req_panic =            http1_req_panic,
226
        .sess_panic =           http1_sess_panic,
227
        .unwait =               http1_unwait,
228
};
229
230
/*----------------------------------------------------------------------
231
 */
232
233
static inline void
234 28
http1_abort(struct req *req, uint16_t status)
235
{
236 28
        AN(req->doclose);
237 28
        assert(status >= 400);
238 28
        (void)http1_minimal_response(req, status);
239 28
}
240
241
static int
242 2652
http1_dissect(struct worker *wrk, struct req *req)
243
{
244
245 2652
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
246 2652
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
247 2652
        CHECK_OBJ_NOTNULL(req->transport, TRANSPORT_MAGIC);
248
249
        /* Allocate a new vxid now that we know we'll need it. */
250 2652
        AZ(req->vsl->wid);
251 2652
        req->vsl->wid = VXID_Get(wrk, VSL_CLIENTMARKER);
252
253 2652
        VSLb(req->vsl, SLT_Begin, "req %u rxreq", VXID(req->sp->vxid));
254 2652
        VSL(SLT_Link, req->sp->vxid, "req %u rxreq", VXID(req->vsl->wid));
255 2652
        AZ(isnan(req->t_first)); /* First byte timestamp set by http1_wait */
256 2652
        AZ(isnan(req->t_req));   /* Complete req rcvd set by http1_wait */
257 2652
        req->t_prev = req->t_first;
258 2652
        VSLb_ts_req(req, "Start", req->t_first);
259 2652
        VSLb_ts_req(req, "Req", req->t_req);
260
261 2652
        HTTP_Setup(req->http, req->ws, req->vsl, SLT_ReqMethod);
262 2652
        req->err_code = HTTP1_DissectRequest(req->htc, req->http);
263
264
        /* If we could not even parse the request, just close */
265 2652
        if (req->err_code != 0) {
266 56
                VSLb(req->vsl, SLT_HttpGarbage, "%.*s",
267 28
                    (int)(req->htc->rxbuf_e - req->htc->rxbuf_b),
268 28
                    req->htc->rxbuf_b);
269 28
                wrk->stats->client_req_400++;
270 28
                req->doclose = SC_RX_JUNK;
271 28
                http1_abort(req, 400);
272 28
                return (-1);
273
        }
274
275 2624
        AZ(req->req_body_status);
276 2624
        req->req_body_status = req->htc->body_status;
277 2624
        return (0);
278 2652
}
279
280
/*----------------------------------------------------------------------
281
 */
282
283
static void
284 1841
HTTP1_Session(struct worker *wrk, struct req *req)
285
{
286
        enum htc_status_e hs;
287
        struct sess *sp;
288
        const char *st;
289
        int i;
290
291 1841
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
292 1841
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
293 1841
        sp = req->sp;
294 1841
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
295
296
        /*
297
         * Whenever we come in from the acceptor or waiter, we need to set
298
         * blocking mode.  It would be simpler to do this in the acceptor
299
         * or waiter, but we'd rather do the syscall in the worker thread.
300
         */
301 1841
        if (http1_getstate(sp) == H1NEWREQ)
302 1807
                VTCP_blocking(sp->fd);
303
304 1841
        req->transport = &HTTP1_transport;
305
306 9445
        while (1) {
307 9475
                st = http1_getstate(sp);
308 9475
                if (st == H1NEWREQ) {
309 4179
                        CHECK_OBJ_NOTNULL(req->transport, TRANSPORT_MAGIC);
310 4179
                        assert(isnan(req->t_prev));
311 4179
                        assert(isnan(req->t_req));
312 4178
                        AZ(req->vcl);
313 4179
                        AZ(req->esi_level);
314 4179
                        AN(req->htc->ws->r);
315
316 8358
                        hs = HTC_RxStuff(req->htc, HTTP1_Complete,
317 4179
                            &req->t_first, &req->t_req,
318 4179
                            sp->t_idle + SESS_TMO(sp, timeout_linger),
319 4179
                            sp->t_idle + SESS_TMO(sp, timeout_idle),
320
                            NAN,
321 4179
                            cache_param->http_req_size);
322 4179
                        AZ(req->htc->ws->r);
323 4179
                        if (hs < HTC_S_EMPTY) {
324 1292
                                req->acct.req_hdrbytes +=
325 1292
                                    req->htc->rxbuf_e - req->htc->rxbuf_b;
326 1292
                                Req_AcctLogCharge(wrk->stats, req);
327 1292
                                Req_Release(req);
328 1292
                                switch (hs) {
329
                                case HTC_S_CLOSE:
330 0
                                        SES_Delete(sp, SC_REM_CLOSE, NAN);
331 0
                                        return;
332
                                case HTC_S_TIMEOUT:
333 0
                                        SES_Delete(sp, SC_RX_TIMEOUT, NAN);
334 0
                                        return;
335
                                case HTC_S_OVERFLOW:
336 2
                                        SES_Delete(sp, SC_RX_OVERFLOW, NAN);
337 2
                                        return;
338
                                case HTC_S_EOF:
339 1290
                                        SES_Delete(sp, SC_REM_CLOSE, NAN);
340 1290
                                        return;
341
                                default:
342 0
                                        WRONG("htc_status (bad)");
343 0
                                }
344 0
                        }
345 2887
                        if (hs == HTC_S_IDLE) {
346 159
                                wrk->stats->sess_herd++;
347 159
                                Req_Release(req);
348 159
                                SES_Wait(sp, &HTTP1_transport);
349 159
                                return;
350
                        }
351 2728
                        if (hs != HTC_S_COMPLETE)
352 0
                                WRONG("htc_status (nonbad)");
353
354 2728
                        if (H2_prism_complete(req->htc) == HTC_S_COMPLETE) {
355 76
                                if (!FEATURE(FEATURE_HTTP2)) {
356 2
                                        SES_Close(req->sp, SC_REQ_HTTP20);
357 2
                                        AZ(req->ws->r);
358 2
                                        AZ(wrk->aws->r);
359 2
                                        http1_setstate(sp, H1CLEANUP);
360 2
                                        continue;
361
                                }
362 74
                                http1_setstate(sp, NULL);
363 74
                                H2_PU_Sess(wrk, sp, req);
364 74
                                return;
365
                        }
366
367 2652
                        i = http1_dissect(wrk, req);
368 2652
                        req->acct.req_hdrbytes +=
369 2652
                            req->htc->rxbuf_e - req->htc->rxbuf_b;
370 2652
                        if (i) {
371 28
                                assert(req->doclose > 0);
372 28
                                SES_Close(req->sp, req->doclose);
373 28
                                AZ(req->ws->r);
374 28
                                AZ(wrk->aws->r);
375 28
                                http1_setstate(sp, H1CLEANUP);
376 28
                                continue;
377
                        }
378 2624
                        if (http_HdrIs(req->http, H_Upgrade, "h2c")) {
379 8
                                if (!FEATURE(FEATURE_HTTP2)) {
380 1
                                        VSLb(req->vsl, SLT_Debug,
381
                                            "H2 upgrade attempt");
382 8
                                } else if (req->htc->body_status != BS_NONE) {
383 1
                                        VSLb(req->vsl, SLT_Debug,
384
                                            "H2 upgrade attempt has body");
385 1
                                } else {
386 6
                                        http1_setstate(sp, NULL);
387 6
                                        req->err_code = 2;
388 6
                                        H2_OU_Sess(wrk, sp, req);
389 6
                                        return;
390
                                }
391 2
                        }
392 2618
                        req->req_step = R_STP_TRANSPORT;
393 2618
                        http1_setstate(sp, H1PROC);
394 7914
                } else if (st == H1PROC) {
395 2652
                        req->task->func = http1_req;
396 2652
                        req->task->priv = req;
397 2652
                        wrk->stats->client_req++;
398 2652
                        CNT_Embark(wrk, req);
399 2652
                        if (req->req_step == R_STP_TRANSPORT) {
400 2618
                                VCL_TaskEnter(req->privs);
401 2618
                                VCL_TaskEnter(req->top->privs);
402 2618
                        }
403 2652
                        if (CNT_Request(req) == REQ_FSM_DISEMBARK)
404 34
                                return;
405 2614
                        AZ(req->top->vcl0);
406 2614
                        req->task->func = NULL;
407 2614
                        req->task->priv = NULL;
408 2614
                        AZ(req->ws->r);
409 2614
                        AZ(wrk->aws->r);
410 2614
                        http1_setstate(sp, H1CLEANUP);
411 5258
                } else if (st == H1CLEANUP) {
412
413 2644
                        AZ(wrk->aws->r);
414 2644
                        AZ(req->ws->r);
415
416 2644
                        if (sp->fd >= 0 && req->doclose != SC_NULL)
417 208
                                SES_Close(sp, req->doclose);
418
419 2644
                        if (sp->fd < 0) {
420 272
                                wrk->stats->sess_closed++;
421 272
                                Req_Cleanup(sp, wrk, req);
422 272
                                Req_Release(req);
423 272
                                SES_Delete(sp, SC_NULL, NAN);
424 272
                                return;
425
                        }
426
427 2372
                        Req_Cleanup(sp, wrk, req);
428 2372
                        HTC_RxInit(req->htc, req->ws);
429 2372
                        if (req->htc->rxbuf_e != req->htc->rxbuf_b)
430 15
                                wrk->stats->sess_readahead++;
431 2372
                        http1_setstate(sp, H1NEWREQ);
432 2372
                } else {
433 0
                        WRONG("Wrong H1 session state");
434
                }
435
        }
436 1837
}