1431Sigor@sysoev.ru 2431Sigor@sysoev.ru /* 3431Sigor@sysoev.ru * Copyright (C) Igor Sysoev 4431Sigor@sysoev.ru * Copyright (C) NGINX, Inc. 5431Sigor@sysoev.ru */ 6431Sigor@sysoev.ru 7431Sigor@sysoev.ru #include <nxt_router.h> 8431Sigor@sysoev.ru #include <nxt_http.h> 9431Sigor@sysoev.ru 10431Sigor@sysoev.ru 11624Sigor@sysoev.ru /* 12624Sigor@sysoev.ru * nxt_h1p_conn_ prefix is used for connection handlers. 13624Sigor@sysoev.ru * nxt_h1p_request_ prefix is used for HTTP/1 protocol request methods. 14624Sigor@sysoev.ru */ 15624Sigor@sysoev.ru 16629Sigor@sysoev.ru static ssize_t nxt_h1p_conn_io_read_handler(nxt_conn_t *c); 17624Sigor@sysoev.ru static void nxt_h1p_conn_proto_init(nxt_task_t *task, void *obj, void *data); 18624Sigor@sysoev.ru static void nxt_h1p_conn_request_init(nxt_task_t *task, void *obj, void *data); 19624Sigor@sysoev.ru static void nxt_h1p_conn_header_parse(nxt_task_t *task, void *obj, void *data); 20620Svbart@nginx.com static nxt_int_t nxt_h1p_header_process(nxt_h1proto_t *h1p, 21620Svbart@nginx.com nxt_http_request_t *r); 22625Sigor@sysoev.ru static nxt_int_t nxt_h1p_header_buffer_test(nxt_task_t *task, 23625Sigor@sysoev.ru nxt_h1proto_t *h1p, nxt_conn_t *c, nxt_socket_conf_t *skcf); 24431Sigor@sysoev.ru static nxt_int_t nxt_h1p_connection(void *ctx, nxt_http_field_t *field, 25431Sigor@sysoev.ru uintptr_t data); 26431Sigor@sysoev.ru static nxt_int_t nxt_h1p_transfer_encoding(void *ctx, nxt_http_field_t *field, 27431Sigor@sysoev.ru uintptr_t data); 28431Sigor@sysoev.ru static void nxt_h1p_request_body_read(nxt_task_t *task, nxt_http_request_t *r); 29624Sigor@sysoev.ru static void nxt_h1p_conn_body_read(nxt_task_t *task, void *obj, void *data); 30431Sigor@sysoev.ru static void nxt_h1p_request_local_addr(nxt_task_t *task, nxt_http_request_t *r); 31431Sigor@sysoev.ru static void nxt_h1p_request_header_send(nxt_task_t *task, 32431Sigor@sysoev.ru nxt_http_request_t *r); 33431Sigor@sysoev.ru static void nxt_h1p_request_send(nxt_task_t *task, nxt_http_request_t *r, 34431Sigor@sysoev.ru nxt_buf_t *out); 35431Sigor@sysoev.ru static nxt_buf_t *nxt_h1p_chunk_create(nxt_task_t *task, nxt_http_request_t *r, 36431Sigor@sysoev.ru nxt_buf_t *out); 37624Sigor@sysoev.ru static void nxt_h1p_conn_request_sent(nxt_task_t *task, void *obj, void *data); 38630Svbart@nginx.com static nxt_off_t nxt_h1p_request_body_bytes_sent(nxt_task_t *task, 39630Svbart@nginx.com nxt_http_proto_t proto); 40608Sigor@sysoev.ru static void nxt_h1p_request_discard(nxt_task_t *task, nxt_http_request_t *r, 41608Sigor@sysoev.ru nxt_buf_t *last); 42431Sigor@sysoev.ru static void nxt_h1p_request_close(nxt_task_t *task, nxt_http_proto_t proto); 43431Sigor@sysoev.ru static void nxt_h1p_keepalive(nxt_task_t *task, nxt_h1proto_t *h1p, 44431Sigor@sysoev.ru nxt_conn_t *c); 45431Sigor@sysoev.ru static void nxt_h1p_conn_error(nxt_task_t *task, void *obj, void *data); 46431Sigor@sysoev.ru static void nxt_h1p_conn_timeout(nxt_task_t *task, void *obj, void *data); 47624Sigor@sysoev.ru static void nxt_h1p_close(nxt_task_t *task, nxt_conn_t *c); 48624Sigor@sysoev.ru static void nxt_h1p_conn_request_error(nxt_task_t *task, void *obj, void *data); 49624Sigor@sysoev.ru static void nxt_h1p_conn_request_timeout(nxt_task_t *task, void *obj, 50624Sigor@sysoev.ru void *data); 51626Sigor@sysoev.ru static void nxt_h1p_conn_request_send_timeout(nxt_task_t *task, void *obj, 52626Sigor@sysoev.ru void *data); 53624Sigor@sysoev.ru nxt_inline void nxt_h1p_request_error(nxt_task_t *task, nxt_http_request_t *r); 54624Sigor@sysoev.ru static nxt_msec_t nxt_h1p_conn_timeout_value(nxt_conn_t *c, uintptr_t data); 55431Sigor@sysoev.ru 56431Sigor@sysoev.ru 57431Sigor@sysoev.ru static const nxt_conn_state_t nxt_h1p_idle_state; 58624Sigor@sysoev.ru static const nxt_conn_state_t nxt_h1p_header_parse_state; 59431Sigor@sysoev.ru static const nxt_conn_state_t nxt_h1p_read_body_state; 60431Sigor@sysoev.ru static const nxt_conn_state_t nxt_h1p_send_state; 61624Sigor@sysoev.ru static const nxt_conn_state_t nxt_h1p_keepalive_state; 62431Sigor@sysoev.ru 63431Sigor@sysoev.ru 64431Sigor@sysoev.ru const nxt_http_proto_body_read_t nxt_http_proto_body_read[3] = { 65431Sigor@sysoev.ru nxt_h1p_request_body_read, 66431Sigor@sysoev.ru NULL, 67431Sigor@sysoev.ru NULL, 68431Sigor@sysoev.ru }; 69431Sigor@sysoev.ru 70431Sigor@sysoev.ru 71431Sigor@sysoev.ru const nxt_http_proto_local_addr_t nxt_http_proto_local_addr[3] = { 72431Sigor@sysoev.ru nxt_h1p_request_local_addr, 73431Sigor@sysoev.ru NULL, 74431Sigor@sysoev.ru NULL, 75431Sigor@sysoev.ru }; 76431Sigor@sysoev.ru 77431Sigor@sysoev.ru 78431Sigor@sysoev.ru const nxt_http_proto_header_send_t nxt_http_proto_header_send[3] = { 79431Sigor@sysoev.ru nxt_h1p_request_header_send, 80431Sigor@sysoev.ru NULL, 81431Sigor@sysoev.ru NULL, 82431Sigor@sysoev.ru }; 83431Sigor@sysoev.ru 84431Sigor@sysoev.ru 85431Sigor@sysoev.ru const nxt_http_proto_send_t nxt_http_proto_send[3] = { 86431Sigor@sysoev.ru nxt_h1p_request_send, 87431Sigor@sysoev.ru NULL, 88431Sigor@sysoev.ru NULL, 89431Sigor@sysoev.ru }; 90431Sigor@sysoev.ru 91431Sigor@sysoev.ru 92630Svbart@nginx.com const nxt_http_proto_body_bytes_sent_t nxt_http_proto_body_bytes_sent[3] = { 93630Svbart@nginx.com nxt_h1p_request_body_bytes_sent, 94630Svbart@nginx.com NULL, 95630Svbart@nginx.com NULL, 96630Svbart@nginx.com }; 97630Svbart@nginx.com 98630Svbart@nginx.com 99608Sigor@sysoev.ru const nxt_http_proto_discard_t nxt_http_proto_discard[3] = { 100608Sigor@sysoev.ru nxt_h1p_request_discard, 101608Sigor@sysoev.ru NULL, 102608Sigor@sysoev.ru NULL, 103608Sigor@sysoev.ru }; 104608Sigor@sysoev.ru 105608Sigor@sysoev.ru 106431Sigor@sysoev.ru const nxt_http_proto_close_t nxt_http_proto_close[3] = { 107431Sigor@sysoev.ru nxt_h1p_request_close, 108431Sigor@sysoev.ru NULL, 109431Sigor@sysoev.ru NULL, 110431Sigor@sysoev.ru }; 111431Sigor@sysoev.ru 112431Sigor@sysoev.ru 113431Sigor@sysoev.ru static nxt_lvlhsh_t nxt_h1p_fields_hash; 114431Sigor@sysoev.ru 115431Sigor@sysoev.ru static nxt_http_field_proc_t nxt_h1p_fields[] = { 116431Sigor@sysoev.ru { nxt_string("Connection"), &nxt_h1p_connection, 0 }, 117431Sigor@sysoev.ru { nxt_string("Transfer-Encoding"), &nxt_h1p_transfer_encoding, 0 }, 118431Sigor@sysoev.ru 119431Sigor@sysoev.ru { nxt_string("Host"), &nxt_http_request_host, 0 }, 120431Sigor@sysoev.ru { nxt_string("Cookie"), &nxt_http_request_field, 121431Sigor@sysoev.ru offsetof(nxt_http_request_t, cookie) }, 122630Svbart@nginx.com { nxt_string("Referer"), &nxt_http_request_field, 123630Svbart@nginx.com offsetof(nxt_http_request_t, referer) }, 124630Svbart@nginx.com { nxt_string("User-Agent"), &nxt_http_request_field, 125630Svbart@nginx.com offsetof(nxt_http_request_t, user_agent) }, 126431Sigor@sysoev.ru { nxt_string("Content-Type"), &nxt_http_request_field, 127431Sigor@sysoev.ru offsetof(nxt_http_request_t, content_type) }, 128431Sigor@sysoev.ru { nxt_string("Content-Length"), &nxt_http_request_content_length, 0 }, 129431Sigor@sysoev.ru }; 130431Sigor@sysoev.ru 131431Sigor@sysoev.ru 132431Sigor@sysoev.ru nxt_int_t 133431Sigor@sysoev.ru nxt_h1p_init(nxt_task_t *task, nxt_runtime_t *rt) 134431Sigor@sysoev.ru { 135431Sigor@sysoev.ru return nxt_http_fields_hash(&nxt_h1p_fields_hash, rt->mem_pool, 136431Sigor@sysoev.ru nxt_h1p_fields, nxt_nitems(nxt_h1p_fields)); 137431Sigor@sysoev.ru } 138431Sigor@sysoev.ru 139431Sigor@sysoev.ru 140431Sigor@sysoev.ru void 141431Sigor@sysoev.ru nxt_http_conn_init(nxt_task_t *task, void *obj, void *data) 142431Sigor@sysoev.ru { 143431Sigor@sysoev.ru nxt_conn_t *c; 144431Sigor@sysoev.ru nxt_socket_conf_t *skcf; 145431Sigor@sysoev.ru nxt_event_engine_t *engine; 146431Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 147431Sigor@sysoev.ru 148431Sigor@sysoev.ru c = obj; 149431Sigor@sysoev.ru joint = data; 150431Sigor@sysoev.ru 151431Sigor@sysoev.ru nxt_debug(task, "http conn init"); 152431Sigor@sysoev.ru 153431Sigor@sysoev.ru c->joint = joint; 154431Sigor@sysoev.ru joint->count++; 155431Sigor@sysoev.ru 156431Sigor@sysoev.ru skcf = joint->socket_conf; 157431Sigor@sysoev.ru c->local = skcf->sockaddr; 158431Sigor@sysoev.ru c->socket.data = NULL; 159431Sigor@sysoev.ru 160431Sigor@sysoev.ru engine = task->thread->engine; 161431Sigor@sysoev.ru c->read_work_queue = &engine->fast_work_queue; 162431Sigor@sysoev.ru c->write_work_queue = &engine->fast_work_queue; 163431Sigor@sysoev.ru 164431Sigor@sysoev.ru c->read_state = &nxt_h1p_idle_state; 165431Sigor@sysoev.ru 166629Sigor@sysoev.ru nxt_conn_read(task->thread->engine, c); 167431Sigor@sysoev.ru } 168431Sigor@sysoev.ru 169431Sigor@sysoev.ru 170431Sigor@sysoev.ru static const nxt_conn_state_t nxt_h1p_idle_state 171431Sigor@sysoev.ru nxt_aligned(64) = 172431Sigor@sysoev.ru { 173629Sigor@sysoev.ru .ready_handler = nxt_h1p_conn_proto_init, 174624Sigor@sysoev.ru .close_handler = nxt_h1p_conn_error, 175431Sigor@sysoev.ru .error_handler = nxt_h1p_conn_error, 176431Sigor@sysoev.ru 177629Sigor@sysoev.ru .io_read_handler = nxt_h1p_conn_io_read_handler, 178431Sigor@sysoev.ru 179431Sigor@sysoev.ru .timer_handler = nxt_h1p_conn_timeout, 180624Sigor@sysoev.ru .timer_value = nxt_h1p_conn_timeout_value, 181635Sigor@sysoev.ru .timer_data = offsetof(nxt_socket_conf_t, idle_timeout), 182*636Sigor@sysoev.ru .timer_autoreset = 1, 183431Sigor@sysoev.ru }; 184431Sigor@sysoev.ru 185431Sigor@sysoev.ru 186629Sigor@sysoev.ru static ssize_t 187629Sigor@sysoev.ru nxt_h1p_conn_io_read_handler(nxt_conn_t *c) 188629Sigor@sysoev.ru { 189629Sigor@sysoev.ru size_t size; 190629Sigor@sysoev.ru ssize_t n; 191629Sigor@sysoev.ru nxt_buf_t *b; 192629Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 193629Sigor@sysoev.ru 194629Sigor@sysoev.ru joint = c->joint; 195629Sigor@sysoev.ru size = joint->socket_conf->header_buffer_size; 196629Sigor@sysoev.ru 197629Sigor@sysoev.ru b = nxt_buf_mem_alloc(c->mem_pool, size, 0); 198629Sigor@sysoev.ru if (nxt_slow_path(b == NULL)) { 199629Sigor@sysoev.ru c->socket.error = NXT_ENOMEM; 200629Sigor@sysoev.ru return NXT_ERROR; 201629Sigor@sysoev.ru } 202629Sigor@sysoev.ru 203629Sigor@sysoev.ru n = c->io->recvbuf(c, b); 204629Sigor@sysoev.ru 205629Sigor@sysoev.ru if (n > 0) { 206629Sigor@sysoev.ru c->read = b; 207629Sigor@sysoev.ru 208629Sigor@sysoev.ru } else { 209629Sigor@sysoev.ru nxt_mp_free(c->mem_pool, b); 210629Sigor@sysoev.ru } 211629Sigor@sysoev.ru 212629Sigor@sysoev.ru return n; 213629Sigor@sysoev.ru } 214629Sigor@sysoev.ru 215629Sigor@sysoev.ru 216431Sigor@sysoev.ru static void 217624Sigor@sysoev.ru nxt_h1p_conn_proto_init(nxt_task_t *task, void *obj, void *data) 218431Sigor@sysoev.ru { 219624Sigor@sysoev.ru nxt_conn_t *c; 220624Sigor@sysoev.ru nxt_h1proto_t *h1p; 221624Sigor@sysoev.ru 222624Sigor@sysoev.ru c = obj; 223624Sigor@sysoev.ru 224624Sigor@sysoev.ru nxt_debug(task, "h1p conn proto init"); 225624Sigor@sysoev.ru 226624Sigor@sysoev.ru h1p = nxt_mp_zget(c->mem_pool, sizeof(nxt_h1proto_t)); 227624Sigor@sysoev.ru if (nxt_slow_path(h1p == NULL)) { 228624Sigor@sysoev.ru nxt_h1p_close(task, c); 229624Sigor@sysoev.ru return; 230624Sigor@sysoev.ru } 231624Sigor@sysoev.ru 232624Sigor@sysoev.ru c->socket.data = h1p; 233624Sigor@sysoev.ru h1p->conn = c; 234624Sigor@sysoev.ru 235624Sigor@sysoev.ru nxt_h1p_conn_request_init(task, c, h1p); 236624Sigor@sysoev.ru } 237624Sigor@sysoev.ru 238624Sigor@sysoev.ru 239624Sigor@sysoev.ru static void 240624Sigor@sysoev.ru nxt_h1p_conn_request_init(nxt_task_t *task, void *obj, void *data) 241624Sigor@sysoev.ru { 242431Sigor@sysoev.ru nxt_int_t ret; 243431Sigor@sysoev.ru nxt_conn_t *c; 244431Sigor@sysoev.ru nxt_h1proto_t *h1p; 245431Sigor@sysoev.ru nxt_http_request_t *r; 246431Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 247431Sigor@sysoev.ru 248431Sigor@sysoev.ru c = obj; 249431Sigor@sysoev.ru h1p = data; 250431Sigor@sysoev.ru 251624Sigor@sysoev.ru nxt_debug(task, "h1p conn request init"); 252431Sigor@sysoev.ru 253624Sigor@sysoev.ru r = nxt_http_request_create(task); 254431Sigor@sysoev.ru 255624Sigor@sysoev.ru if (nxt_fast_path(r != NULL)) { 256431Sigor@sysoev.ru h1p->request = r; 257431Sigor@sysoev.ru r->proto.h1 = h1p; 258624Sigor@sysoev.ru 259431Sigor@sysoev.ru joint = c->joint; 260431Sigor@sysoev.ru r->socket_conf = joint->socket_conf; 261431Sigor@sysoev.ru 262431Sigor@sysoev.ru r->remote = c->remote; 263431Sigor@sysoev.ru 264431Sigor@sysoev.ru ret = nxt_http_parse_request_init(&h1p->parser, r->mem_pool); 265624Sigor@sysoev.ru 266624Sigor@sysoev.ru if (nxt_fast_path(ret == NXT_OK)) { 267624Sigor@sysoev.ru nxt_h1p_conn_header_parse(task, c, h1p); 268624Sigor@sysoev.ru return; 269431Sigor@sysoev.ru } 270624Sigor@sysoev.ru 271624Sigor@sysoev.ru /* 272624Sigor@sysoev.ru * The request is very incomplete here, 273624Sigor@sysoev.ru * so "internal server error" useless here. 274624Sigor@sysoev.ru */ 275624Sigor@sysoev.ru nxt_mp_release(r->mem_pool); 276431Sigor@sysoev.ru } 277431Sigor@sysoev.ru 278624Sigor@sysoev.ru nxt_h1p_close(task, c); 279624Sigor@sysoev.ru } 280624Sigor@sysoev.ru 281624Sigor@sysoev.ru 282624Sigor@sysoev.ru static const nxt_conn_state_t nxt_h1p_header_parse_state 283624Sigor@sysoev.ru nxt_aligned(64) = 284624Sigor@sysoev.ru { 285624Sigor@sysoev.ru .ready_handler = nxt_h1p_conn_header_parse, 286624Sigor@sysoev.ru .close_handler = nxt_h1p_conn_request_error, 287624Sigor@sysoev.ru .error_handler = nxt_h1p_conn_request_error, 288624Sigor@sysoev.ru 289624Sigor@sysoev.ru .timer_handler = nxt_h1p_conn_request_timeout, 290624Sigor@sysoev.ru .timer_value = nxt_h1p_conn_timeout_value, 291624Sigor@sysoev.ru .timer_data = offsetof(nxt_socket_conf_t, header_read_timeout), 292624Sigor@sysoev.ru }; 293624Sigor@sysoev.ru 294624Sigor@sysoev.ru 295624Sigor@sysoev.ru static void 296624Sigor@sysoev.ru nxt_h1p_conn_header_parse(nxt_task_t *task, void *obj, void *data) 297624Sigor@sysoev.ru { 298624Sigor@sysoev.ru nxt_int_t ret; 299624Sigor@sysoev.ru nxt_conn_t *c; 300624Sigor@sysoev.ru nxt_h1proto_t *h1p; 301624Sigor@sysoev.ru nxt_http_status_t status; 302624Sigor@sysoev.ru nxt_http_request_t *r; 303624Sigor@sysoev.ru 304624Sigor@sysoev.ru c = obj; 305624Sigor@sysoev.ru h1p = data; 306624Sigor@sysoev.ru 307624Sigor@sysoev.ru nxt_debug(task, "h1p conn header parse"); 308624Sigor@sysoev.ru 309431Sigor@sysoev.ru ret = nxt_http_parse_request(&h1p->parser, &c->read->mem); 310431Sigor@sysoev.ru 311*636Sigor@sysoev.ru ret = nxt_expect(NXT_DONE, ret); 312624Sigor@sysoev.ru 313*636Sigor@sysoev.ru if (ret != NXT_AGAIN) { 314*636Sigor@sysoev.ru nxt_timer_disable(task->thread->engine, &c->read_timer); 315*636Sigor@sysoev.ru } 316*636Sigor@sysoev.ru 317*636Sigor@sysoev.ru r = h1p->request; 318625Sigor@sysoev.ru 319625Sigor@sysoev.ru switch (ret) { 320625Sigor@sysoev.ru 321625Sigor@sysoev.ru case NXT_DONE: 322431Sigor@sysoev.ru /* 323431Sigor@sysoev.ru * By default the keepalive mode is disabled in HTTP/1.0 and 324431Sigor@sysoev.ru * enabled in HTTP/1.1. The mode can be overridden later by 325431Sigor@sysoev.ru * the "Connection" field processed in nxt_h1p_connection(). 326431Sigor@sysoev.ru */ 327481Svbart@nginx.com h1p->keepalive = (h1p->parser.version.s.minor != '0'); 328431Sigor@sysoev.ru 329620Svbart@nginx.com ret = nxt_h1p_header_process(h1p, r); 330431Sigor@sysoev.ru 331431Sigor@sysoev.ru if (nxt_fast_path(ret == NXT_OK)) { 332431Sigor@sysoev.ru r->state->ready_handler(task, r, NULL); 333431Sigor@sysoev.ru return; 334431Sigor@sysoev.ru } 335431Sigor@sysoev.ru 336480Svbart@nginx.com /* ret == NXT_ERROR */ 337625Sigor@sysoev.ru status = NXT_HTTP_BAD_REQUEST; 338480Svbart@nginx.com 339625Sigor@sysoev.ru goto error; 340431Sigor@sysoev.ru 341625Sigor@sysoev.ru case NXT_AGAIN: 342625Sigor@sysoev.ru status = nxt_h1p_header_buffer_test(task, h1p, c, r->socket_conf); 343431Sigor@sysoev.ru 344625Sigor@sysoev.ru if (nxt_fast_path(status == NXT_OK)) { 345625Sigor@sysoev.ru c->read_state = &nxt_h1p_header_parse_state; 346431Sigor@sysoev.ru 347625Sigor@sysoev.ru nxt_conn_read(task->thread->engine, c); 348625Sigor@sysoev.ru return; 349431Sigor@sysoev.ru } 350431Sigor@sysoev.ru 351625Sigor@sysoev.ru break; 352480Svbart@nginx.com 353480Svbart@nginx.com case NXT_HTTP_PARSE_INVALID: 354480Svbart@nginx.com status = NXT_HTTP_BAD_REQUEST; 355480Svbart@nginx.com break; 356431Sigor@sysoev.ru 357482Svbart@nginx.com case NXT_HTTP_PARSE_UNSUPPORTED_VERSION: 358482Svbart@nginx.com status = NXT_HTTP_VERSION_NOT_SUPPORTED; 359482Svbart@nginx.com break; 360482Svbart@nginx.com 361480Svbart@nginx.com case NXT_HTTP_PARSE_TOO_LARGE_FIELD: 362480Svbart@nginx.com status = NXT_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE; 363480Svbart@nginx.com break; 364480Svbart@nginx.com 365480Svbart@nginx.com default: 366480Svbart@nginx.com case NXT_ERROR: 367480Svbart@nginx.com status = NXT_HTTP_INTERNAL_SERVER_ERROR; 368480Svbart@nginx.com break; 369480Svbart@nginx.com } 370480Svbart@nginx.com 371620Svbart@nginx.com (void) nxt_h1p_header_process(h1p, r); 372625Sigor@sysoev.ru 373625Sigor@sysoev.ru error: 374625Sigor@sysoev.ru 375480Svbart@nginx.com nxt_http_request_error(task, r, status); 376431Sigor@sysoev.ru } 377431Sigor@sysoev.ru 378431Sigor@sysoev.ru 379431Sigor@sysoev.ru static nxt_int_t 380620Svbart@nginx.com nxt_h1p_header_process(nxt_h1proto_t *h1p, nxt_http_request_t *r) 381620Svbart@nginx.com { 382620Svbart@nginx.com r->target.start = h1p->parser.target_start; 383620Svbart@nginx.com r->target.length = h1p->parser.target_end - h1p->parser.target_start; 384620Svbart@nginx.com 385620Svbart@nginx.com if (h1p->parser.version.ui64 != 0) { 386620Svbart@nginx.com r->version.start = h1p->parser.version.str; 387620Svbart@nginx.com r->version.length = sizeof(h1p->parser.version.str); 388620Svbart@nginx.com } 389620Svbart@nginx.com 390620Svbart@nginx.com r->method = &h1p->parser.method; 391620Svbart@nginx.com r->path = &h1p->parser.path; 392620Svbart@nginx.com r->args = &h1p->parser.args; 393620Svbart@nginx.com 394620Svbart@nginx.com r->fields = h1p->parser.fields; 395620Svbart@nginx.com 396620Svbart@nginx.com return nxt_http_fields_process(r->fields, &nxt_h1p_fields_hash, r); 397620Svbart@nginx.com } 398620Svbart@nginx.com 399620Svbart@nginx.com 400620Svbart@nginx.com static nxt_int_t 401625Sigor@sysoev.ru nxt_h1p_header_buffer_test(nxt_task_t *task, nxt_h1proto_t *h1p, nxt_conn_t *c, 402625Sigor@sysoev.ru nxt_socket_conf_t *skcf) 403625Sigor@sysoev.ru { 404625Sigor@sysoev.ru size_t size, used; 405625Sigor@sysoev.ru nxt_buf_t *in, *b; 406625Sigor@sysoev.ru 407625Sigor@sysoev.ru in = c->read; 408625Sigor@sysoev.ru 409625Sigor@sysoev.ru if (nxt_buf_mem_free_size(&in->mem) == 0) { 410625Sigor@sysoev.ru size = skcf->large_header_buffer_size; 411625Sigor@sysoev.ru used = nxt_buf_mem_used_size(&in->mem); 412625Sigor@sysoev.ru 413625Sigor@sysoev.ru if (size <= used || h1p->nbuffers >= skcf->large_header_buffers) { 414625Sigor@sysoev.ru return NXT_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE; 415625Sigor@sysoev.ru } 416625Sigor@sysoev.ru 417625Sigor@sysoev.ru b = nxt_buf_mem_alloc(c->mem_pool, size, 0); 418625Sigor@sysoev.ru if (nxt_slow_path(b == NULL)) { 419625Sigor@sysoev.ru return NXT_HTTP_INTERNAL_SERVER_ERROR; 420625Sigor@sysoev.ru } 421625Sigor@sysoev.ru 422625Sigor@sysoev.ru b->mem.free = nxt_cpymem(b->mem.pos, in->mem.pos, used); 423625Sigor@sysoev.ru 424625Sigor@sysoev.ru in->next = h1p->buffers; 425625Sigor@sysoev.ru h1p->buffers = in; 426625Sigor@sysoev.ru h1p->nbuffers++; 427625Sigor@sysoev.ru 428625Sigor@sysoev.ru c->read = b; 429625Sigor@sysoev.ru } 430625Sigor@sysoev.ru 431625Sigor@sysoev.ru return NXT_OK; 432625Sigor@sysoev.ru } 433625Sigor@sysoev.ru 434625Sigor@sysoev.ru 435625Sigor@sysoev.ru static nxt_int_t 436431Sigor@sysoev.ru nxt_h1p_connection(void *ctx, nxt_http_field_t *field, uintptr_t data) 437431Sigor@sysoev.ru { 438431Sigor@sysoev.ru nxt_http_request_t *r; 439431Sigor@sysoev.ru 440431Sigor@sysoev.ru r = ctx; 441431Sigor@sysoev.ru 442431Sigor@sysoev.ru if (field->value_length == 5 && nxt_memcmp(field->value, "close", 5) == 0) { 443431Sigor@sysoev.ru r->proto.h1->keepalive = 0; 444431Sigor@sysoev.ru } 445431Sigor@sysoev.ru 446431Sigor@sysoev.ru return NXT_OK; 447431Sigor@sysoev.ru } 448431Sigor@sysoev.ru 449431Sigor@sysoev.ru 450431Sigor@sysoev.ru static nxt_int_t 451431Sigor@sysoev.ru nxt_h1p_transfer_encoding(void *ctx, nxt_http_field_t *field, uintptr_t data) 452431Sigor@sysoev.ru { 453431Sigor@sysoev.ru nxt_http_te_t te; 454431Sigor@sysoev.ru nxt_http_request_t *r; 455431Sigor@sysoev.ru 456431Sigor@sysoev.ru r = ctx; 457431Sigor@sysoev.ru 458431Sigor@sysoev.ru if (field->value_length == 7 459431Sigor@sysoev.ru && nxt_memcmp(field->value, "chunked", 7) == 0) 460431Sigor@sysoev.ru { 461431Sigor@sysoev.ru te = NXT_HTTP_TE_CHUNKED; 462431Sigor@sysoev.ru 463431Sigor@sysoev.ru } else { 464431Sigor@sysoev.ru te = NXT_HTTP_TE_UNSUPPORTED; 465431Sigor@sysoev.ru } 466431Sigor@sysoev.ru 467431Sigor@sysoev.ru r->proto.h1->transfer_encoding = te; 468431Sigor@sysoev.ru 469431Sigor@sysoev.ru return NXT_OK; 470431Sigor@sysoev.ru } 471431Sigor@sysoev.ru 472431Sigor@sysoev.ru 473431Sigor@sysoev.ru static void 474431Sigor@sysoev.ru nxt_h1p_request_body_read(nxt_task_t *task, nxt_http_request_t *r) 475431Sigor@sysoev.ru { 476527Svbart@nginx.com size_t size, body_length; 477459Sigor@sysoev.ru nxt_buf_t *in, *b; 478431Sigor@sysoev.ru nxt_conn_t *c; 479459Sigor@sysoev.ru nxt_h1proto_t *h1p; 480431Sigor@sysoev.ru nxt_http_status_t status; 481431Sigor@sysoev.ru 482459Sigor@sysoev.ru h1p = r->proto.h1; 483459Sigor@sysoev.ru 484624Sigor@sysoev.ru nxt_debug(task, "h1p request body read %O te:%d", 485459Sigor@sysoev.ru r->content_length_n, h1p->transfer_encoding); 486431Sigor@sysoev.ru 487459Sigor@sysoev.ru switch (h1p->transfer_encoding) { 488431Sigor@sysoev.ru 489431Sigor@sysoev.ru case NXT_HTTP_TE_CHUNKED: 490431Sigor@sysoev.ru status = NXT_HTTP_LENGTH_REQUIRED; 491431Sigor@sysoev.ru goto error; 492431Sigor@sysoev.ru 493431Sigor@sysoev.ru case NXT_HTTP_TE_UNSUPPORTED: 494431Sigor@sysoev.ru status = NXT_HTTP_NOT_IMPLEMENTED; 495431Sigor@sysoev.ru goto error; 496431Sigor@sysoev.ru 497431Sigor@sysoev.ru default: 498431Sigor@sysoev.ru case NXT_HTTP_TE_NONE: 499431Sigor@sysoev.ru break; 500431Sigor@sysoev.ru } 501431Sigor@sysoev.ru 502431Sigor@sysoev.ru if (r->content_length_n == -1 || r->content_length_n == 0) { 503431Sigor@sysoev.ru goto ready; 504431Sigor@sysoev.ru } 505431Sigor@sysoev.ru 506431Sigor@sysoev.ru if (r->content_length_n > (nxt_off_t) r->socket_conf->max_body_size) { 507431Sigor@sysoev.ru status = NXT_HTTP_PAYLOAD_TOO_LARGE; 508431Sigor@sysoev.ru goto error; 509431Sigor@sysoev.ru } 510431Sigor@sysoev.ru 511527Svbart@nginx.com body_length = (size_t) r->content_length_n; 512431Sigor@sysoev.ru 513431Sigor@sysoev.ru b = r->body; 514431Sigor@sysoev.ru 515431Sigor@sysoev.ru if (b == NULL) { 516527Svbart@nginx.com b = nxt_buf_mem_alloc(r->mem_pool, body_length, 0); 517431Sigor@sysoev.ru if (nxt_slow_path(b == NULL)) { 518431Sigor@sysoev.ru status = NXT_HTTP_INTERNAL_SERVER_ERROR; 519431Sigor@sysoev.ru goto error; 520431Sigor@sysoev.ru } 521431Sigor@sysoev.ru 522431Sigor@sysoev.ru r->body = b; 523431Sigor@sysoev.ru } 524431Sigor@sysoev.ru 525459Sigor@sysoev.ru in = h1p->conn->read; 526431Sigor@sysoev.ru 527459Sigor@sysoev.ru size = nxt_buf_mem_used_size(&in->mem); 528431Sigor@sysoev.ru 529431Sigor@sysoev.ru if (size != 0) { 530527Svbart@nginx.com if (size > body_length) { 531527Svbart@nginx.com size = body_length; 532431Sigor@sysoev.ru } 533431Sigor@sysoev.ru 534459Sigor@sysoev.ru b->mem.free = nxt_cpymem(b->mem.free, in->mem.pos, size); 535459Sigor@sysoev.ru in->mem.pos += size; 536431Sigor@sysoev.ru } 537431Sigor@sysoev.ru 538527Svbart@nginx.com size = nxt_buf_mem_free_size(&b->mem); 539431Sigor@sysoev.ru 540527Svbart@nginx.com nxt_debug(task, "h1p body rest: %uz", size); 541431Sigor@sysoev.ru 542527Svbart@nginx.com if (size != 0) { 543459Sigor@sysoev.ru in->next = h1p->buffers; 544459Sigor@sysoev.ru h1p->buffers = in; 545459Sigor@sysoev.ru 546459Sigor@sysoev.ru c = h1p->conn; 547431Sigor@sysoev.ru c->read = b; 548431Sigor@sysoev.ru c->read_state = &nxt_h1p_read_body_state; 549431Sigor@sysoev.ru 550431Sigor@sysoev.ru nxt_conn_read(task->thread->engine, c); 551431Sigor@sysoev.ru return; 552431Sigor@sysoev.ru } 553431Sigor@sysoev.ru 554431Sigor@sysoev.ru ready: 555431Sigor@sysoev.ru 556431Sigor@sysoev.ru nxt_work_queue_add(&task->thread->engine->fast_work_queue, 557431Sigor@sysoev.ru r->state->ready_handler, task, r, NULL); 558431Sigor@sysoev.ru 559431Sigor@sysoev.ru return; 560431Sigor@sysoev.ru 561431Sigor@sysoev.ru error: 562431Sigor@sysoev.ru 563459Sigor@sysoev.ru h1p->keepalive = 0; 564431Sigor@sysoev.ru 565431Sigor@sysoev.ru nxt_http_request_error(task, r, status); 566431Sigor@sysoev.ru } 567431Sigor@sysoev.ru 568431Sigor@sysoev.ru 569431Sigor@sysoev.ru static const nxt_conn_state_t nxt_h1p_read_body_state 570431Sigor@sysoev.ru nxt_aligned(64) = 571431Sigor@sysoev.ru { 572624Sigor@sysoev.ru .ready_handler = nxt_h1p_conn_body_read, 573624Sigor@sysoev.ru .close_handler = nxt_h1p_conn_request_error, 574624Sigor@sysoev.ru .error_handler = nxt_h1p_conn_request_error, 575431Sigor@sysoev.ru 576624Sigor@sysoev.ru .timer_handler = nxt_h1p_conn_request_timeout, 577624Sigor@sysoev.ru .timer_value = nxt_h1p_conn_timeout_value, 578431Sigor@sysoev.ru .timer_data = offsetof(nxt_socket_conf_t, body_read_timeout), 579431Sigor@sysoev.ru .timer_autoreset = 1, 580431Sigor@sysoev.ru }; 581431Sigor@sysoev.ru 582431Sigor@sysoev.ru 583431Sigor@sysoev.ru static void 584624Sigor@sysoev.ru nxt_h1p_conn_body_read(nxt_task_t *task, void *obj, void *data) 585431Sigor@sysoev.ru { 586431Sigor@sysoev.ru size_t size; 587431Sigor@sysoev.ru nxt_conn_t *c; 588431Sigor@sysoev.ru nxt_h1proto_t *h1p; 589431Sigor@sysoev.ru nxt_http_request_t *r; 590431Sigor@sysoev.ru 591431Sigor@sysoev.ru c = obj; 592431Sigor@sysoev.ru h1p = data; 593431Sigor@sysoev.ru 594624Sigor@sysoev.ru nxt_debug(task, "h1p conn body read"); 595431Sigor@sysoev.ru 596527Svbart@nginx.com size = nxt_buf_mem_free_size(&c->read->mem); 597431Sigor@sysoev.ru 598527Svbart@nginx.com nxt_debug(task, "h1p body rest: %uz", size); 599431Sigor@sysoev.ru 600527Svbart@nginx.com if (size != 0) { 601431Sigor@sysoev.ru nxt_conn_read(task->thread->engine, c); 602431Sigor@sysoev.ru 603431Sigor@sysoev.ru } else { 604527Svbart@nginx.com r = h1p->request; 605459Sigor@sysoev.ru c->read = NULL; 606431Sigor@sysoev.ru nxt_work_queue_add(&task->thread->engine->fast_work_queue, 607431Sigor@sysoev.ru r->state->ready_handler, task, r, NULL); 608431Sigor@sysoev.ru } 609431Sigor@sysoev.ru } 610431Sigor@sysoev.ru 611431Sigor@sysoev.ru 612431Sigor@sysoev.ru static void 613431Sigor@sysoev.ru nxt_h1p_request_local_addr(nxt_task_t *task, nxt_http_request_t *r) 614431Sigor@sysoev.ru { 615431Sigor@sysoev.ru r->local = nxt_conn_local_addr(task, r->proto.h1->conn); 616431Sigor@sysoev.ru } 617431Sigor@sysoev.ru 618431Sigor@sysoev.ru 619431Sigor@sysoev.ru #define NXT_HTTP_LAST_SUCCESS \ 620431Sigor@sysoev.ru (NXT_HTTP_OK + nxt_nitems(nxt_http_success) - 1) 621431Sigor@sysoev.ru 622431Sigor@sysoev.ru static const nxt_str_t nxt_http_success[] = { 623431Sigor@sysoev.ru nxt_string("HTTP/1.1 200 OK\r\n"), 624431Sigor@sysoev.ru nxt_string("HTTP/1.1 201 Created\r\n"), 625431Sigor@sysoev.ru nxt_string("HTTP/1.1 202 Accepted\r\n"), 626431Sigor@sysoev.ru nxt_string("HTTP/1.1 203 Non-Authoritative Information\r\n"), 627431Sigor@sysoev.ru nxt_string("HTTP/1.1 204 No Content\r\n"), 628431Sigor@sysoev.ru nxt_string("HTTP/1.1 205 Reset Content\r\n"), 629431Sigor@sysoev.ru nxt_string("HTTP/1.1 206 Partial Content\r\n"), 630431Sigor@sysoev.ru }; 631431Sigor@sysoev.ru 632431Sigor@sysoev.ru 633431Sigor@sysoev.ru #define NXT_HTTP_LAST_REDIRECTION \ 634431Sigor@sysoev.ru (NXT_HTTP_MULTIPLE_CHOICES + nxt_nitems(nxt_http_redirection) - 1) 635431Sigor@sysoev.ru 636431Sigor@sysoev.ru static const nxt_str_t nxt_http_redirection[] = { 637431Sigor@sysoev.ru nxt_string("HTTP/1.1 300 Multiple Choices\r\n"), 638431Sigor@sysoev.ru nxt_string("HTTP/1.1 301 Moved Permanently\r\n"), 639431Sigor@sysoev.ru nxt_string("HTTP/1.1 302 Found\r\n"), 640431Sigor@sysoev.ru nxt_string("HTTP/1.1 303 See Other\r\n"), 641431Sigor@sysoev.ru nxt_string("HTTP/1.1 304 Not Modified\r\n"), 642431Sigor@sysoev.ru }; 643431Sigor@sysoev.ru 644431Sigor@sysoev.ru 645431Sigor@sysoev.ru #define NXT_HTTP_LAST_CLIENT_ERROR \ 646431Sigor@sysoev.ru (NXT_HTTP_BAD_REQUEST + nxt_nitems(nxt_http_client_error) - 1) 647431Sigor@sysoev.ru 648431Sigor@sysoev.ru static const nxt_str_t nxt_http_client_error[] = { 649431Sigor@sysoev.ru nxt_string("HTTP/1.1 400 Bad Request\r\n"), 650431Sigor@sysoev.ru nxt_string("HTTP/1.1 401 Unauthorized\r\n"), 651431Sigor@sysoev.ru nxt_string("HTTP/1.1 402 Payment Required\r\n"), 652431Sigor@sysoev.ru nxt_string("HTTP/1.1 403 Forbidden\r\n"), 653431Sigor@sysoev.ru nxt_string("HTTP/1.1 404 Not Found\r\n"), 654431Sigor@sysoev.ru nxt_string("HTTP/1.1 405 Method Not Allowed\r\n"), 655431Sigor@sysoev.ru nxt_string("HTTP/1.1 406 Not Acceptable\r\n"), 656431Sigor@sysoev.ru nxt_string("HTTP/1.1 407 Proxy Authentication Required\r\n"), 657431Sigor@sysoev.ru nxt_string("HTTP/1.1 408 Request Timeout\r\n"), 658431Sigor@sysoev.ru nxt_string("HTTP/1.1 409 Conflict\r\n"), 659431Sigor@sysoev.ru nxt_string("HTTP/1.1 410 Gone\r\n"), 660431Sigor@sysoev.ru nxt_string("HTTP/1.1 411 Length Required\r\n"), 661431Sigor@sysoev.ru nxt_string("HTTP/1.1 412 Precondition Failed\r\n"), 662431Sigor@sysoev.ru nxt_string("HTTP/1.1 413 Payload Too Large\r\n"), 663431Sigor@sysoev.ru nxt_string("HTTP/1.1 414 URI Too Long\r\n"), 664431Sigor@sysoev.ru nxt_string("HTTP/1.1 415 Unsupported Media Type\r\n"), 665431Sigor@sysoev.ru nxt_string("HTTP/1.1 416 Range Not Satisfiable\r\n"), 666431Sigor@sysoev.ru nxt_string("HTTP/1.1 417 Expectation Failed\r\n"), 667431Sigor@sysoev.ru nxt_string("HTTP/1.1 418\r\n"), 668431Sigor@sysoev.ru nxt_string("HTTP/1.1 419\r\n"), 669431Sigor@sysoev.ru nxt_string("HTTP/1.1 420\r\n"), 670431Sigor@sysoev.ru nxt_string("HTTP/1.1 421\r\n"), 671431Sigor@sysoev.ru nxt_string("HTTP/1.1 422\r\n"), 672431Sigor@sysoev.ru nxt_string("HTTP/1.1 423\r\n"), 673431Sigor@sysoev.ru nxt_string("HTTP/1.1 424\r\n"), 674431Sigor@sysoev.ru nxt_string("HTTP/1.1 425\r\n"), 675431Sigor@sysoev.ru nxt_string("HTTP/1.1 426\r\n"), 676431Sigor@sysoev.ru nxt_string("HTTP/1.1 427\r\n"), 677431Sigor@sysoev.ru nxt_string("HTTP/1.1 428\r\n"), 678431Sigor@sysoev.ru nxt_string("HTTP/1.1 429\r\n"), 679431Sigor@sysoev.ru nxt_string("HTTP/1.1 430\r\n"), 680431Sigor@sysoev.ru nxt_string("HTTP/1.1 431 Request Header Fields Too Large\r\n"), 681431Sigor@sysoev.ru }; 682431Sigor@sysoev.ru 683431Sigor@sysoev.ru 684431Sigor@sysoev.ru #define NXT_HTTP_LAST_SERVER_ERROR \ 685431Sigor@sysoev.ru (NXT_HTTP_INTERNAL_SERVER_ERROR + nxt_nitems(nxt_http_server_error) - 1) 686431Sigor@sysoev.ru 687431Sigor@sysoev.ru static const nxt_str_t nxt_http_server_error[] = { 688431Sigor@sysoev.ru nxt_string("HTTP/1.1 500 Internal Server Error\r\n"), 689431Sigor@sysoev.ru nxt_string("HTTP/1.1 501 Not Implemented\r\n"), 690431Sigor@sysoev.ru nxt_string("HTTP/1.1 502 Bad Gateway\r\n"), 691431Sigor@sysoev.ru nxt_string("HTTP/1.1 503 Service Unavailable\r\n"), 692431Sigor@sysoev.ru nxt_string("HTTP/1.1 504 Gateway Timeout\r\n"), 693482Svbart@nginx.com nxt_string("HTTP/1.1 505 HTTP Version Not Supported\r\n"), 694431Sigor@sysoev.ru }; 695431Sigor@sysoev.ru 696431Sigor@sysoev.ru 697431Sigor@sysoev.ru #define UNKNOWN_STATUS_LENGTH (sizeof("HTTP/1.1 65536\r\n") - 1) 698431Sigor@sysoev.ru 699431Sigor@sysoev.ru static void 700431Sigor@sysoev.ru nxt_h1p_request_header_send(nxt_task_t *task, nxt_http_request_t *r) 701431Sigor@sysoev.ru { 702431Sigor@sysoev.ru u_char *p; 703431Sigor@sysoev.ru size_t size; 704431Sigor@sysoev.ru nxt_buf_t *header; 705431Sigor@sysoev.ru nxt_str_t unknown_status; 706431Sigor@sysoev.ru nxt_int_t conn; 707431Sigor@sysoev.ru nxt_uint_t n; 708431Sigor@sysoev.ru nxt_bool_t http11; 709431Sigor@sysoev.ru nxt_conn_t *c; 710431Sigor@sysoev.ru nxt_h1proto_t *h1p; 711431Sigor@sysoev.ru const nxt_str_t *status; 712431Sigor@sysoev.ru nxt_http_field_t *field; 713431Sigor@sysoev.ru nxt_event_engine_t *engine; 714431Sigor@sysoev.ru u_char buf[UNKNOWN_STATUS_LENGTH]; 715431Sigor@sysoev.ru 716431Sigor@sysoev.ru static const char chunked[] = "Transfer-Encoding: chunked\r\n"; 717431Sigor@sysoev.ru 718431Sigor@sysoev.ru static const nxt_str_t connection[2] = { 719431Sigor@sysoev.ru nxt_string("Connection: close\r\n"), 720431Sigor@sysoev.ru nxt_string("Connection: keep-alive\r\n"), 721431Sigor@sysoev.ru }; 722431Sigor@sysoev.ru 723431Sigor@sysoev.ru nxt_debug(task, "h1p request header send"); 724431Sigor@sysoev.ru 725431Sigor@sysoev.ru r->header_sent = 1; 726431Sigor@sysoev.ru h1p = r->proto.h1; 727431Sigor@sysoev.ru n = r->status; 728431Sigor@sysoev.ru 729431Sigor@sysoev.ru if (n >= NXT_HTTP_OK && n <= NXT_HTTP_LAST_SUCCESS) { 730431Sigor@sysoev.ru status = &nxt_http_success[n - NXT_HTTP_OK]; 731431Sigor@sysoev.ru 732431Sigor@sysoev.ru } else if (n >= NXT_HTTP_MULTIPLE_CHOICES 733431Sigor@sysoev.ru && n <= NXT_HTTP_LAST_REDIRECTION) 734431Sigor@sysoev.ru { 735431Sigor@sysoev.ru status = &nxt_http_redirection[n - NXT_HTTP_MULTIPLE_CHOICES]; 736431Sigor@sysoev.ru 737431Sigor@sysoev.ru } else if (n >= NXT_HTTP_BAD_REQUEST && n <= NXT_HTTP_LAST_CLIENT_ERROR) { 738431Sigor@sysoev.ru status = &nxt_http_client_error[n - NXT_HTTP_BAD_REQUEST]; 739431Sigor@sysoev.ru 740431Sigor@sysoev.ru } else if (n >= NXT_HTTP_INTERNAL_SERVER_ERROR 741431Sigor@sysoev.ru && n <= NXT_HTTP_LAST_SERVER_ERROR) 742431Sigor@sysoev.ru { 743431Sigor@sysoev.ru status = &nxt_http_server_error[n - NXT_HTTP_INTERNAL_SERVER_ERROR]; 744431Sigor@sysoev.ru 745431Sigor@sysoev.ru } else { 746431Sigor@sysoev.ru p = nxt_sprintf(buf, buf + UNKNOWN_STATUS_LENGTH, 747431Sigor@sysoev.ru "HTTP/1.1 %03d\r\n", n); 748431Sigor@sysoev.ru 749431Sigor@sysoev.ru unknown_status.length = p - buf; 750431Sigor@sysoev.ru unknown_status.start = buf; 751431Sigor@sysoev.ru status = &unknown_status; 752431Sigor@sysoev.ru } 753431Sigor@sysoev.ru 754450Sigor@sysoev.ru size = status->length; 755450Sigor@sysoev.ru /* Trailing CRLF at the end of header. */ 756450Sigor@sysoev.ru size += sizeof("\r\n") - 1; 757431Sigor@sysoev.ru 758481Svbart@nginx.com http11 = (h1p->parser.version.s.minor != '0'); 759431Sigor@sysoev.ru 760431Sigor@sysoev.ru if (r->resp.content_length == NULL || r->resp.content_length->skip) { 761431Sigor@sysoev.ru if (http11) { 762431Sigor@sysoev.ru h1p->chunked = 1; 763431Sigor@sysoev.ru size += sizeof(chunked) - 1; 764450Sigor@sysoev.ru /* Trailing CRLF will be added by the first chunk header. */ 765450Sigor@sysoev.ru size -= sizeof("\r\n") - 1; 766431Sigor@sysoev.ru 767431Sigor@sysoev.ru } else { 768431Sigor@sysoev.ru h1p->keepalive = 0; 769431Sigor@sysoev.ru } 770431Sigor@sysoev.ru } 771431Sigor@sysoev.ru 772431Sigor@sysoev.ru conn = -1; 773431Sigor@sysoev.ru 774431Sigor@sysoev.ru if (http11 ^ h1p->keepalive) { 775431Sigor@sysoev.ru conn = h1p->keepalive; 776431Sigor@sysoev.ru size += connection[conn].length; 777431Sigor@sysoev.ru } 778431Sigor@sysoev.ru 779431Sigor@sysoev.ru nxt_list_each(field, r->resp.fields) { 780431Sigor@sysoev.ru 781431Sigor@sysoev.ru if (!field->skip) { 782431Sigor@sysoev.ru size += field->name_length + field->value_length; 783431Sigor@sysoev.ru size += sizeof(": \r\n") - 1; 784431Sigor@sysoev.ru } 785431Sigor@sysoev.ru 786431Sigor@sysoev.ru } nxt_list_loop; 787431Sigor@sysoev.ru 788608Sigor@sysoev.ru header = nxt_http_buf_mem(task, r, size); 789431Sigor@sysoev.ru if (nxt_slow_path(header == NULL)) { 790608Sigor@sysoev.ru nxt_h1p_request_error(task, r); 791431Sigor@sysoev.ru return; 792431Sigor@sysoev.ru } 793431Sigor@sysoev.ru 794431Sigor@sysoev.ru p = header->mem.free; 795431Sigor@sysoev.ru 796431Sigor@sysoev.ru p = nxt_cpymem(p, status->start, status->length); 797431Sigor@sysoev.ru 798431Sigor@sysoev.ru nxt_list_each(field, r->resp.fields) { 799431Sigor@sysoev.ru 800431Sigor@sysoev.ru if (!field->skip) { 801431Sigor@sysoev.ru p = nxt_cpymem(p, field->name, field->name_length); 802431Sigor@sysoev.ru *p++ = ':'; *p++ = ' '; 803431Sigor@sysoev.ru p = nxt_cpymem(p, field->value, field->value_length); 804431Sigor@sysoev.ru *p++ = '\r'; *p++ = '\n'; 805431Sigor@sysoev.ru } 806431Sigor@sysoev.ru 807431Sigor@sysoev.ru } nxt_list_loop; 808431Sigor@sysoev.ru 809431Sigor@sysoev.ru if (conn >= 0) { 810431Sigor@sysoev.ru p = nxt_cpymem(p, connection[conn].start, connection[conn].length); 811431Sigor@sysoev.ru } 812431Sigor@sysoev.ru 813431Sigor@sysoev.ru if (h1p->chunked) { 814431Sigor@sysoev.ru p = nxt_cpymem(p, chunked, sizeof(chunked) - 1); 815450Sigor@sysoev.ru /* Trailing CRLF will be added by the first chunk header. */ 816431Sigor@sysoev.ru 817431Sigor@sysoev.ru } else { 818431Sigor@sysoev.ru *p++ = '\r'; *p++ = '\n'; 819431Sigor@sysoev.ru } 820431Sigor@sysoev.ru 821431Sigor@sysoev.ru header->mem.free = p; 822431Sigor@sysoev.ru 823630Svbart@nginx.com h1p->header_size = nxt_buf_mem_used_size(&header->mem); 824630Svbart@nginx.com 825431Sigor@sysoev.ru c = h1p->conn; 826431Sigor@sysoev.ru 827431Sigor@sysoev.ru c->write = header; 828431Sigor@sysoev.ru c->write_state = &nxt_h1p_send_state; 829431Sigor@sysoev.ru 830431Sigor@sysoev.ru engine = task->thread->engine; 831431Sigor@sysoev.ru 832431Sigor@sysoev.ru nxt_work_queue_add(&engine->fast_work_queue, r->state->ready_handler, 833431Sigor@sysoev.ru task, r, NULL); 834431Sigor@sysoev.ru 835431Sigor@sysoev.ru nxt_conn_write(engine, c); 836431Sigor@sysoev.ru } 837431Sigor@sysoev.ru 838431Sigor@sysoev.ru 839431Sigor@sysoev.ru static const nxt_conn_state_t nxt_h1p_send_state 840431Sigor@sysoev.ru nxt_aligned(64) = 841431Sigor@sysoev.ru { 842624Sigor@sysoev.ru .ready_handler = nxt_h1p_conn_request_sent, 843624Sigor@sysoev.ru .error_handler = nxt_h1p_conn_request_error, 844431Sigor@sysoev.ru 845626Sigor@sysoev.ru .timer_handler = nxt_h1p_conn_request_send_timeout, 846624Sigor@sysoev.ru .timer_value = nxt_h1p_conn_timeout_value, 847431Sigor@sysoev.ru .timer_data = offsetof(nxt_socket_conf_t, send_timeout), 848431Sigor@sysoev.ru .timer_autoreset = 1, 849431Sigor@sysoev.ru }; 850431Sigor@sysoev.ru 851431Sigor@sysoev.ru 852431Sigor@sysoev.ru static void 853431Sigor@sysoev.ru nxt_h1p_request_send(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *out) 854431Sigor@sysoev.ru { 855431Sigor@sysoev.ru nxt_conn_t *c; 856431Sigor@sysoev.ru 857431Sigor@sysoev.ru nxt_debug(task, "h1p request send"); 858431Sigor@sysoev.ru 859431Sigor@sysoev.ru c = r->proto.h1->conn; 860431Sigor@sysoev.ru 861431Sigor@sysoev.ru if (r->proto.h1->chunked) { 862431Sigor@sysoev.ru out = nxt_h1p_chunk_create(task, r, out); 863431Sigor@sysoev.ru if (nxt_slow_path(out == NULL)) { 864608Sigor@sysoev.ru nxt_h1p_request_error(task, r); 865431Sigor@sysoev.ru return; 866431Sigor@sysoev.ru } 867431Sigor@sysoev.ru } 868431Sigor@sysoev.ru 869431Sigor@sysoev.ru if (c->write == NULL) { 870431Sigor@sysoev.ru c->write = out; 871431Sigor@sysoev.ru c->write_state = &nxt_h1p_send_state; 872431Sigor@sysoev.ru 873431Sigor@sysoev.ru nxt_conn_write(task->thread->engine, c); 874431Sigor@sysoev.ru 875431Sigor@sysoev.ru } else { 876431Sigor@sysoev.ru nxt_buf_chain_add(&c->write, out); 877431Sigor@sysoev.ru } 878431Sigor@sysoev.ru } 879431Sigor@sysoev.ru 880431Sigor@sysoev.ru 881431Sigor@sysoev.ru static nxt_buf_t * 882431Sigor@sysoev.ru nxt_h1p_chunk_create(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *out) 883431Sigor@sysoev.ru { 884483Sigor@sysoev.ru nxt_off_t size; 885431Sigor@sysoev.ru nxt_buf_t *b, **prev, *header, *tail; 886431Sigor@sysoev.ru 887431Sigor@sysoev.ru const size_t chunk_size = 2 * (sizeof("\r\n") - 1) + NXT_OFF_T_HEXLEN; 888431Sigor@sysoev.ru static const char tail_chunk[] = "\r\n0\r\n\r\n"; 889431Sigor@sysoev.ru 890431Sigor@sysoev.ru size = 0; 891431Sigor@sysoev.ru prev = &out; 892431Sigor@sysoev.ru 893431Sigor@sysoev.ru for (b = out; b != NULL; b = b->next) { 894431Sigor@sysoev.ru 895431Sigor@sysoev.ru if (nxt_buf_is_last(b)) { 896608Sigor@sysoev.ru tail = nxt_http_buf_mem(task, r, chunk_size); 897431Sigor@sysoev.ru if (nxt_slow_path(tail == NULL)) { 898431Sigor@sysoev.ru return NULL; 899431Sigor@sysoev.ru } 900431Sigor@sysoev.ru 901431Sigor@sysoev.ru *prev = tail; 902431Sigor@sysoev.ru tail->next = b; 903431Sigor@sysoev.ru /* 904431Sigor@sysoev.ru * The tail_chunk size with trailing zero is 8 bytes, so 905431Sigor@sysoev.ru * memcpy may be inlined with just single 8 byte move operation. 906431Sigor@sysoev.ru */ 907431Sigor@sysoev.ru nxt_memcpy(tail->mem.free, tail_chunk, sizeof(tail_chunk)); 908431Sigor@sysoev.ru tail->mem.free += sizeof(tail_chunk) - 1; 909431Sigor@sysoev.ru 910431Sigor@sysoev.ru break; 911431Sigor@sysoev.ru } 912431Sigor@sysoev.ru 913431Sigor@sysoev.ru size += nxt_buf_used_size(b); 914431Sigor@sysoev.ru prev = &b->next; 915431Sigor@sysoev.ru } 916431Sigor@sysoev.ru 917431Sigor@sysoev.ru if (size == 0) { 918431Sigor@sysoev.ru return out; 919431Sigor@sysoev.ru } 920431Sigor@sysoev.ru 921608Sigor@sysoev.ru header = nxt_http_buf_mem(task, r, chunk_size); 922431Sigor@sysoev.ru if (nxt_slow_path(header == NULL)) { 923431Sigor@sysoev.ru return NULL; 924431Sigor@sysoev.ru } 925431Sigor@sysoev.ru 926431Sigor@sysoev.ru header->next = out; 927431Sigor@sysoev.ru header->mem.free = nxt_sprintf(header->mem.free, header->mem.end, 928431Sigor@sysoev.ru "\r\n%xO\r\n", size); 929431Sigor@sysoev.ru return header; 930431Sigor@sysoev.ru } 931431Sigor@sysoev.ru 932431Sigor@sysoev.ru 933431Sigor@sysoev.ru static void 934624Sigor@sysoev.ru nxt_h1p_conn_request_sent(nxt_task_t *task, void *obj, void *data) 935431Sigor@sysoev.ru { 936431Sigor@sysoev.ru nxt_conn_t *c; 937431Sigor@sysoev.ru nxt_event_engine_t *engine; 938431Sigor@sysoev.ru 939431Sigor@sysoev.ru c = obj; 940431Sigor@sysoev.ru 941624Sigor@sysoev.ru nxt_debug(task, "h1p conn request sent"); 942431Sigor@sysoev.ru 943431Sigor@sysoev.ru engine = task->thread->engine; 944431Sigor@sysoev.ru 945592Sigor@sysoev.ru c->write = nxt_sendbuf_completion(task, &engine->fast_work_queue, c->write); 946592Sigor@sysoev.ru 947431Sigor@sysoev.ru if (c->write != NULL) { 948431Sigor@sysoev.ru nxt_conn_write(engine, c); 949431Sigor@sysoev.ru } 950431Sigor@sysoev.ru } 951431Sigor@sysoev.ru 952431Sigor@sysoev.ru 953630Svbart@nginx.com static nxt_off_t 954630Svbart@nginx.com nxt_h1p_request_body_bytes_sent(nxt_task_t *task, nxt_http_proto_t proto) 955630Svbart@nginx.com { 956630Svbart@nginx.com nxt_off_t sent; 957630Svbart@nginx.com nxt_h1proto_t *h1p; 958630Svbart@nginx.com 959630Svbart@nginx.com h1p = proto.h1; 960630Svbart@nginx.com 961630Svbart@nginx.com sent = h1p->conn->sent - h1p->header_size; 962630Svbart@nginx.com 963630Svbart@nginx.com return (sent > 0) ? sent : 0; 964630Svbart@nginx.com } 965630Svbart@nginx.com 966630Svbart@nginx.com 967431Sigor@sysoev.ru static void 968608Sigor@sysoev.ru nxt_h1p_request_discard(nxt_task_t *task, nxt_http_request_t *r, 969608Sigor@sysoev.ru nxt_buf_t *last) 970608Sigor@sysoev.ru { 971608Sigor@sysoev.ru nxt_buf_t *b; 972608Sigor@sysoev.ru nxt_conn_t *c; 973608Sigor@sysoev.ru nxt_h1proto_t *h1p; 974608Sigor@sysoev.ru nxt_work_queue_t *wq; 975608Sigor@sysoev.ru 976608Sigor@sysoev.ru nxt_debug(task, "h1p request discard"); 977608Sigor@sysoev.ru 978608Sigor@sysoev.ru h1p = r->proto.h1; 979608Sigor@sysoev.ru h1p->keepalive = 0; 980608Sigor@sysoev.ru 981608Sigor@sysoev.ru c = h1p->conn; 982608Sigor@sysoev.ru b = c->write; 983608Sigor@sysoev.ru c->write = NULL; 984608Sigor@sysoev.ru 985608Sigor@sysoev.ru wq = &task->thread->engine->fast_work_queue; 986608Sigor@sysoev.ru 987608Sigor@sysoev.ru nxt_sendbuf_drain(task, wq, b); 988608Sigor@sysoev.ru nxt_sendbuf_drain(task, wq, last); 989608Sigor@sysoev.ru } 990608Sigor@sysoev.ru 991608Sigor@sysoev.ru 992608Sigor@sysoev.ru static void 993431Sigor@sysoev.ru nxt_h1p_request_close(nxt_task_t *task, nxt_http_proto_t proto) 994431Sigor@sysoev.ru { 995431Sigor@sysoev.ru nxt_conn_t *c; 996431Sigor@sysoev.ru nxt_h1proto_t *h1p; 997431Sigor@sysoev.ru 998431Sigor@sysoev.ru nxt_debug(task, "h1p request close"); 999431Sigor@sysoev.ru 1000431Sigor@sysoev.ru h1p = proto.h1; 1001431Sigor@sysoev.ru h1p->request = NULL; 1002431Sigor@sysoev.ru 1003431Sigor@sysoev.ru c = h1p->conn; 1004431Sigor@sysoev.ru 1005431Sigor@sysoev.ru if (h1p->keepalive) { 1006431Sigor@sysoev.ru nxt_h1p_keepalive(task, h1p, c); 1007431Sigor@sysoev.ru 1008431Sigor@sysoev.ru } else { 1009431Sigor@sysoev.ru nxt_h1p_close(task, c); 1010431Sigor@sysoev.ru } 1011431Sigor@sysoev.ru } 1012431Sigor@sysoev.ru 1013431Sigor@sysoev.ru 1014431Sigor@sysoev.ru static void 1015431Sigor@sysoev.ru nxt_h1p_keepalive(nxt_task_t *task, nxt_h1proto_t *h1p, nxt_conn_t *c) 1016431Sigor@sysoev.ru { 1017431Sigor@sysoev.ru size_t size; 1018431Sigor@sysoev.ru nxt_buf_t *in, *b, *next; 1019431Sigor@sysoev.ru 1020431Sigor@sysoev.ru nxt_debug(task, "h1p keepalive"); 1021431Sigor@sysoev.ru 1022436Sigor@sysoev.ru if (!c->tcp_nodelay) { 1023436Sigor@sysoev.ru nxt_conn_tcp_nodelay_on(task, c); 1024436Sigor@sysoev.ru } 1025436Sigor@sysoev.ru 1026431Sigor@sysoev.ru b = h1p->buffers; 1027431Sigor@sysoev.ru 1028452Sigor@sysoev.ru nxt_memzero(h1p, offsetof(nxt_h1proto_t, conn)); 1029431Sigor@sysoev.ru 1030630Svbart@nginx.com c->sent = 0; 1031630Svbart@nginx.com 1032431Sigor@sysoev.ru in = c->read; 1033431Sigor@sysoev.ru 1034459Sigor@sysoev.ru if (in == NULL) { 1035459Sigor@sysoev.ru /* A request with large body. */ 1036459Sigor@sysoev.ru in = b; 1037459Sigor@sysoev.ru c->read = in; 1038459Sigor@sysoev.ru 1039459Sigor@sysoev.ru b = in->next; 1040459Sigor@sysoev.ru in->next = NULL; 1041459Sigor@sysoev.ru } 1042459Sigor@sysoev.ru 1043459Sigor@sysoev.ru while (b != NULL) { 1044459Sigor@sysoev.ru next = b->next; 1045459Sigor@sysoev.ru nxt_mp_free(c->mem_pool, b); 1046459Sigor@sysoev.ru b = next; 1047459Sigor@sysoev.ru } 1048459Sigor@sysoev.ru 1049431Sigor@sysoev.ru size = nxt_buf_mem_used_size(&in->mem); 1050431Sigor@sysoev.ru 1051431Sigor@sysoev.ru if (size == 0) { 1052629Sigor@sysoev.ru nxt_mp_free(c->mem_pool, in); 1053431Sigor@sysoev.ru 1054629Sigor@sysoev.ru c->read = NULL; 1055628Sigor@sysoev.ru c->read_state = &nxt_h1p_keepalive_state; 1056431Sigor@sysoev.ru 1057628Sigor@sysoev.ru nxt_conn_read(task->thread->engine, c); 1058431Sigor@sysoev.ru 1059431Sigor@sysoev.ru } else { 1060431Sigor@sysoev.ru nxt_debug(task, "h1p pipelining"); 1061431Sigor@sysoev.ru 1062431Sigor@sysoev.ru nxt_memmove(in->mem.start, in->mem.pos, size); 1063431Sigor@sysoev.ru 1064431Sigor@sysoev.ru in->mem.pos = in->mem.start; 1065431Sigor@sysoev.ru in->mem.free = in->mem.start + size; 1066431Sigor@sysoev.ru 1067627Svbart@nginx.com nxt_h1p_conn_request_init(task, c, c->socket.data); 1068431Sigor@sysoev.ru } 1069431Sigor@sysoev.ru } 1070431Sigor@sysoev.ru 1071431Sigor@sysoev.ru 1072624Sigor@sysoev.ru static const nxt_conn_state_t nxt_h1p_keepalive_state 1073624Sigor@sysoev.ru nxt_aligned(64) = 1074431Sigor@sysoev.ru { 1075628Sigor@sysoev.ru .ready_handler = nxt_h1p_conn_request_init, 1076624Sigor@sysoev.ru .close_handler = nxt_h1p_conn_error, 1077624Sigor@sysoev.ru .error_handler = nxt_h1p_conn_error, 1078624Sigor@sysoev.ru 1079629Sigor@sysoev.ru .io_read_handler = nxt_h1p_conn_io_read_handler, 1080629Sigor@sysoev.ru 1081624Sigor@sysoev.ru .timer_handler = nxt_h1p_conn_timeout, 1082624Sigor@sysoev.ru .timer_value = nxt_h1p_conn_timeout_value, 1083624Sigor@sysoev.ru .timer_data = offsetof(nxt_socket_conf_t, idle_timeout), 1084*636Sigor@sysoev.ru .timer_autoreset = 1, 1085624Sigor@sysoev.ru }; 1086624Sigor@sysoev.ru 1087624Sigor@sysoev.ru 1088624Sigor@sysoev.ru static void 1089431Sigor@sysoev.ru nxt_h1p_conn_error(nxt_task_t *task, void *obj, void *data) 1090431Sigor@sysoev.ru { 1091624Sigor@sysoev.ru nxt_conn_t *c; 1092431Sigor@sysoev.ru 1093431Sigor@sysoev.ru c = obj; 1094431Sigor@sysoev.ru 1095431Sigor@sysoev.ru nxt_debug(task, "h1p conn error"); 1096431Sigor@sysoev.ru 1097624Sigor@sysoev.ru nxt_h1p_close(task, c); 1098431Sigor@sysoev.ru } 1099431Sigor@sysoev.ru 1100431Sigor@sysoev.ru 1101431Sigor@sysoev.ru static void 1102431Sigor@sysoev.ru nxt_h1p_conn_timeout(nxt_task_t *task, void *obj, void *data) 1103431Sigor@sysoev.ru { 1104431Sigor@sysoev.ru nxt_conn_t *c; 1105431Sigor@sysoev.ru nxt_timer_t *timer; 1106431Sigor@sysoev.ru 1107431Sigor@sysoev.ru timer = obj; 1108431Sigor@sysoev.ru 1109431Sigor@sysoev.ru nxt_debug(task, "h1p conn timeout"); 1110431Sigor@sysoev.ru 1111431Sigor@sysoev.ru c = nxt_read_timer_conn(timer); 1112431Sigor@sysoev.ru 1113624Sigor@sysoev.ru nxt_h1p_close(task, c); 1114624Sigor@sysoev.ru } 1115624Sigor@sysoev.ru 1116624Sigor@sysoev.ru 1117624Sigor@sysoev.ru static void 1118624Sigor@sysoev.ru nxt_h1p_close(nxt_task_t *task, nxt_conn_t *c) 1119624Sigor@sysoev.ru { 1120624Sigor@sysoev.ru nxt_debug(task, "h1p close"); 1121624Sigor@sysoev.ru 1122624Sigor@sysoev.ru c->socket.data = NULL; 1123624Sigor@sysoev.ru 1124624Sigor@sysoev.ru c->write_state = &nxt_router_conn_close_state; 1125624Sigor@sysoev.ru 1126624Sigor@sysoev.ru nxt_conn_close(task->thread->engine, c); 1127624Sigor@sysoev.ru } 1128624Sigor@sysoev.ru 1129624Sigor@sysoev.ru 1130624Sigor@sysoev.ru static void 1131624Sigor@sysoev.ru nxt_h1p_conn_request_error(nxt_task_t *task, void *obj, void *data) 1132624Sigor@sysoev.ru { 1133624Sigor@sysoev.ru nxt_h1proto_t *h1p; 1134624Sigor@sysoev.ru nxt_http_request_t *r; 1135624Sigor@sysoev.ru 1136624Sigor@sysoev.ru h1p = data; 1137624Sigor@sysoev.ru 1138624Sigor@sysoev.ru nxt_debug(task, "h1p conn request error"); 1139624Sigor@sysoev.ru 1140624Sigor@sysoev.ru r = h1p->request; 1141624Sigor@sysoev.ru 1142624Sigor@sysoev.ru if (r->fields == NULL) { 1143624Sigor@sysoev.ru (void) nxt_h1p_header_process(h1p, r); 1144624Sigor@sysoev.ru } 1145624Sigor@sysoev.ru 1146624Sigor@sysoev.ru if (r->status == 0) { 1147624Sigor@sysoev.ru r->status = NXT_HTTP_BAD_REQUEST; 1148624Sigor@sysoev.ru } 1149624Sigor@sysoev.ru 1150624Sigor@sysoev.ru nxt_h1p_request_error(task, r); 1151624Sigor@sysoev.ru } 1152624Sigor@sysoev.ru 1153624Sigor@sysoev.ru 1154624Sigor@sysoev.ru static void 1155624Sigor@sysoev.ru nxt_h1p_conn_request_timeout(nxt_task_t *task, void *obj, void *data) 1156624Sigor@sysoev.ru { 1157624Sigor@sysoev.ru nxt_conn_t *c; 1158624Sigor@sysoev.ru nxt_timer_t *timer; 1159624Sigor@sysoev.ru nxt_h1proto_t *h1p; 1160624Sigor@sysoev.ru nxt_http_request_t *r; 1161624Sigor@sysoev.ru 1162624Sigor@sysoev.ru timer = obj; 1163624Sigor@sysoev.ru 1164624Sigor@sysoev.ru nxt_debug(task, "h1p conn request timeout"); 1165624Sigor@sysoev.ru 1166624Sigor@sysoev.ru c = nxt_read_timer_conn(timer); 1167626Sigor@sysoev.ru /* 1168626Sigor@sysoev.ru * Disable SO_LINGER off during socket closing 1169626Sigor@sysoev.ru * to send "408 Request Timeout" error response. 1170626Sigor@sysoev.ru */ 1171626Sigor@sysoev.ru c->socket.timedout = 0; 1172626Sigor@sysoev.ru 1173624Sigor@sysoev.ru h1p = c->socket.data; 1174624Sigor@sysoev.ru r = h1p->request; 1175624Sigor@sysoev.ru 1176624Sigor@sysoev.ru if (r->fields == NULL) { 1177624Sigor@sysoev.ru (void) nxt_h1p_header_process(h1p, r); 1178624Sigor@sysoev.ru } 1179624Sigor@sysoev.ru 1180626Sigor@sysoev.ru nxt_http_request_error(task, r, NXT_HTTP_REQUEST_TIMEOUT); 1181626Sigor@sysoev.ru } 1182626Sigor@sysoev.ru 1183624Sigor@sysoev.ru 1184626Sigor@sysoev.ru static void 1185626Sigor@sysoev.ru nxt_h1p_conn_request_send_timeout(nxt_task_t *task, void *obj, void *data) 1186626Sigor@sysoev.ru { 1187626Sigor@sysoev.ru nxt_conn_t *c; 1188626Sigor@sysoev.ru nxt_timer_t *timer; 1189626Sigor@sysoev.ru nxt_h1proto_t *h1p; 1190626Sigor@sysoev.ru 1191626Sigor@sysoev.ru timer = obj; 1192626Sigor@sysoev.ru 1193626Sigor@sysoev.ru nxt_debug(task, "h1p conn request send timeout"); 1194626Sigor@sysoev.ru 1195626Sigor@sysoev.ru c = nxt_read_timer_conn(timer); 1196626Sigor@sysoev.ru h1p = c->socket.data; 1197626Sigor@sysoev.ru 1198626Sigor@sysoev.ru nxt_h1p_request_error(task, h1p->request); 1199624Sigor@sysoev.ru } 1200624Sigor@sysoev.ru 1201624Sigor@sysoev.ru 1202624Sigor@sysoev.ru nxt_inline void 1203624Sigor@sysoev.ru nxt_h1p_request_error(nxt_task_t *task, nxt_http_request_t *r) 1204624Sigor@sysoev.ru { 1205624Sigor@sysoev.ru r->state->error_handler(task, r, r->proto.h1); 1206431Sigor@sysoev.ru } 1207431Sigor@sysoev.ru 1208431Sigor@sysoev.ru 1209431Sigor@sysoev.ru static nxt_msec_t 1210624Sigor@sysoev.ru nxt_h1p_conn_timeout_value(nxt_conn_t *c, uintptr_t data) 1211431Sigor@sysoev.ru { 1212431Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 1213431Sigor@sysoev.ru 1214431Sigor@sysoev.ru joint = c->joint; 1215431Sigor@sysoev.ru 1216431Sigor@sysoev.ru return nxt_value_at(nxt_msec_t, joint->socket_conf, data); 1217431Sigor@sysoev.ru } 1218