Coverage Report

Created: 2026-03-21 06:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/h2o/lib/common/http1client.c
Line
Count
Source
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
3.52k
{
99
3.52k
    if (client->sock != NULL) {
100
3.52k
        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
3.52k
        } else {
105
3.52k
            h2o_socket_close(client->sock);
106
3.52k
        }
107
3.52k
    }
108
3.52k
    if (h2o_timer_is_linked(&client->super._timeout))
109
352
        h2o_timer_unlink(&client->super._timeout);
110
3.52k
    if (client->body_buf.buf != NULL)
111
1.00k
        h2o_buffer_dispose(&client->body_buf.buf);
112
3.52k
    if (!client->_delay_free)
113
3.52k
        free(client);
114
3.52k
}
115
116
static void close_response(struct st_h2o_http1client_t *client)
117
3.08k
{
118
3.08k
    assert(client->state.res == STREAM_STATE_CLOSED);
119
3.08k
    if (client->state.req == STREAM_STATE_CLOSED) {
120
2.50k
        close_client(client);
121
2.50k
    } else {
122
580
        h2o_socket_read_stop(client->sock);
123
580
    }
124
3.08k
}
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
3.23k
{
128
3.23k
    assert(!client->_delay_free);
129
3.23k
    client->_delay_free = 1;
130
3.23k
    h2o_httpclient_body_cb cb = client->super._cb.on_head(&client->super, errstr, args);
131
3.23k
    client->_delay_free = 0;
132
3.23k
    return cb;
133
3.23k
}
134
135
static int call_on_body(struct st_h2o_http1client_t *client, const char *errstr)
136
5.10k
{
137
5.10k
    assert(!client->_delay_free);
138
5.10k
    client->_delay_free = 1;
139
5.10k
    int ret = (client->reader == on_body_to_pipe ? client->pipe_reader.on_body_piped : client->super._cb.on_body)(&client->super,
140
5.10k
                                                                                                                  errstr, NULL, 0);
141
5.10k
    client->_delay_free = 0;
142
5.10k
    return ret;
143
5.10k
}
144
145
static void call_proceed_req(struct st_h2o_http1client_t *client, const char *errstr)
146
1.65k
{
147
1.65k
    assert(!client->_delay_free);
148
1.65k
    client->_delay_free = 1;
149
1.65k
    client->proceed_req(&client->super, errstr);
150
1.65k
    client->_delay_free = 0;
151
1.65k
}
152
153
static void on_error(struct st_h2o_http1client_t *client, const char *errstr)
154
442
{
155
442
    switch (client->state.res) {
156
48
    case STREAM_STATE_HEAD:
157
48
        call_on_head(client, errstr, NULL);
158
48
        break;
159
49
    case STREAM_STATE_BODY:
160
49
        call_on_body(client, errstr);
161
49
        break;
162
345
    case STREAM_STATE_CLOSED:
163
345
        if (client->proceed_req != NULL)
164
342
            call_proceed_req(client, errstr);
165
345
        break;
166
442
    }
167
442
    close_client(client);
168
442
}
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
5.05k
{
178
5.05k
    struct st_h2o_http1client_t *client = sock->data;
179
180
5.05k
    h2o_timer_unlink(&client->super._timeout);
181
182
5.05k
    if (err != NULL) {
183
2.47k
        client->state.res = STREAM_STATE_CLOSED;
184
2.47k
        client->super.timings.response_end_at = h2o_gettimeofday(client->super.ctx->loop);
185
2.47k
        call_on_body(client, h2o_httpclient_error_is_eos);
186
2.47k
        close_response(client);
187
2.47k
        return;
188
2.47k
    }
189
2.58k
    uint64_t size = sock->bytes_read - client->_socket_bytes_processed;
190
2.58k
    client->_socket_bytes_processed = sock->bytes_read;
191
192
2.58k
    client->super.bytes_read.body += size;
193
2.58k
    client->super.bytes_read.total += size;
194
195
2.58k
    if (size != 0) {
196
2.58k
        if (call_on_body(client, NULL) != 0) {
197
0
            close_client(client);
198
0
            return;
199
0
        }
200
2.58k
        update_read_state(client);
201
2.58k
    }
202
2.58k
}
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
    size_t bytes_to_splice = client->_body_decoder.content_length.bytesleft < H2O_PULL_SENDVEC_MAX_SIZE
268
0
                                 ? client->_body_decoder.content_length.bytesleft
269
0
                                 : H2O_PULL_SENDVEC_MAX_SIZE;
270
271
0
    ssize_t bytes_read;
272
0
    while ((bytes_read = splice(h2o_socket_get_fd(client->sock), NULL, client->pipe_reader.fd, NULL, bytes_to_splice,
273
0
                                SPLICE_F_NONBLOCK)) == -1 &&
274
0
           errno == EINTR)
275
0
        ;
276
0
    if (bytes_read == -1 && errno == EAGAIN) {
277
0
        update_read_state(client);
278
0
        return;
279
0
    }
280
0
    if (bytes_read <= 0) {
281
0
        on_error(client, h2o_httpclient_error_io);
282
0
        return;
283
0
    }
284
285
0
    client->_socket_bytes_processed += bytes_read;
286
0
    client->sock->bytes_read += bytes_read;
287
0
    client->super.bytes_read.body += bytes_read;
288
0
    client->super.bytes_read.total += bytes_read;
289
290
0
    client->_body_decoder.content_length.bytesleft -= bytes_read;
