Coverage Report

Created: 2026-04-09 06:51

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/unit/src/nxt_h1proto.c
Line
Count
Source
1
2
/*
3
 * Copyright (C) Igor Sysoev
4
 * Copyright (C) NGINX, Inc.
5
 */
6
7
#include <nxt_router.h>
8
#include <nxt_http.h>
9
#include <nxt_upstream.h>
10
#include <nxt_h1proto.h>
11
#include <nxt_websocket.h>
12
#include <nxt_websocket_header.h>
13
14
15
/*
16
 * nxt_http_conn_ and nxt_h1p_conn_ prefixes are used for connection handlers.
17
 * nxt_h1p_idle_ prefix is used for idle connection handlers.
18
 * nxt_h1p_request_ prefix is used for HTTP/1 protocol request methods.
19
 */
20
21
#if (NXT_TLS)
22
static ssize_t nxt_http_idle_io_read_handler(nxt_task_t *task, nxt_conn_t *c);
23
static void nxt_http_conn_test(nxt_task_t *task, void *obj, void *data);
24
#endif
25
static ssize_t nxt_h1p_idle_io_read_handler(nxt_task_t *task, nxt_conn_t *c);
26
static void nxt_h1p_conn_proto_init(nxt_task_t *task, void *obj, void *data);
27
static void nxt_h1p_conn_request_init(nxt_task_t *task, void *obj, void *data);
28
static void nxt_h1p_conn_request_header_parse(nxt_task_t *task, void *obj,
29
    void *data);
30
static nxt_int_t nxt_h1p_header_process(nxt_task_t *task, nxt_h1proto_t *h1p,
31
    nxt_http_request_t *r);
32
static nxt_int_t nxt_h1p_header_buffer_test(nxt_task_t *task,
33
    nxt_h1proto_t *h1p, nxt_conn_t *c, nxt_socket_conf_t *skcf);
34
static nxt_int_t nxt_h1p_connection(void *ctx, nxt_http_field_t *field,
35
    uintptr_t data);
36
static nxt_int_t nxt_h1p_upgrade(void *ctx, nxt_http_field_t *field,
37
    uintptr_t data);
38
static nxt_int_t nxt_h1p_websocket_key(void *ctx, nxt_http_field_t *field,
39
    uintptr_t data);
40
static nxt_int_t nxt_h1p_websocket_version(void *ctx, nxt_http_field_t *field,
41
    uintptr_t data);
42
static nxt_int_t nxt_h1p_transfer_encoding(void *ctx, nxt_http_field_t *field,
43
    uintptr_t data);
44
static void nxt_h1p_request_body_read(nxt_task_t *task, nxt_http_request_t *r);
45
static void nxt_h1p_conn_request_body_read(nxt_task_t *task, void *obj,
46
    void *data);
47
static void nxt_h1p_request_local_addr(nxt_task_t *task, nxt_http_request_t *r);
48
static void nxt_h1p_request_header_send(nxt_task_t *task,
49
    nxt_http_request_t *r, nxt_work_handler_t body_handler, void *data);
50
static void nxt_h1p_request_send(nxt_task_t *task, nxt_http_request_t *r,
51
    nxt_buf_t *out);
52
static nxt_buf_t *nxt_h1p_chunk_create(nxt_task_t *task, nxt_http_request_t *r,
53
    nxt_buf_t *out);
54
static nxt_off_t nxt_h1p_request_body_bytes_sent(nxt_task_t *task,
55
    nxt_http_proto_t proto);
56
static void nxt_h1p_request_discard(nxt_task_t *task, nxt_http_request_t *r,
57
    nxt_buf_t *last);
58
static void nxt_h1p_conn_request_error(nxt_task_t *task, void *obj, void *data);
59
static void nxt_h1p_conn_request_timeout(nxt_task_t *task, void *obj,
60
    void *data);
61
static void nxt_h1p_conn_request_send_timeout(nxt_task_t *task, void *obj,
62
    void *data);
63
nxt_inline void nxt_h1p_request_error(nxt_task_t *task, nxt_h1proto_t *h1p,
64
    nxt_http_request_t *r);
65
static void nxt_h1p_request_close(nxt_task_t *task, nxt_http_proto_t proto,
66
    nxt_socket_conf_joint_t *joint);
67
static void nxt_h1p_conn_sent(nxt_task_t *task, void *obj, void *data);
68
static void nxt_h1p_conn_close(nxt_task_t *task, void *obj, void *data);
69
static void nxt_h1p_conn_error(nxt_task_t *task, void *obj, void *data);
70
static nxt_msec_t nxt_h1p_conn_timer_value(nxt_conn_t *c, uintptr_t data);
71
static void nxt_h1p_keepalive(nxt_task_t *task, nxt_h1proto_t *h1p,
72
    nxt_conn_t *c);
73
static void nxt_h1p_idle_close(nxt_task_t *task, void *obj, void *data);
74
static void nxt_h1p_idle_timeout(nxt_task_t *task, void *obj, void *data);
75
static void nxt_h1p_idle_response(nxt_task_t *task, nxt_conn_t *c);
76
static void nxt_h1p_idle_response_sent(nxt_task_t *task, void *obj, void *data);
77
static void nxt_h1p_idle_response_error(nxt_task_t *task, void *obj,
78
    void *data);
79
static void nxt_h1p_idle_response_timeout(nxt_task_t *task, void *obj,
80
    void *data);
81
static nxt_msec_t nxt_h1p_idle_response_timer_value(nxt_conn_t *c,
82
    uintptr_t data);
83
static void nxt_h1p_shutdown(nxt_task_t *task, nxt_conn_t *c);
84
static void nxt_h1p_closing(nxt_task_t *task, nxt_conn_t *c);
85
static void nxt_h1p_conn_ws_shutdown(nxt_task_t *task, void *obj, void *data);
86
static void nxt_h1p_conn_closing(nxt_task_t *task, void *obj, void *data);
87
static void nxt_h1p_conn_free(nxt_task_t *task, void *obj, void *data);
88
89
static void nxt_h1p_peer_connect(nxt_task_t *task, nxt_http_peer_t *peer);
90
static void nxt_h1p_peer_connected(nxt_task_t *task, void *obj, void *data);
91
static void nxt_h1p_peer_refused(nxt_task_t *task, void *obj, void *data);
92
static void nxt_h1p_peer_header_send(nxt_task_t *task, nxt_http_peer_t *peer);
93
static nxt_int_t nxt_h1p_peer_request_target(nxt_http_request_t *r,
94
    nxt_str_t *target);
95
static void nxt_h1p_peer_header_sent(nxt_task_t *task, void *obj, void *data);
96
static void nxt_h1p_peer_header_read(nxt_task_t *task, nxt_http_peer_t *peer);
97
static ssize_t nxt_h1p_peer_io_read_handler(nxt_task_t *task, nxt_conn_t *c);
98
static void nxt_h1p_peer_header_read_done(nxt_task_t *task, void *obj,
99
    void *data);
100
static nxt_int_t nxt_h1p_peer_header_parse(nxt_http_peer_t *peer,
101
    nxt_buf_mem_t *bm);
102
static void nxt_h1p_peer_read(nxt_task_t *task, nxt_http_peer_t *peer);
103
static void nxt_h1p_peer_read_done(nxt_task_t *task, void *obj, void *data);
104
static void nxt_h1p_peer_body_process(nxt_task_t *task, nxt_http_peer_t *peer, nxt_buf_t *out);
105
static void nxt_h1p_peer_closed(nxt_task_t *task, void *obj, void *data);
106
static void nxt_h1p_peer_error(nxt_task_t *task, void *obj, void *data);
107
static void nxt_h1p_peer_send_timeout(nxt_task_t *task, void *obj, void *data);
108
static void nxt_h1p_peer_read_timeout(nxt_task_t *task, void *obj, void *data);
109
static nxt_msec_t nxt_h1p_peer_timer_value(nxt_conn_t *c, uintptr_t data);
110
static void nxt_h1p_peer_close(nxt_task_t *task, nxt_http_peer_t *peer);
111
static void nxt_h1p_peer_free(nxt_task_t *task, void *obj, void *data);
112
static nxt_int_t nxt_h1p_peer_transfer_encoding(void *ctx,
113
    nxt_http_field_t *field, uintptr_t data);
114
115
#if (NXT_TLS)
116
static const nxt_conn_state_t  nxt_http_idle_state;
117
static const nxt_conn_state_t  nxt_h1p_shutdown_state;
118
#endif
119
static const nxt_conn_state_t  nxt_h1p_idle_state;
120
static const nxt_conn_state_t  nxt_h1p_header_parse_state;
121
static const nxt_conn_state_t  nxt_h1p_read_body_state;
122
static const nxt_conn_state_t  nxt_h1p_request_send_state;
123
static const nxt_conn_state_t  nxt_h1p_timeout_response_state;
124
static const nxt_conn_state_t  nxt_h1p_keepalive_state;
125
static const nxt_conn_state_t  nxt_h1p_close_state;
126
static const nxt_conn_state_t  nxt_h1p_peer_connect_state;
127
static const nxt_conn_state_t  nxt_h1p_peer_header_send_state;
128
static const nxt_conn_state_t  nxt_h1p_peer_header_body_send_state;
129
static const nxt_conn_state_t  nxt_h1p_peer_header_read_state;
130
static const nxt_conn_state_t  nxt_h1p_peer_header_read_timer_state;
131
static const nxt_conn_state_t  nxt_h1p_peer_read_state;
132
static const nxt_conn_state_t  nxt_h1p_peer_close_state;
133
134
135
const nxt_http_proto_table_t  nxt_http_proto[3] = {
136
    /* NXT_HTTP_PROTO_H1 */
137
    {
138
        .body_read        = nxt_h1p_request_body_read,
139
        .local_addr       = nxt_h1p_request_local_addr,
140
        .header_send      = nxt_h1p_request_header_send,
141
        .send             = nxt_h1p_request_send,
142
        .body_bytes_sent  = nxt_h1p_request_body_bytes_sent,
143
        .discard          = nxt_h1p_request_discard,
144
        .close            = nxt_h1p_request_close,
145
146
        .peer_connect     = nxt_h1p_peer_connect,
147
        .peer_header_send = nxt_h1p_peer_header_send,
148
        .peer_header_read = nxt_h1p_peer_header_read,
149
        .peer_read        = nxt_h1p_peer_read,
150
        .peer_close       = nxt_h1p_peer_close,
151
152
        .ws_frame_start   = nxt_h1p_websocket_frame_start,
153
    },
154
    /* NXT_HTTP_PROTO_H2      */
155
    /* NXT_HTTP_PROTO_DEVNULL */
156
};
157
158
159
static nxt_lvlhsh_t                    nxt_h1p_fields_hash;
160
161
static nxt_http_field_proc_t           nxt_h1p_fields[] = {
162
    { nxt_string("Connection"),        &nxt_h1p_connection, 0 },
163
    { nxt_string("Upgrade"),           &nxt_h1p_upgrade, 0 },
164
    { nxt_string("Sec-WebSocket-Key"), &nxt_h1p_websocket_key, 0 },
165
    { nxt_string("Sec-WebSocket-Version"),
166
                                       &nxt_h1p_websocket_version, 0 },
167
    { nxt_string("Transfer-Encoding"), &nxt_h1p_transfer_encoding, 0 },
168
169
    { nxt_string("Host"),              &nxt_http_request_host, 0 },
170
    { nxt_string("Cookie"),            &nxt_http_request_field,
171
        offsetof(nxt_http_request_t, cookie) },
172
    { nxt_string("Referer"),           &nxt_http_request_field,
173
        offsetof(nxt_http_request_t, referer) },
174
    { nxt_string("User-Agent"),        &nxt_http_request_field,
175
        offsetof(nxt_http_request_t, user_agent) },
176
    { nxt_string("Content-Type"),      &nxt_http_request_field,
177
        offsetof(nxt_http_request_t, content_type) },
178
    { nxt_string("Content-Length"),    &nxt_http_request_content_length, 0 },
179
    { nxt_string("Authorization"),     &nxt_http_request_field,
180
        offsetof(nxt_http_request_t, authorization) },
181
#if (NXT_HAVE_OTEL)
182
    { nxt_string("Traceparent"),       &nxt_otel_parse_traceparent, 0 },
183
    { nxt_string("Tracestate"),        &nxt_otel_parse_tracestate,  0 },
184
#endif
185
};
186
187
188
static nxt_lvlhsh_t                    nxt_h1p_peer_fields_hash;
189
190
static nxt_http_field_proc_t           nxt_h1p_peer_fields[] = {
191
    { nxt_string("Connection"),        &nxt_http_proxy_skip, 0 },
192
    { nxt_string("Transfer-Encoding"), &nxt_h1p_peer_transfer_encoding, 0 },
193
    { nxt_string("Server"),            &nxt_http_proxy_skip, 0 },
194
    { nxt_string("Date"),              &nxt_http_proxy_date, 0 },
195
    { nxt_string("Content-Length"),    &nxt_http_proxy_content_length, 0 },
196
};
197
198
199
nxt_int_t
200
nxt_h1p_init(nxt_task_t *task)
201
0
{
202
0
    nxt_int_t  ret;
203
204
0
    ret = nxt_http_fields_hash(&nxt_h1p_fields_hash,
205
0
                               nxt_h1p_fields, nxt_nitems(nxt_h1p_fields));
206
207
0
    if (nxt_fast_path(ret == NXT_OK)) {
208
0
        ret = nxt_http_fields_hash(&nxt_h1p_peer_fields_hash,
209
0
                                   nxt_h1p_peer_fields,
210
0
                                   nxt_nitems(nxt_h1p_peer_fields));
211
0
    }
212
213
0
    return ret;
214
0
}
215
216
217
void
218
nxt_http_conn_init(nxt_task_t *task, void *obj, void *data)
219
0
{
220
0
    nxt_conn_t               *c;
221
0
    nxt_socket_conf_t        *skcf;
222
0
    nxt_event_engine_t       *engine;
223
0
    nxt_listen_event_t       *lev;
224
0
    nxt_socket_conf_joint_t  *joint;
225
226
0
    c = obj;
227
0
    lev = data;
228
229
0
    nxt_debug(task, "http conn init");
230
231
0
    joint = lev->socket.data;
232
0
    skcf = joint->socket_conf;
233
0
    c->local = skcf->sockaddr;
234
235
0
    engine = task->thread->engine;
236
0
    c->read_work_queue = &engine->fast_work_queue;
237
0
    c->write_work_queue = &engine->fast_work_queue;
238
239
0
    c->read_state = &nxt_h1p_idle_state;
240
241
#if (NXT_TLS)
242
    if (skcf->tls != NULL) {
243
        c->read_state = &nxt_http_idle_state;
244
    }
245
#endif
246
247
0
    nxt_conn_read(engine, c);
248
0
}
249
250
251
#if (NXT_TLS)
252
253
static const nxt_conn_state_t  nxt_http_idle_state
254
    nxt_aligned(64) =
