Coverage Report

Created: 2024-02-11 06:11

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