Coverage Report

Created: 2025-08-03 06:58

/src/h2o/lib/common/http1client.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2014 DeNA Co., Ltd.
3
 *
4
 * Permission is hereby granted, free of charge, to any person obtaining a copy
5
 * of this software and associated documentation files (the "Software"), to
6
 * deal in the Software without restriction, including without limitation the
7
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8
 * sell copies of the Software, and to permit persons to whom the Software is
9
 * furnished to do so, subject to the following conditions:
10
 *
11
 * The above copyright notice and this permission notice shall be included in
12
 * all copies or substantial portions of the Software.
13
 *
14
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20
 * IN THE SOFTWARE.
21
 */
22
#include <arpa/inet.h>
23
#include <fcntl.h>
24
#include <netdb.h>
25
#include <netinet/in.h>
26
#include <sys/socket.h>
27
#include <sys/types.h>
28
#include <sys/un.h>
29
#include "picohttpparser.h"
30
#include "h2o/httpclient.h"
31
#include "h2o/token.h"
32
33
#if !H2O_USE_LIBUV && defined(__linux__)
34
#define USE_PIPE_READER 1
35
#else
36
#define USE_PIPE_READER 0
37
#endif
38
39
enum enum_h2o_http1client_stream_state {
40
    STREAM_STATE_HEAD,
41
    STREAM_STATE_BODY,
42
    STREAM_STATE_CLOSED,
43
};
44
45
struct st_h2o_http1client_t {
46
    h2o_httpclient_t super;
47
    h2o_socket_t *sock;
48
    struct {
49
        enum enum_h2o_http1client_stream_state req;
50
        enum enum_h2o_http1client_stream_state res;
51
    } state;
52
    h2o_url_t *_origin;
53
    int _method_is_head;
54
    int _do_keepalive;
55
    union {
56
        struct {
57
            size_t bytesleft;
58
        } content_length;
59
        struct {
60
            struct phr_chunked_decoder decoder;
61
            size_t bytes_decoded_in_buf;
62
        } chunked;
63
    } _body_decoder;
64
    h2o_socket_cb reader;
65
    h2o_httpclient_proceed_req_cb proceed_req;
66
    /**
67
     * buffer used to hold chunk headers of a request body; the size is SIZE_MAX in hex + CRLF + '\0'
68
     */
69
    char _chunk_len_str[(sizeof(H2O_UINT64_LONGEST_HEX_STR) - 1) + 2 + 1];
70
    /**
71
     * buffer used to retain request body that is inflight
72
     */
73
    struct {
74
        h2o_buffer_t *buf;
75
        int is_end_stream;
76
    } body_buf;
77
    /**
78
     * `on_body_piped` is non-NULL iff used
79
     */
80
    h2o_httpclient_pipe_reader_t pipe_reader;
81
    /**
82
     * maintain the number of bytes being already processed on the associated socket
83
     */
84
    uint64_t _socket_bytes_processed;
85
    unsigned _is_chunked : 1;
86
    unsigned _seen_at_least_one_chunk : 1;
87
    unsigned _delay_free : 1;
88
    unsigned _app_prefers_pipe_reader : 1;
89
    unsigned _send_own_expect : 1;
90
};
91
92
static void on_body_to_pipe(h2o_socket_t *_sock, const char *err);
93
94
static void req_body_send(struct st_h2o_http1client_t *client);
95
static void update_read_state(struct st_h2o_http1client_t *client);
96
97
static void close_client(struct st_h2o_http1client_t *client)
98
617
{
99
617
    if (client->sock != NULL) {
100
617
        if (client->super.connpool != NULL && client->_do_keepalive && client->super.connpool->socketpool->timeout > 0) {
101
            /* we do not send pipelined requests, and thus can trash all the received input at the end of the request */
102
0
            h2o_buffer_consume(&client->sock->input, client->sock->input->size);
103
0
            h2o_socketpool_return(client->super.connpool->socketpool, client->sock);
104
617
        } else {
105
617
            h2o_socket_close(client->sock);
106
617
        }
107
617
    }
108
617
    if (h2o_timer_is_linked(&client->super._timeout))
109
0
        h2o_timer_unlink(&client->super._timeout);
110
617
    if (client->body_buf.buf != NULL)
111
0
        h2o_buffer_dispose(&client->body_buf.buf);
112
617
    if (!client->_delay_free)
113
617
        free(client);
114
617
}
115
116
static void close_response(struct st_h2o_http1client_t *client)
117
601
{
118
601
    assert(client->state.res == STREAM_STATE_CLOSED);
119
601
    if (client->state.req == STREAM_STATE_CLOSED) {
120
599
        close_client(client);
121
599
    } else {
122
2
        h2o_socket_read_stop(client->sock);
123
2
    }
124
601
}
125
126
static h2o_httpclient_body_cb call_on_head(struct st_h2o_http1client_t *client, const char *errstr, h2o_httpclient_on_head_t *args)
127
617
{
128
617
    assert(!client->_delay_free);
129
617
    client->_delay_free = 1;
130
617
    h2o_httpclient_body_cb cb = client->super._cb.on_head(&client->super, errstr, args);
131
617
    client->_delay_free = 0;
132
617
    return cb;
133
617
}
134
135
static int call_on_body(struct st_h2o_http1client_t *client, const char *errstr)
136
998
{
137
998
    assert(!client->_delay_free);
138
998
    client->_delay_free = 1;
139
998
    int ret = (client->reader == on_body_to_pipe ? client->pipe_reader.on_body_piped : client->super._cb.on_body)(&client->super,
140
998
                                                                                                                  errstr, NULL, 0);
141
998
    client->_delay_free = 0;
142
998
    return ret;
143
998
}
144
145
static void call_proceed_req(struct st_h2o_http1client_t *client, const char *errstr)
146
0
{
147
0
    assert(!client->_delay_free);
148
0
    client->_delay_free = 1;
149
0
    client->proceed_req(&client->super, errstr);
150
0
    client->_delay_free = 0;
151
0
}
152
153
static void on_error(struct st_h2o_http1client_t *client, const char *errstr)
154
18
{
155
18
    switch (client->state.res) {
156
2
    case STREAM_STATE_HEAD:
157
2
        call_on_head(client, errstr, NULL);
158
2
        break;
159
14
    case STREAM_STATE_BODY:
160
14
        call_on_body(client, errstr);
161
14
        break;
162
2
    case STREAM_STATE_CLOSED:
163
2
        if (client->proceed_req != NULL)
164
0
            call_proceed_req(client, errstr);
165
2
        break;
166
18
    }
167
18
    close_client(client);
168
18
}
169
170
static void on_body_timeout(h2o_timer_t *entry)
171
0
{
172
0
    struct st_h2o_http1client_t *client = H2O_STRUCT_FROM_MEMBER(struct st_h2o_http1client_t, super._timeout, entry);
173
0
    on_error(client, h2o_httpclient_error_io_timeout);
174
0
}
175
176
static void on_body_until_close(h2o_socket_t *sock, const char *err)
177
984
{
178
984
    struct st_h2o_http1client_t *client = sock->data;
179
180
984
    h2o_timer_unlink(&client->super._timeout);
181
182
984
    if (err != NULL) {
183
485
        client->state.res = STREAM_STATE_CLOSED;
184
485
        client->super.timings.response_end_at = h2o_gettimeofday(client->super.ctx->loop);
185
485
        call_on_body(client, h2o_httpclient_error_is_eos);
186
485
        close_response(client);
187
485
        return;
188
485
    }
189
499
    uint64_t size = sock->bytes_read - client->_socket_bytes_processed;
190
499
    client->_socket_bytes_processed = sock->bytes_read;
191
192
499
    client->super.bytes_read.body += size;
193
499
    client->super.bytes_read.total += size;
194
195
499
    if (size != 0) {
196
499
        if (call_on_body(client, NULL) != 0) {
197
0
            close_client(client);
198
0
            return;
199
0
        }
200
499
        update_read_state(client);
201
499
    }
202
499
}
203
204
static void on_body_content_length(h2o_socket_t *sock, const char *err)
205
0
{
206
0
    struct st_h2o_http1client_t *client = sock->data;
207
208
0
    h2o_timer_unlink(&client->super._timeout);
209
210
0
    if (err != NULL) {
211
0
        on_error(client, h2o_httpclient_error_io);
212
0
        return;
213
0
    }
214
0
    uint64_t size = sock->bytes_read - client->_socket_bytes_processed;
215
0
    client->_socket_bytes_processed = sock->bytes_read;
216
217
0
    client->super.bytes_read.body += size;
218
0
    client->super.bytes_read.total += size;
219
220
0
    if (size != 0 || client->_body_decoder.content_length.bytesleft == 0) {
221
0
        int ret;
222
0
        if (client->_body_decoder.content_length.bytesleft <= size) {
223
0
            if (client->_body_decoder.content_length.bytesleft < size) {
224
                /* remove the trailing garbage from buf, and disable keepalive */
225
0
                client->sock->input->size -= size - client->_body_decoder.content_length.bytesleft;
226
0
                client->_do_keepalive = 0;
227
0
            }
228
0
            client->_body_decoder.content_length.bytesleft = 0;
229
0
            client->state.res = STREAM_STATE_CLOSED;
230
0
            client->super.timings.response_end_at = h2o_gettimeofday(client->super.ctx->loop);
231
0
        } else {
232
0
            client->_body_decoder.content_length.bytesleft -= size;
233
0
        }
234
0
        ret = call_on_body(client, client->state.res == STREAM_STATE_CLOSED ? h2o_httpclient_error_is_eos : NULL);
235
0
        if (client->state.res == STREAM_STATE_CLOSED) {
236
0
            close_response(client);
237
0
            return;
238
0
        } else if (ret != 0) {
239
0
            client->_do_keepalive = 0;
240
0
            close_client(client);
241
0
            return;
242
0
        }
243
0
    }
244
245
0
#if USE_PIPE_READER
246
0
    if (client->pipe_reader.on_body_piped != NULL) {
247
0
        h2o_socket_dont_read(client->sock, 1);
248
0
        client->reader = on_body_to_pipe;
249
0
    }
250
0
#endif
251
0
    update_read_state(client);
252
0
}
253
254
void on_body_to_pipe(h2o_socket_t *_sock, const char *err)
255
0
{
256
0
#if USE_PIPE_READER
257
0
    struct st_h2o_http1client_t *client = _sock->data;
258
259
0
    h2o_timer_unlink(&client->super._timeout);
260
0
    h2o_socket_read_stop(client->sock);
261
262
0
    if (err != NULL) {
263
0
        on_error(client, h2o_httpclient_error_io);
264
0
        return;
265
0
    }
266
267
0
    ssize_t bytes_read;
268
0
    while ((bytes_read = splice(h2o_socket_get_fd(client->sock), NULL, client->pipe_reader.fd, NULL,
269
0
                                client->_body_decoder.content_length.bytesleft, SPLICE_F_NONBLOCK)) == -1 &&
270
0
           errno == EINTR)
271
0
        ;
272
0
    if (bytes_read == -1 && errno == EAGAIN) {
273
0
        update_read_state(client);
274
0
        return;
275
0
    }
276
0
    if (bytes_read <= 0) {
277
0
        on_error(client, h2o_httpclient_error_io);
278
0
        return;
279
0
    }
280
281
0
    client->_socket_bytes_processed += bytes_read;
282
0
    client->sock->bytes_read += bytes_read;
283
0
    client->super.bytes_read.body += bytes_read;
284
0
    client->super.bytes_read.total += bytes_read;
285
286
0
    client->_body_decoder.content_length.bytesleft -= bytes_read;
287
0
    if (client->_body_decoder.content_length.bytesleft == 0) {
288
0
        client->state.res = STREAM_STATE_CLOSED;
289
0
        client->super.timings.response_end_at = h2o_gettimeofday(client->super.ctx->loop);
290
0
        h2o_socket_dont_read(client->sock, 0);
291
0
    }
292
293
0
    int ret = call_on_body(client, client->state.res == STREAM_STATE_CLOSED ? h2o_httpclient_error_is_eos : NULL);
294
295
0
    if (client->state.res == STREAM_STATE_CLOSED) {
296
0
        close_response(client);
297
0
    } else if (ret != 0) {
298
0
        client->_do_keepalive = 0;
299
0
        close_client(client);
300
0
    }
301
#else
302
    h2o_fatal("%s cannot be called", __FUNCTION__);
303
#endif
304
0
}
305
306
static void on_body_chunked(h2o_socket_t *sock, const char *err)
307
0
{
308
0
    struct st_h2o_http1client_t *client = sock->data;
309
0
    h2o_buffer_t *inbuf;
310
311
0
    h2o_timer_unlink(&client->super._timeout);
312
313
0
    if (err != NULL) {
314
0
        if (err == h2o_socket_error_closed && !phr_decode_chunked_is_in_data(&client->_body_decoder.chunked.decoder) &&
315
0
            client->_seen_at_least_one_chunk) {
316
            /*
317
             * if the peer closed after a full chunk, treat this
318
             * as if the transfer had complete, browsers appear to ignore
319
             * a missing 0\r\n chunk
320
             */
321
0
            client->_do_keepalive = 0;
322
0
            client->state.res = STREAM_STATE_CLOSED;
323
0
            client->super.timings.response_end_at = h2o_gettimeofday(client->super.ctx->loop);
324
0
            call_on_body(client, h2o_httpclient_error_is_eos);
325
0
            close_response(client);
326
0
        } else {
327
0
            on_error(client, h2o_httpclient_error_io);
328
0
        }
329
0
        return;
330
0
    }
331
0
    uint64_t size = sock->bytes_read - client->_socket_bytes_processed;
332
0
    client->_socket_bytes_processed = sock->bytes_read;
333
334
0
    client->super.bytes_read.body += size;
335
0
    client->super.bytes_read.total += size;
336
337
0
    inbuf = client->sock->input;
338
0
    if (size != 0) {
339
0
        const char *errstr;
340
0
        int cb_ret;
341
0
        size_t newsz = size;
342
343
0
        switch (phr_decode_chunked(&client->_body_decoder.chunked.decoder, inbuf->bytes + inbuf->size - newsz, &newsz)) {
344
0
        case -1: /* error */
345
0
            newsz = size;
346
0
            client->_do_keepalive = 0;
347
0
            errstr = h2o_httpclient_error_http1_parse_failed;
348
0
            break;
349
0
        case -2: /* incomplete */
350
0
            errstr = NULL;
351
0
            break;
352
0
        default: /* complete, with garbage on tail; should disable keepalive */
353
0
            client->_do_keepalive = 0;
354
        /* fallthru */
355
0
        case 0: /* complete */
356
0
            client->state.res = STREAM_STATE_CLOSED;
357
0
            errstr = h2o_httpclient_error_is_eos;
358
0
            client->super.timings.response_end_at = h2o_gettimeofday(client->super.ctx->loop);
359
0
            break;
360
0
        }
361
0
        inbuf->size -= size - newsz;
362
0
        if (inbuf->size > 0)
363
0
            client->_seen_at_least_one_chunk = 1;
364
0
        cb_ret = call_on_body(client, errstr);
365
0
        if (client->state.res == STREAM_STATE_CLOSED) {
366
0
            close_response(client);
367
0
            return;
368
0
        } else if (errstr != NULL) {
369
0
            close_client(client);
370
0
            return;
371
0
        } else if (cb_ret != 0) {
372
0
            client->_do_keepalive = 0;
373
0
            close_client(client);
374
0
            return;
375
0
        }
376
0
        update_read_state(client);
377
0
    }
378
0
}
379
380
static void on_head_timeout(h2o_timer_t *entry)
381
0
{
382
0
    struct st_h2o_http1client_t *client = H2O_STRUCT_FROM_MEMBER(struct st_h2o_http1client_t, super._timeout, entry);
383
0
    on_error(client, h2o_httpclient_error_io_timeout);
384
0
}
385
386
static void on_head(h2o_socket_t *sock, const char *err)
387
615
{
388
615
    struct st_h2o_http1client_t *client = sock->data;
389
615
    int minor_version, version, http_status, rlen;
390
615
    const char *msg;
391
615
#define MAX_HEADERS 100
392
615
    h2o_header_t *headers;
393
615
    h2o_iovec_t *header_names;
394
615
    size_t msg_len, num_headers, i;
395
615
    h2o_socket_cb reader;
396
397
615
    h2o_timer_unlink(&client->super._timeout);
398
399
615
    if (err != NULL) {
400
0
        on_error(client, h2o_httpclient_error_io);
401
0
        return;
402
0
    }
403
404
    /* revert max read size to 1MB now that we have received the first chunk, presumably carrying all the response headers */
405
615
#if USE_PIPE_READER
406
615
    if (client->_app_prefers_pipe_reader)
407
0
        h2o_evloop_socket_set_max_read_size(client->sock, h2o_evloop_socket_max_read_size);
408
615
#endif
409
410
615
    client->super._timeout.cb = on_head_timeout;
411
412
615
    headers = h2o_mem_alloc_pool(client->super.pool, *headers, MAX_HEADERS);
413
615
    header_names = h2o_mem_alloc_pool(client->super.pool, *header_names, MAX_HEADERS);
414
415
    /* continue parsing the responses until we see a final one */
416
615
    while (1) {
417
        /* parse response */
418
615
        struct phr_header src_headers[MAX_HEADERS];
419
615
        num_headers = MAX_HEADERS;
420
615
        rlen = phr_parse_response(sock->input->bytes, sock->input->size, &minor_version, &http_status, &msg, &msg_len, src_headers,
421
615
                                  &num_headers, 0);
422
615
        switch (rlen) {
423
0
        case -1: /* error */
424
0
            on_error(client, h2o_httpclient_error_http1_parse_failed);
425
0
            return;
426
0
        case -2: /* incomplete */
427
0
            h2o_timer_link(client->super.ctx->loop, client->super.ctx->io_timeout, &client->super._timeout);
428
0
            return;
429
615
        }
430
431
615
        client->super.bytes_read.header += rlen;
432
615
        client->super.bytes_read.total += rlen;
433
434
615
        version = 0x100 | (minor_version != 0);
435
436
        /* fill-in the headers */
437
1.23k
        for (i = 0; i != num_headers; ++i) {
438
615
            if (src_headers[i].name_len == 0) {
439
                /* reject multiline header */
440
0
                on_error(client, h2o_httpclient_error_http1_line_folding);
441
0
                return;
442
0
            }
443
615
            const h2o_token_t *token;
444
615
            char *orig_name = h2o_strdup(client->super.pool, src_headers[i].name, src_headers[i].name_len).base;
445
615
            h2o_strtolower((char *)src_headers[i].name, src_headers[i].name_len);
446
615
            token = h2o_lookup_token(src_headers[i].name, src_headers[i].name_len);
447
615
            if (token != NULL) {
448
615
                headers[i].name = (h2o_iovec_t *)&token->buf;
449
615
            } else {
450
0
                header_names[i] = h2o_iovec_init(src_headers[i].name, src_headers[i].name_len);
451
0
                headers[i].name = &header_names[i];
452
0
            }
453
615
            headers[i].value = h2o_iovec_init(src_headers[i].value, src_headers[i].value_len);
454
615
            headers[i].orig_name = orig_name;
455
615
            headers[i].flags = (h2o_header_flags_t){0};
456
615
        }
457
458
615
        if (http_status == 101) {
459
0
            if (client->_send_own_expect) {
460
                /* expect: 100-continue is incompatible CONNECT or upgrade (when trying to establish a tunnel */
461
0
                on_error(client, h2o_httpclient_error_unexpected_101);
462
0
                return;
463
0
            }
464
0
            break;
465
615
        } else if (http_status == 100 || http_status >= 200) {
466
            /* When request body has been withheld and a 100 or a final response has been received, start sending the request body,
467
             * see: https://github.com/h2o/h2o/pull/3316#discussion_r1456859634. */
468
615
            if (client->_send_own_expect) {
469
0
                client->_send_own_expect = 0;
470
0
                req_body_send(client);
471
0
            }
472
615
            if (http_status >= 200)
473
615
                break;
474
615
        }
475
0
        assert(http_status <= 199);
476
0
        if (client->super.informational_cb != NULL &&
477
0
            client->super.informational_cb(&client->super, version, http_status, h2o_iovec_init(msg, msg_len), headers,
478
0
                                           num_headers) != 0) {
479
0
            close_client(client);
480
0
            return;
481
0
        }
482
483
0
        h2o_buffer_consume(&client->sock->input, rlen);
484
0
        if (client->sock->input->size == 0) {
485
0
            if (!h2o_timer_is_linked(&client->super._timeout)) {
486
0
                h2o_timer_link(client->super.ctx->loop, client->super.ctx->io_timeout, &client->super._timeout);
487
0
            }
488
0
            return;
489
0
        }
490
0
    }
491
492
    /* recognize hop-by-hop response headers */
493
615
    reader = on_body_until_close;
494
615
    if (!h2o_httpclient__tunnel_is_ready(&client->super, http_status, version)) {
495
615
        client->_do_keepalive = minor_version >= 1;
496
1.23k
        for (i = 0; i != num_headers; ++i) {
497
615
            if (headers[i].name == &H2O_TOKEN_CONNECTION->buf) {
498
615
                if (h2o_contains_token(headers[i].value.base, headers[i].value.len, H2O_STRLIT("keep-alive"), ',')) {
499
0
                    client->_do_keepalive = 1;
500
615
                } else {
501
615
                    client->_do_keepalive = 0;
502
615
                }
503
615
            } else if (headers[i].name == &H2O_TOKEN_TRANSFER_ENCODING->buf) {
504
0
                if (h2o_memis(headers[i].value.base, headers[i].value.len, H2O_STRLIT("chunked"))) {
505
                    /* precond: _body_decoder.chunked is zero-filled */
506
0
                    client->_body_decoder.chunked.decoder.consume_trailer = 1;
507
0
                    reader = on_body_chunked;
508
0
                } else if (h2o_memis(headers[i].value.base, headers[i].value.len, H2O_STRLIT("identity"))) {
509
                    /* continue */
510
0
                } else {
511
0
                    on_error(client, h2o_httpclient_error_http1_unexpected_transfer_encoding);
512
0
                    return;
513
0
                }
514
0
            } else if (headers[i].name == &H2O_TOKEN_CONTENT_LENGTH->buf) {
515
0
                if ((client->_body_decoder.content_length.bytesleft = h2o_strtosize(headers[i].value.base, headers[i].value.len)) ==
516
0
                    SIZE_MAX) {
517
0
                    on_error(client, h2o_httpclient_error_invalid_content_length);
518
0
                    return;
519
0
                }
520
0
                if (reader != on_body_chunked)
521
0
                    reader = on_body_content_length;
522
0
            }
523
615
        }
524
615
    }
525
526
615
    client->state.res = STREAM_STATE_BODY;
527
615
    client->super.timings.response_start_at = h2o_gettimeofday(client->super.ctx->loop);
528
529
    /* RFC 2616 4.4 */
530
615
    if (client->_method_is_head || http_status == 204 || http_status == 304) {
531
116
        client->state.res = STREAM_STATE_CLOSED;
532
116
        client->super.timings.response_end_at = h2o_gettimeofday(client->super.ctx->loop);
533
499
    } else {
534
        /* close the connection if impossible to determine the end of the response (RFC 7230 3.3.3) */
535
499
        if (reader == on_body_until_close)
536
499
            client->_do_keepalive = 0;
537
499
    }
538
539
615
    h2o_httpclient_on_head_t on_head = {
540
615
        .version = version,
541
615
        .status = http_status,
542
615
        .msg = h2o_iovec_init(msg, msg_len),
543
615
        .headers = headers,
544
615
        .num_headers = num_headers,
545
615
        .header_requires_dup = 1,
546
615
    };
547
615
#if USE_PIPE_READER
548
    /* If there is no less than 64KB of data to be read from the socket, offer the application the opportunity to use pipe for
549
     * transferring the content zero-copy. As switching to pipe involves the cost of creating a pipe (and disposing it when the
550
     * request is complete), we adopt this margin of 64KB, which offers clear improvement (5%) on 9th-gen Intel Core. */
551
615
    if (client->_app_prefers_pipe_reader && reader == on_body_content_length &&
552
615
        client->sock->input->size + 65536 <= client->_body_decoder.content_length.bytesleft &&
553
615
        client->sock->ssl == NULL)
554
0
        on_head.pipe_reader = &client->pipe_reader;
555
615
#endif
556
557
    /* call the callback */
558
615
    client->super._cb.on_body =
559
615
        call_on_head(client, client->state.res == STREAM_STATE_CLOSED ? h2o_httpclient_error_is_eos : NULL, &on_head);
560
561
615
    if (client->state.res == STREAM_STATE_CLOSED) {
562
116
        close_response(client);
563
116
        return;
564
499
    } else if (client->super._cb.on_body == NULL) {
565
0
        client->_do_keepalive = 0;
566
0
        close_client(client);
567
0
        return;
568
0
    }
569
570
499
    h2o_buffer_consume(&sock->input, rlen);
571
499
    client->_socket_bytes_processed = client->sock->bytes_read - client->sock->input->size;
572
573
499
    client->super._timeout.cb = on_body_timeout;
574
499
    h2o_socket_read_start(sock, reader);
575
499
    reader(client->sock, 0);
576
577
499
#undef MAX_HEADERS
578
499
}
579
580
static void on_head_first_byte_timeout(h2o_timer_t *entry)
581
0
{
582
0
    struct st_h2o_http1client_t *client = H2O_STRUCT_FROM_MEMBER(struct st_h2o_http1client_t, super._timeout, entry);
583
0
    on_error(client, h2o_httpclient_error_first_byte_timeout);
584
0
}
585
586
static void on_whole_request_sent(h2o_socket_t *sock, const char *err)
587
617
{
588
617
    struct st_h2o_http1client_t *client = sock->data;
589
590
617
    h2o_timer_unlink(&client->super._timeout);
591
592
617
    if (err != NULL) {
593
18
        on_error(client, h2o_httpclient_error_io);
594
18
        return;
595
18
    }
596
597
599
    client->state.req = STREAM_STATE_CLOSED;
598
599
    client->super.timings.request_end_at = h2o_gettimeofday(client->super.ctx->loop);
599
600
599
    if (client->super.upgrade_to != NULL) {
601
        /* TODO use shutdown(2) to signal the peer that our send side has been closed, but continue reading on the receive side. */
602
0
        on_error(client, client->state.res < STREAM_STATE_BODY ? h2o_httpclient_error_io : h2o_httpclient_error_is_eos);
603
599
    } else {
604
599
        switch (client->state.res) {
605
599
        case STREAM_STATE_HEAD:
606
599
            client->super._timeout.cb = on_head_first_byte_timeout;
607
599
            h2o_timer_link(client->super.ctx->loop, client->super.ctx->first_byte_timeout, &client->super._timeout);
608
599
            break;
609
0
        case STREAM_STATE_BODY:
610
0
            break;
611
0
        case STREAM_STATE_CLOSED:
612
0
            close_client(client);
613
0
            break;
614
599
        }
615
599
    }
616
599
}
617
618
static void on_header_sent_wait_100(h2o_socket_t *sock, const char *err)
619
0
{
620
0
    struct st_h2o_http1client_t *client = sock->data;
621
622
0
    h2o_timer_unlink(&client->super._timeout);
623
624
0
    if (err != NULL) {
625
0
        on_error(client, h2o_httpclient_error_io);
626
0
        return;
627
0
    }
628
629
0
    if (client->state.res == STREAM_STATE_HEAD) {
630
0
        client->super._timeout.cb = on_head_first_byte_timeout;
631
0
        h2o_timer_link(client->super.ctx->loop, client->super.ctx->first_byte_timeout, &client->super._timeout);
632
0
    }
633
0
}
634
635
static void req_body_send_complete(h2o_socket_t *sock, const char *err)
636
0
{
637
0
    struct st_h2o_http1client_t *client = sock->data;
638
639
0
    h2o_buffer_consume(&client->body_buf.buf, client->body_buf.buf->size);
640
641
0
    if (err != NULL) {
642
0
        on_whole_request_sent(client->sock, err);
643
0
        return;
644
0
    }
645
646
0
    int is_end_stream = client->body_buf.is_end_stream;
647
648
0
    if (client->proceed_req != NULL) {
649
0
        call_proceed_req(client, NULL);
650
0
    }
651
652
0
    if (is_end_stream)
653
0
        on_whole_request_sent(client->sock, NULL);
654
0
}
655
656
/**
657
 * Encodes data. `bufs` must have at least 4 elements of space.
658
 */