255
{
256
    .ready_handler = nxt_http_conn_test,
257
    .close_handler = nxt_h1p_conn_close,
258
    .error_handler = nxt_h1p_conn_error,
259
260
    .io_read_handler = nxt_http_idle_io_read_handler,
261
262
    .timer_handler = nxt_h1p_idle_timeout,
263
    .timer_value = nxt_h1p_conn_timer_value,
264
    .timer_data = offsetof(nxt_socket_conf_t, idle_timeout),
265
};
266
267
268
static ssize_t
269
nxt_http_idle_io_read_handler(nxt_task_t *task, nxt_conn_t *c)
270
{
271
    size_t                   size;
272
    ssize_t                  n;
273
    nxt_buf_t                *b;
274
    nxt_socket_conf_joint_t  *joint;
275
276
    joint = c->listen->socket.data;
277
278
    if (nxt_slow_path(joint == NULL)) {
279
        /*
280
         * Listening socket had been closed while
281
         * connection was in keep-alive state.
282
         */
283
        c->read_state = &nxt_h1p_idle_close_state;
284
        return 0;
285
    }
286
287
    size = joint->socket_conf->header_buffer_size;
288
289
    b = nxt_event_engine_buf_mem_alloc(task->thread->engine, size);
290
    if (nxt_slow_path(b == NULL)) {
291
        c->socket.error = NXT_ENOMEM;
292
        return NXT_ERROR;
293
    }
294
295
    /*
296
     * 1 byte is enough to distinguish between SSLv3/TLS and plain HTTP.
297
     * 11 bytes are enough to log supported SSLv3/TLS version.
298
     * 16 bytes are just for more optimized kernel copy-out operation.
299
     */
300
    n = c->io->recv(c, b->mem.pos, 16, MSG_PEEK);
301
302
    if (n > 0) {
303
        c->read = b;
304
305
    } else {
306
        c->read = NULL;
307
        nxt_event_engine_buf_mem_free(task->thread->engine, b);
308
    }
309
310
    return n;
311
}
312
313
314
static void
315
nxt_http_conn_test(nxt_task_t *task, void *obj, void *data)
316
{
317
    u_char                   *p;
318
    nxt_buf_t                *b;
319
    nxt_conn_t               *c;
320
    nxt_tls_conf_t           *tls;
321
    nxt_event_engine_t       *engine;
322
    nxt_socket_conf_joint_t  *joint;
323
324
    c = obj;
325
326
    nxt_debug(task, "h1p conn https test");
327
328
    engine = task->thread->engine;
329
    b = c->read;
330
    p = b->mem.pos;
331
332
    c->read_state = &nxt_h1p_idle_state;
333
334
    if (p[0] != 0x16) {
335
        b->mem.free = b->mem.pos;
336
337
        nxt_conn_read(engine, c);
338
        return;
339
    }
340
341
    /* SSLv3/TLS ClientHello message. */
342
343
#if (NXT_DEBUG)
344
    if (nxt_buf_mem_used_size(&b->mem) >= 11) {
345
        u_char      major, minor;
346
        const char  *protocol;
347
348
        major = p[9];
349
        minor = p[10];
350
351
        if (major == 3) {
352
            if (minor == 0) {
353
                protocol = "SSLv";
354
355
            } else {
356
                protocol = "TLSv";
357
                major -= 2;
358
                minor -= 1;
359
            }
360
361
            nxt_debug(task, "SSL/TLS: %s%ud.%ud", protocol, major, minor);
362
        }
363
    }
364
#endif
365
366
    c->read = NULL;
367
    nxt_event_engine_buf_mem_free(engine, b);
368
369
    joint = c->listen->socket.data;
370
371
    if (nxt_slow_path(joint == NULL)) {
372
        /*
373
         * Listening socket had been closed while
374
         * connection was in keep-alive state.
375
         */
376
        nxt_h1p_closing(task, c);
377
        return;
378
    }
379
380
    tls = joint->socket_conf->tls;
381
382
    tls->conn_init(task, tls, c);
383
}
384
385
#endif
386
387
388
static const nxt_conn_state_t  nxt_h1p_idle_state
389
    nxt_aligned(64) =
