Coverage Report

Created: 2022-11-30 06:08

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