659
static size_t req_body_send_prepare(struct st_h2o_http1client_t *client, h2o_iovec_t *bufs, size_t *bytes)
660
0
{
661
0
    size_t bufcnt = 0;
662
0
    *bytes = 0;
663
664
0
    if (client->_is_chunked) {
665
0
        if (client->body_buf.buf->size != 0) {
666
            /* build chunk header */
667
0
            bufs[bufcnt].base = client->_chunk_len_str;
668
0
            bufs[bufcnt].len =
669
0
                snprintf(client->_chunk_len_str, sizeof(client->_chunk_len_str), "%zx\r\n", client->body_buf.buf->size);
670
0
            *bytes += bufs[bufcnt].len;
671
0
            ++bufcnt;
672
            /* append chunk body */
673
0
            bufs[bufcnt++] = h2o_iovec_init(client->body_buf.buf->bytes, client->body_buf.buf->size);
674
0
            *bytes += client->body_buf.buf->size;
675
            /* append CRLF */
676
0
            bufs[bufcnt++] = h2o_iovec_init("\r\n", 2);
677
0
            *bytes += 2;
678
0
        }
679
0
        if (client->body_buf.is_end_stream) {
680
0
            static const h2o_iovec_t terminator = {H2O_STRLIT("0\r\n\r\n")};
681
0
            bufs[bufcnt++] = terminator;
682
0
            *bytes += terminator.len;
683
0
        }
684
0
    } else if (client->body_buf.buf->size != 0) {
685
0
        bufs[bufcnt++] = h2o_iovec_init(client->body_buf.buf->bytes, client->body_buf.buf->size);
686
0
        *bytes += client->body_buf.buf->size;
687
0
    }
688
689
0
    return bufcnt;
690
0
}
691
692
static void req_body_send(struct st_h2o_http1client_t *client)
693
0
{
694
0
    h2o_iovec_t bufs[4];
695
0
    size_t bytes, bufcnt = req_body_send_prepare(client, bufs, &bytes);
696
697
0
    h2o_timer_unlink(&client->super._timeout);
698
699
0
    h2o_socket_write(client->sock, bufs, bufcnt, req_body_send_complete);
700
0
    client->super.bytes_written.body += bytes;
701
0
    client->super.bytes_written.total += bytes;
702
703
0
    h2o_timer_link(client->super.ctx->loop, client->super.ctx->io_timeout, &client->super._timeout);
704
0
}
705
706
static int do_write_req(h2o_httpclient_t *_client, h2o_iovec_t chunk, int is_end_stream)
707
0
{
708
0
    struct st_h2o_http1client_t *client = (struct st_h2o_http1client_t *)_client;
709
710
0
    assert(chunk.len != 0 || is_end_stream);
711
0
    assert(!h2o_socket_is_writing(client->sock));
712
0
    assert(client->body_buf.buf->size == 0);
713
714
    /* store given content to buffer */
715
0
    if (chunk.len != 0) {
716
0
        if (!h2o_buffer_try_append(&client->body_buf.buf, chunk.base, chunk.len))
717
0
            return -1;
718
0
    }
719
0
    client->body_buf.is_end_stream = is_end_stream;
720
721
    /* check if the connection has to be closed for correct framing */
722
0
    if (client->state.res == STREAM_STATE_CLOSED)
723
0
        client->_do_keepalive = 0;
724
725
0
    req_body_send(client);
726
727
0
    return 0;
728
0
}
729
730
static void on_send_timeout(h2o_timer_t *entry)
731
0
{
732
0
    struct st_h2o_http1client_t *client = H2O_STRUCT_FROM_MEMBER(struct st_h2o_http1client_t, super._timeout, entry);
733
0
    on_error(client, h2o_httpclient_error_io_timeout);
734
0
}
735
736
static h2o_iovec_t build_request(struct st_h2o_http1client_t *client, h2o_iovec_t method, const h2o_url_t *url,
737
                                 h2o_iovec_t connection, const h2o_header_t *headers, size_t num_headers)