291
0
    if (client->_body_decoder.content_length.bytesleft == 0) {
292
0
        client->state.res = STREAM_STATE_CLOSED;
293
0
        client->super.timings.response_end_at = h2o_gettimeofday(client->super.ctx->loop);
294
0
        h2o_socket_dont_read(client->sock, 0);
295
0
    }
296
297
0
    int ret = call_on_body(client, client->state.res == STREAM_STATE_CLOSED ? h2o_httpclient_error_is_eos : NULL);
298
299
0
    if (client->state.res == STREAM_STATE_CLOSED) {
300
0
        close_response(client);
301
0
    } else if (ret != 0) {
302
0
        client->_do_keepalive = 0;
303
0
        close_client(client);
304
0
    }
305
#else
306
    h2o_fatal("%s cannot be called", __FUNCTION__);
307
#endif
308
0
}
309
310
static void on_body_chunked(h2o_socket_t *sock, const char *err)
311
0
{
312
0
    struct st_h2o_http1client_t *client = sock->data;
313
0
    h2o_buffer_t *inbuf;
314
315
0
    h2o_timer_unlink(&client->super._timeout);
316
317
0
    if (err != NULL) {
318
0
        if (err == h2o_socket_error_closed && !phr_decode_chunked_is_in_data(&client->_body_decoder.chunked.decoder) &&
319
0
            client->_seen_at_least_one_chunk) {
320
            /*
321
             * if the peer closed after a full chunk, treat this
322
             * as if the transfer had complete, browsers appear to ignore
323
             * a missing 0\r\n chunk
324
             */
325
0
            client->_do_keepalive = 0;
326
0
            client->state.res = STREAM_STATE_CLOSED;
327
0
            client->super.timings.response_end_at = h2o_gettimeofday(client->super.ctx->loop);
328
0
            call_on_body(client, h2o_httpclient_error_is_eos);
329
0
            close_response(client);
330
0
        } else {
331
0
            on_error(client, h2o_httpclient_error_io);
332
0
        }
333
0
        return;
334
0
    }
335
0
    uint64_t size = sock->bytes_read - client->_socket_bytes_processed;
336
0
    client->_socket_bytes_processed = sock->bytes_read;
337
338
0
    client->super.bytes_read.body += size;
339
0
    client->super.bytes_read.total += size;
340
341
0
    inbuf = client->sock->input;
342
0
    if (size != 0) {
343
0
        const char *errstr;
344
0
        int cb_ret;
345
0
        size_t newsz = size;
346
347
0
        switch (phr_decode_chunked(&client->_body_decoder.chunked.decoder, inbuf->bytes + inbuf->size - newsz, &newsz)) {
348
0
        case -1: /* error */
349
0
            newsz = size;
350
0
            client->_do_keepalive = 0;
351
0
            errstr = h2o_httpclient_error_http1_parse_failed;
352
0
            break;
353
0
        case -2: /* incomplete */
354
0
            errstr = NULL;
355
0
            break;
356
0
        default: /* complete, with garbage on tail; should disable keepalive */
357
0
            client->_do_keepalive = 0;
358
        /* fallthru */
359
0
        case 0: /* complete */
360
0
            client->state.res = STREAM_STATE_CLOSED;
361
0
            errstr = h2o_httpclient_error_is_eos;
362
0
            client->super.timings.response_end_at = h2o_gettimeofday(client->super.ctx->loop);
363
0
            break;
364
0
        }
365
0
        inbuf->size -= size - newsz;
366
0
        if (inbuf->size > 0)
367
0
            client->_seen_at_least_one_chunk = 1;
368
0
        cb_ret = call_on_body(client, errstr);
369
0
        if (client->state.res == STREAM_STATE_CLOSED) {
370
0
            close_response(client);
371
0
            return;
372
0
        } else if (errstr != NULL) {
373
0
            close_client(client);
374
0
            return;
375
0
        } else if (cb_ret != 0) {
376
0
            client->_do_keepalive = 0;
377
0
            close_client(client);
378
0
            return;
379
0
        }
380
0
        update_read_state(client);
381
0
    }
382
0
}
383
384
static void on_head_timeout(h2o_timer_t *entry)
385
0
{
386
0
    struct st_h2o_http1client_t *client = H2O_STRUCT_FROM_MEMBER(struct st_h2o_http1client_t, super._timeout, entry);
387
0
    on_error(client, h2o_httpclient_error_io_timeout);
388
0
}
389
390
static void on_head(h2o_socket_t *sock, const char *err)
391
3.18k
{
392
3.18k
    struct st_h2o_http1client_t *client = sock->data;
393
3.18k
    int minor_version, version, http_status, rlen;
394
3.18k
    const char *msg;
395
3.18k
#define MAX_HEADERS 100
396
3.18k
    h2o_header_t *headers;
397
3.18k
    h2o_iovec_t *header_names;
398
3.18k
    size_t msg_len, num_headers, i;
399
3.18k
    h2o_socket_cb reader;
400
401
3.18k
    h2o_timer_unlink(&client->super._timeout);
402
403
3.18k
    if (err != NULL) {
404
0
        on_error(client, h2o_httpclient_error_io);
405
0
        return;
406
0
    }
407
408
    /* revert max read size to 1MB now that we have received the first chunk, presumably carrying all the response headers */
409
3.18k
#if USE_PIPE_READER
410
3.18k
    if (client->_app_prefers_pipe_reader)
411
1.99k
        h2o_evloop_socket_set_max_read_size(client->sock, h2o_evloop_socket_max_read_size);
412
3.18k
#endif
413
414
3.18k
    client->super._timeout.cb = on_head_timeout;
415
416
3.18k
    headers = h2o_mem_alloc_pool(client->super.pool, *headers, MAX_HEADERS);
417
3.18k
    header_names = h2o_mem_alloc_pool(client->super.pool, *header_names, MAX_HEADERS);
418
419
    /* continue parsing the responses until we see a final one */
420
3.18k
    while (1) {
421
        /* parse response */
422
3.18k
        struct phr_header src_headers[MAX_HEADERS];
423
3.18k
        num_headers = MAX_HEADERS;
424
3.18k
        rlen = phr_parse_response(sock->input->bytes, sock->input->size, &minor_version, &http_status, &msg, &msg_len, src_headers,
425
3.18k
                                  &num_headers, 0);
426
3.18k
        switch (rlen) {
427
0
        case -1: /* error */
428
0
            on_error(client, h2o_httpclient_error_http1_parse_failed);
429
0
            return;
430
0
        case -2: /* incomplete */
431
0
            h2o_timer_link(client->super.ctx->loop, client->super.ctx->io_timeout, &client->super._timeout);
432
0
            return;
433
3.18k
        }
434
435
3.18k
        client->super.bytes_read.header += rlen;
436
3.18k
        client->super.bytes_read.total += rlen;
437
438
3.18k
        version = 0x100 | (minor_version != 0);
439
440
        /* fill-in the headers */
441
6.37k
        for (i = 0; i != num_headers; ++i) {
442
3.18k
            if (src_headers[i].name_len == 0) {
443
                /* reject multiline header */
444
0
                on_error(client, h2o_httpclient_error_http1_line_folding);
445
0
                return;
446
0
            }
447
3.18k
            const h2o_token_t *token;
448
3.18k
            char *orig_name = h2o_strdup(client->super.pool, src_headers[i].name, src_headers[i].name_len).base;
449
3.18k
            h2o_strtolower((char *)src_headers[i].name, src_headers[i].name_len);
450
3.18k
            token = h2o_lookup_token(src_headers[i].name, src_headers[i].name_len);
451
3.18k
            if (token != NULL) {
452
3.18k
                headers[i].name = (h2o_iovec_t *)&token->buf;
453
3.18k
            } else {
454
0
                header_names[i] = h2o_iovec_init(src_headers[i].name, src_headers[i].name_len);
455
0
                headers[i].name = &header_names[i];
456
0
            }
457
3.18k
            headers[i].value = h2o_iovec_init(src_headers[i].value, src_headers[i].value_len);
458
3.18k
            headers[i].orig_name = orig_name;
459
3.18k
            headers[i].flags = (h2o_header_flags_t){0};
460
3.18k
        }
461
462
3.18k
        if (http_status == 101) {
463
0
            if (client->_send_own_expect) {
464
                /* expect: 100-continue is incompatible CONNECT or upgrade (when trying to establish a tunnel */
465
0
                on_error(client, h2o_httpclient_error_unexpected_101);
466
0
                return;
467
0
            }
468
0
            break;
469
3.18k
        } else if (http_status == 100 || http_status >= 200) {
470
            /* When request body has been withheld and a 100 or a final response has been received, start sending the request body,
471
             * see: https://github.com/h2o/h2o/pull/3316#discussion_r1456859634. */
472
3.18k
            if (client->_send_own_expect) {
473
0
                client->_send_own_expect = 0;
474
0
                req_body_send(client);
475
0
            }
476
3.18k
            if (http_status >= 200)
477
3.18k
                break;
478
3.18k
        }
479
3.18k
        assert(http_status <= 199);
480
0
        if (client->super.informational_cb != NULL &&
481
0
            client->super.informational_cb(&client->super, version, http_status, h2o_iovec_init(msg, msg_len), headers,
482
0
                                           num_headers) != 0) {
483
0
            close_client(client);
484
0
            return;
485
0
        }
486
487
0
        h2o_buffer_consume(&client->sock->input, rlen);
488
0
        if (client->sock->input->size == 0) {
489
0
            if (!h2o_timer_is_linked(&client->super._timeout)) {
490
0
                h2o_timer_link(client->super.ctx->loop, client->super.ctx->io_timeout, &client->super._timeout);
491
0
            }
492
0
            return;
493
0
        }
494
0
    }
495
496
    /* recognize hop-by-hop response headers */
497
3.18k
    reader = on_body_until_close;
498
3.18k
    if (!h2o_httpclient__tunnel_is_ready(&client->super, http_status, version)) {
499
3.18k
        client->_do_keepalive = minor_version >= 1;
500
6.37k
        for (i = 0; i != num_headers; ++i) {
501
3.18k
            if (headers[i].name == &H2O_TOKEN_CONNECTION->buf) {
502
3.18k
                if (h2o_contains_token(headers[i].value.base, headers[i].value.len, H2O_STRLIT("keep-alive"), ',')) {
503
0
                    client->_do_keepalive = 1;
504
3.18k
                } else {
505
3.18k
                    client->_do_keepalive = 0;
506
3.18k
                }
507
3.18k
            } else if (headers[i].name == &H2O_TOKEN_TRANSFER_ENCODING->buf) {
508
0
                if (h2o_memis(headers[i].value.base, headers[i].value.len, H2O_STRLIT("chunked"))) {
509
                    /* precond: _body_decoder.chunked is zero-filled */
510
0
                    client->_body_decoder.chunked.decoder.consume_trailer = 1;
511
0
                    reader = on_body_chunked;
512
0
                } else if (h2o_memis(headers[i].value.base, headers[i].value.len, H2O_STRLIT("identity"))) {
513
                    /* continue */
514
0
                } else {
515
0
                    on_error(client, h2o_httpclient_error_http1_unexpected_transfer_encoding);
516
0
                    return;
517
0
                }
518
0
            } else if (headers[i].name == &H2O_TOKEN_CONTENT_LENGTH->buf) {
519
0
                if ((client->_body_decoder.content_length.bytesleft = h2o_strtosize(headers[i].value.base, headers[i].value.len)) ==
520
0
                    SIZE_MAX) {
521
0
                    on_error(client, h2o_httpclient_error_invalid_content_length);
522
0
                    return;
523
0
                }
524
0
                if (reader != on_body_chunked)
525
0
                    reader = on_body_content_length;
526
0
            }
527
3.18k
        }
528
3.18k
    }
529
530
3.18k
    client->state.res = STREAM_STATE_BODY;
531
3.18k
    client->super.timings.response_start_at = h2o_gettimeofday(client->super.ctx->loop);
532
533
    /* RFC 2616 4.4 */
534
3.18k
    if (client->_method_is_head || http_status == 204 || http_status == 304) {
535
606
        client->state.res = STREAM_STATE_CLOSED;
536
606
        client->super.timings.response_end_at = h2o_gettimeofday(client->super.ctx->loop);
537
2.58k
    } else {
538
        /* close the connection if impossible to determine the end of the response (RFC 7230 3.3.3) */
539
2.58k
        if (reader == on_body_until_close)
540
2.58k
            client->_do_keepalive = 0;
541
2.58k
    }
542
543
3.18k
    h2o_httpclient_on_head_t on_head = {
544
3.18k
        .version = version,
545
3.18k
        .status = http_status,
546
3.18k
        .msg = h2o_iovec_init(msg, msg_len),
547
3.18k
        .headers = headers,
548
3.18k
        .num_headers = num_headers,
549
3.18k
        .header_requires_dup = 1,
550
3.18k
    };
551
3.18k
#if USE_PIPE_READER
552
    /* If there is no less than 64KB of data to be read from the socket, offer the application the opportunity to use pipe for
553
     * transferring the content zero-copy. As switching to pipe involves the cost of creating a pipe (and disposing it when the
554
     * request is complete), we adopt this margin of 64KB, which offers clear improvement (5%) on 9th-gen Intel Core. */
555
3.18k
    if (client->_app_prefers_pipe_reader && reader == on_body_content_length &&
556
0
        client->sock->input->size + 65536 <= client->_body_decoder.content_length.bytesleft && client->sock->ssl == NULL)
557
0
        on_head.pipe_reader = &client->pipe_reader;
558
3.18k
#endif
559
560
    /* call the callback */
561
3.18k
    client->super._cb.on_body =
562
3.18k
        call_on_head(client, client->state.res == STREAM_STATE_CLOSED ? h2o_httpclient_error_is_eos : NULL, &on_head);
563
564
3.18k
    if (client->state.res == STREAM_STATE_CLOSED) {
565
606
        close_response(client);
566
606
        return;
567
2.58k
    } else if (client->super._cb.on_body == NULL) {
568
0
        client->_do_keepalive = 0;
569
0
        close_client(client);
570
0
        return;
571
0
    }
572
573
2.58k
    h2o_buffer_consume(&sock->input, rlen);
574
2.58k
    client->_socket_bytes_processed = client->sock->bytes_read - client->sock->input->size;
575
576
2.58k
    client->super._timeout.cb = on_body_timeout;
577
2.58k
    h2o_socket_read_start(sock, reader);
578
2.58k
    reader(client->sock, 0);
579
580
2.58k
#undef MAX_HEADERS
581
2.58k
}
582
583
static void on_head_first_byte_timeout(h2o_timer_t *entry)
584
0
{
585
0
    struct st_h2o_http1client_t *client = H2O_STRUCT_FROM_MEMBER(struct st_h2o_http1client_t, super._timeout, entry);
586
0
    on_error(client, h2o_httpclient_error_first_byte_timeout);
587
0
}
588
589
static void on_whole_request_sent(h2o_socket_t *sock, const char *err)
590
3.18k
{
591
3.18k
    struct st_h2o_http1client_t *client = sock->data;
592
593
3.18k
    h2o_timer_unlink(&client->super._timeout);
594
595
3.18k
    if (err != NULL) {
596
442
        on_error(client, h2o_httpclient_error_io);
597
442
        return;
598
442
    }
599
600
2.74k
    client->state.req = STREAM_STATE_CLOSED;
601
2.74k
    client->super.timings.request_end_at = h2o_gettimeofday(client->super.ctx->loop);
602
603
2.74k
    if (client->super.upgrade_to != NULL) {
604
        /* TODO use shutdown(2) to signal the peer that our send side has been closed, but continue reading on the receive side. */
605
0
        on_error(client, client->state.res < STREAM_STATE_BODY ? h2o_httpclient_error_io : h2o_httpclient_error_is_eos);
606
2.74k
    } else {
607
2.74k
        switch (client->state.res) {
608
2.74k
        case STREAM_STATE_HEAD:
609
2.74k
            client->super._timeout.cb = on_head_first_byte_timeout;
610
2.74k
            h2o_timer_link(client->super.ctx->loop, client->super.ctx->first_byte_timeout, &client->super._timeout);
611
2.74k
            break;
612
0
        case STREAM_STATE_BODY:
613
0
            break;
614
0
        case STREAM_STATE_CLOSED:
615
0
            close_client(client);
616
0
            break;
617
2.74k
        }
618
2.74k
    }
619
2.74k
}
620
621
static void on_header_sent_wait_100(h2o_socket_t *sock, const char *err)
622
0
{
623
0
    struct st_h2o_http1client_t *client = sock->data;
624
625
0
    h2o_timer_unlink(&client->super._timeout);
626
627
0
    if (err != NULL) {
628
0
        on_error(client, h2o_httpclient_error_io);
629
0
        return;
630
0
    }
631
632
0
    if (client->state.res == STREAM_STATE_HEAD) {
633
0
        client->super._timeout.cb = on_head_first_byte_timeout;
634
0
        h2o_timer_link(client->super.ctx->loop, client->super.ctx->first_byte_timeout, &client->super._timeout);
635
0
    }
636
0
}
637
638
static void req_body_send_complete(h2o_socket_t *sock, const char *err)
639
1.72k
{
640
1.72k
    struct st_h2o_http1client_t *client = sock->data;
641
642
1.72k
    h2o_buffer_consume(&client->body_buf.buf, client->body_buf.buf->size);
643
644
1.72k
    if (err != NULL) {
645
411
        on_whole_request_sent(client->sock, err);
646
411
        return;
647
411
    }
648
649
1.31k
    int is_end_stream = client->body_buf.is_end_stream;
650
651
1.31k
    if (client->proceed_req != NULL) {
652
1.31k
        call_proceed_req(client, NULL);
653
1.31k
    }
654
655
1.31k
    if (is_end_stream)
656
247
        on_whole_request_sent(client->sock, NULL);
657
1.31k
}
658
659
/**
660
 * Encodes data. `bufs` must have at least 4 elements of space.
661
 */