390
{
391
    .ready_handler = nxt_h1p_conn_proto_init,
392
    .close_handler = nxt_h1p_conn_close,
393
    .error_handler = nxt_h1p_conn_error,
394
395
    .io_read_handler = nxt_h1p_idle_io_read_handler,
396
397
    .timer_handler = nxt_h1p_idle_timeout,
398
    .timer_value = nxt_h1p_conn_timer_value,
399
    .timer_data = offsetof(nxt_socket_conf_t, idle_timeout),
400
    .timer_autoreset = 1,
401
};
402
403
404
static ssize_t
405
nxt_h1p_idle_io_read_handler(nxt_task_t *task, nxt_conn_t *c)
406
0
{
407
0
    size_t                   size;
408
0
    ssize_t                  n;
409
0
    nxt_buf_t                *b;
410
0
    nxt_socket_conf_joint_t  *joint;
411
412
0
    joint = c->listen->socket.data;
413
414
0
    if (nxt_slow_path(joint == NULL)) {
415
        /*
416
         * Listening socket had been closed while
417
         * connection was in keep-alive state.
418
         */
419
0
        c->read_state = &nxt_h1p_idle_close_state;
420
0
        return 0;
421
0
    }
422
423
0
    b = c->read;
424
425
0
    if (b == NULL) {
426
0
        size = joint->socket_conf->header_buffer_size;
427
428
0
        b = nxt_event_engine_buf_mem_alloc(task->thread->engine, size);
429
0
        if (nxt_slow_path(b == NULL)) {
430
0
            c->socket.error = NXT_ENOMEM;
431
0
            return NXT_ERROR;
432
0
        }
433
0
    }
434
435
0
    n = c->io->recvbuf(c, b);
436
437
0
    if (n > 0) {
438
0
        c->read = b;
439
440
0
    } else {
441
0
        c->read = NULL;
442
0
        nxt_event_engine_buf_mem_free(task->thread->engine, b);
443
0
    }
444
445
0
    return n;
446
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_idle_io_read_handler
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_idle_io_read_handler
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_idle_io_read_handler
447
448
449
static void
450
nxt_h1p_conn_proto_init(nxt_task_t *task, void *obj, void *data)
451
0
{
452
0
    nxt_conn_t     *c;
453
0
    nxt_h1proto_t  *h1p;
454
455
0
    c = obj;
456
457
0
    nxt_debug(task, "h1p conn proto init");
458
459
0
    h1p = nxt_mp_zget(c->mem_pool, sizeof(nxt_h1proto_t));
460
0
    if (nxt_slow_path(h1p == NULL)) {
461
0
        nxt_h1p_closing(task, c);
462
0
        return;
463
0
    }
464
465
0
    c->socket.data = h1p;
466
0
    h1p->conn = c;
467
468
0
    nxt_h1p_conn_request_init(task, c, h1p);
469
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_conn_proto_init
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_conn_proto_init
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_conn_proto_init
470
471
472
static void
473
nxt_h1p_conn_request_init(nxt_task_t *task, void *obj, void *data)
474
0
{
475
0
    nxt_int_t                ret;
476
0
    nxt_conn_t               *c;
477
0
    nxt_h1proto_t            *h1p;
478
0
    nxt_socket_conf_t        *skcf;
479
0
    nxt_http_request_t       *r;
480
0
    nxt_socket_conf_joint_t  *joint;
481
482
0
    c = obj;
483
0
    h1p = data;
484
485
0
    nxt_debug(task, "h1p conn request init");
486
487
0
    nxt_conn_active(task->thread->engine, c);
488
489
0
    r = nxt_http_request_create(task);
490
491
0
    if (nxt_fast_path(r != NULL)) {
492
0
        h1p->request = r;
493
0
        r->proto.h1 = h1p;
494
495
        /* r->protocol = NXT_HTTP_PROTO_H1 is done by zeroing. */
496
0
        r->remote = c->remote;
497
498
#if (NXT_TLS)
499
        r->tls = (c->u.tls != NULL);
500
#endif
501
502
0
        r->task = c->task;
503
0
        task = &r->task;
504
0
        c->socket.task = task;
505
0
        c->read_timer.task = task;
506
0
        c->write_timer.task = task;
507
508
0
        ret = nxt_http_parse_request_init(&h1p->parser, r->mem_pool);
509
510
0
        if (nxt_fast_path(ret == NXT_OK)) {
511
0
            joint = c->listen->socket.data;
512
0
            joint->count++;
513
514
0
            r->conf = joint;
515
0
            skcf = joint->socket_conf;
516
0
            r->log_route = skcf->log_route;
517
518
0
            if (c->local == NULL) {
519
0
                c->local = skcf->sockaddr;
520
0
            }
521
522
0
            h1p->parser.discard_unsafe_fields = skcf->discard_unsafe_fields;
523
524
0
            nxt_h1p_conn_request_header_parse(task, c, h1p);
525
526
0
            NXT_OTEL_TRACE();
527
528
0
            return;
529
0
        }
530
531
        /*
532
         * The request is very incomplete here,
533
         * so "internal server error" useless here.
534
         */
535
0
        nxt_mp_release(r->mem_pool);
536
0
    }
537
538
0
    nxt_h1p_closing(task, c);
539
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_conn_request_init
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_conn_request_init
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_conn_request_init
540
541
542
static const nxt_conn_state_t  nxt_h1p_header_parse_state
543
    nxt_aligned(64) =
544
{
545
    .ready_handler = nxt_h1p_conn_request_header_parse,
546
    .close_handler = nxt_h1p_conn_request_error,
547
    .error_handler = nxt_h1p_conn_request_error,
548
549
    .timer_handler = nxt_h1p_conn_request_timeout,
550
    .timer_value = nxt_h1p_conn_request_timer_value,
551
    .timer_data = offsetof(nxt_socket_conf_t, header_read_timeout),
552
};
553
554
555
static void
556
nxt_h1p_conn_request_header_parse(nxt_task_t *task, void *obj, void *data)
557
0
{
558
0
    nxt_int_t           ret;
559
0
    nxt_conn_t          *c;
560
0
    nxt_h1proto_t       *h1p;
561
0
    nxt_http_status_t   status;
562
0
    nxt_http_request_t  *r;
563
564
0
    c = obj;
565
0
    h1p = data;
566
567
0
    nxt_debug(task, "h1p conn header parse");
568
569
0
    ret = nxt_http_parse_request(&h1p->parser, &c->read->mem);
570
571
0
    ret = nxt_expect(NXT_DONE, ret);
572
573
0
    if (ret != NXT_AGAIN) {
574
0
        nxt_timer_disable(task->thread->engine, &c->read_timer);
575
0
    }
576
577
0
    r = h1p->request;
578
579
0
    switch (ret) {
580
581
0
    case NXT_DONE:
582
        /*
583
         * By default the keepalive mode is disabled in HTTP/1.0 and
584
         * enabled in HTTP/1.1.  The mode can be overridden later by
585
         * the "Connection" field processed in nxt_h1p_connection().
586
         */
587
0
        h1p->keepalive = (h1p->parser.version.s.minor != '0');
588
589
0
        r->request_line.start = h1p->parser.method.start;
590
0
        r->request_line.length = h1p->parser.request_line_end
591
0
                                 - r->request_line.start;
592
593
0
        if (nxt_slow_path(r->log_route)) {
594
0
            nxt_log(task, NXT_LOG_NOTICE, "http request line \"%V\"",
595
0
                    &r->request_line);
596
0
        }
597
598
0
        ret = nxt_h1p_header_process(task, h1p, r);
599
600
0
        if (nxt_fast_path(ret == NXT_OK)) {
601
602
#if (NXT_TLS)
603
            if (c->u.tls == NULL && r->conf->socket_conf->tls != NULL) {
604
                status = NXT_HTTP_TO_HTTPS;
605
                goto error;
606
            }
607
#endif
608
609
0
            r->state->ready_handler(task, r, NULL);
610
0
            return;
611
0
        }
612
613
0
        status = ret;
614
0
        goto error;
615
616
0
    case NXT_AGAIN:
617
0
        status = nxt_h1p_header_buffer_test(task, h1p, c, r->conf->socket_conf);
618
619
0
        if (nxt_fast_path(status == NXT_OK)) {
620
0
            c->read_state = &nxt_h1p_header_parse_state;
621
622
0
            nxt_conn_read(task->thread->engine, c);
623
0
            return;
624
0
        }
625
626
0
        break;
627
628
0
    case NXT_HTTP_PARSE_INVALID:
629
0
        status = NXT_HTTP_BAD_REQUEST;
630
0
        break;
631
632
0
    case NXT_HTTP_PARSE_UNSUPPORTED_VERSION:
633
0
        status = NXT_HTTP_VERSION_NOT_SUPPORTED;
634
0
        break;
635
636
0
    case NXT_HTTP_PARSE_TOO_LARGE_FIELD:
637
0
        status = NXT_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE;
638
0
        break;
639
640
0
    default:
641
0
    case NXT_ERROR:
642
0
        status = NXT_HTTP_INTERNAL_SERVER_ERROR;
643
0
        break;
644
0
    }
645
646
0
    (void) nxt_h1p_header_process(task, h1p, r);
647
648
0
error:
649
650
0
    h1p->keepalive = 0;
651
652
0
    nxt_http_request_error(task, r, status);
653
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_conn_request_header_parse
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_conn_request_header_parse
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_conn_request_header_parse
654
655
656
static nxt_int_t
657
nxt_h1p_header_process(nxt_task_t *task, nxt_h1proto_t *h1p,
658
    nxt_http_request_t *r)
659
0
{
660
0
    u_char     *m;
661
0
    nxt_int_t  ret;
662
663
0
    r->target.start = h1p->parser.target_start;
664
0
    r->target.length = h1p->parser.target_end - h1p->parser.target_start;
665
666
0
    r->quoted_target = h1p->parser.quoted_target;
667
668
0
    if (h1p->parser.version.ui64 != 0) {
669
0
        r->version.start = h1p->parser.version.str;
670
0
        r->version.length = sizeof(h1p->parser.version.str);
671
0
    }
672
673
0
    r->method = &h1p->parser.method;
674
0
    r->path = &h1p->parser.path;
675
0
    r->args = &h1p->parser.args;
676
677
0
    r->fields = h1p->parser.fields;
678
679
0
    ret = nxt_http_fields_process(r->fields, &nxt_h1p_fields_hash, r);
680
0
    if (nxt_slow_path(ret != NXT_OK)) {
681
0
        return ret;
682
0
    }
683
684
0
    if (h1p->connection_upgrade && h1p->upgrade_websocket) {
685
0
        m = h1p->parser.method.start;
686
687
0
        if (nxt_slow_path(h1p->parser.method.length != 3
688
0
                          || m[0] != 'G'
689
0
                          || m[1] != 'E'
690
0
                          || m[2] != 'T'))
691
0
        {
692
0
            nxt_log(task, NXT_LOG_INFO, "h1p upgrade: bad method");
693
694
0
            return NXT_HTTP_BAD_REQUEST;
695
0
        }
696
697
0
        if (nxt_slow_path(h1p->parser.version.s.minor != '1')) {
698
0
            nxt_log(task, NXT_LOG_INFO, "h1p upgrade: bad protocol version");
699
700
0
            return NXT_HTTP_BAD_REQUEST;
701
0
        }
702
703
0
        if (nxt_slow_path(h1p->websocket_key == NULL)) {
704
0
            nxt_log(task, NXT_LOG_INFO,
705
0
                    "h1p upgrade: bad or absent websocket key");
706
707
0
            return NXT_HTTP_BAD_REQUEST;
708
0
        }
709
710
0
        if (nxt_slow_path(h1p->websocket_version_ok == 0)) {
711
0
            nxt_log(task, NXT_LOG_INFO,
712
0
                    "h1p upgrade: bad or absent websocket version");
713
714
0
            return NXT_HTTP_UPGRADE_REQUIRED;
715
0
        }
716
717
0
        r->websocket_handshake = 1;
718
0
    }
719
720
0
    return ret;
721
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_header_process
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_header_process
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_header_process
722
723
724
static nxt_int_t
725
nxt_h1p_header_buffer_test(nxt_task_t *task, nxt_h1proto_t *h1p, nxt_conn_t *c,
726
    nxt_socket_conf_t *skcf)
727
0
{
728
0
    size_t     size, used;
729
0
    nxt_buf_t  *in, *b;
730
731
0
    in = c->read;
732
733
0
    if (nxt_buf_mem_free_size(&in->mem) == 0) {
734
0
        size = skcf->large_header_buffer_size;
735
0
        used = nxt_buf_mem_used_size(&in->mem);
736
737
0
        if (size <= used || h1p->nbuffers >= skcf->large_header_buffers) {
738
0
            return NXT_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE;
739
0
        }
740
741
0
        b = nxt_buf_mem_alloc(c->mem_pool, size, 0);
742
0
        if (nxt_slow_path(b == NULL)) {
743
0
            return NXT_HTTP_INTERNAL_SERVER_ERROR;
744
0
        }
745
746
0
        b->mem.free = nxt_cpymem(b->mem.pos, in->mem.pos, used);
747
748
0
        in->next = h1p->buffers;
749
0
        h1p->buffers = in;
750
0
        h1p->nbuffers++;
751
752
0
        c->read = b;
753
0
    }
754
755
0
    return NXT_OK;
756
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_header_buffer_test
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_header_buffer_test
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_header_buffer_test
757
758
759
static nxt_int_t
760
nxt_h1p_connection(void *ctx, nxt_http_field_t *field, uintptr_t data)
761
605
{
762
605
    const u_char        *end;
763
605
    nxt_http_request_t  *r;
764
765
605
    r = ctx;
766
605
    field->hopbyhop = 1;
767
768
605
    end = field->value + field->value_length;
769
770
605
    if (nxt_memcasestrn(field->value, end, "close", 5) != NULL) {
771
92
        r->proto.h1->keepalive = 0;
772
92
    }
773
774
605
    if (nxt_memcasestrn(field->value, end, "keep-alive", 10) != NULL) {
775
86
        r->proto.h1->keepalive = 1;
776
86
    }
777
778
605
    if (nxt_memcasestrn(field->value, end, "upgrade", 7) != NULL) {
779
94
        r->proto.h1->connection_upgrade = 1;
780
94
    }
781
782
605
    return NXT_OK;
783
605
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_connection
nxt_http_h1p_fuzz.c:nxt_h1p_connection
Line
Count
Source
761
605
{
762
605
    const u_char        *end;
763
605
    nxt_http_request_t  *r;
764
765
605
    r = ctx;
766
605
    field->hopbyhop = 1;
767
768
605
    end = field->value + field->value_length;
769
770
605
    if (nxt_memcasestrn(field->value, end, "close", 5) != NULL) {
771
92
        r->proto.h1->keepalive = 0;
772
92
    }
773
774
605
    if (nxt_memcasestrn(field->value, end, "keep-alive", 10) != NULL) {
775
86
        r->proto.h1->keepalive = 1;
776
86
    }
777
778
605
    if (nxt_memcasestrn(field->value, end, "upgrade", 7) != NULL) {
779
94
        r->proto.h1->connection_upgrade = 1;
780
94
    }
781
782
605
    return NXT_OK;
783
605
}
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_connection
784
785
786
static nxt_int_t
787
nxt_h1p_upgrade(void *ctx, nxt_http_field_t *field, uintptr_t data)
788
233
{
789
233
    nxt_http_request_t  *r;
790
791
233
    r = ctx;
792
793
233
    if (field->value_length == 9
794
164
        && nxt_memcasecmp(field->value, "websocket", 9) == 0)
795
74
    {
796
74
        r->proto.h1->upgrade_websocket = 1;
797
74
    }
798
799
233
    return NXT_OK;
800
233
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_upgrade
nxt_http_h1p_fuzz.c:nxt_h1p_upgrade
Line
Count
Source
788
233
{
789
233
    nxt_http_request_t  *r;
790
791
233
    r = ctx;
792
793
233
    if (field->value_length == 9
794
164
        && nxt_memcasecmp(field->value, "websocket", 9) == 0)
795
74
    {
796
74
        r->proto.h1->upgrade_websocket = 1;
797
74
    }
798
799
233
    return NXT_OK;
800
233
}
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_upgrade
801
802
803
static nxt_int_t
804
nxt_h1p_websocket_key(void *ctx, nxt_http_field_t *field, uintptr_t data)
805
121
{
806
121
    nxt_http_request_t  *r;
807
808
121
    r = ctx;
809
810
121
    if (field->value_length == 24) {
811
34
        r->proto.h1->websocket_key = field;
812
34
    }
813
814
121
    return NXT_OK;
815
121
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_websocket_key
nxt_http_h1p_fuzz.c:nxt_h1p_websocket_key
Line
Count
Source
805
121
{
806
121
    nxt_http_request_t  *r;
807
808
121
    r = ctx;
809
810
121
    if (field->value_length == 24) {
811
34
        r->proto.h1->websocket_key = field;
812
34
    }
813
814
121
    return NXT_OK;
815
121
}
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_websocket_key
816
817
818
static nxt_int_t
819
nxt_h1p_websocket_version(void *ctx, nxt_http_field_t *field, uintptr_t data)
820
301
{
821
301
    nxt_http_request_t  *r;
822
823
301
    r = ctx;
824
825
301
    if (field->value_length == 2
826
221
        && field->value[0] == '1' && field->value[1] == '3')
827
66
    {
828
66
        r->proto.h1->websocket_version_ok = 1;
829
66
    }
830
831
301
    return NXT_OK;
832
301
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_websocket_version
nxt_http_h1p_fuzz.c:nxt_h1p_websocket_version
Line
Count
Source
820
301
{
821
301
    nxt_http_request_t  *r;
822
823
301
    r = ctx;
824
825
301
    if (field->value_length == 2
826
221
        && field->value[0] == '1' && field->value[1] == '3')
827
66
    {
828
66
        r->proto.h1->websocket_version_ok = 1;
829
66
    }
830
831
301
    return NXT_OK;
832
301
}
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_websocket_version
833
834
835
static nxt_int_t
836
nxt_h1p_transfer_encoding(void *ctx, nxt_http_field_t *field, uintptr_t data)
837
139
{
838
139
    nxt_http_te_t       te;
839
139
    nxt_http_request_t  *r;
840
841
139
    r = ctx;
842
139
    field->skip = 1;
843
139
    field->hopbyhop = 1;
844
845
139
    if (field->value_length == 7
846
69
        && memcmp(field->value, "chunked", 7) == 0)
847
3
    {
848
3
        if (r->chunked_field != NULL) {
849
1
            return NXT_HTTP_BAD_REQUEST;
850
1
        }
851
852
2
        te = NXT_HTTP_TE_CHUNKED;
853
2
        r->chunked_field = field;
854
855
136
    } else {
856
136
        te = NXT_HTTP_TE_UNSUPPORTED;
857
136
    }
858
859
138
    r->proto.h1->transfer_encoding = te;
860
861
138
    return NXT_OK;
862
139
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_transfer_encoding
nxt_http_h1p_fuzz.c:nxt_h1p_transfer_encoding
Line
Count
Source
837
139
{
838
139
    nxt_http_te_t       te;
839
139
    nxt_http_request_t  *r;
840
841
139
    r = ctx;
842
139
    field->skip = 1;
843
139
    field->hopbyhop = 1;
844
845
139
    if (field->value_length == 7
846
69
        && memcmp(field->value, "chunked", 7) == 0)
847
3
    {
848
3
        if (r->chunked_field != NULL) {
849
1
            return NXT_HTTP_BAD_REQUEST;
850
1
        }
851
852
2
        te = NXT_HTTP_TE_CHUNKED;
853
2
        r->chunked_field = field;
854
855
136
    } else {
856
136
        te = NXT_HTTP_TE_UNSUPPORTED;
857
136
    }
858
859
138
    r->proto.h1->transfer_encoding = te;
860
861
138
    return NXT_OK;
862
139
}
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_transfer_encoding
863
864
865
static void
866
nxt_h1p_request_body_read(nxt_task_t *task, nxt_http_request_t *r)
867
0
{
868
0
    size_t             size, body_length, body_buffer_size, body_rest;
869
0
    ssize_t            res;
870
0
    nxt_buf_t          *in, *b, *out, *chunk;
871
0
    nxt_conn_t         *c;
872
0
    nxt_h1proto_t      *h1p;
873
0
    nxt_socket_conf_t  *skcf;
874
0
    nxt_http_status_t  status;
875
876
0
    static const nxt_str_t tmp_name_pattern = nxt_string("/req-XXXXXXXX");
877
878
0
    h1p = r->proto.h1;
879
0
    skcf = r->conf->socket_conf;
880
881
0
    nxt_debug(task, "h1p request body read %O te:%d",
882
0
              r->content_length_n, h1p->transfer_encoding);
883
884
0
    switch (h1p->transfer_encoding) {
885
886
0
    case NXT_HTTP_TE_CHUNKED:
887
0
        if (!skcf->chunked_transform) {
888
0
            status = NXT_HTTP_LENGTH_REQUIRED;
889
0
            goto error;
890
0
        }
891
892
0
        if (r->content_length != NULL || !nxt_h1p_is_http11(h1p)) {
893
0
            status = NXT_HTTP_BAD_REQUEST;
894
0
            goto error;
895
0
        }
896
897
0
        r->chunked = 1;
898
0
        h1p->chunked_parse.mem_pool = r->mem_pool;
899
0
        break;
900
901
0
    case NXT_HTTP_TE_UNSUPPORTED:
902
0
        status = NXT_HTTP_NOT_IMPLEMENTED;
903
0
        goto error;
904
905
0
    default:
906
0
    case NXT_HTTP_TE_NONE:
907
0
        break;
908
0
    }
909
910
0
    if (!r->chunked &&
911
0
        (r->content_length_n == -1 || r->content_length_n == 0))
912
0
    {
913
0
        goto ready;
914
0
    }
915
916
0
    body_length = (size_t) r->content_length_n;
917
918
0
    body_buffer_size = nxt_min(skcf->body_buffer_size, body_length);
919
920
0
    if (body_length > body_buffer_size) {
921
0
        nxt_str_t  *tmp_path, tmp_name;
922
923
0
        tmp_path = &skcf->body_temp_path;
924
925
0
        tmp_name.length = tmp_path->length + tmp_name_pattern.length;
926
927
0
        b = nxt_buf_file_alloc(r->mem_pool,
928
0
                               body_buffer_size + sizeof(nxt_file_t)
929
0
                               + tmp_name.length + 1, 0);
930
0
        if (nxt_slow_path(b == NULL)) {
931
0
            status = NXT_HTTP_INTERNAL_SERVER_ERROR;
932
0
            goto error;
933
0
        }
934
935
0
        tmp_name.start = nxt_pointer_to(b->mem.start, sizeof(nxt_file_t));
936
937
0
        memcpy(tmp_name.start, tmp_path->start, tmp_path->length);
938
0
        memcpy(tmp_name.start + tmp_path->length, tmp_name_pattern.start,
939
0
               tmp_name_pattern.length);
940
0
        tmp_name.start[tmp_name.length] = '\0';
941
942
0
        b->file = (nxt_file_t *) b->mem.start;
943
0
        nxt_memzero(b->file, sizeof(nxt_file_t));
944
0
        b->file->fd = -1;
945
0
        b->file->size = body_length;
946
947
0
        b->mem.start += sizeof(nxt_file_t) + tmp_name.length + 1;
948
0
        b->mem.pos = b->mem.start;
949
0
        b->mem.free = b->mem.start;
950
951
0
        b->file->fd = mkstemp((char *) tmp_name.start);
952
0
        if (nxt_slow_path(b->file->fd == -1)) {
953
0
            nxt_alert(task, "mkstemp(%s) failed %E", tmp_name.start, nxt_errno);
954
955
0
            status = NXT_HTTP_INTERNAL_SERVER_ERROR;
956
0
            goto error;
957
0
        }
958
959
0
        nxt_debug(task, "create body tmp file \"%V\", %d",
960
0
                  &tmp_name, b->file->fd);
961
962
0
        unlink((char *) tmp_name.start);
963
964
0
    } else {
965
0
        b = nxt_buf_mem_alloc(r->mem_pool, body_buffer_size, 0);
966
0
        if (nxt_slow_path(b == NULL)) {
967
0
            status = NXT_HTTP_INTERNAL_SERVER_ERROR;
968
0
            goto error;
969
0
        }
970
0
    }
971
972
0
    r->body = b;
973
974
0
    body_rest = r->chunked ? 1 : body_length;
975
976
0
    in = h1p->conn->read;
977
978
0
    size = nxt_buf_mem_used_size(&in->mem);
979
980
0
    if (size != 0) {
981
0
        if (nxt_buf_is_file(b)) {
982
0
            if (r->chunked) {
983
0
                out = nxt_http_chunk_parse(task, &h1p->chunked_parse, in);
984
985
0
                if (h1p->chunked_parse.error) {
986
0
                    status = NXT_HTTP_INTERNAL_SERVER_ERROR;
987
0
                    goto error;
988
0
                }
989
990
0
                if (h1p->chunked_parse.chunk_error) {
991
0
                    status = NXT_HTTP_BAD_REQUEST;
992
0
                    goto error;
993
0
                }
994
995
0
                for (chunk = out; chunk != NULL; chunk = chunk->next) {
996
0
                    size = nxt_buf_mem_used_size(&chunk->mem);
997
998
0
                    res = nxt_fd_write(b->file->fd, chunk->mem.pos, size);
999
0
                    if (nxt_slow_path(res < (ssize_t) size)) {
1000
0
                        status = NXT_HTTP_INTERNAL_SERVER_ERROR;
1001
0
                        goto error;
1002
0
                    }
1003
1004
0
                    b->file_end += size;
1005
1006
0
                    if ((size_t) b->file_end > skcf->max_body_size) {
1007
0
                        status = NXT_HTTP_PAYLOAD_TOO_LARGE;
1008
0
                        goto error;
1009
0
                    }
1010
0
                }
1011
1012
0
                if (h1p->chunked_parse.last) {
1013
0
                    body_rest = 0;
1014
0
                }
1015
1016
0
            } else {
1017
0
                size = nxt_min(size, body_length);
1018
0
                res = nxt_fd_write(b->file->fd, in->mem.pos, size);
1019
0
                if (nxt_slow_path(res < (ssize_t) size)) {
1020
0
                    status = NXT_HTTP_INTERNAL_SERVER_ERROR;
1021
0
                    goto error;
1022
0
                }
1023
1024
0
                b->file_end += size;
1025
1026
0
                in->mem.pos += size;
1027
0
                body_rest -= size;
1028
0
            }
1029
1030
0
        } else {
1031
0
            size = nxt_min(body_buffer_size, size);
1032
0
            b->mem.free = nxt_cpymem(b->mem.free, in->mem.pos, size);
1033
1034
0
            in->mem.pos += size;
1035
0
            body_rest -= size;
1036
0
        }
1037
0
    }
1038
1039
0
    nxt_debug(task, "h1p body rest: %uz", body_rest);
1040
1041
0
    if (body_rest != 0) {
1042
0
        in->next = h1p->buffers;
1043
0
        h1p->buffers = in;
1044
0
        h1p->nbuffers++;
1045
1046
0
        c = h1p->conn;
1047
0
        c->read = b;
1048
0
        c->read_state = &nxt_h1p_read_body_state;
1049
1050
0
        nxt_conn_read(task->thread->engine, c);
1051
0
        return;
1052
0
    }
1053
1054
0
    if (nxt_buf_is_file(b)) {
1055
0
        b->mem.start = NULL;
1056
0
        b->mem.end = NULL;
1057
0
        b->mem.pos = NULL;
1058
0
        b->mem.free = NULL;
1059
0
    }
1060
1061
0
ready:
1062
1063
0
    r->state->ready_handler(task, r, NULL);
1064
1065
0
    return;
1066
1067
0
error:
1068
1069
0
    h1p->keepalive = 0;
1070
1071
0
    nxt_http_request_error(task, r, status);
1072
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_request_body_read
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_request_body_read
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_request_body_read
1073
1074
1075
static const nxt_conn_state_t  nxt_h1p_read_body_state
1076
    nxt_aligned(64) =
1077
{
1078
    .ready_handler = nxt_h1p_conn_request_body_read,
1079
    .close_handler = nxt_h1p_conn_request_error,
1080
    .error_handler = nxt_h1p_conn_request_error,
1081
1082
    .timer_handler = nxt_h1p_conn_request_timeout,
1083
    .timer_value = nxt_h1p_conn_request_timer_value,
1084
    .timer_data = offsetof(nxt_socket_conf_t, body_read_timeout),
1085
    .timer_autoreset = 1,
1086
};
1087
1088
1089
static void
1090
nxt_h1p_conn_request_body_read(nxt_task_t *task, void *obj, void *data)
1091
0
{
1092
0
    size_t              size, body_rest;
1093
0
    ssize_t             res;
1094
0
    nxt_buf_t           *b, *out, *chunk;
1095
0
    nxt_conn_t          *c;
1096
0
    nxt_h1proto_t       *h1p;
1097
0
    nxt_socket_conf_t   *skcf;
1098
0
    nxt_http_request_t  *r;
1099
0
    nxt_event_engine_t  *engine;
1100
1101
0
    c = obj;
1102
0
    h1p = data;
1103
1104
0
    nxt_debug(task, "h1p conn request body read");
1105
1106
0
    r = h1p->request;
1107
0
    skcf = r->conf->socket_conf;
1108
1109
0
    engine = task->thread->engine;
1110
1111
0
    b = c->read;
1112
1113
0
    if (nxt_buf_is_file(b)) {
1114
1115
0
        if (r->chunked) {
1116
0
            body_rest = 1;
1117
1118
0
            out = nxt_http_chunk_parse(task, &h1p->chunked_parse, b);
1119
1120
0
            if (h1p->chunked_parse.error) {
1121
0
                nxt_h1p_request_error(task, h1p, r);
1122
0
                return;
1123
0
            }
1124
1125
0
            if (h1p->chunked_parse.chunk_error) {
1126
0
                nxt_http_request_error(task, r, NXT_HTTP_BAD_REQUEST);
1127
0
                return;
1128
0
            }
1129
1130
0
            for (chunk = out; chunk != NULL; chunk = chunk->next) {
1131
0
                size = nxt_buf_mem_used_size(&chunk->mem);
1132
0
                res = nxt_fd_write(b->file->fd, chunk->mem.pos, size);
1133
0
                if (nxt_slow_path(res < (ssize_t) size)) {
1134
0
                    nxt_h1p_request_error(task, h1p, r);
1135
0
                    return;
1136
0
                }
1137
1138
0
                b->file_end += size;
1139
1140
0
                if ((size_t) b->file_end > skcf->max_body_size) {
1141
0
                    nxt_h1p_request_error(task, h1p, r);
1142
0
                    return;
1143
0
                }
1144
0
            }
1145
1146
0
            if (h1p->chunked_parse.last) {
1147
0
                body_rest = 0;
1148
0
            }
1149
1150
0
        } else {
1151
0
            body_rest = b->file->size - b->file_end;
1152
1153
0
            size = nxt_buf_mem_used_size(&b->mem);
1154
0
            size = nxt_min(size, body_rest);
1155
1156
0
            res = nxt_fd_write(b->file->fd, b->mem.pos, size);
1157
0
            if (nxt_slow_path(res < (ssize_t) size)) {
1158
0
                nxt_h1p_request_error(task, h1p, r);
1159
0
                return;
1160
0
            }
1161
1162
0
            b->file_end += size;
1163
0
            body_rest -= res;
1164
1165
0
            b->mem.pos += size;
1166
1167
0
            if (b->mem.pos == b->mem.free) {
1168
0
                if (body_rest >= (size_t) nxt_buf_mem_size(&b->mem)) {
1169
0
                    b->mem.free = b->mem.start;
1170
1171
0
                } else {
1172
                    /* This required to avoid reading next request. */
1173
0
                    b->mem.free = b->mem.end - body_rest;
1174
0
                }
1175
1176
0
                b->mem.pos = b->mem.free;
1177
0
            }
1178
0
        }
1179
1180
0
    } else {
1181
0
        body_rest = nxt_buf_mem_free_size(&c->read->mem);
1182
0
    }
1183
1184
0
    nxt_debug(task, "h1p body rest: %uz", body_rest);
1185
1186
0
    if (body_rest != 0) {
1187
0
        nxt_conn_read(engine, c);
1188
1189
0
    } else {
1190
0
        if (nxt_buf_is_file(b)) {
1191
0
            b->mem.start = NULL;
1192
0
            b->mem.end = NULL;
1193
0
            b->mem.pos = NULL;
1194
0
            b->mem.free = NULL;
1195
0
        }
1196
1197
0
        c->read = NULL;
1198
1199
0
        r->state->ready_handler(task, r, NULL);
1200
0
    }
1201
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_conn_request_body_read
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_conn_request_body_read
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_conn_request_body_read
1202
1203
1204
static void
1205
nxt_h1p_request_local_addr(nxt_task_t *task, nxt_http_request_t *r)
1206
0
{
1207
0
    r->local = nxt_conn_local_addr(task, r->proto.h1->conn);
1208
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_request_local_addr
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_request_local_addr
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_request_local_addr
1209
1210
1211
#define NXT_HTTP_LAST_INFORMATIONAL                                           \
1212
0
    (NXT_HTTP_CONTINUE + nxt_nitems(nxt_http_informational) - 1)
1213
1214
static const nxt_str_t  nxt_http_informational[] = {
1215
    nxt_string("HTTP/1.1 100 Continue\r\n"),
1216
    nxt_string("HTTP/1.1 101 Switching Protocols\r\n"),
1217
};
1218
1219
1220
#define NXT_HTTP_LAST_SUCCESS                                                 \
1221
0
    (NXT_HTTP_OK + nxt_nitems(nxt_http_success) - 1)
1222
1223
static const nxt_str_t  nxt_http_success[] = {
1224
    nxt_string("HTTP/1.1 200 OK\r\n"),
1225
    nxt_string("HTTP/1.1 201 Created\r\n"),
1226
    nxt_string("HTTP/1.1 202 Accepted\r\n"),
1227
    nxt_string("HTTP/1.1 203 Non-Authoritative Information\r\n"),
1228
    nxt_string("HTTP/1.1 204 No Content\r\n"),
1229
    nxt_string("HTTP/1.1 205 Reset Content\r\n"),
1230
    nxt_string("HTTP/1.1 206 Partial Content\r\n"),
1231
};
1232
1233
1234
#define NXT_HTTP_LAST_REDIRECTION                                             \
1235
0
    (NXT_HTTP_MULTIPLE_CHOICES + nxt_nitems(nxt_http_redirection) - 1)
1236
1237
static const nxt_str_t  nxt_http_redirection[] = {
1238
    nxt_string("HTTP/1.1 300 Multiple Choices\r\n"),
1239
    nxt_string("HTTP/1.1 301 Moved Permanently\r\n"),
1240
    nxt_string("HTTP/1.1 302 Found\r\n"),
1241
    nxt_string("HTTP/1.1 303 See Other\r\n"),
1242
    nxt_string("HTTP/1.1 304 Not Modified\r\n"),
1243
    nxt_string("HTTP/1.1 307 Temporary Redirect\r\n"),
1244
    nxt_string("HTTP/1.1 308 Permanent Redirect\r\n"),
1245
};
1246
1247
1248
#define NXT_HTTP_LAST_CLIENT_ERROR                                            \
1249
0
    (NXT_HTTP_BAD_REQUEST + nxt_nitems(nxt_http_client_error) - 1)
1250
1251
static const nxt_str_t  nxt_http_client_error[] = {
1252
    nxt_string("HTTP/1.1 400 Bad Request\r\n"),
1253
    nxt_string("HTTP/1.1 401 Unauthorized\r\n"),
1254
    nxt_string("HTTP/1.1 402 Payment Required\r\n"),
1255
    nxt_string("HTTP/1.1 403 Forbidden\r\n"),
1256
    nxt_string("HTTP/1.1 404 Not Found\r\n"),
1257
    nxt_string("HTTP/1.1 405 Method Not Allowed\r\n"),
1258
    nxt_string("HTTP/1.1 406 Not Acceptable\r\n"),
1259
    nxt_string("HTTP/1.1 407 Proxy Authentication Required\r\n"),
1260
    nxt_string("HTTP/1.1 408 Request Timeout\r\n"),
1261
    nxt_string("HTTP/1.1 409 Conflict\r\n"),
1262
    nxt_string("HTTP/1.1 410 Gone\r\n"),
1263
    nxt_string("HTTP/1.1 411 Length Required\r\n"),
1264
    nxt_string("HTTP/1.1 412 Precondition Failed\r\n"),
1265
    nxt_string("HTTP/1.1 413 Payload Too Large\r\n"),
1266
    nxt_string("HTTP/1.1 414 URI Too Long\r\n"),
1267
    nxt_string("HTTP/1.1 415 Unsupported Media Type\r\n"),
1268
    nxt_string("HTTP/1.1 416 Range Not Satisfiable\r\n"),
1269
    nxt_string("HTTP/1.1 417 Expectation Failed\r\n"),
1270
    nxt_string("HTTP/1.1 418 I'm a teapot\r\n"),
1271
    nxt_string("HTTP/1.1 419 \r\n"),
1272
    nxt_string("HTTP/1.1 420 \r\n"),
1273
    nxt_string("HTTP/1.1 421 Misdirected Request\r\n"),
1274
    nxt_string("HTTP/1.1 422 Unprocessable Entity\r\n"),
1275
    nxt_string("HTTP/1.1 423 Locked\r\n"),
1276
    nxt_string("HTTP/1.1 424 Failed Dependency\r\n"),
1277
    nxt_string("HTTP/1.1 425 \r\n"),
1278
    nxt_string("HTTP/1.1 426 Upgrade Required\r\n"),
1279
    nxt_string("HTTP/1.1 427 \r\n"),
1280
    nxt_string("HTTP/1.1 428 \r\n"),
1281
    nxt_string("HTTP/1.1 429 \r\n"),
1282
    nxt_string("HTTP/1.1 430 \r\n"),
1283
    nxt_string("HTTP/1.1 431 Request Header Fields Too Large\r\n"),
1284
};
1285
1286
1287
#define NXT_HTTP_LAST_NGINX_ERROR                                             \
1288
0
    (NXT_HTTP_TO_HTTPS + nxt_nitems(nxt_http_nginx_error) - 1)
1289
1290
static const nxt_str_t  nxt_http_nginx_error[] = {
1291
    nxt_string("HTTP/1.1 400 "
1292
               "The plain HTTP request was sent to HTTPS port\r\n"),
1293
};
1294
1295
1296
#define NXT_HTTP_LAST_SERVER_ERROR                                            \
1297
0
    (NXT_HTTP_INTERNAL_SERVER_ERROR + nxt_nitems(nxt_http_server_error) - 1)
1298
1299
static const nxt_str_t  nxt_http_server_error[] = {
1300
    nxt_string("HTTP/1.1 500 Internal Server Error\r\n"),
1301
    nxt_string("HTTP/1.1 501 Not Implemented\r\n"),
1302
    nxt_string("HTTP/1.1 502 Bad Gateway\r\n"),
1303
    nxt_string("HTTP/1.1 503 Service Unavailable\r\n"),
1304
    nxt_string("HTTP/1.1 504 Gateway Timeout\r\n"),
1305
    nxt_string("HTTP/1.1 505 HTTP Version Not Supported\r\n"),
1306
};
1307
1308
1309
0
#define UNKNOWN_STATUS_LENGTH  nxt_length("HTTP/1.1 999 \r\n")
1310
1311
static void
1312
nxt_h1p_request_header_send(nxt_task_t *task, nxt_http_request_t *r,
1313
    nxt_work_handler_t body_handler, void *data)
1314
0
{
1315
0
    u_char              *p;
1316
0
    size_t              size;
1317
0
    nxt_buf_t           *header;
1318
0
    nxt_str_t           unknown_status;
1319
0
    nxt_int_t           conn;
1320
0
    nxt_uint_t          n;
1321
0
    nxt_bool_t          http11;
1322
0
    nxt_conn_t          *c;
1323
0
    nxt_h1proto_t       *h1p;
1324
0
    const nxt_str_t     *status;
1325
0
    nxt_http_field_t    *field;
1326
0
    u_char              buf[UNKNOWN_STATUS_LENGTH];
1327
1328
0
    static const char   chunked[] = "Transfer-Encoding: chunked\r\n";
1329
0
    static const char   websocket_version[] = "Sec-WebSocket-Version: 13\r\n";
1330
1331
0
    static const nxt_str_t  connection[3] = {
1332
0
        nxt_string("Connection: close\r\n"),
1333
0
        nxt_string("Connection: keep-alive\r\n"),
1334
0
        nxt_string("Upgrade: websocket\r\n"
1335
0
                   "Connection: Upgrade\r\n"
1336
0
                   "Sec-WebSocket-Accept: "),
1337
0
    };
1338
1339
0
    nxt_debug(task, "h1p request header send");
1340
1341
0
    NXT_OTEL_TRACE();
1342
1343
0
    r->header_sent = 1;
1344
0
    h1p = r->proto.h1;
1345
0
    n = r->status;
1346
1347
0
    if (n >= NXT_HTTP_CONTINUE && n <= NXT_HTTP_LAST_INFORMATIONAL) {
1348
0
        status = &nxt_http_informational[n - NXT_HTTP_CONTINUE];
1349
1350
0
    } else if (n >= NXT_HTTP_OK && n <= NXT_HTTP_LAST_SUCCESS) {
1351
0
        status = &nxt_http_success[n - NXT_HTTP_OK];
1352
1353
0
    } else if (n >= NXT_HTTP_MULTIPLE_CHOICES
1354
0
               && n <= NXT_HTTP_LAST_REDIRECTION)
1355
0
    {
1356
0
        status = &nxt_http_redirection[n - NXT_HTTP_MULTIPLE_CHOICES];
1357
1358
0
    } else if (n >= NXT_HTTP_BAD_REQUEST && n <= NXT_HTTP_LAST_CLIENT_ERROR) {
1359
0
        status = &nxt_http_client_error[n - NXT_HTTP_BAD_REQUEST];
1360
1361
0
    } else if (n >= NXT_HTTP_TO_HTTPS && n <= NXT_HTTP_LAST_NGINX_ERROR) {
1362
0
        status = &nxt_http_nginx_error[n - NXT_HTTP_TO_HTTPS];
1363
1364
0
    } else if (n >= NXT_HTTP_INTERNAL_SERVER_ERROR
1365
0
               && n <= NXT_HTTP_LAST_SERVER_ERROR)
1366
0
    {
1367
0
        status = &nxt_http_server_error[n - NXT_HTTP_INTERNAL_SERVER_ERROR];
1368
1369
0
    } else if (n <= NXT_HTTP_STATUS_MAX) {
1370
0
        (void) nxt_sprintf(buf, buf + UNKNOWN_STATUS_LENGTH,
1371
0
                           "HTTP/1.1 %03d \r\n", n);
1372
1373
0
        unknown_status.length = UNKNOWN_STATUS_LENGTH;
1374
0
        unknown_status.start = buf;
1375
0
        status = &unknown_status;
1376
1377
0
    } else {
1378
0
        status = &nxt_http_server_error[0];
1379
0
    }
1380
1381
0
    size = status->length;
1382
    /* Trailing CRLF at the end of header. */
1383
0
    size += nxt_length("\r\n");
1384
1385
0
    conn = -1;
1386
1387
0
    if (r->websocket_handshake && n == NXT_HTTP_SWITCHING_PROTOCOLS) {
1388
0
        h1p->websocket = 1;
1389
0
        h1p->keepalive = 0;
1390
0
        conn = 2;
1391
0
        size += NXT_WEBSOCKET_ACCEPT_SIZE + 2;
1392
1393
0
    } else {
1394
0
        http11 = nxt_h1p_is_http11(h1p);
1395
1396
0
        if (r->resp.content_length == NULL || r->resp.content_length->skip) {
1397
1398
0
            if (http11) {
1399
0
                if (n != NXT_HTTP_NOT_MODIFIED
1400
0
                    && n != NXT_HTTP_NO_CONTENT
1401
0
                    && body_handler != NULL
1402
0
                    && !h1p->websocket)
1403
0
                {
1404
0
                    h1p->chunked = 1;
1405
0
                    size += nxt_length(chunked);
1406
                    /* Trailing CRLF will be added by the first chunk header. */
1407
0
                    size -= nxt_length("\r\n");
1408
0
                }
1409
1410
0
            } else {
1411
0
                h1p->keepalive = 0;
1412
0
            }
1413
0
        }
1414
1415
0
        if (http11 ^ h1p->keepalive) {
1416
0
            conn = h1p->keepalive;
1417
0
        }
1418
0
    }
1419
1420
0
    if (conn >= 0) {
1421
0
        size += connection[conn].length;
1422
0
    }
1423
1424
0
    nxt_list_each(field, r->resp.fields) {
1425
1426
0
        if (!field->skip) {
1427
0
            size += field->name_length + field->value_length;
1428
0
            size += nxt_length(": \r\n");
1429
0
        }
1430
1431
0
    } nxt_list_loop;
1432
1433
0
    if (nxt_slow_path(n == NXT_HTTP_UPGRADE_REQUIRED)) {
1434
0
        size += nxt_length(websocket_version);
1435
0
    }
1436
1437
0
    header = nxt_http_buf_mem(task, r, size);
1438
0
    if (nxt_slow_path(header == NULL)) {
1439
0
        nxt_h1p_request_error(task, h1p, r);
1440
0
        return;
1441
0
    }
1442
1443
0
    p = nxt_cpymem(header->mem.free, status->start, status->length);
1444
1445
0
    nxt_list_each(field, r->resp.fields) {
1446
1447
0
        if (!field->skip) {
1448
0
            p = nxt_cpymem(p, field->name, field->name_length);
1449
0
            *p++ = ':'; *p++ = ' ';
1450
0
            p = nxt_cpymem(p, field->value, field->value_length);
1451
0
            *p++ = '\r'; *p++ = '\n';
1452
0
        }
1453
1454
0
    } nxt_list_loop;
1455
1456
0
    if (conn >= 0) {
1457
0
        p = nxt_cpymem(p, connection[conn].start, connection[conn].length);
1458
0
    }
1459
1460
0
    if (h1p->websocket) {
1461
0
        nxt_websocket_accept(p, h1p->websocket_key->value);
1462
0
        p += NXT_WEBSOCKET_ACCEPT_SIZE;
1463
1464
0
        *p++ = '\r'; *p++ = '\n';
1465
0
    }
1466
1467
0
    if (nxt_slow_path(n == NXT_HTTP_UPGRADE_REQUIRED)) {
1468
0
        p = nxt_cpymem(p, websocket_version, nxt_length(websocket_version));
1469
0
    }
1470
1471
0
    if (h1p->chunked) {
1472
0
        p = nxt_cpymem(p, chunked, nxt_length(chunked));
1473
        /* Trailing CRLF will be added by the first chunk header. */
1474
1475
0
    } else {
1476
0
        *p++ = '\r'; *p++ = '\n';
1477
0
    }
1478
1479
0
    header->mem.free = p;
1480
1481
0
    h1p->header_size = nxt_buf_mem_used_size(&header->mem);
1482
1483
0
    c = h1p->conn;
1484
1485
0
    c->write = header;
1486
0
    h1p->conn_write_tail = &header->next;
1487
0
    c->write_state = &nxt_h1p_request_send_state;
1488
1489
0
    if (body_handler != NULL) {
1490
        /*
1491
         * The body handler will run before c->io->write() handler,
1492
         * because the latter was inqueued by nxt_conn_write()
1493
         * in engine->write_work_queue.
1494
         */
1495
0
        nxt_work_queue_add(&task->thread->engine->fast_work_queue,
1496
0
                           body_handler, task, r, data);
1497
1498
0
    } else {
1499
0
        header->next = nxt_http_buf_last(r);
1500
0
    }
1501
1502
0
    nxt_conn_write(task->thread->engine, c);
1503
1504
0
    if (h1p->websocket) {
1505
0
        nxt_h1p_websocket_first_frame_start(task, r, c->read);
1506
0
    }
1507
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_request_header_send
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_request_header_send
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_request_header_send
1508
1509
1510
void
1511
nxt_h1p_complete_buffers(nxt_task_t *task, nxt_h1proto_t *h1p, nxt_bool_t all)
1512
0
{
1513
0
    size_t            size;
1514
0
    nxt_buf_t         *b, *in, *next;
1515
0
    nxt_conn_t        *c;
1516
1517
0
    nxt_debug(task, "h1p complete buffers");
1518
1519
0
    b = h1p->buffers;
1520
0
    c = h1p->conn;
1521
0
    in = c->read;
1522
1523
0
    if (b != NULL) {
1524
0
        if (in == NULL) {
1525
            /* A request with large body. */
1526
0
            in = b;
1527
0
            c->read = in;
1528
1529
0
            b = in->next;
1530
0
            in->next = NULL;
1531
0
        }
1532
1533
0
        while (b != NULL) {
1534
0
            next = b->next;
1535
0
            b->next = NULL;
1536
1537
0
            b->completion_handler(task, b, b->parent);
1538
1539
0
            b = next;
1540
0
        }
1541
1542
0
        h1p->buffers = NULL;
1543
0
        h1p->nbuffers = 0;
1544
0
    }
1545
1546
0
    if (in != NULL) {
1547
0
        size = nxt_buf_mem_used_size(&in->mem);
1548
1549
0
        if (size == 0 || all) {
1550
0
            in->completion_handler(task, in, in->parent);
1551
1552
0
            c->read = NULL;
1553
0
        }
1554
0
    }
1555
0
}
1556
1557
1558
static const nxt_conn_state_t  nxt_h1p_request_send_state
1559
    nxt_aligned(64) =
1560
{
1561
    .ready_handler = nxt_h1p_conn_sent,
1562
    .error_handler = nxt_h1p_conn_request_error,
1563
1564
    .timer_handler = nxt_h1p_conn_request_send_timeout,
1565
    .timer_value = nxt_h1p_conn_request_timer_value,
1566
    .timer_data = offsetof(nxt_socket_conf_t, send_timeout),
1567
    .timer_autoreset = 1,
1568
};
1569
1570
1571
static void
1572
nxt_h1p_request_send(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *out)
1573
0
{
1574
0
    nxt_conn_t     *c;
1575
0
    nxt_h1proto_t  *h1p;
1576
1577
0
    nxt_debug(task, "h1p request send");
1578
1579
0
    h1p = r->proto.h1;
1580
0
    c = h1p->conn;
1581
1582
0
    if (h1p->chunked) {
1583
0
        out = nxt_h1p_chunk_create(task, r, out);
1584
0
        if (nxt_slow_path(out == NULL)) {
1585
0
            nxt_h1p_request_error(task, h1p, r);
1586
0
            return;
1587
0
        }
1588
0
    }
1589
1590
0
    if (c->write == NULL) {
1591
0
        c->write = out;
1592
0
        c->write_state = &nxt_h1p_request_send_state;
1593
1594
0
        nxt_conn_write(task->thread->engine, c);
1595
1596
0
    } else {
1597
0
        *h1p->conn_write_tail = out;
1598
0
    }
1599
1600
0
    while (out->next != NULL) {
1601
0
        out = out->next;
1602
0
    }
1603
1604
0
    h1p->conn_write_tail = &out->next;
1605
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_request_send
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_request_send
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_request_send
1606
1607
1608
static nxt_buf_t *
1609
nxt_h1p_chunk_create(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *out)
1610
0
{
1611
0
    nxt_off_t          size;
1612
0
    nxt_buf_t          *b, **prev, *header, *tail;
1613
1614
0
    const size_t       chunk_size = 2 * nxt_length("\r\n") + NXT_OFF_T_HEXLEN;
1615
0
    static const char  tail_chunk[] = "\r\n0\r\n\r\n";
1616
1617
0
    size = 0;
1618
0
    prev = &out;
1619
1620
0
    for (b = out; b != NULL; b = b->next) {
1621
1622
0
        if (nxt_buf_is_last(b)) {
1623
0
            tail = nxt_http_buf_mem(task, r, sizeof(tail_chunk));
1624
0
            if (nxt_slow_path(tail == NULL)) {
1625
0
                return NULL;
1626
0
            }
1627
1628
0
            *prev = tail;
1629
0
            tail->next = b;
1630
            /*
1631
             * The tail_chunk size with trailing zero is 8 bytes, so
1632
             * memcpy may be inlined with just single 8 byte move operation.
1633
             */
1634
0
            nxt_memcpy(tail->mem.free, tail_chunk, sizeof(tail_chunk));
1635
0
            tail->mem.free += nxt_length(tail_chunk);
1636
1637
0
            break;
1638
0
        }
1639
1640
0
        size += nxt_buf_used_size(b);
1641
0
        prev = &b->next;
1642
0
    }
1643
1644
0
    if (size == 0) {
1645
0
        return out;
1646
0
    }
1647
1648
0
    header = nxt_http_buf_mem(task, r, chunk_size);
1649
0
    if (nxt_slow_path(header == NULL)) {
1650
0
        return NULL;
1651
0
    }
1652
1653
0
    header->next = out;
1654
0
    header->mem.free = nxt_sprintf(header->mem.free, header->mem.end,
1655
0
                                   "\r\n%xO\r\n", size);
1656
0
    return header;
1657
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_chunk_create
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_chunk_create
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_chunk_create
1658
1659
1660
static nxt_off_t
1661
nxt_h1p_request_body_bytes_sent(nxt_task_t *task, nxt_http_proto_t proto)
1662
0
{
1663
0
    nxt_off_t      sent;
1664
0
    nxt_h1proto_t  *h1p;
1665
1666
0
    h1p = proto.h1;
1667
1668
0
    sent = h1p->conn->sent - h1p->header_size;
1669
1670
0
    return (sent > 0) ? sent : 0;
1671
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_request_body_bytes_sent
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_request_body_bytes_sent
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_request_body_bytes_sent
1672
1673
1674
static void
1675
nxt_h1p_request_discard(nxt_task_t *task, nxt_http_request_t *r,
1676
    nxt_buf_t *last)
1677
0
{
1678
0
    nxt_buf_t         *b;
1679
0
    nxt_conn_t        *c;
1680
0
    nxt_h1proto_t     *h1p;
1681
0
    nxt_work_queue_t  *wq;
1682
1683
0
    nxt_debug(task, "h1p request discard");
1684
1685
0
    h1p = r->proto.h1;
1686
0
    h1p->keepalive = 0;
1687
1688
0
    c = h1p->conn;
1689
0
    b = c->write;
1690
0
    c->write = NULL;
1691
1692
0
    wq = &task->thread->engine->fast_work_queue;
1693
1694
0
    nxt_sendbuf_drain(task, wq, b);
1695
0
    nxt_sendbuf_drain(task, wq, last);
1696
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_request_discard
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_request_discard
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_request_discard
1697
1698
1699
static void
1700
nxt_h1p_conn_request_error(nxt_task_t *task, void *obj, void *data)
1701
0
{
1702
0
    nxt_h1proto_t       *h1p;
1703
0
    nxt_http_request_t  *r;
1704
1705
0
    h1p = data;
1706
1707
0
    nxt_debug(task, "h1p conn request error");
1708
1709
0
    r = h1p->request;
1710
1711
0
    if (nxt_slow_path(r == NULL)) {
1712
0
        nxt_h1p_shutdown(task, h1p->conn);
1713
0
        return;
1714
0
    }
1715
1716
0
    if (r->fields == NULL) {
1717
0
        (void) nxt_h1p_header_process(task, h1p, r);
1718
0
    }
1719
1720
0
    if (r->status == 0) {
1721
0
        r->status = NXT_HTTP_BAD_REQUEST;
1722
0
    }
1723
1724
0
    nxt_h1p_request_error(task, h1p, r);
1725
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_conn_request_error
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_conn_request_error
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_conn_request_error
1726
1727
1728
static void
1729
nxt_h1p_conn_request_timeout(nxt_task_t *task, void *obj, void *data)
1730
0
{
1731
0
    nxt_conn_t          *c;
1732
0
    nxt_timer_t         *timer;
1733
0
    nxt_h1proto_t       *h1p;
1734
0
    nxt_http_request_t  *r;
1735
1736
0
    timer = obj;
1737
1738
0
    nxt_debug(task, "h1p conn request timeout");
1739
1740
0
    c = nxt_read_timer_conn(timer);
1741
0
    c->block_read = 1;
1742
    /*
1743
     * Disable SO_LINGER off during socket closing
1744
     * to send "408 Request Timeout" error response.
1745
     */
1746
0
    c->socket.timedout = 0;
1747
1748
0
    h1p = c->socket.data;
1749
0
    h1p->keepalive = 0;
1750
0
    r = h1p->request;
1751
1752
0
    if (r->fields == NULL) {
1753
0
        (void) nxt_h1p_header_process(task, h1p, r);
1754
0
    }
1755
1756
0
    nxt_http_request_error(task, r, NXT_HTTP_REQUEST_TIMEOUT);
1757
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_conn_request_timeout
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_conn_request_timeout
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_conn_request_timeout
1758
1759
1760
static void
1761
nxt_h1p_conn_request_send_timeout(nxt_task_t *task, void *obj, void *data)
1762
0
{
1763
0
    nxt_conn_t     *c;
1764
0
    nxt_timer_t    *timer;
1765
0
    nxt_h1proto_t  *h1p;
1766
1767
0
    timer = obj;
1768
1769
0
    nxt_debug(task, "h1p conn request send timeout");
1770
1771
0
    c = nxt_write_timer_conn(timer);
1772
0
    c->block_write = 1;
1773
0
    h1p = c->socket.data;
1774
1775
0
    nxt_h1p_request_error(task, h1p, h1p->request);
1776
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_conn_request_send_timeout
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_conn_request_send_timeout
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_conn_request_send_timeout
1777
1778
1779
nxt_msec_t
1780
nxt_h1p_conn_request_timer_value(nxt_conn_t *c, uintptr_t data)
1781
0
{
1782
0
    nxt_h1proto_t  *h1p;
1783
1784
0
    h1p = c->socket.data;
1785
1786
0
    return nxt_value_at(nxt_msec_t, h1p->request->conf->socket_conf, data);
1787
0
}
1788
1789
1790
nxt_inline void
1791
nxt_h1p_request_error(nxt_task_t *task, nxt_h1proto_t *h1p,
1792
    nxt_http_request_t *r)
1793
0
{
1794
0
    h1p->keepalive = 0;
1795
1796
0
    r->state->error_handler(task, r, h1p);
1797
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_request_error
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_request_error
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_request_error
1798
1799
1800
static void
1801
nxt_h1p_request_close(nxt_task_t *task, nxt_http_proto_t proto,
1802
    nxt_socket_conf_joint_t *joint)
1803
0
{
1804
0
    nxt_conn_t     *c;
1805
0
    nxt_h1proto_t  *h1p;
1806
1807
0
    nxt_debug(task, "h1p request close");
1808
1809
0
    h1p = proto.h1;
1810
0
    h1p->keepalive &= !h1p->request->inconsistent;
1811
0
    h1p->request = NULL;
1812
1813
0
    nxt_router_conf_release(task, joint);
1814
1815
0
    c = h1p->conn;
1816
0
    task = &c->task;
1817
0
    c->socket.task = task;
1818
0
    c->read_timer.task = task;
1819
0
    c->write_timer.task = task;
1820
1821
0
    if (h1p->keepalive) {
1822
0
        nxt_h1p_keepalive(task, h1p, c);
1823
1824
0
    } else {
1825
0
        nxt_h1p_shutdown(task, c);
1826
0
    }
1827
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_request_close
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_request_close
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_request_close
1828
1829
1830
static void
1831
nxt_h1p_conn_sent(nxt_task_t *task, void *obj, void *data)
1832
0
{
1833
0
    nxt_conn_t          *c;
1834
0
    nxt_event_engine_t  *engine;
1835
1836
0
    c = obj;
1837
1838
0
    nxt_debug(task, "h1p conn sent");
1839
1840
0
    engine = task->thread->engine;
1841
1842
0
    c->write = nxt_sendbuf_completion(task, &engine->fast_work_queue, c->write);
1843
1844
0
    if (c->write != NULL) {
1845
0
        nxt_conn_write(engine, c);
1846
0
    }
1847
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_conn_sent
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_conn_sent
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_conn_sent
1848
1849
1850
static void
1851
nxt_h1p_conn_close(nxt_task_t *task, void *obj, void *data)
1852
0
{
1853
0
    nxt_conn_t  *c;
1854
1855
0
    c = obj;
1856
1857
0
    nxt_debug(task, "h1p conn close");
1858
1859
0
    nxt_conn_active(task->thread->engine, c);
1860
1861
0
    nxt_h1p_shutdown(task, c);
1862
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_conn_close
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_conn_close
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_conn_close
1863
1864
1865
static void
1866
nxt_h1p_conn_error(nxt_task_t *task, void *obj, void *data)
1867
0
{
1868
0
    nxt_conn_t  *c;
1869
1870
0
    c = obj;
1871
1872
0
    nxt_debug(task, "h1p conn error");
1873
1874
0
    nxt_conn_active(task->thread->engine, c);
1875
1876
0
    nxt_h1p_shutdown(task, c);
1877
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_conn_error
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_conn_error
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_conn_error
1878
1879
1880
static nxt_msec_t
1881
nxt_h1p_conn_timer_value(nxt_conn_t *c, uintptr_t data)
1882
0
{
1883
0
    nxt_socket_conf_joint_t  *joint;
1884
1885
0
    joint = c->listen->socket.data;
1886
1887
0
    if (nxt_fast_path(joint != NULL)) {
1888
0
        return nxt_value_at(nxt_msec_t, joint->socket_conf, data);
1889
0
    }
1890
1891
    /*
1892
     * Listening socket had been closed while
1893
     * connection was in keep-alive state.
1894
     */
1895
0
    return 1;
1896
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_conn_timer_value
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_conn_timer_value
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_conn_timer_value
1897
1898
1899
static void
1900
nxt_h1p_keepalive(nxt_task_t *task, nxt_h1proto_t *h1p, nxt_conn_t *c)
1901
0
{
1902
0
    size_t              size;
1903
0
    nxt_buf_t           *in;
1904
0
    nxt_event_engine_t  *engine;
1905
1906
0
    nxt_debug(task, "h1p keepalive");
1907
1908
0
    if (!c->tcp_nodelay) {
1909
0
        nxt_conn_tcp_nodelay_on(task, c);
1910
0
    }
1911
1912
0
    nxt_h1p_complete_buffers(task, h1p, 0);
1913
1914
0
    in = c->read;
1915
1916
0
    nxt_memzero(h1p, offsetof(nxt_h1proto_t, conn));
1917
1918
0
    c->sent = 0;
1919
1920
0
    engine = task->thread->engine;
1921
1922
0
    nxt_conn_idle(engine, c);
1923
1924
0
    if (in == NULL) {
1925
0
        c->read_state = &nxt_h1p_keepalive_state;
1926
1927
0
        nxt_conn_read(engine, c);
1928
1929
0
    } else {
1930
0
        size = nxt_buf_mem_used_size(&in->mem);
1931
1932
0
        nxt_debug(task, "h1p pipelining");
1933
1934
0
        nxt_memmove(in->mem.start, in->mem.pos, size);
1935
1936
0
        in->mem.pos = in->mem.start;
1937
0
        in->mem.free = in->mem.start + size;
1938
1939
0
        nxt_h1p_conn_request_init(task, c, c->socket.data);
1940
0
    }
1941
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_keepalive
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_keepalive
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_keepalive
1942
1943
1944
static const nxt_conn_state_t  nxt_h1p_keepalive_state
1945
    nxt_aligned(64) =
1946
{
1947
    .ready_handler = nxt_h1p_conn_request_init,
1948
    .close_handler = nxt_h1p_conn_close,
1949
    .error_handler = nxt_h1p_conn_error,
1950
1951
    .io_read_handler = nxt_h1p_idle_io_read_handler,
1952
1953
    .timer_handler = nxt_h1p_idle_timeout,
1954
    .timer_value = nxt_h1p_conn_timer_value,
1955
    .timer_data = offsetof(nxt_socket_conf_t, idle_timeout),
1956
    .timer_autoreset = 1,
1957
};
1958
1959
1960
const nxt_conn_state_t  nxt_h1p_idle_close_state
1961
    nxt_aligned(64) =
1962
{
1963
    .close_handler = nxt_h1p_idle_close,
1964
};
1965
1966
1967
static void
1968
nxt_h1p_idle_close(nxt_task_t *task, void *obj, void *data)
1969
0
{
1970
0
    nxt_conn_t  *c;
1971
1972
0
    c = obj;
1973
1974
0
    nxt_debug(task, "h1p idle close");
1975
1976
0
    nxt_conn_active(task->thread->engine, c);
1977
1978
0
    nxt_h1p_idle_response(task, c);
1979
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_idle_close
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_idle_close
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_idle_close
1980
1981
1982
static void
1983
nxt_h1p_idle_timeout(nxt_task_t *task, void *obj, void *data)
1984
0
{
1985
0
    nxt_conn_t   *c;
1986
0
    nxt_timer_t  *timer;
1987
1988
0
    timer = obj;
1989
1990
0
    nxt_debug(task, "h1p idle timeout");
1991
1992
0
    c = nxt_read_timer_conn(timer);
1993
0
    c->block_read = 1;
1994
1995
0
    nxt_conn_active(task->thread->engine, c);
1996
1997
0
    nxt_h1p_idle_response(task, c);
1998
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_idle_timeout
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_idle_timeout
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_idle_timeout
1999
2000
2001
#define NXT_H1P_IDLE_TIMEOUT                                                  \
2002
0
    "HTTP/1.1 408 Request Timeout\r\n"                                        \
2003
0
    "Server: " NXT_SERVER "\r\n"                                              \
2004
0
    "Connection: close\r\n"                                                   \
2005
0
    "Content-Length: 0\r\n"                                                   \
2006
0
    "Date: "
2007
2008
2009
static void
2010
nxt_h1p_idle_response(nxt_task_t *task, nxt_conn_t *c)
2011
0
{
2012
0
    u_char     *p;
2013
0
    size_t     size;
2014
0
    nxt_buf_t  *out, *last;
2015
2016
0
    size = nxt_length(NXT_H1P_IDLE_TIMEOUT)
2017
0
           + nxt_http_date_cache.size
2018
0
           + nxt_length("\r\n\r\n");
2019
2020
0
    out = nxt_buf_mem_alloc(c->mem_pool, size, 0);
2021
0
    if (nxt_slow_path(out == NULL)) {
2022
0
        goto fail;
2023
0
    }
2024
2025
0
    p = nxt_cpymem(out->mem.free, NXT_H1P_IDLE_TIMEOUT,
2026
0
                   nxt_length(NXT_H1P_IDLE_TIMEOUT));
2027
2028
0
    p = nxt_thread_time_string(task->thread, &nxt_http_date_cache, p);
2029
2030
0
    out->mem.free = nxt_cpymem(p, "\r\n\r\n", 4);
2031
2032
0
    last = nxt_mp_zget(c->mem_pool, NXT_BUF_SYNC_SIZE);
2033
0
    if (nxt_slow_path(last == NULL)) {
2034
0
        goto fail;
2035
0
    }
2036
2037
0
    out->next = last;
2038
0
    nxt_buf_set_sync(last);
2039
0
    nxt_buf_set_last(last);
2040
2041
0
    last->completion_handler = nxt_h1p_idle_response_sent;
2042
0
    last->parent = c;
2043
2044
0
    c->write = out;
2045
0
    c->write_state = &nxt_h1p_timeout_response_state;
2046
2047
0
    nxt_conn_write(task->thread->engine, c);
2048
0
    return;
2049
2050
0
fail:
2051
2052
0
    nxt_h1p_shutdown(task, c);
2053
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_idle_response
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_idle_response
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_idle_response
2054
2055
2056
static const nxt_conn_state_t  nxt_h1p_timeout_response_state
2057
    nxt_aligned(64) =
2058
{
2059
    .ready_handler = nxt_h1p_conn_sent,
2060
    .error_handler = nxt_h1p_idle_response_error,
2061
2062
    .timer_handler = nxt_h1p_idle_response_timeout,
2063
    .timer_value = nxt_h1p_idle_response_timer_value,
2064
};
2065
2066
2067
static void
2068
nxt_h1p_idle_response_sent(nxt_task_t *task, void *obj, void *data)
2069
0
{
2070
0
    nxt_conn_t  *c;
2071
2072
0
    c = data;
2073
2074
0
    nxt_debug(task, "h1p idle timeout response sent");
2075
2076
0
    nxt_h1p_shutdown(task, c);
2077
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_idle_response_sent
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_idle_response_sent
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_idle_response_sent
2078
2079
2080
static void
2081
nxt_h1p_idle_response_error(nxt_task_t *task, void *obj, void *data)
2082
0
{
2083
0
    nxt_conn_t  *c;
2084
2085
0
    c = obj;
2086
2087
0
    nxt_debug(task, "h1p response error");
2088
2089
0
    nxt_h1p_shutdown(task, c);
2090
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_idle_response_error
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_idle_response_error
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_idle_response_error
2091
2092
2093
static void
2094
nxt_h1p_idle_response_timeout(nxt_task_t *task, void *obj, void *data)
2095
0
{
2096
0
    nxt_conn_t   *c;
2097
0
    nxt_timer_t  *timer;
2098
2099
0
    timer = obj;
2100
2101
0
    nxt_debug(task, "h1p idle timeout response timeout");
2102
2103
0
    c = nxt_read_timer_conn(timer);
2104
0
    c->block_write = 1;
2105
2106
0
    nxt_h1p_shutdown(task, c);
2107
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_idle_response_timeout
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_idle_response_timeout
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_idle_response_timeout
2108
2109
2110
static nxt_msec_t
2111
nxt_h1p_idle_response_timer_value(nxt_conn_t *c, uintptr_t data)
2112
0
{
2113
0
    return 10 * 1000;
2114
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_idle_response_timer_value
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_idle_response_timer_value
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_idle_response_timer_value
2115
2116
2117
static void
2118
nxt_h1p_shutdown(nxt_task_t *task, nxt_conn_t *c)
2119
0
{
2120
0
    nxt_timer_t    *timer;
2121
0
    nxt_h1proto_t  *h1p;
2122
2123
0
    nxt_debug(task, "h1p shutdown");
2124
2125
0
    h1p = c->socket.data;
2126
2127
0
    if (h1p != NULL) {
2128
0
        nxt_h1p_complete_buffers(task, h1p, 1);
2129
2130
0
        if (nxt_slow_path(h1p->websocket_timer != NULL)) {
2131
0
            timer = &h1p->websocket_timer->timer;
2132
2133
0
            if (timer->handler != nxt_h1p_conn_ws_shutdown) {
2134
0
                timer->handler = nxt_h1p_conn_ws_shutdown;
2135
0
                nxt_timer_add(task->thread->engine, timer, 0);
2136
2137
0
            } else {
2138
0
                nxt_debug(task, "h1p already scheduled ws shutdown");
2139
0
            }
2140
2141
0
            return;
2142
0
        }
2143
0
    }
2144
2145
0
    nxt_h1p_closing(task, c);
2146
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_shutdown
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_shutdown
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_shutdown
2147
2148
2149
static void
2150
nxt_h1p_conn_ws_shutdown(nxt_task_t *task, void *obj, void *data)
2151
0
{
2152
0
    nxt_timer_t                *timer;
2153
0
    nxt_h1p_websocket_timer_t  *ws_timer;
2154
2155
0
    nxt_debug(task, "h1p conn ws shutdown");
2156
2157
0
    timer = obj;
2158
0
    ws_timer = nxt_timer_data(timer, nxt_h1p_websocket_timer_t, timer);
2159
2160
0
    nxt_h1p_closing(task, ws_timer->h1p->conn);
2161
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_conn_ws_shutdown
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_conn_ws_shutdown
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_conn_ws_shutdown
2162
2163
2164
static void
2165
nxt_h1p_closing(nxt_task_t *task, nxt_conn_t *c)
2166
0
{
2167
0
    nxt_debug(task, "h1p closing");
2168
2169
0
    c->socket.data = NULL;
2170
2171
#if (NXT_TLS)
2172
2173
    if (c->u.tls != NULL) {
2174
        c->write_state = &nxt_h1p_shutdown_state;
2175
2176
        c->io->shutdown(task, c, NULL);
2177
        return;
2178
    }
2179
2180
#endif
2181
2182
0
    nxt_h1p_conn_closing(task, c, NULL);
2183
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_closing
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_closing
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_closing
2184
2185
2186
#if (NXT_TLS)
2187
2188
static const nxt_conn_state_t  nxt_h1p_shutdown_state
2189
    nxt_aligned(64) =
2190
{
2191
    .ready_handler = nxt_h1p_conn_closing,
2192
    .close_handler = nxt_h1p_conn_closing,
2193
    .error_handler = nxt_h1p_conn_closing,
2194
};
2195
2196
#endif
2197
2198
2199
static void
2200
nxt_h1p_conn_closing(nxt_task_t *task, void *obj, void *data)
2201
0
{
2202
0
    nxt_conn_t  *c;
2203
2204
0
    c = obj;
2205
2206
0
    nxt_debug(task, "h1p conn closing");
2207
2208
0
    c->write_state = &nxt_h1p_close_state;
2209
2210
0
    nxt_conn_close(task->thread->engine, c);
2211
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_conn_closing
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_conn_closing
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_conn_closing
2212
2213
2214
static const nxt_conn_state_t  nxt_h1p_close_state
2215
    nxt_aligned(64) =
2216
{
2217
    .ready_handler = nxt_h1p_conn_free,
2218
};
2219
2220
2221
static void
2222
nxt_h1p_conn_free(nxt_task_t *task, void *obj, void *data)
2223
0
{
2224
0
    nxt_conn_t          *c;
2225
0
    nxt_listen_event_t  *lev;
2226
0
    nxt_event_engine_t  *engine;
2227
2228
0
    c = obj;
2229
2230
0
    nxt_debug(task, "h1p conn free");
2231
2232
0
    engine = task->thread->engine;
2233
2234
0
    nxt_sockaddr_cache_free(engine, c);
2235
2236
0
    lev = c->listen;
2237
2238
0
    nxt_conn_free(task, c);
2239
2240
0
    nxt_router_listen_event_release(&engine->task, lev, NULL);
2241
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_conn_free
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_conn_free
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_conn_free
2242
2243
2244
static void
2245
nxt_h1p_peer_connect(nxt_task_t *task, nxt_http_peer_t *peer)
2246
0
{
2247
0
    nxt_mp_t            *mp;
2248
0
    nxt_int_t           ret;
2249
0
    nxt_conn_t          *c, *client;
2250
0
    nxt_h1proto_t       *h1p;
2251
0
    nxt_fd_event_t      *socket;
2252
0
    nxt_work_queue_t    *wq;
2253
0
    nxt_http_request_t  *r;
2254
2255
0
    nxt_debug(task, "h1p peer connect");
2256
2257
0
    peer->status = NXT_HTTP_UNSET;
2258
0
    r = peer->request;
2259
2260
0
    mp = nxt_mp_create(1024, 128, 256, 32);
2261
2262
0
    if (nxt_slow_path(mp == NULL)) {
2263
0
        goto fail;
2264
0
    }
2265
2266
0
    h1p = nxt_mp_zalloc(mp, sizeof(nxt_h1proto_t));
2267
0
    if (nxt_slow_path(h1p == NULL)) {
2268
0
        goto fail;
2269
0
    }
2270
2271
0
    ret = nxt_http_parse_request_init(&h1p->parser, r->mem_pool);
2272
0
    if (nxt_slow_path(ret != NXT_OK)) {
2273
0
        goto fail;
2274
0
    }
2275
2276
0
    c = nxt_conn_create(mp, task);
2277
0
    if (nxt_slow_path(c == NULL)) {
2278
0
        goto fail;
2279
0
    }
2280
2281
0
    c->mem_pool = mp;
2282
0
    h1p->conn = c;
2283
2284
0
    peer->proto.h1 = h1p;
2285
0
    h1p->request = r;
2286
2287
0
    c->socket.data = peer;
2288
0
    c->remote = peer->server->sockaddr;
2289
2290
0
    c->socket.write_ready = 1;
2291
0
    c->write_state = &nxt_h1p_peer_connect_state;
2292
2293
    /*
2294
     * TODO: queues should be implemented via client proto interface.
2295
     */
2296
0
    client = r->proto.h1->conn;
2297
2298
0
    socket = &client->socket;
2299
0
    wq = socket->read_work_queue;
2300
0
    c->read_work_queue = wq;
2301
0
    c->socket.read_work_queue = wq;
2302
0
    c->read_timer.work_queue = wq;
2303
2304
0
    wq = socket->write_work_queue;
2305
0
    c->write_work_queue = wq;
2306
0
    c->socket.write_work_queue = wq;
2307
0
    c->write_timer.work_queue = wq;
2308
    /* TODO END */
2309
2310
0
    nxt_conn_connect(task->thread->engine, c);
2311
2312
0
    return;
2313
2314
0
fail:
2315
2316
0
    peer->status = NXT_HTTP_INTERNAL_SERVER_ERROR;
2317
2318
0
    r->state->error_handler(task, r, peer);
2319
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_peer_connect
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_peer_connect
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_peer_connect
2320
2321
2322
static const nxt_conn_state_t  nxt_h1p_peer_connect_state
2323
    nxt_aligned(64) =
2324
{
2325
    .ready_handler = nxt_h1p_peer_connected,
2326
    .close_handler = nxt_h1p_peer_refused,
2327
    .error_handler = nxt_h1p_peer_error,
2328
2329
    .timer_handler = nxt_h1p_peer_send_timeout,
2330
    .timer_value = nxt_h1p_peer_timer_value,
2331
    .timer_data = offsetof(nxt_socket_conf_t, proxy_timeout),
2332
};
2333
2334
2335
static void
2336
nxt_h1p_peer_connected(nxt_task_t *task, void *obj, void *data)
2337
0
{
2338
0
    nxt_http_peer_t     *peer;
2339
0
    nxt_http_request_t  *r;
2340
2341
0
    peer = data;
2342
2343
0
    nxt_debug(task, "h1p peer connected");
2344
2345
0
    r = peer->request;
2346
0
    r->state->ready_handler(task, r, peer);
2347
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_peer_connected
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_peer_connected
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_peer_connected
2348
2349
2350
static void
2351
nxt_h1p_peer_refused(nxt_task_t *task, void *obj, void *data)
2352
0
{
2353
0
    nxt_http_peer_t     *peer;
2354
0
    nxt_http_request_t  *r;
2355
2356
0
    peer = data;
2357
2358
0
    nxt_debug(task, "h1p peer refused");
2359
2360
    //peer->status = NXT_HTTP_SERVICE_UNAVAILABLE;
2361
0
    peer->status = NXT_HTTP_BAD_GATEWAY;
2362
2363
0
    r = peer->request;
2364
0
    r->state->error_handler(task, r, peer);
2365
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_peer_refused
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_peer_refused
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_peer_refused
2366
2367
2368
static void
2369
nxt_h1p_peer_header_send(nxt_task_t *task, nxt_http_peer_t *peer)
2370
0
{
2371
0
    u_char              *p;
2372
0
    size_t              size;
2373
0
    nxt_int_t           ret;
2374
0
    nxt_str_t           target;
2375
0
    nxt_buf_t           *header, *body;
2376
0
    nxt_conn_t          *c;
2377
0
    nxt_http_field_t    *field;
2378
0
    nxt_http_request_t  *r;
2379
2380
0
    nxt_debug(task, "h1p peer header send");
2381
2382
0
    r = peer->request;
2383
2384
0
    ret = nxt_h1p_peer_request_target(r, &target);
2385
0
    if (nxt_slow_path(ret != NXT_OK)) {
2386
0
        goto fail;
2387
0
    }
2388
2389
0
    size = r->method->length + sizeof(" ") + target.length
2390
0
           + sizeof(" HTTP/1.1\r\n")
2391
0
           + sizeof("Connection: close\r\n")
2392
0
           + sizeof("\r\n");
2393
2394
0
    nxt_list_each(field, r->fields) {
2395
2396
0
        if (!field->hopbyhop) {
2397
0
            size += field->name_length + field->value_length;
2398
0
            size += nxt_length(": \r\n");
2399
0
        }
2400
2401
0
    } nxt_list_loop;
2402
2403
0
    header = nxt_http_buf_mem(task, r, size);
2404
0
    if (nxt_slow_path(header == NULL)) {
2405
0
        goto fail;
2406
0
    }
2407
2408
0
    p = header->mem.free;
2409
2410
0
    p = nxt_cpymem(p, r->method->start, r->method->length);
2411
0
    *p++ = ' ';
2412
0
    p = nxt_cpymem(p, target.start, target.length);
2413
0
    p = nxt_cpymem(p, " HTTP/1.1\r\n", 11);
2414
0
    p = nxt_cpymem(p, "Connection: close\r\n", 19);
2415
2416
0
    nxt_list_each(field, r->fields) {
2417
2418
0
        if (!field->hopbyhop) {
2419
0
            p = nxt_cpymem(p, field->name, field->name_length);
2420
0
            *p++ = ':'; *p++ = ' ';
2421
0
            p = nxt_cpymem(p, field->value, field->value_length);
2422
0
            *p++ = '\r'; *p++ = '\n';
2423
0
        }
2424
2425
0
    } nxt_list_loop;
2426
2427
0
    *p++ = '\r'; *p++ = '\n';
2428
0
    header->mem.free = p;
2429
0
    size = p - header->mem.pos;
2430
2431
0
    c = peer->proto.h1->conn;
2432
0
    c->write = header;
2433
0
    c->write_state = &nxt_h1p_peer_header_send_state;
2434
2435
0
    if (r->body != NULL) {
2436
0
        if (nxt_buf_is_file(r->body)) {
2437
0
            body = nxt_buf_file_alloc(r->mem_pool, 0, 0);
2438
2439
0
        } else {
2440
0
            body = nxt_buf_mem_alloc(r->mem_pool, 0, 0);
2441
0
        }
2442
2443
0
        if (nxt_slow_path(body == NULL)) {
2444
0
            goto fail;
2445
0
        }
2446
2447
0
        header->next = body;
2448
2449
0
        if (nxt_buf_is_file(r->body)) {
2450
0
            body->file = r->body->file;
2451
0
            body->file_end = r->body->file_end;
2452
2453
0
        } else {
2454
0
            body->mem = r->body->mem;
2455
0
        }
2456
2457
0
        size += nxt_buf_used_size(body);
2458
2459
//        nxt_mp_retain(r->mem_pool);
2460
0
    }
2461
2462
0
    if (size > 16384) {
2463
        /* Use proxy_send_timeout instead of proxy_timeout. */
2464
0
        c->write_state = &nxt_h1p_peer_header_body_send_state;
2465
0
    }
2466
2467
0
    nxt_conn_write(task->thread->engine, c);
2468
2469
0
    return;
2470
2471
0
fail:
2472
2473
0
    r->state->error_handler(task, r, peer);
2474
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_peer_header_send
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_peer_header_send
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_peer_header_send
2475
2476
2477
static nxt_int_t
2478
nxt_h1p_peer_request_target(nxt_http_request_t *r, nxt_str_t *target)
2479
0
{
2480
0
    u_char  *p;
2481
0
    size_t  size, encode;
2482
2483
0
    if (!r->uri_changed) {
2484
0
        *target = r->target;
2485
0
        return NXT_OK;
2486
0
    }
2487
2488
0
    if (!r->quoted_target && r->args->length == 0) {
2489
0
        *target = *r->path;
2490
0
        return NXT_OK;
2491
0
    }
2492
2493
0
    if (r->quoted_target) {
2494
0
        encode = nxt_encode_complex_uri(NULL, r->path->start,
2495
0
                                        r->path->length);
2496
0
    } else {
2497
0
        encode = 0;
2498
0
    }
2499
2500
0
    size = r->path->length + encode * 2 + 1 + r->args->length;
2501
2502
0
    target->start = nxt_mp_nget(r->mem_pool, size);
2503
0
    if (target->start == NULL) {
2504
0
        return NXT_ERROR;
2505
0
    }
2506
2507
0
    if (r->quoted_target) {
2508
0
        p = (u_char *) nxt_encode_complex_uri(target->start, r->path->start,
2509
0
                                              r->path->length);
2510
2511
0
    } else {
2512
0
        p = nxt_cpymem(target->start, r->path->start, r->path->length);
2513
0
    }
2514
2515
0
    if (r->args->length > 0) {
2516
0
        *p++ = '?';
2517
0
        p = nxt_cpymem(p, r->args->start, r->args->length);
2518
0
    }
2519
2520
0
    target->length = p - target->start;
2521
2522
0
    return NXT_OK;
2523
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_peer_request_target
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_peer_request_target
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_peer_request_target
2524
2525
2526
static const nxt_conn_state_t  nxt_h1p_peer_header_send_state
2527
    nxt_aligned(64) =
2528
{
2529
    .ready_handler = nxt_h1p_peer_header_sent,
2530
    .error_handler = nxt_h1p_peer_error,
2531
2532
    .timer_handler = nxt_h1p_peer_send_timeout,
2533
    .timer_value = nxt_h1p_peer_timer_value,
2534
    .timer_data = offsetof(nxt_socket_conf_t, proxy_timeout),
2535
};
2536
2537
2538
static const nxt_conn_state_t  nxt_h1p_peer_header_body_send_state
2539
    nxt_aligned(64) =
2540
{
2541
    .ready_handler = nxt_h1p_peer_header_sent,
2542
    .error_handler = nxt_h1p_peer_error,
2543
2544
    .timer_handler = nxt_h1p_peer_send_timeout,
2545
    .timer_value = nxt_h1p_peer_timer_value,
2546
    .timer_data = offsetof(nxt_socket_conf_t, proxy_send_timeout),
2547
    .timer_autoreset = 1,
2548
};
2549
2550
2551
static void
2552
nxt_h1p_peer_header_sent(nxt_task_t *task, void *obj, void *data)
2553
0
{
2554
0
    nxt_conn_t          *c;
2555
0
    nxt_http_peer_t     *peer;
2556
0
    nxt_http_request_t  *r;
2557
0
    nxt_event_engine_t  *engine;
2558
2559
0
    c = obj;
2560
0
    peer = data;
2561
2562
0
    nxt_debug(task, "h1p peer header sent");
2563
2564
0
    engine = task->thread->engine;
2565
2566
0
    c->write = nxt_sendbuf_completion(task, &engine->fast_work_queue, c->write);
2567
2568
0
    if (c->write != NULL) {
2569
0
        nxt_conn_write(engine, c);
2570
0
        return;
2571
0
    }
2572
2573
0
    r = peer->request;
2574
0
    r->state->ready_handler(task, r, peer);
2575
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_peer_header_sent
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_peer_header_sent
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_peer_header_sent
2576
2577
2578
static void
2579
nxt_h1p_peer_header_read(nxt_task_t *task, nxt_http_peer_t *peer)
2580
0
{
2581
0
    nxt_conn_t  *c;
2582
2583
0
    nxt_debug(task, "h1p peer header read");
2584
2585
0
    c = peer->proto.h1->conn;
2586
2587
0
    if (c->write_timer.enabled) {
2588
0
        c->read_state = &nxt_h1p_peer_header_read_state;
2589
2590
0
    } else {
2591
0
        c->read_state = &nxt_h1p_peer_header_read_timer_state;
2592
0
    }
2593
2594
0
    nxt_conn_read(task->thread->engine, c);
2595
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_peer_header_read
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_peer_header_read
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_peer_header_read
2596
2597
2598
static const nxt_conn_state_t  nxt_h1p_peer_header_read_state
2599
    nxt_aligned(64) =
2600
{
2601
    .ready_handler = nxt_h1p_peer_header_read_done,
2602
    .close_handler = nxt_h1p_peer_closed,
2603
    .error_handler = nxt_h1p_peer_error,
2604
2605
    .io_read_handler = nxt_h1p_peer_io_read_handler,
2606
};
2607
2608
2609
static const nxt_conn_state_t  nxt_h1p_peer_header_read_timer_state
2610
    nxt_aligned(64) =
2611
{
2612
    .ready_handler = nxt_h1p_peer_header_read_done,
2613
    .close_handler = nxt_h1p_peer_closed,
2614
    .error_handler = nxt_h1p_peer_error,
2615
2616
    .io_read_handler = nxt_h1p_peer_io_read_handler,
2617
2618
    .timer_handler = nxt_h1p_peer_read_timeout,
2619
    .timer_value = nxt_h1p_peer_timer_value,
2620
    .timer_data = offsetof(nxt_socket_conf_t, proxy_timeout),
2621
};
2622
2623
2624
static ssize_t
2625
nxt_h1p_peer_io_read_handler(nxt_task_t *task, nxt_conn_t *c)
2626
0
{
2627
0
    size_t              size;
2628
0
    ssize_t             n;
2629
0
    nxt_buf_t           *b;
2630
0
    nxt_http_peer_t     *peer;
2631
0
    nxt_socket_conf_t   *skcf;
2632
0
    nxt_http_request_t  *r;
2633
2634
0
    peer = c->socket.data;
2635
0
    r = peer->request;
2636
0
    b = c->read;
2637
2638
0
    if (b == NULL) {
2639
0
        skcf = r->conf->socket_conf;
2640
2641
0
        size = (peer->header_received) ? skcf->proxy_buffer_size
2642
0
                                       : skcf->proxy_header_buffer_size;
2643
2644
0
        nxt_debug(task, "h1p peer io read: %z", size);
2645
2646
0
        b = nxt_http_proxy_buf_mem_alloc(task, r, size);
2647
0
        if (nxt_slow_path(b == NULL)) {
2648
0
            c->socket.error = NXT_ENOMEM;
2649
0
            return NXT_ERROR;
2650
0
        }
2651
0
    }
2652
2653
0
    n = c->io->recvbuf(c, b);
2654
2655
0
    if (n > 0) {
2656
0
        c->read = b;
2657
2658
0
    } else {
2659
0
        c->read = NULL;
2660
0
        nxt_http_proxy_buf_mem_free(task, r, b);
2661
0
    }
2662
2663
0
    return n;
2664
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_peer_io_read_handler
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_peer_io_read_handler
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_peer_io_read_handler
2665
2666
2667
static void
2668
nxt_h1p_peer_header_read_done(nxt_task_t *task, void *obj, void *data)
2669
0
{
2670
0
    nxt_int_t           ret;
2671
0
    nxt_buf_t           *b;
2672
0
    nxt_conn_t          *c;
2673
0
    nxt_h1proto_t       *h1p;
2674
0
    nxt_http_peer_t     *peer;
2675
0
    nxt_http_request_t  *r;
2676
0
    nxt_event_engine_t  *engine;
2677
2678
0
    c = obj;
2679
0
    peer = data;
2680
2681
0
    nxt_debug(task, "h1p peer header read done");
2682
2683
0
    b = c->read;
2684
2685
0
    ret = nxt_h1p_peer_header_parse(peer, &b->mem);
2686
2687
0
    r = peer->request;
2688
2689
0
    ret = nxt_expect(NXT_DONE, ret);
2690
2691
0
    if (ret != NXT_AGAIN) {
2692
0
        engine = task->thread->engine;
2693
0
        nxt_timer_disable(engine, &c->write_timer);
2694
0
        nxt_timer_disable(engine, &c->read_timer);
2695
0
    }
2696
2697
0
    switch (ret) {
2698
2699
0
    case NXT_DONE:
2700
0
        peer->fields = peer->proto.h1->parser.fields;
2701
2702
0
        ret = nxt_http_fields_process(peer->fields,
2703
0
                                      &nxt_h1p_peer_fields_hash, r);
2704
0
        if (nxt_slow_path(ret != NXT_OK)) {
2705
0
            peer->status = NXT_HTTP_INTERNAL_SERVER_ERROR;
2706
0
            break;
2707
0
        }
2708
2709
0
        c->read = NULL;
2710
2711
0
        peer->header_received = 1;
2712
2713
0
        h1p = peer->proto.h1;
2714
2715
0
        if (h1p->chunked) {
2716
0
            if (r->resp.content_length != NULL) {
2717
0
                peer->status = NXT_HTTP_BAD_GATEWAY;
2718
0
                break;
2719
0
            }
2720
2721
0
            h1p->chunked_parse.mem_pool = c->mem_pool;
2722
2723
0
        } else if (r->resp.content_length_n > 0) {
2724
0
            h1p->remainder = r->resp.content_length_n;
2725
0
        }
2726
2727
0
        if (nxt_buf_mem_used_size(&b->mem) != 0) {
2728
0
            nxt_h1p_peer_body_process(task, peer, b);
2729
0
            return;
2730
0
        }
2731
2732
0
        r->state->ready_handler(task, r, peer);
2733
0
        return;
2734
2735
0
    case NXT_AGAIN:
2736
0
        if (nxt_buf_mem_free_size(&b->mem) != 0) {
2737
0
            nxt_conn_read(task->thread->engine, c);
2738
0
            return;
2739
0
        }
2740
2741
        /* Fall through. */
2742
2743
0
    default:
2744
0
    case NXT_ERROR:
2745
0
    case NXT_HTTP_PARSE_INVALID:
2746
0
    case NXT_HTTP_PARSE_UNSUPPORTED_VERSION:
2747
0
    case NXT_HTTP_PARSE_TOO_LARGE_FIELD:
2748
0
        peer->status = NXT_HTTP_BAD_GATEWAY;
2749
0
        break;
2750
0
    }
2751
2752
0
    nxt_http_proxy_buf_mem_free(task, r, b);
2753
2754
0
    r->state->error_handler(task, r, peer);
2755
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_peer_header_read_done
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_peer_header_read_done
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_peer_header_read_done
2756
2757
2758
static nxt_int_t
2759
nxt_h1p_peer_header_parse(nxt_http_peer_t *peer, nxt_buf_mem_t *bm)
2760
0
{
2761
0
    u_char     *p;
2762
0
    size_t     length;
2763
0
    nxt_int_t  status;
2764
2765
0
    if (peer->status < 0) {
2766
0
        length = nxt_buf_mem_used_size(bm);
2767
2768
0
        if (nxt_slow_path(length < 12)) {
2769
0
            return NXT_AGAIN;
2770
0
        }
2771
2772
0
        p = bm->pos;
2773
2774
0
        if (nxt_slow_path(memcmp(p, "HTTP/1.", 7) != 0
2775
0
                          || (p[7] != '0' && p[7] != '1')))
2776
0
        {
2777
0
            return NXT_ERROR;
2778
0
        }
2779
2780
0
        status = nxt_int_parse(&p[9], 3);
2781
2782
0
        if (nxt_slow_path(status < 0)) {
2783
0
            return NXT_ERROR;
2784
0
        }
2785
2786
0
        p += 12;
2787
0
        length -= 12;
2788
2789
0
        p = memchr(p, '\n', length);
2790
2791
0
        if (nxt_slow_path(p == NULL)) {
2792
0
            return NXT_AGAIN;
2793
0
        }
2794
2795
0
        bm->pos = p + 1;
2796
0
        peer->status = status;
2797
0
    }
2798
2799
0
    return nxt_http_parse_fields(&peer->proto.h1->parser, bm);
2800
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_peer_header_parse
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_peer_header_parse
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_peer_header_parse
2801
2802
2803
static void
2804
nxt_h1p_peer_read(nxt_task_t *task, nxt_http_peer_t *peer)
2805
0
{
2806
0
    nxt_conn_t  *c;
2807
2808
0
    nxt_debug(task, "h1p peer read");
2809
2810
0
    c = peer->proto.h1->conn;
2811
0
    c->read_state = &nxt_h1p_peer_read_state;
2812
2813
0
    nxt_conn_read(task->thread->engine, c);
2814
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_peer_read
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_peer_read
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_peer_read
2815
2816
2817
static const nxt_conn_state_t  nxt_h1p_peer_read_state
2818
    nxt_aligned(64) =
2819
{
2820
    .ready_handler = nxt_h1p_peer_read_done,
2821
    .close_handler = nxt_h1p_peer_closed,
2822
    .error_handler = nxt_h1p_peer_error,
2823
2824
    .io_read_handler = nxt_h1p_peer_io_read_handler,
2825
2826
    .timer_handler = nxt_h1p_peer_read_timeout,
2827
    .timer_value = nxt_h1p_peer_timer_value,
2828
    .timer_data = offsetof(nxt_socket_conf_t, proxy_read_timeout),
2829
    .timer_autoreset = 1,
2830
};
2831
2832
2833
static void
2834
nxt_h1p_peer_read_done(nxt_task_t *task, void *obj, void *data)
2835
0
{
2836
0
    nxt_buf_t        *out;
2837
0
    nxt_conn_t       *c;
2838
0
    nxt_http_peer_t  *peer;
2839
2840
0
    c = obj;
2841
0
    peer = data;
2842
2843
0
    nxt_debug(task, "h1p peer read done");
2844
2845
0
    out = c->read;
2846
0
    c->read = NULL;
2847
2848
0
    nxt_h1p_peer_body_process(task, peer, out);
2849
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_peer_read_done
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_peer_read_done
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_peer_read_done
2850
2851
2852
static void
2853
nxt_h1p_peer_body_process(nxt_task_t *task, nxt_http_peer_t *peer,
2854
    nxt_buf_t *out)
2855
0
{
2856
0
    size_t              length;
2857
0
    nxt_h1proto_t       *h1p;
2858
0
    nxt_http_request_t  *r;
2859
2860
0
    h1p = peer->proto.h1;
2861
2862
0
    if (h1p->chunked) {
2863
0
        out = nxt_http_chunk_parse(task, &h1p->chunked_parse, out);
2864
2865
0
        if (h1p->chunked_parse.chunk_error || h1p->chunked_parse.error) {
2866
0
            peer->status = NXT_HTTP_BAD_GATEWAY;
2867
0
            r = peer->request;
2868
0
            r->state->error_handler(task, r, peer);
2869
0
            return;
2870
0
        }
2871
2872
0
        if (h1p->chunked_parse.last) {
2873
0
            nxt_buf_chain_add(&out, nxt_http_buf_last(peer->request));
2874
0
            peer->closed = 1;
2875
0
        }
2876
2877
0
    } else if (h1p->remainder > 0) {
2878
0
        length = nxt_buf_chain_length(out);
2879
0
        h1p->remainder -= length;
2880
2881
0
        if (h1p->remainder == 0) {
2882
0
            nxt_buf_chain_add(&out, nxt_http_buf_last(peer->request));
2883
0
            peer->closed = 1;
2884
0
        }
2885
0
    }
2886
2887
0
    peer->body = out;
2888
2889
0
    r = peer->request;
2890
0
    r->state->ready_handler(task, r, peer);
2891
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_peer_body_process
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_peer_body_process
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_peer_body_process
2892
2893
2894
static void
2895
nxt_h1p_peer_closed(nxt_task_t *task, void *obj, void *data)
2896
0
{
2897
0
    nxt_http_peer_t     *peer;
2898
0
    nxt_http_request_t  *r;
2899
2900
0
    peer = data;
2901
2902
0
    nxt_debug(task, "h1p peer closed");
2903
2904
0
    r = peer->request;
2905
2906
0
    if (peer->header_received) {
2907
0
        peer->body = nxt_http_buf_last(r);
2908
0
        peer->closed = 1;
2909
0
        r->inconsistent = (peer->proto.h1->remainder != 0);
2910
2911
0
        r->state->ready_handler(task, r, peer);
2912
2913
0
    } else {
2914
0
        peer->status = NXT_HTTP_BAD_GATEWAY;
2915
2916
0
        r->state->error_handler(task, r, peer);
2917
0
    }
2918
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_peer_closed
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_peer_closed
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_peer_closed
2919
2920
2921
static void
2922
nxt_h1p_peer_error(nxt_task_t *task, void *obj, void *data)
2923
0
{
2924
0
    nxt_http_peer_t     *peer;
2925
0
    nxt_http_request_t  *r;
2926
2927
0
    peer = data;
2928
2929
0
    nxt_debug(task, "h1p peer error");
2930
2931
0
    peer->status = NXT_HTTP_BAD_GATEWAY;
2932
2933
0
    r = peer->request;
2934
0
    r->state->error_handler(task, r, peer);
2935
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_peer_error
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_peer_error
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_peer_error
2936
2937
2938
static void
2939
nxt_h1p_peer_send_timeout(nxt_task_t *task, void *obj, void *data)
2940
0
{
2941
0
    nxt_conn_t          *c;
2942
0
    nxt_timer_t         *timer;
2943
0
    nxt_http_peer_t     *peer;
2944
0
    nxt_http_request_t  *r;
2945
2946
0
    timer = obj;
2947
2948
0
    nxt_debug(task, "h1p peer send timeout");
2949
2950
0
    c = nxt_write_timer_conn(timer);
2951
0
    c->block_write = 1;
2952
0
    c->block_read = 1;
2953
2954
0
    peer = c->socket.data;
2955
0
    peer->status = NXT_HTTP_GATEWAY_TIMEOUT;
2956
2957
0
    r = peer->request;
2958
0
    r->state->error_handler(task, r, peer);
2959
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_peer_send_timeout
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_peer_send_timeout
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_peer_send_timeout
2960
2961
2962
static void
2963
nxt_h1p_peer_read_timeout(nxt_task_t *task, void *obj, void *data)
2964
0
{
2965
0
    nxt_conn_t          *c;
2966
0
    nxt_timer_t         *timer;
2967
0
    nxt_http_peer_t     *peer;
2968
0
    nxt_http_request_t  *r;
2969
2970
0
    timer = obj;
2971
2972
0
    nxt_debug(task, "h1p peer read timeout");
2973
2974
0
    c = nxt_read_timer_conn(timer);
2975
0
    c->block_write = 1;
2976
0
    c->block_read = 1;
2977
2978
0
    peer = c->socket.data;
2979
0
    peer->status = NXT_HTTP_GATEWAY_TIMEOUT;
2980
2981
0
    r = peer->request;
2982
0
    r->state->error_handler(task, r, peer);
2983
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_peer_read_timeout
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_peer_read_timeout
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_peer_read_timeout
2984
2985
2986
static nxt_msec_t
2987
nxt_h1p_peer_timer_value(nxt_conn_t *c, uintptr_t data)
2988
0
{
2989
0
    nxt_http_peer_t  *peer;
2990
2991
0
    peer = c->socket.data;
2992
2993
0
    return nxt_value_at(nxt_msec_t, peer->request->conf->socket_conf, data);
2994
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_peer_timer_value
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_peer_timer_value
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_peer_timer_value
2995
2996
2997
static void
2998
nxt_h1p_peer_close(nxt_task_t *task, nxt_http_peer_t *peer)
2999
0
{
3000
0
    nxt_conn_t  *c;
3001
3002
0
    nxt_debug(task, "h1p peer close");
3003
3004
0
    peer->closed = 1;
3005
3006
0
    c = peer->proto.h1->conn;
3007
0
    task = &c->task;
3008
0
    c->socket.task = task;
3009
0
    c->read_timer.task = task;
3010
0
    c->write_timer.task = task;
3011
3012
0
    if (c->socket.fd != -1) {
3013
0
        c->write_state = &nxt_h1p_peer_close_state;
3014
3015
0
        nxt_conn_close(task->thread->engine, c);
3016
3017
0
    } else {
3018
0
        nxt_h1p_peer_free(task, c, NULL);
3019
0
    }
3020
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_peer_close
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_peer_close
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_peer_close
3021
3022
3023
static const nxt_conn_state_t  nxt_h1p_peer_close_state
3024
    nxt_aligned(64) =
3025
{
3026
    .ready_handler = nxt_h1p_peer_free,
3027
};
3028
3029
3030
static void
3031
nxt_h1p_peer_free(nxt_task_t *task, void *obj, void *data)
3032
0
{
3033
0
    nxt_conn_t  *c;
3034
3035
0
    c = obj;
3036
3037
0
    nxt_debug(task, "h1p peer free");
3038
3039
0
    nxt_conn_free(task, c);
3040
0
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_peer_free
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_peer_free
Unexecuted instantiation: nxt_http_h1p_peer_fuzz.c:nxt_h1p_peer_free
3041
3042
3043
static nxt_int_t
3044
nxt_h1p_peer_transfer_encoding(void *ctx, nxt_http_field_t *field,
3045
    uintptr_t data)
3046
227
{
3047
227
    nxt_http_request_t  *r;
3048
3049
227
    r = ctx;
3050
227
    field->skip = 1;
3051
3052
227
    if (field->value_length == 7
3053
133
        && memcmp(field->value, "chunked", 7) == 0)
3054
66
    {
3055
66
        r->peer->proto.h1->chunked = 1;
3056
66
    }
3057
3058
227
    return NXT_OK;
3059
227
}
Unexecuted instantiation: nxt_h1proto.c:nxt_h1p_peer_transfer_encoding
Unexecuted instantiation: nxt_http_h1p_fuzz.c:nxt_h1p_peer_transfer_encoding
nxt_http_h1p_peer_fuzz.c:nxt_h1p_peer_transfer_encoding
Line
Count
Source
3046
227
{
3047
227
    nxt_http_request_t  *r;
3048
3049
227
    r = ctx;
3050
227
    field->skip = 1;
3051
3052
227
    if (field->value_length == 7
3053
133
        && memcmp(field->value, "chunked", 7) == 0)
3054
66
    {
3055
66
        r->peer->proto.h1->chunked = 1;
3056
66
    }
3057
3058
227
    return NXT_OK;
3059
227
}