738
617
{
739
617
    h2o_iovec_t buf;
740
617
    size_t offset = 0;
741
742
617
    buf.len = method.len + url->path.len + url->authority.len + 512;
743
617
    buf.base = h2o_mem_alloc_pool(client->super.pool, char, buf.len);
744
745
617
#define RESERVE(sz)                                                                                                                \
746
272k
    do {                                                                                                                           \
747
272k
        size_t required = offset + sz + 4 /* for "\r\n\r\n" */;                                                                    \
748
272k
        if (required > buf.len) {                                                                                                  \
749
1.45k
            do {                                                                                                                   \
750
1.45k
                buf.len *= 2;                                                                                                      \
751
1.45k
            } while (required > buf.len);                                                                                          \
752
1.39k
            char *newp = h2o_mem_alloc_pool(client->super.pool, char, buf.len);                                                    \
753
1.39k
            memcpy(newp, buf.base, offset);                                                                                        \
754
1.39k
            buf.base = newp;                                                                                                       \
755
1.39k
        }                                                                                                                          \
756
272k
    } while (0)
757
617
#define APPEND(s, l)                                                                                                               \
758
548k
    do {                                                                                                                           \
759
548k
        h2o_memcpy(buf.base + offset, (s), (l));                                                                                   \
760
548k
        offset += (l);                                                                                                             \
761
548k
    } while (0)
762
1.23k
#define APPEND_STRLIT(lit) APPEND((lit), sizeof(lit) - 1)
763
617
#define APPEND_HEADER(h)                                                                                                           \
764
272k
    do {                                                                                                                           \
765
272k
        RESERVE((h)->name->len + (h)->value.len + 4);                                                                              \
766
272k
        APPEND((h)->orig_name ? (h)->orig_name : (h)->name->base, (h)->name->len);                                                 \
767
272k
        buf.base[offset++] = ':';                                                                                                  \
768
272k
        buf.base[offset++] = ' ';                                                                                                  \
769
272k
        APPEND((h)->value.base, (h)->value.len);                                                                                   \
770
272k
        buf.base[offset++] = '\r';                                                                                                 \
771
272k
        buf.base[offset++] = '\n';                                                                                                 \
772
272k
    } while (0)
773
774
617
    APPEND(method.base, method.len);
775
617
    buf.base[offset++] = ' ';
776
617
    if (client->super.upgrade_to == h2o_httpclient_upgrade_to_connect) {
777
0
        if (h2o_memis(method.base, method.len, H2O_STRLIT("CONNECT-UDP"))) {
778
0
            APPEND_STRLIT("masque://");
779
0
            APPEND(url->authority.base, url->authority.len);
780
0
            APPEND_STRLIT("/");
781
0
        } else {
782
0
            APPEND(url->authority.base, url->authority.len);
783
0
        }
784
617
    } else {
785
617
        APPEND(url->path.base, url->path.len);
786
617
    }
787
617
    APPEND_STRLIT(" HTTP/1.1\r\nhost: ");
788
617
    APPEND(url->authority.base, url->authority.len);
789
617
    buf.base[offset++] = '\r';
790
617
    buf.base[offset++] = '\n';
791
617
    assert(offset <= buf.len);
792
793
    /* append supplied connection header, or "connection: upgrade" and upgrade header when request an upgrade */
794
617
    if (client->super.upgrade_to != NULL && client->super.upgrade_to != h2o_httpclient_upgrade_to_connect) {
795
0
        h2o_header_t c = {&H2O_TOKEN_CONNECTION->buf, NULL, h2o_iovec_init(H2O_STRLIT("upgrade"))},
796
0
                     u = {&H2O_TOKEN_UPGRADE->buf, NULL,
797
0
                          h2o_iovec_init(client->super.upgrade_to, strlen(client->super.upgrade_to))};
798
0
        APPEND_HEADER(&c);
799
0
        APPEND_HEADER(&u);
800
617
    } else if (connection.base != NULL) {
801
617
        h2o_header_t h = {&H2O_TOKEN_CONNECTION->buf, NULL, connection};
802
617
        APPEND_HEADER(&h);
803
617
    }
804
805
617
    if (client->_send_own_expect) {
806
0
        h2o_header_t h = {&H2O_TOKEN_EXPECT->buf, NULL, h2o_iovec_init(H2O_STRLIT("100-continue"))};
807
0
        APPEND_HEADER(&h);
808
0
    }
809
810
617
    if (num_headers != 0) {
811
272k
        for (const h2o_header_t *h = headers, *h_end = h + num_headers; h != h_end; ++h)
812
271k
            APPEND_HEADER(h);
813
617
    }
814
815
617
    APPEND_STRLIT("\r\n");
816
817
    /* set the length */
818
617
    assert(offset <= buf.len);
819
617
    buf.len = offset;
820
821
617
    return buf;
822
823
617
#undef RESERVE
824
617
#undef APPEND
825
617
#undef APPEND_STRLIT
826
617
}
827
828
static void start_request(struct st_h2o_http1client_t *client, h2o_iovec_t method, const h2o_url_t *url,
829
                          const h2o_header_t *headers, size_t num_headers, h2o_iovec_t body,
830
                          const h2o_httpclient_properties_t *props)