662
static size_t req_body_send_prepare(struct st_h2o_http1client_t *client, h2o_iovec_t *bufs, size_t *bytes)
663
1.74k
{
664
1.74k
    size_t bufcnt = 0;
665
1.74k
    *bytes = 0;
666
667
1.74k
    if (client->_is_chunked) {
668
727
        if (client->body_buf.buf->size != 0) {
669
            /* build chunk header */
670
703
            bufs[bufcnt].base = client->_chunk_len_str;
671
703
            bufs[bufcnt].len =
672
703
                snprintf(client->_chunk_len_str, sizeof(client->_chunk_len_str), "%zx\r\n", client->body_buf.buf->size);
673
703
            *bytes += bufs[bufcnt].len;
674
703
            ++bufcnt;
675
            /* append chunk body */
676
703
            bufs[bufcnt++] = h2o_iovec_init(client->body_buf.buf->bytes, client->body_buf.buf->size);
677
703
            *bytes += client->body_buf.buf->size;
678
            /* append CRLF */
679
703
            bufs[bufcnt++] = h2o_iovec_init("\r\n", 2);
680
703
            *bytes += 2;
681
703
        }
682
727
        if (client->body_buf.is_end_stream) {
683
143
            static const h2o_iovec_t terminator = {H2O_STRLIT("0\r\n\r\n")};
684
143
            bufs[bufcnt++] = terminator;
685
143
            *bytes += terminator.len;
686
143
        }
687
1.01k
    } else if (client->body_buf.buf->size != 0) {
688
1.00k
        bufs[bufcnt++] = h2o_iovec_init(client->body_buf.buf->bytes, client->body_buf.buf->size);
689
1.00k
        *bytes += client->body_buf.buf->size;
690
1.00k
    }
691
692
1.74k
    return bufcnt;
693
1.74k
}
694
695
static void req_body_send(struct st_h2o_http1client_t *client)
696
739
{
697
739
    h2o_iovec_t bufs[4];
698
739
    size_t bytes, bufcnt = req_body_send_prepare(client, bufs, &bytes);
699
700
739
    h2o_timer_unlink(&client->super._timeout);
701
702
739
    h2o_socket_write(client->sock, bufs, bufcnt, req_body_send_complete);
703
739
    client->super.bytes_written.body += bytes;
704
739
    client->super.bytes_written.total += bytes;
705
706
739
    h2o_timer_link(client->super.ctx->loop, client->super.ctx->io_timeout, &client->super._timeout);
707
739
}
708
709
static int do_write_req(h2o_httpclient_t *_client, h2o_iovec_t chunk, int is_end_stream)
710
739
{
711
739
    struct st_h2o_http1client_t *client = (struct st_h2o_http1client_t *)_client;
712
713
739
    assert(chunk.len != 0 || is_end_stream);
714
739
    assert(!h2o_socket_is_writing(client->sock));
715
739
    assert(client->body_buf.buf->size == 0);
716
717
    /* store given content to buffer */
718
739
    if (chunk.len != 0) {
719
715
        if (!h2o_buffer_try_append(&client->body_buf.buf, chunk.base, chunk.len))
720
0
            return -1;
721
715
    }
722
739
    client->body_buf.is_end_stream = is_end_stream;
723
724
    /* check if the connection has to be closed for correct framing */
725
739
    if (client->state.res == STREAM_STATE_CLOSED)
726
347
        client->_do_keepalive = 0;
727
728
739
    req_body_send(client);
729
730
739
    return 0;
731
739
}
732
733
static void on_send_timeout(h2o_timer_t *entry)
734
0
{
735
0
    struct st_h2o_http1client_t *client = H2O_STRUCT_FROM_MEMBER(struct st_h2o_http1client_t, super._timeout, entry);
736
0
    on_error(client, h2o_httpclient_error_io_timeout);
737
0
}
738
739
static h2o_iovec_t build_request(struct st_h2o_http1client_t *client, h2o_iovec_t method, const h2o_url_t *url,
740
                                 h2o_iovec_t connection, const h2o_header_t *headers, size_t num_headers)
