varnish-cache/bin/varnishd/http1/cache_http1_deliver.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
32
#include "config.h"
33
34
#include "cache/cache_varnishd.h"
35
#include "cache/cache_filter.h"
36
#include "cache_http1.h"
37
38
/*--------------------------------------------------------------------*/
39
40
static int v_matchproto_(vdp_bytes_f)
41 4520
v1d_bytes(struct req *req, enum vdp_action act, void **priv,
42
    const void *ptr, ssize_t len)
43
{
44 4520
        ssize_t wl = 0;
45
46 4520
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
47 4520
        (void)priv;
48
49 4520
        AZ(req->vdc->nxt);              /* always at the bottom of the pile */
50
51 4519
        if (len > 0)
52 2421
                wl = V1L_Write(req->wrk, ptr, len);
53 4520
        if (act > VDP_NULL && V1L_Flush(req->wrk))
54 10
                return (-1);
55 4510
        if (len != wl)
56 0
                return (-1);
57 4510
        return (0);
58 4520
}
59
60
static const struct vdp v1d_vdp = {
61
        .name =         "V1B",
62
        .bytes =        v1d_bytes,
63
};
64
65
static void
66 26
v1d_error(struct req *req, const char *msg)
67
{
68
        static const char r_500[] =
69
            "HTTP/1.1 500 Internal Server Error\r\n"
70
            "Server: Varnish\r\n"
71
            "Connection: close\r\n\r\n";
72
73 26
        VSLb(req->vsl, SLT_Error, "%s", msg);
74 26
        VSLb(req->vsl, SLT_RespProtocol, "HTTP/1.1");
75 26
        VSLb(req->vsl, SLT_RespStatus, "500");
76 26
        VSLb(req->vsl, SLT_RespReason, "Internal Server Error");
77
78 26
        req->wrk->stats->client_resp_500++;
79 26
        (void)write(req->sp->fd, r_500, sizeof r_500 - 1);
80 26
        req->doclose = SC_TX_EOF;
81 26
}
82
83
/*--------------------------------------------------------------------
84
 */
85
86
void v_matchproto_(vtr_deliver_f)
87 2588
V1D_Deliver(struct req *req, struct boc *boc, int sendbody)
88
{
89 2588
        int err = 0, chunked = 0;
90
        enum sess_close sc;
91
        uint64_t hdrbytes, bytes;
92
93 2588
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
94 2588
        CHECK_OBJ_ORNULL(boc, BOC_MAGIC);
95 2588
        CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC);
96
97 2588
        if (!req->doclose && http_HdrIs(req->resp, H_Connection, "close")) {
98 7
                req->doclose = SC_RESP_CLOSE;
99 2588
        } else if (req->doclose) {
100 163
                if (!http_HdrIs(req->resp, H_Connection, "close")) {
101 160
                        http_Unset(req->resp, H_Connection);
102 160
                        http_SetHeader(req->resp, "Connection: close");
103 160
                }
104 2581
        } else if (!http_GetHdr(req->resp, H_Connection, NULL))
105 2418
                http_SetHeader(req->resp, "Connection: keep-alive");
106
107 2588
        if (sendbody) {
108 1761
                if (!http_GetHdr(req->resp, H_Content_Length, NULL)) {
109 234
                        if (req->http->protover == 11) {
110 230
                                chunked = 1;
111 230
                                http_SetHeader(req->resp,
112
                                    "Transfer-Encoding: chunked");
113 230
                        } else {
114 4
                                req->doclose = SC_TX_EOF;
115
                        }
116 234
                }
117 1761
                if (VDP_Push(req, &v1d_vdp, NULL)) {
118 17
                        v1d_error(req, "workspace_thread overflow");
119 17
                        AZ(req->wrk->v1l);
120 17
                        return;
121
                }
122 1744
        }
123
124 2571
        if (WS_Overflowed(req->ws)) {
125 8
                v1d_error(req, "workspace_client overflow");
126 8
                return;
127
        }
128
129 2563
        if (WS_Overflowed(req->sp->ws)) {
130 1
                v1d_error(req, "workspace_session overflow");
131 1
                return;
132
        }
133
134 2562
        AZ(req->wrk->v1l);
135 5124
        V1L_Open(req->wrk, req->wrk->aws, &req->sp->fd, req->vsl,
136 2562
            req->t_prev + SESS_TMO(req->sp, send_timeout),
137 2562
            cache_param->http1_iovs);
138
139 2562
        if (WS_Overflowed(req->wrk->aws)) {
140 0
                v1d_error(req, "workspace_thread overflow");
141 0
                AZ(req->wrk->v1l);
142 0
                return;
143
        }
144
145 2562
        hdrbytes = HTTP1_Write(req->wrk, req->resp, HTTP1_Resp);
146
147 2562
        if (sendbody) {
148 1743
                if (DO_DEBUG(DBG_FLUSH_HEAD))
149 7
                        (void)V1L_Flush(req->wrk);
150 1743
                if (chunked)
151 230
                        V1L_Chunked(req->wrk);
152 1743
                err = VDP_DeliverObj(req);
153 1743
                if (!err && chunked)
154 214
                        V1L_EndChunk(req->wrk);
155 1743
        }
156
157 2562
        sc = V1L_Close(req->wrk, &bytes);
158 2562
        AZ(req->wrk->v1l);
159
160
        /* Bytes accounting */
161 2562
        if (bytes < hdrbytes)
162 1
                req->acct.resp_hdrbytes += bytes;
163
        else {
164 2561
                req->acct.resp_hdrbytes += hdrbytes;
165 2561
                req->acct.resp_bodybytes += bytes - hdrbytes;
166
        }
167
168 2562
        if (sc == SC_NULL && err && req->sp->fd >= 0)
169 9
                sc = SC_REM_CLOSE;
170 2562
        if (sc != SC_NULL)
171 19
                Req_Fail(req, sc);
172 2562
        VDP_close(req);
173 2588
}