831
617
{
832
617
    h2o_iovec_t reqbufs[6]; /* 6 should be the maximum possible elements used */
833
617
    size_t reqbufcnt = 0;
834
617
    if (props->proxy_protocol->base != NULL)
835
0
        reqbufs[reqbufcnt++] = *props->proxy_protocol;
836
837
617
    if (props->send_own_expect && (client->proceed_req != NULL || body.len != 0) && client->super.upgrade_to == NULL)
838
0
        client->_send_own_expect = 1; /* this must be set before calling build_request */
839
840
617
    h2o_iovec_t header = build_request(client, method, url, *props->connection_header, headers, num_headers);
841
617
    reqbufs[reqbufcnt++] = header;
842
617
    client->super.bytes_written.header = header.len;
843
844
617
    client->_is_chunked = *props->chunked;
845
617
    client->_method_is_head = h2o_memis(method.base, method.len, H2O_STRLIT("HEAD"));
846
847
617
    assert(PTLS_ELEMENTSOF(reqbufs) - reqbufcnt >= 4); /* req_body_send_prepare could write to 4 additional elements */
848
617
    if (client->proceed_req != NULL) {
849
0
        h2o_buffer_init(&client->body_buf.buf, &h2o_socket_buffer_prototype);
850
0
        if (body.len != 0 && !h2o_buffer_try_append(&client->body_buf.buf, body.base, body.len)) {
851
0
            on_whole_request_sent(client->sock, h2o_httpclient_error_internal);
852
0
            return;
853
0
        }
854
0
        if (client->_send_own_expect) {
855
0
            h2o_socket_write(client->sock, reqbufs, reqbufcnt, on_header_sent_wait_100);
856
0
        } else {
857
0
            size_t bytes_written;
858
0
            reqbufcnt += req_body_send_prepare(client, reqbufs + reqbufcnt, &bytes_written);
859
0
            client->super.bytes_written.body = bytes_written;
860
0
            h2o_socket_write(client->sock, reqbufs, reqbufcnt, req_body_send_complete);
861
0
        }
862
617
    } else if (body.len != 0) {
863
41
        assert(!client->_is_chunked);
864
41
        if (client->_send_own_expect) {
865
0
            h2o_buffer_init(&client->body_buf.buf, &h2o_socket_buffer_prototype);
866
0
            client->body_buf.is_end_stream = 1;
867
0
            if (!h2o_buffer_try_append(&client->body_buf.buf, body.base, body.len)) {
868
0
                on_whole_request_sent(client->sock, h2o_httpclient_error_internal);
869
0
                return;
870
0
            }
871
0
            h2o_socket_write(client->sock, reqbufs, reqbufcnt, on_header_sent_wait_100);
872
41
        } else {
873
41
            reqbufs[reqbufcnt++] = body;
874
41
            client->super.bytes_written.body = body.len;
875
41
            h2o_socket_write(client->sock, reqbufs, reqbufcnt, on_whole_request_sent);
876
41
        }
877
576
    } else {
878
576
        assert(!client->_is_chunked);
879
576
        h2o_socket_write(client->sock, reqbufs, reqbufcnt, on_whole_request_sent);
880
576
    }
881
617
    client->super.bytes_written.total = client->sock->bytes_written;
882
883
    /* Even all data highly likely has been written into TCP sendbuf, it is our practice to assume the socket write operation is
884
     * asynchronous and link the timer. */
885
617
    client->super._timeout.cb = on_send_timeout;
886
617
    h2o_timer_link(client->super.ctx->loop, client->super.ctx->io_timeout, &client->super._timeout);
887
888
617
    client->state.req = STREAM_STATE_BODY;
889
617
    client->super.timings.request_begin_at = h2o_gettimeofday(client->super.ctx->loop);
890
891
    /* If there's possibility of using a pipe for forwarding the content, reduce maximum read size before fetching headers. The
892
     * intent here is to not do a full-sized read of 1MB. 16KB has been chosen so that all HTTP response headers would be available,
893
     * and that an almost full-sized HTTP/2 frame / TLS record can be generated for the first chunk of data that we pass through
894
     * memory. */
895
617
#if USE_PIPE_READER
896
617
    if (client->_app_prefers_pipe_reader && h2o_evloop_socket_max_read_size > 16384)
897
0
        h2o_evloop_socket_set_max_read_size(client->sock, 16384);
898
617
#endif
899
900
617
    h2o_socket_read_start(client->sock, on_head);
901
617
}
902
903
static void on_connection_ready(struct st_h2o_http1client_t *client)
904
617
{
905
617
    h2o_iovec_t proxy_protocol = h2o_iovec_init(NULL, 0);
906
617
    int chunked = 0;
907
617
    h2o_iovec_t connection_header = h2o_iovec_init(NULL, 0);
908
617
    h2o_httpclient_properties_t props = {
909
617
        &proxy_protocol,
910
617
        &chunked,
911
617
        &connection_header,
912
617
    };
913
617
    h2o_iovec_t method;
914
617
    h2o_url_t url;
915
617
    h2o_header_t *headers;
916
617
    size_t num_headers;
917
617
    h2o_iovec_t body;
918
919
617
    client->super._cb.on_head = client->super._cb.on_connect(&client->super, NULL, &method, &url, (const h2o_header_t **)&headers,
920
617
                                                             &num_headers, &body, &client->proceed_req, &props, client->_origin);
921
617
    client->_app_prefers_pipe_reader = props.prefer_pipe_reader;
922
923
617
    if (client->super._cb.on_head == NULL) {
924
0
        close_client(client);
925
0
        return;
926
0
    }
927
928
617
    start_request(client, method, &url, headers, num_headers, body, &props);
929
617
}
930
931
static void do_cancel(h2o_httpclient_t *_client)
932
0
{
933
0
    struct st_h2o_http1client_t *client = (struct st_h2o_http1client_t *)_client;
934
0
    client->_do_keepalive = 0;
935
0
    close_client(client);
936
0
}
937
938
void update_read_state(struct st_h2o_http1client_t *client)
939
499
{
940
    /* If pipe used, `client->reader` would have switched to `on_body_pipe` by the time this function is called for the first time.
941
     */
942
499
    assert((client->pipe_reader.on_body_piped != NULL) == (client->reader == on_body_to_pipe));
943
944
499
    if (client->reader == on_body_to_pipe) {
945
        /* When pipe is being used, resume read when consumption is notified from user. `h2o_socket_read_start` is invoked without
946
         * checking if we are already reading; this is because we want to make sure that the read callback replaced to the current
947
         * one. */
948
0
        h2o_socket_read_start(client->sock, client->reader);
949
499
    } else {
950
        /* When buffer is used, start / stop reading based on the amount of data being buffered. */
951
499
        if ((*client->super.buf)->size >= client->super.ctx->max_buffer_size) {
952
0
            if (h2o_socket_is_reading(client->sock)) {
953
0
                client->reader = client->sock->_cb.read;
954
0
                h2o_socket_read_stop(client->sock);
955
0
            }
956
499
        } else {
957
499
            if (!h2o_socket_is_reading(client->sock))
958
0
                h2o_socket_read_start(client->sock, client->reader);
959
499
        }
960
499
    }
961
962
    /* arm or unarm i/o timeout depending on if we are reading */
963
499
    if (h2o_socket_is_reading(client->sock)) {
964
499
        if (h2o_timer_is_linked(&client->super._timeout))
965
0
            h2o_timer_unlink(&client->super._timeout);
966
499
        h2o_timer_link(client->super.ctx->loop, client->super.ctx->io_timeout, &client->super._timeout);
967
499
    } else {
968
0
        if (h2o_timer_is_linked(&client->super._timeout))
969
0
            h2o_timer_unlink(&client->super._timeout);
970
0
    }
971
499
}
972
973
static void do_update_window(struct st_h2o_httpclient_t *_client)
974
0
{
975
0
    struct st_h2o_http1client_t *client = (void *)_client;
976
977
    /* When we are splicing to pipe, read synchronously. For prioritization logic to work correctly, it is important to provide
978
     * additional data synchronously in response to the invocation of `h2o_proceed_response`. When memory buffers are used,
979
     * lib/core/proxy.c uses a double buffering to prepare next chunk of data while a chunk of data is being fed to the HTTP
980
     * handlers via `h2o_sendvec`. But when using splice, the pipe is the only one buffer available. */
981
0
    if (client->reader == on_body_to_pipe) {
982
0
        on_body_to_pipe(client->sock, NULL);
983
0
        return;
984
0
    }
985
986
0
    update_read_state(client);
987
0
}
988
989
static void do_get_conn_properties(h2o_httpclient_t *_client, h2o_httpclient_conn_properties_t *properties)
990
617
{
991
617
    struct st_h2o_http1client_t *client = (void *)_client;
992
617
    h2o_httpclient_set_conn_properties_of_socket(client->sock, properties);
993
617
}
994
995
static void setup_client(struct st_h2o_http1client_t *client, h2o_socket_t *sock, h2o_url_t *origin)
996
617
{
997
617
    memset(&client->sock, 0, sizeof(*client) - offsetof(struct st_h2o_http1client_t, sock));
998
617
    client->super.cancel = do_cancel;
999
617
    client->super.get_conn_properties = do_get_conn_properties;
1000
617
    client->super.update_window = do_update_window;
1001
617
    client->super.write_req = do_write_req;
1002
617
    client->super.buf = &sock->input;
1003
617
    client->sock = sock;
1004
617
    sock->data = client;
1005
617
    client->_origin = origin;
1006
617
}
1007
1008
void h2o_httpclient__h1_on_connect(h2o_httpclient_t *_client, h2o_socket_t *sock, h2o_url_t *origin)
1009
617
{
1010
617
    struct st_h2o_http1client_t *client = (void *)_client;
1011
1012
617
    assert(!h2o_timer_is_linked(&client->super._timeout));
1013
1014
617
    setup_client(client, sock, origin);
1015
617
    on_connection_ready(client);
1016
617
}
1017
1018
const size_t h2o_httpclient__h1_size = sizeof(struct st_h2o_http1client_t);