741
3.52k
{
742
3.52k
    h2o_iovec_t buf;
743
3.52k
    size_t offset = 0;
744
745
3.52k
    buf.len = method.len + url->path.len + url->authority.len + 512;
746
3.52k
    buf.base = h2o_mem_alloc_pool(client->super.pool, char, buf.len);
747
748
3.52k
#define RESERVE(sz)                                                                                                                \
749
329k
    do {                                                                                                                           \
750
329k
        size_t required = offset + sz + 4 /* for "\r\n\r\n" */;                                                                    \
751
329k
        if (required > buf.len) {                                                                                                  \
752
8.51k
            do {                                                                                                                   \
753
8.51k
                buf.len *= 2;                                                                                                      \
754
8.51k
            } while (required > buf.len);                                                                                          \
755
3.77k
            char *newp = h2o_mem_alloc_pool(client->super.pool, char, buf.len);                                                    \
756
3.77k
            memcpy(newp, buf.base, offset);                                                                                        \
757
3.77k
            buf.base = newp;                                                                                                       \
758
3.77k
        }                                                                                                                          \
759
329k
    } while (0)
760
3.52k
#define APPEND(s, l)                                                                                                               \
761
676k
    do {                                                                                                                           \
762
676k
        h2o_memcpy(buf.base + offset, (s), (l));                                                                                   \
763
676k
        offset += (l);                                                                                                             \
764
676k
    } while (0)
765
7.05k
#define APPEND_STRLIT(lit) APPEND((lit), sizeof(lit) - 1)
766
3.52k
#define APPEND_HEADER(h)                                                                                                           \
767
329k
    do {                                                                                                                           \
768
329k
        RESERVE((h)->name->len + (h)->value.len + 4);                                                                              \
769
329k
        APPEND((h)->orig_name ? (h)->orig_name : (h)->name->base, (h)->name->len);                                                 \
770
329k
        buf.base[offset++] = ':';                                                                                                  \
771
329k
        buf.base[offset++] = ' ';                                                                                                  \
772
329k
        APPEND((h)->value.base, (h)->value.len);                                                                                   \
773
329k
        buf.base[offset++] = '\r';                                                                                                 \
774
329k
        buf.base[offset++] = '\n';                                                                                                 \
775
329k
    } while (0)
776
777
3.52k
    APPEND(method.base, method.len);
778
3.52k
    buf.base[offset++] = ' ';
779
3.52k
    if (client->super.upgrade_to == h2o_httpclient_upgrade_to_connect) {
780
0
        if (h2o_memis(method.base, method.len, H2O_STRLIT("CONNECT-UDP"))) {
781
0
            APPEND_STRLIT("masque://");
782
0
            APPEND(url->authority.base, url->authority.len);
783
0
            APPEND_STRLIT("/");
784
0
        } else {
785
0
            APPEND(url->authority.base, url->authority.len);
786
0
        }
787
3.52k
    } else {
788
3.52k
        APPEND(url->path.base, url->path.len);
789
3.52k
    }
790
3.52k
    APPEND_STRLIT(" HTTP/1.1\r\nhost: ");
791
3.52k
    APPEND(url->authority.base, url->authority.len);
792
3.52k
    buf.base[offset++] = '\r';
793
3.52k
    buf.base[offset++] = '\n';
794
3.52k
    assert(offset <= buf.len);
795
796
    /* append supplied connection header, or "connection: upgrade" and upgrade header when request an upgrade */
797
3.52k
    if (client->super.upgrade_to != NULL && client->super.upgrade_to != h2o_httpclient_upgrade_to_connect) {
798
0
        h2o_header_t c = {&H2O_TOKEN_CONNECTION->buf, NULL, h2o_iovec_init(H2O_STRLIT("upgrade"))},
799
0
                     u = {&H2O_TOKEN_UPGRADE->buf, NULL,
800
0
                          h2o_iovec_init(client->super.upgrade_to, strlen(client->super.upgrade_to))};
801
0
        APPEND_HEADER(&c);
802
0
        APPEND_HEADER(&u);
803
3.52k
    } else if (connection.base != NULL) {
804
3.52k
        h2o_header_t h = {&H2O_TOKEN_CONNECTION->buf, NULL, connection};
805
3.52k
        APPEND_HEADER(&h);
806
3.52k
    }
807
808
3.52k
    if (client->_send_own_expect) {
809
0
        h2o_header_t h = {&H2O_TOKEN_EXPECT->buf, NULL, h2o_iovec_init(H2O_STRLIT("100-continue"))};
810
0
        APPEND_HEADER(&h);
811
0
    }
812
813
3.52k
    if (num_headers != 0) {
814
329k
        for (const h2o_header_t *h = headers, *h_end = h + num_headers; h != h_end; ++h)
815
326k
            APPEND_HEADER(h);
816
3.52k
    }
817
818
3.52k
    APPEND_STRLIT("\r\n");
819
820
    /* set the length */
821
3.52k
    assert(offset <= buf.len);
822
3.52k
    buf.len = offset;
823
824
3.52k
    return buf;
825
826
3.52k
#undef RESERVE
827
3.52k
#undef APPEND
828
3.52k
#undef APPEND_STRLIT
829
3.52k
}
830
831
static void start_request(struct st_h2o_http1client_t *client, h2o_iovec_t method, const h2o_url_t *url,
832
                          const h2o_header_t *headers, size_t num_headers, h2o_iovec_t body,
833
                          const h2o_httpclient_properties_t *props)
834
3.52k
{
835
3.52k
    h2o_iovec_t reqbufs[6]; /* 6 should be the maximum possible elements used */
836
3.52k
    size_t reqbufcnt = 0;
837
3.52k
    if (props->proxy_protocol->base != NULL)
838
0
        reqbufs[reqbufcnt++] = *props->proxy_protocol;
839
840
3.52k
    if (props->send_own_expect && (client->proceed_req != NULL || body.len != 0) && client->super.upgrade_to == NULL)
841
0
        client->_send_own_expect = 1; /* this must be set before calling build_request */
842
843
3.52k
    h2o_iovec_t header = build_request(client, method, url, *props->connection_header, headers, num_headers);
844
3.52k
    reqbufs[reqbufcnt++] = header;
845
3.52k
    client->super.bytes_written.header = header.len;
846
847
3.52k
    client->_is_chunked = *props->chunked;
848
3.52k
    client->_method_is_head = h2o_memis(method.base, method.len, H2O_STRLIT("HEAD"));
849
850
3.52k
    assert(PTLS_ELEMENTSOF(reqbufs) - reqbufcnt >= 4); /* req_body_send_prepare could write to 4 additional elements */
851
3.52k
    if (client->proceed_req != NULL) {
852
1.00k
        h2o_buffer_init(&client->body_buf.buf, &h2o_socket_buffer_prototype);
853
1.00k
        if (body.len != 0 && !h2o_buffer_try_append(&client->body_buf.buf, body.base, body.len)) {
854
0
            on_whole_request_sent(client->sock, h2o_httpclient_error_internal);
855
0
            return;
856
0
        }
857
1.00k
        if (client->_send_own_expect) {
858
0
            h2o_socket_write(client->sock, reqbufs, reqbufcnt, on_header_sent_wait_100);
859
1.00k
        } else {
860
1.00k
            size_t bytes_written;
861
1.00k
            reqbufcnt += req_body_send_prepare(client, reqbufs + reqbufcnt, &bytes_written);
862
1.00k
            client->super.bytes_written.body = bytes_written;
863
1.00k
            h2o_socket_write(client->sock, reqbufs, reqbufcnt, req_body_send_complete);
864
1.00k
        }
865
2.52k
    } else if (body.len != 0) {
866
137
        assert(!client->_is_chunked);
867
137
        if (client->_send_own_expect) {
868
0
            h2o_buffer_init(&client->body_buf.buf, &h2o_socket_buffer_prototype);
869
0
            client->body_buf.is_end_stream = 1;
870
0
            if (!h2o_buffer_try_append(&client->body_buf.buf, body.base, body.len)) {
871
0
                on_whole_request_sent(client->sock, h2o_httpclient_error_internal);
872
0
                return;
873
0
            }
874
0
            h2o_socket_write(client->sock, reqbufs, reqbufcnt, on_header_sent_wait_100);
875
137
        } else {
876
137
            reqbufs[reqbufcnt++] = body;
877
137
            client->super.bytes_written.body = body.len;
878
137
            h2o_socket_write(client->sock, reqbufs, reqbufcnt, on_whole_request_sent);
879
137
        }
880
2.38k
    } else {
881
2.38k
        assert(!client->_is_chunked);
882
2.38k
        h2o_socket_write(client->sock, reqbufs, reqbufcnt, on_whole_request_sent);
883
2.38k
    }
884
3.52k
    client->super.bytes_written.total = client->sock->bytes_written;
885
886
    /* Even all data highly likely has been written into TCP sendbuf, it is our practice to assume the socket write operation is
887
     * asynchronous and link the timer. */
888
3.52k
    client->super._timeout.cb = on_send_timeout;
889
3.52k
    h2o_timer_link(client->super.ctx->loop, client->super.ctx->io_timeout, &client->super._timeout);
890
891
3.52k
    client->state.req = STREAM_STATE_BODY;
892
3.52k
    client->super.timings.request_begin_at = h2o_gettimeofday(client->super.ctx->loop);
893
894
    /* If there's possibility of using a pipe for forwarding the content, reduce maximum read size before fetching headers. The
895
     * 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,
896
     * and that an almost full-sized HTTP/2 frame / TLS record can be generated for the first chunk of data that we pass through
897
     * memory. */
898
3.52k
#if USE_PIPE_READER
899
3.52k
    if (client->_app_prefers_pipe_reader && h2o_evloop_socket_max_read_size > 16384)
900
2.02k
        h2o_evloop_socket_set_max_read_size(client->sock, 16384);
901
3.52k
#endif
902
903
3.52k
    h2o_socket_read_start(client->sock, on_head);
904
3.52k
}
905
906
static void on_connection_ready(struct st_h2o_http1client_t *client)
907
3.52k
{
908
3.52k
    h2o_iovec_t proxy_protocol = h2o_iovec_init(NULL, 0);
909
3.52k
    int chunked = 0;
910
3.52k
    h2o_iovec_t connection_header = h2o_iovec_init(NULL, 0);
911
3.52k
    h2o_httpclient_properties_t props = {
912
3.52k
        &proxy_protocol,
913
3.52k
        &chunked,
914
3.52k
        &connection_header,
915
3.52k
    };
916
3.52k
    h2o_iovec_t method;
917
3.52k
    h2o_url_t url;
918
3.52k
    h2o_header_t *headers;
919
3.52k
    size_t num_headers;
920
3.52k
    h2o_iovec_t body;
921
922
3.52k
    client->super._cb.on_head = client->super._cb.on_connect(&client->super, NULL, &method, &url, (const h2o_header_t **)&headers,
923
3.52k
                                                             &num_headers, &body, &client->proceed_req, &props, client->_origin);
924
3.52k
    client->_app_prefers_pipe_reader = props.prefer_pipe_reader;
925
926
3.52k
    if (client->super._cb.on_head == NULL) {
927
0
        close_client(client);
928
0
        return;
929
0
    }
930
931
3.52k
    start_request(client, method, &url, headers, num_headers, body, &props);
932
3.52k
}
933
934
static void do_cancel(h2o_httpclient_t *_client)
935
582
{
936
582
    struct st_h2o_http1client_t *client = (struct st_h2o_http1client_t *)_client;
937
582
    client->_do_keepalive = 0;
938
582
    close_client(client);
939
582
}
940
941
void update_read_state(struct st_h2o_http1client_t *client)
942
4.59k
{
943
    /* If pipe used, `client->reader` would have switched to `on_body_pipe` by the time this function is called for the first time.
944
     */
945
4.59k
    assert((client->pipe_reader.on_body_piped != NULL) == (client->reader == on_body_to_pipe));
946
947
4.59k
    if (client->reader == on_body_to_pipe) {
948
        /* When pipe is being used, resume read when consumption is notified from user. `h2o_socket_read_start` is invoked without
949
         * checking if we are already reading; this is because we want to make sure that the read callback replaced to the current
950
         * one. */
951
0
        h2o_socket_read_start(client->sock, client->reader);
952
4.59k
    } else {
953
        /* When buffer is used, start / stop reading based on the amount of data being buffered. */
954
4.59k
        if ((*client->super.buf)->size >= client->super.ctx->max_buffer_size) {
955
0
            if (h2o_socket_is_reading(client->sock)) {
956
0
                client->reader = client->sock->_cb.read;
957
0
                h2o_socket_read_stop(client->sock);
958
0
            }
959
4.59k
        } else {
960
4.59k
            if (!h2o_socket_is_reading(client->sock))
961
0
                h2o_socket_read_start(client->sock, client->reader);
962
4.59k
        }
963
4.59k
    }
964
965
    /* arm or unarm i/o timeout depending on if we are reading */
966
4.59k
    if (h2o_socket_is_reading(client->sock)) {
967
4.59k
        if (h2o_timer_is_linked(&client->super._timeout))
968
2.01k
            h2o_timer_unlink(&client->super._timeout);
969
4.59k
        h2o_timer_link(client->super.ctx->loop, client->super.ctx->io_timeout, &client->super._timeout);
970
4.59k
    } else {
971
0
        if (h2o_timer_is_linked(&client->super._timeout))
972
0
            h2o_timer_unlink(&client->super._timeout);
973
0
    }
974
4.59k
}
975
976
static void do_update_window(struct st_h2o_httpclient_t *_client)
977
2.01k
{
978
2.01k
    struct st_h2o_http1client_t *client = (void *)_client;
979
980
    /* When we are splicing to pipe, read synchronously. For prioritization logic to work correctly, it is important to provide
981
     * additional data synchronously in response to the invocation of `h2o_proceed_response`. When memory buffers are used,
982
     * 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
983
     * handlers via `h2o_sendvec`. But when using splice, the pipe is the only one buffer available. */
984
2.01k
    if (client->reader == on_body_to_pipe) {
985
0
        on_body_to_pipe(client->sock, NULL);
986
0
        return;
987
0
    }
988
989
2.01k
    update_read_state(client);
990
2.01k
}
991
992
static void do_get_conn_properties(h2o_httpclient_t *_client, h2o_httpclient_conn_properties_t *properties)
993
3.52k
{
994
3.52k
    struct st_h2o_http1client_t *client = (void *)_client;
995
3.52k
    h2o_httpclient_set_conn_properties_of_socket(client->sock, properties);
996
3.52k
}
997
998
static void setup_client(struct st_h2o_http1client_t *client, h2o_socket_t *sock, h2o_url_t *origin)
999
3.52k
{
1000
3.52k
    memset(&client->sock, 0, sizeof(*client) - offsetof(struct st_h2o_http1client_t, sock));
1001
3.52k
    client->super.cancel = do_cancel;
1002
3.52k
    client->super.get_conn_properties = do_get_conn_properties;
1003
3.52k
    client->super.update_window = do_update_window;
1004
3.52k
    client->super.write_req = do_write_req;
1005
3.52k
    client->super.buf = &sock->input;
1006
3.52k
    client->sock = sock;
1007
3.52k
    sock->data = client;
1008
3.52k
    client->_origin = origin;
1009
3.52k
}
1010
1011
void h2o_httpclient__h1_on_connect(h2o_httpclient_t *_client, h2o_socket_t *sock, h2o_url_t *origin)
1012
3.52k
{
1013
3.52k
    struct st_h2o_http1client_t *client = (void *)_client;
1014
1015
3.52k
    assert(!h2o_timer_is_linked(&client->super._timeout));
1016
1017
3.52k
    setup_client(client, sock, origin);
1018
3.52k
    on_connection_ready(client);
1019
3.52k
}
1020
1021
const size_t h2o_httpclient__h1_size = sizeof(struct st_h2o_http1client_t);