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); 38*630Svbart@nginx.com static nxt_off_t nxt_h1p_request_body_bytes_sent(nxt_task_t *task, 39*630Svbart@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 92*630Svbart@nginx.com const nxt_http_proto_body_bytes_sent_t nxt_http_proto_body_bytes_sent[3] = { 93*630Svbart@nginx.com nxt_h1p_request_body_bytes_sent, 94*630Svbart@nginx.com NULL, 95*630Svbart@nginx.com NULL, 96*630Svbart@nginx.com }; 97*630Svbart@nginx.com 98*630Svbart@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) }, 122*630Svbart@nginx.com { nxt_string("Referer"), &nxt_http_request_field, 123*630Svbart@nginx.com offsetof(nxt_http_request_t, referer) }, 124*630Svbart@nginx.com { nxt_string("User-Agent"), &nxt_http_request_field, 125*630Svbart@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, 181431Sigor@sysoev.ru .timer_data = offsetof(nxt_socket_conf_t, header_read_timeout), 182431Sigor@sysoev.ru }; 183431Sigor@sysoev.ru 184431Sigor@sysoev.ru 185629Sigor@sysoev.ru static ssize_t 186629Sigor@sysoev.ru nxt_h1p_conn_io_read_handler(nxt_conn_t *c) 187629Sigor@sysoev.ru { 188629Sigor@sysoev.ru size_t size; 189629Sigor@sysoev.ru ssize_t n; 190629Sigor@sysoev.ru nxt_buf_t *b; 191629Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 192629Sigor@sysoev.ru 193629Sigor@sysoev.ru joint = c->joint; 194629Sigor@sysoev.ru size = joint->socket_conf->header_buffer_size; 195629Sigor@sysoev.ru 196629Sigor@sysoev.ru b = nxt_buf_mem_alloc(c->mem_pool, size, 0); 197629Sigor@sysoev.ru if (nxt_slow_path(b == NULL)) { 198629Sigor@sysoev.ru c->socket.error = NXT_ENOMEM; 199629Sigor@sysoev.ru return NXT_ERROR; 200629Sigor@sysoev.ru } 201629Sigor@sysoev.ru 202629Sigor@sysoev.ru n = c->io->recvbuf(c, b); 203629Sigor@sysoev.ru 204629Sigor@sysoev.ru if (n > 0) { 205629Sigor@sysoev.ru c->read = b; 206629Sigor@sysoev.ru 207629Sigor@sysoev.ru } else { 208629Sigor@sysoev.ru nxt_mp_free(c->mem_pool, b); 209629Sigor@sysoev.ru } 210629Sigor@sysoev.ru 211629Sigor@sysoev.ru return n; 212629Sigor@sysoev.ru } 213629Sigor@sysoev.ru 214629Sigor@sysoev.ru 215431Sigor@sysoev.ru static void 216624Sigor@sysoev.ru nxt_h1p_conn_proto_init(nxt_task_t *task, void *obj, void *data) 217431Sigor@sysoev.ru { 218624Sigor@sysoev.ru nxt_conn_t *c; 219624Sigor@sysoev.ru nxt_h1proto_t *h1p; 220624Sigor@sysoev.ru 221624Sigor@sysoev.ru c = obj; 222624Sigor@sysoev.ru 223624Sigor@sysoev.ru nxt_debug(task, "h1p conn proto init"); 224624Sigor@sysoev.ru 225624Sigor@sysoev.ru h1p = nxt_mp_zget(c->mem_pool, sizeof(nxt_h1proto_t)); 226624Sigor@sysoev.ru if (nxt_slow_path(h1p == NULL)) { 227624Sigor@sysoev.ru nxt_h1p_close(task, c); 228624Sigor@sysoev.ru return; 229624Sigor@sysoev.ru } 230624Sigor@sysoev.ru 231624Sigor@sysoev.ru c->socket.data = h1p; 232624Sigor@sysoev.ru h1p->conn = c; 233624Sigor@sysoev.ru 234624Sigor@sysoev.ru nxt_h1p_conn_request_init(task, c, h1p); 235624Sigor@sysoev.ru } 236624Sigor@sysoev.ru 237624Sigor@sysoev.ru 238624Sigor@sysoev.ru static void 239624Sigor@sysoev.ru nxt_h1p_conn_request_init(nxt_task_t *task, void *obj, void *data) 240624Sigor@sysoev.ru { 241431Sigor@sysoev.ru nxt_int_t ret; 242431Sigor@sysoev.ru nxt_conn_t *c; 243431Sigor@sysoev.ru nxt_h1proto_t *h1p; 244431Sigor@sysoev.ru nxt_http_request_t *r; 245431Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 246431Sigor@sysoev.ru 247431Sigor@sysoev.ru c = obj; 248431Sigor@sysoev.ru h1p = data; 249431Sigor@sysoev.ru 250624Sigor@sysoev.ru nxt_debug(task, "h1p conn request init"); 251431Sigor@sysoev.ru 252624Sigor@sysoev.ru r = nxt_http_request_create(task); 253431Sigor@sysoev.ru 254624Sigor@sysoev.ru if (nxt_fast_path(r != NULL)) { 255431Sigor@sysoev.ru h1p->request = r; 256431Sigor@sysoev.ru r->proto.h1 = h1p; 257624Sigor@sysoev.ru 258431Sigor@sysoev.ru joint = c->joint; 259431Sigor@sysoev.ru r->socket_conf = joint->socket_conf; 260431Sigor@sysoev.ru 261431Sigor@sysoev.ru r->remote = c->remote; 262431Sigor@sysoev.ru 263431Sigor@sysoev.ru ret = nxt_http_parse_request_init(&h1p->parser, r->mem_pool); 264624Sigor@sysoev.ru 265624Sigor@sysoev.ru if (nxt_fast_path(ret == NXT_OK)) { 266624Sigor@sysoev.ru nxt_h1p_conn_header_parse(task, c, h1p); 267624Sigor@sysoev.ru return; 268431Sigor@sysoev.ru } 269624Sigor@sysoev.ru 270624Sigor@sysoev.ru /* 271624Sigor@sysoev.ru * The request is very incomplete here, 272624Sigor@sysoev.ru * so "internal server error" useless here. 273624Sigor@sysoev.ru */ 274624Sigor@sysoev.ru nxt_mp_release(r->mem_pool); 275431Sigor@sysoev.ru } 276431Sigor@sysoev.ru 277624Sigor@sysoev.ru nxt_h1p_close(task, c); 278624Sigor@sysoev.ru } 279624Sigor@sysoev.ru 280624Sigor@sysoev.ru 281624Sigor@sysoev.ru static const nxt_conn_state_t nxt_h1p_header_parse_state 282624Sigor@sysoev.ru nxt_aligned(64) = 283624Sigor@sysoev.ru { 284624Sigor@sysoev.ru .ready_handler = nxt_h1p_conn_header_parse, 285624Sigor@sysoev.ru .close_handler = nxt_h1p_conn_request_error, 286624Sigor@sysoev.ru .error_handler = nxt_h1p_conn_request_error, 287624Sigor@sysoev.ru 288624Sigor@sysoev.ru .timer_handler = nxt_h1p_conn_request_timeout, 289624Sigor@sysoev.ru .timer_value = nxt_h1p_conn_timeout_value, 290624Sigor@sysoev.ru .timer_data = offsetof(nxt_socket_conf_t, header_read_timeout), 291624Sigor@sysoev.ru }; 292624Sigor@sysoev.ru 293624Sigor@sysoev.ru 294624Sigor@sysoev.ru static void 295624Sigor@sysoev.ru nxt_h1p_conn_header_parse(nxt_task_t *task, void *obj, void *data) 296624Sigor@sysoev.ru { 297624Sigor@sysoev.ru nxt_int_t ret; 298624Sigor@sysoev.ru nxt_conn_t *c; 299624Sigor@sysoev.ru nxt_h1proto_t *h1p; 300624Sigor@sysoev.ru nxt_http_status_t status; 301624Sigor@sysoev.ru nxt_http_request_t *r; 302624Sigor@sysoev.ru 303624Sigor@sysoev.ru c = obj; 304624Sigor@sysoev.ru h1p = data; 305624Sigor@sysoev.ru 306624Sigor@sysoev.ru nxt_debug(task, "h1p conn header parse"); 307624Sigor@sysoev.ru 308431Sigor@sysoev.ru ret = nxt_http_parse_request(&h1p->parser, &c->read->mem); 309431Sigor@sysoev.ru 310624Sigor@sysoev.ru r = h1p->request; 311624Sigor@sysoev.ru 312625Sigor@sysoev.ru ret = nxt_expect(NXT_DONE, ret); 313625Sigor@sysoev.ru 314625Sigor@sysoev.ru switch (ret) { 315625Sigor@sysoev.ru 316625Sigor@sysoev.ru case NXT_DONE: 317431Sigor@sysoev.ru /* 318431Sigor@sysoev.ru * By default the keepalive mode is disabled in HTTP/1.0 and 319431Sigor@sysoev.ru * enabled in HTTP/1.1. The mode can be overridden later by 320431Sigor@sysoev.ru * the "Connection" field processed in nxt_h1p_connection(). 321431Sigor@sysoev.ru */ 322481Svbart@nginx.com h1p->keepalive = (h1p->parser.version.s.minor != '0'); 323431Sigor@sysoev.ru 324620Svbart@nginx.com ret = nxt_h1p_header_process(h1p, r); 325431Sigor@sysoev.ru 326431Sigor@sysoev.ru if (nxt_fast_path(ret == NXT_OK)) { 327431Sigor@sysoev.ru r->state->ready_handler(task, r, NULL); 328431Sigor@sysoev.ru return; 329431Sigor@sysoev.ru } 330431Sigor@sysoev.ru 331480Svbart@nginx.com /* ret == NXT_ERROR */ 332625Sigor@sysoev.ru status = NXT_HTTP_BAD_REQUEST; 333480Svbart@nginx.com 334625Sigor@sysoev.ru goto error; 335431Sigor@sysoev.ru 336625Sigor@sysoev.ru case NXT_AGAIN: 337625Sigor@sysoev.ru status = nxt_h1p_header_buffer_test(task, h1p, c, r->socket_conf); 338431Sigor@sysoev.ru 339625Sigor@sysoev.ru if (nxt_fast_path(status == NXT_OK)) { 340625Sigor@sysoev.ru c->read_state = &nxt_h1p_header_parse_state; 341431Sigor@sysoev.ru 342625Sigor@sysoev.ru nxt_conn_read(task->thread->engine, c); 343625Sigor@sysoev.ru return; 344431Sigor@sysoev.ru } 345431Sigor@sysoev.ru 346625Sigor@sysoev.ru break; 347480Svbart@nginx.com 348480Svbart@nginx.com case NXT_HTTP_PARSE_INVALID: 349480Svbart@nginx.com status = NXT_HTTP_BAD_REQUEST; 350480Svbart@nginx.com break; 351431Sigor@sysoev.ru 352482Svbart@nginx.com case NXT_HTTP_PARSE_UNSUPPORTED_VERSION: 353482Svbart@nginx.com status = NXT_HTTP_VERSION_NOT_SUPPORTED; 354482Svbart@nginx.com break; 355482Svbart@nginx.com 356480Svbart@nginx.com case NXT_HTTP_PARSE_TOO_LARGE_FIELD: 357480Svbart@nginx.com status = NXT_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE; 358480Svbart@nginx.com break; 359480Svbart@nginx.com 360480Svbart@nginx.com default: 361480Svbart@nginx.com case NXT_ERROR: 362480Svbart@nginx.com status = NXT_HTTP_INTERNAL_SERVER_ERROR; 363480Svbart@nginx.com break; 364480Svbart@nginx.com } 365480Svbart@nginx.com 366620Svbart@nginx.com (void) nxt_h1p_header_process(h1p, r); 367625Sigor@sysoev.ru 368625Sigor@sysoev.ru error: 369625Sigor@sysoev.ru 370480Svbart@nginx.com nxt_http_request_error(task, r, status); 371431Sigor@sysoev.ru } 372431Sigor@sysoev.ru 373431Sigor@sysoev.ru 374431Sigor@sysoev.ru static nxt_int_t 375620Svbart@nginx.com nxt_h1p_header_process(nxt_h1proto_t *h1p, nxt_http_request_t *r) 376620Svbart@nginx.com { 377620Svbart@nginx.com r->target.start = h1p->parser.target_start; 378620Svbart@nginx.com r->target.length = h1p->parser.target_end - h1p->parser.target_start; 379620Svbart@nginx.com 380620Svbart@nginx.com if (h1p->parser.version.ui64 != 0) { 381620Svbart@nginx.com r->version.start = h1p->parser.version.str; 382620Svbart@nginx.com r->version.length = sizeof(h1p->parser.version.str); 383620Svbart@nginx.com } 384620Svbart@nginx.com 385620Svbart@nginx.com r->method = &h1p->parser.method; 386620Svbart@nginx.com r->path = &h1p->parser.path; 387620Svbart@nginx.com r->args = &h1p->parser.args; 388620Svbart@nginx.com 389620Svbart@nginx.com r->fields = h1p->parser.fields; 390620Svbart@nginx.com 391620Svbart@nginx.com return nxt_http_fields_process(r->fields, &nxt_h1p_fields_hash, r); 392620Svbart@nginx.com } 393620Svbart@nginx.com 394620Svbart@nginx.com 395620Svbart@nginx.com static nxt_int_t 396625Sigor@sysoev.ru nxt_h1p_header_buffer_test(nxt_task_t *task, nxt_h1proto_t *h1p, nxt_conn_t *c, 397625Sigor@sysoev.ru nxt_socket_conf_t *skcf) 398625Sigor@sysoev.ru { 399625Sigor@sysoev.ru size_t size, used; 400625Sigor@sysoev.ru nxt_buf_t *in, *b; 401625Sigor@sysoev.ru 402625Sigor@sysoev.ru in = c->read; 403625Sigor@sysoev.ru 404625Sigor@sysoev.ru if (nxt_buf_mem_free_size(&in->mem) == 0) { 405625Sigor@sysoev.ru size = skcf->large_header_buffer_size; 406625Sigor@sysoev.ru used = nxt_buf_mem_used_size(&in->mem); 407625Sigor@sysoev.ru 408625Sigor@sysoev.ru if (size <= used || h1p->nbuffers >= skcf->large_header_buffers) { 409625Sigor@sysoev.ru return NXT_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE; 410625Sigor@sysoev.ru } 411625Sigor@sysoev.ru 412625Sigor@sysoev.ru b = nxt_buf_mem_alloc(c->mem_pool, size, 0); 413625Sigor@sysoev.ru if (nxt_slow_path(b == NULL)) { 414625Sigor@sysoev.ru return NXT_HTTP_INTERNAL_SERVER_ERROR; 415625Sigor@sysoev.ru } 416625Sigor@sysoev.ru 417625Sigor@sysoev.ru b->mem.free = nxt_cpymem(b->mem.pos, in->mem.pos, used); 418625Sigor@sysoev.ru 419625Sigor@sysoev.ru in->next = h1p->buffers; 420625Sigor@sysoev.ru h1p->buffers = in; 421625Sigor@sysoev.ru h1p->nbuffers++; 422625Sigor@sysoev.ru 423625Sigor@sysoev.ru c->read = b; 424625Sigor@sysoev.ru } 425625Sigor@sysoev.ru 426625Sigor@sysoev.ru return NXT_OK; 427625Sigor@sysoev.ru } 428625Sigor@sysoev.ru 429625Sigor@sysoev.ru 430625Sigor@sysoev.ru static nxt_int_t 431431Sigor@sysoev.ru nxt_h1p_connection(void *ctx, nxt_http_field_t *field, uintptr_t data) 432431Sigor@sysoev.ru { 433431Sigor@sysoev.ru nxt_http_request_t *r; 434431Sigor@sysoev.ru 435431Sigor@sysoev.ru r = ctx; 436431Sigor@sysoev.ru 437431Sigor@sysoev.ru if (field->value_length == 5 && nxt_memcmp(field->value, "close", 5) == 0) { 438431Sigor@sysoev.ru r->proto.h1->keepalive = 0; 439431Sigor@sysoev.ru } 440431Sigor@sysoev.ru 441431Sigor@sysoev.ru return NXT_OK; 442431Sigor@sysoev.ru } 443431Sigor@sysoev.ru 444431Sigor@sysoev.ru 445431Sigor@sysoev.ru static nxt_int_t 446431Sigor@sysoev.ru nxt_h1p_transfer_encoding(void *ctx, nxt_http_field_t *field, uintptr_t data) 447431Sigor@sysoev.ru { 448431Sigor@sysoev.ru nxt_http_te_t te; 449431Sigor@sysoev.ru nxt_http_request_t *r; 450431Sigor@sysoev.ru 451431Sigor@sysoev.ru r = ctx; 452431Sigor@sysoev.ru 453431Sigor@sysoev.ru if (field->value_length == 7 454431Sigor@sysoev.ru && nxt_memcmp(field->value, "chunked", 7) == 0) 455431Sigor@sysoev.ru { 456431Sigor@sysoev.ru te = NXT_HTTP_TE_CHUNKED; 457431Sigor@sysoev.ru 458431Sigor@sysoev.ru } else { 459431Sigor@sysoev.ru te = NXT_HTTP_TE_UNSUPPORTED; 460431Sigor@sysoev.ru } 461431Sigor@sysoev.ru 462431Sigor@sysoev.ru r->proto.h1->transfer_encoding = te; 463431Sigor@sysoev.ru 464431Sigor@sysoev.ru return NXT_OK; 465431Sigor@sysoev.ru } 466431Sigor@sysoev.ru 467431Sigor@sysoev.ru 468431Sigor@sysoev.ru static void 469431Sigor@sysoev.ru nxt_h1p_request_body_read(nxt_task_t *task, nxt_http_request_t *r) 470431Sigor@sysoev.ru { 471527Svbart@nginx.com size_t size, body_length; 472459Sigor@sysoev.ru nxt_buf_t *in, *b; 473431Sigor@sysoev.ru nxt_conn_t *c; 474459Sigor@sysoev.ru nxt_h1proto_t *h1p; 475431Sigor@sysoev.ru nxt_http_status_t status; 476431Sigor@sysoev.ru 477459Sigor@sysoev.ru h1p = r->proto.h1; 478459Sigor@sysoev.ru 479624Sigor@sysoev.ru nxt_debug(task, "h1p request body read %O te:%d", 480459Sigor@sysoev.ru r->content_length_n, h1p->transfer_encoding); 481431Sigor@sysoev.ru 482459Sigor@sysoev.ru switch (h1p->transfer_encoding) { 483431Sigor@sysoev.ru 484431Sigor@sysoev.ru case NXT_HTTP_TE_CHUNKED: 485431Sigor@sysoev.ru status = NXT_HTTP_LENGTH_REQUIRED; 486431Sigor@sysoev.ru goto error; 487431Sigor@sysoev.ru 488431Sigor@sysoev.ru case NXT_HTTP_TE_UNSUPPORTED: 489431Sigor@sysoev.ru status = NXT_HTTP_NOT_IMPLEMENTED; 490431Sigor@sysoev.ru goto error; 491431Sigor@sysoev.ru 492431Sigor@sysoev.ru default: 493431Sigor@sysoev.ru case NXT_HTTP_TE_NONE: 494431Sigor@sysoev.ru break; 495431Sigor@sysoev.ru } 496431Sigor@sysoev.ru 497431Sigor@sysoev.ru if (r->content_length_n == -1 || r->content_length_n == 0) { 498431Sigor@sysoev.ru goto ready; 499431Sigor@sysoev.ru } 500431Sigor@sysoev.ru 501431Sigor@sysoev.ru if (r->content_length_n > (nxt_off_t) r->socket_conf->max_body_size) { 502431Sigor@sysoev.ru status = NXT_HTTP_PAYLOAD_TOO_LARGE; 503431Sigor@sysoev.ru goto error; 504431Sigor@sysoev.ru } 505431Sigor@sysoev.ru 506527Svbart@nginx.com body_length = (size_t) r->content_length_n; 507431Sigor@sysoev.ru 508431Sigor@sysoev.ru b = r->body; 509431Sigor@sysoev.ru 510431Sigor@sysoev.ru if (b == NULL) { 511527Svbart@nginx.com b = nxt_buf_mem_alloc(r->mem_pool, body_length, 0); 512431Sigor@sysoev.ru if (nxt_slow_path(b == NULL)) { 513431Sigor@sysoev.ru status = NXT_HTTP_INTERNAL_SERVER_ERROR; 514431Sigor@sysoev.ru goto error; 515431Sigor@sysoev.ru } 516431Sigor@sysoev.ru 517431Sigor@sysoev.ru r->body = b; 518431Sigor@sysoev.ru } 519431Sigor@sysoev.ru 520459Sigor@sysoev.ru in = h1p->conn->read; 521431Sigor@sysoev.ru 522459Sigor@sysoev.ru size = nxt_buf_mem_used_size(&in->mem); 523431Sigor@sysoev.ru 524431Sigor@sysoev.ru if (size != 0) { 525527Svbart@nginx.com if (size > body_length) { 526527Svbart@nginx.com size = body_length; 527431Sigor@sysoev.ru } 528431Sigor@sysoev.ru 529459Sigor@sysoev.ru b->mem.free = nxt_cpymem(b->mem.free, in->mem.pos, size); 530459Sigor@sysoev.ru in->mem.pos += size; 531431Sigor@sysoev.ru } 532431Sigor@sysoev.ru 533527Svbart@nginx.com size = nxt_buf_mem_free_size(&b->mem); 534431Sigor@sysoev.ru 535527Svbart@nginx.com nxt_debug(task, "h1p body rest: %uz", size); 536431Sigor@sysoev.ru 537527Svbart@nginx.com if (size != 0) { 538459Sigor@sysoev.ru in->next = h1p->buffers; 539459Sigor@sysoev.ru h1p->buffers = in; 540459Sigor@sysoev.ru 541459Sigor@sysoev.ru c = h1p->conn; 542431Sigor@sysoev.ru c->read = b; 543431Sigor@sysoev.ru c->read_state = &nxt_h1p_read_body_state; 544431Sigor@sysoev.ru 545431Sigor@sysoev.ru nxt_conn_read(task->thread->engine, c); 546431Sigor@sysoev.ru return; 547431Sigor@sysoev.ru } 548431Sigor@sysoev.ru 549431Sigor@sysoev.ru ready: 550431Sigor@sysoev.ru 551431Sigor@sysoev.ru nxt_work_queue_add(&task->thread->engine->fast_work_queue, 552431Sigor@sysoev.ru r->state->ready_handler, task, r, NULL); 553431Sigor@sysoev.ru 554431Sigor@sysoev.ru return; 555431Sigor@sysoev.ru 556431Sigor@sysoev.ru error: 557431Sigor@sysoev.ru 558459Sigor@sysoev.ru h1p->keepalive = 0; 559431Sigor@sysoev.ru 560431Sigor@sysoev.ru nxt_http_request_error(task, r, status); 561431Sigor@sysoev.ru } 562431Sigor@sysoev.ru 563431Sigor@sysoev.ru 564431Sigor@sysoev.ru static const nxt_conn_state_t nxt_h1p_read_body_state 565431Sigor@sysoev.ru nxt_aligned(64) = 566431Sigor@sysoev.ru { 567624Sigor@sysoev.ru .ready_handler = nxt_h1p_conn_body_read, 568624Sigor@sysoev.ru .close_handler = nxt_h1p_conn_request_error, 569624Sigor@sysoev.ru .error_handler = nxt_h1p_conn_request_error, 570431Sigor@sysoev.ru 571624Sigor@sysoev.ru .timer_handler = nxt_h1p_conn_request_timeout, 572624Sigor@sysoev.ru .timer_value = nxt_h1p_conn_timeout_value, 573431Sigor@sysoev.ru .timer_data = offsetof(nxt_socket_conf_t, body_read_timeout), 574431Sigor@sysoev.ru .timer_autoreset = 1, 575431Sigor@sysoev.ru }; 576431Sigor@sysoev.ru 577431Sigor@sysoev.ru 578431Sigor@sysoev.ru static void 579624Sigor@sysoev.ru nxt_h1p_conn_body_read(nxt_task_t *task, void *obj, void *data) 580431Sigor@sysoev.ru { 581431Sigor@sysoev.ru size_t size; 582431Sigor@sysoev.ru nxt_conn_t *c; 583431Sigor@sysoev.ru nxt_h1proto_t *h1p; 584431Sigor@sysoev.ru nxt_http_request_t *r; 585431Sigor@sysoev.ru 586431Sigor@sysoev.ru c = obj; 587431Sigor@sysoev.ru h1p = data; 588431Sigor@sysoev.ru 589624Sigor@sysoev.ru nxt_debug(task, "h1p conn body read"); 590431Sigor@sysoev.ru 591527Svbart@nginx.com size = nxt_buf_mem_free_size(&c->read->mem); 592431Sigor@sysoev.ru 593527Svbart@nginx.com nxt_debug(task, "h1p body rest: %uz", size); 594431Sigor@sysoev.ru 595527Svbart@nginx.com if (size != 0) { 596431Sigor@sysoev.ru nxt_conn_read(task->thread->engine, c); 597431Sigor@sysoev.ru 598431Sigor@sysoev.ru } else { 599527Svbart@nginx.com r = h1p->request; 600459Sigor@sysoev.ru c->read = NULL; 601431Sigor@sysoev.ru nxt_work_queue_add(&task->thread->engine->fast_work_queue, 602431Sigor@sysoev.ru r->state->ready_handler, task, r, NULL); 603431Sigor@sysoev.ru } 604431Sigor@sysoev.ru } 605431Sigor@sysoev.ru 606431Sigor@sysoev.ru 607431Sigor@sysoev.ru static void 608431Sigor@sysoev.ru nxt_h1p_request_local_addr(nxt_task_t *task, nxt_http_request_t *r) 609431Sigor@sysoev.ru { 610431Sigor@sysoev.ru r->local = nxt_conn_local_addr(task, r->proto.h1->conn); 611431Sigor@sysoev.ru } 612431Sigor@sysoev.ru 613431Sigor@sysoev.ru 614431Sigor@sysoev.ru #define NXT_HTTP_LAST_SUCCESS \ 615431Sigor@sysoev.ru (NXT_HTTP_OK + nxt_nitems(nxt_http_success) - 1) 616431Sigor@sysoev.ru 617431Sigor@sysoev.ru static const nxt_str_t nxt_http_success[] = { 618431Sigor@sysoev.ru nxt_string("HTTP/1.1 200 OK\r\n"), 619431Sigor@sysoev.ru nxt_string("HTTP/1.1 201 Created\r\n"), 620431Sigor@sysoev.ru nxt_string("HTTP/1.1 202 Accepted\r\n"), 621431Sigor@sysoev.ru nxt_string("HTTP/1.1 203 Non-Authoritative Information\r\n"), 622431Sigor@sysoev.ru nxt_string("HTTP/1.1 204 No Content\r\n"), 623431Sigor@sysoev.ru nxt_string("HTTP/1.1 205 Reset Content\r\n"), 624431Sigor@sysoev.ru nxt_string("HTTP/1.1 206 Partial Content\r\n"), 625431Sigor@sysoev.ru }; 626431Sigor@sysoev.ru 627431Sigor@sysoev.ru 628431Sigor@sysoev.ru #define NXT_HTTP_LAST_REDIRECTION \ 629431Sigor@sysoev.ru (NXT_HTTP_MULTIPLE_CHOICES + nxt_nitems(nxt_http_redirection) - 1) 630431Sigor@sysoev.ru 631431Sigor@sysoev.ru static const nxt_str_t nxt_http_redirection[] = { 632431Sigor@sysoev.ru nxt_string("HTTP/1.1 300 Multiple Choices\r\n"), 633431Sigor@sysoev.ru nxt_string("HTTP/1.1 301 Moved Permanently\r\n"), 634431Sigor@sysoev.ru nxt_string("HTTP/1.1 302 Found\r\n"), 635431Sigor@sysoev.ru nxt_string("HTTP/1.1 303 See Other\r\n"), 636431Sigor@sysoev.ru nxt_string("HTTP/1.1 304 Not Modified\r\n"), 637431Sigor@sysoev.ru }; 638431Sigor@sysoev.ru 639431Sigor@sysoev.ru 640431Sigor@sysoev.ru #define NXT_HTTP_LAST_CLIENT_ERROR \ 641431Sigor@sysoev.ru (NXT_HTTP_BAD_REQUEST + nxt_nitems(nxt_http_client_error) - 1) 642431Sigor@sysoev.ru 643431Sigor@sysoev.ru static const nxt_str_t nxt_http_client_error[] = { 644431Sigor@sysoev.ru nxt_string("HTTP/1.1 400 Bad Request\r\n"), 645431Sigor@sysoev.ru nxt_string("HTTP/1.1 401 Unauthorized\r\n"), 646431Sigor@sysoev.ru nxt_string("HTTP/1.1 402 Payment Required\r\n"), 647431Sigor@sysoev.ru nxt_string("HTTP/1.1 403 Forbidden\r\n"), 648431Sigor@sysoev.ru nxt_string("HTTP/1.1 404 Not Found\r\n"), 649431Sigor@sysoev.ru nxt_string("HTTP/1.1 405 Method Not Allowed\r\n"), 650431Sigor@sysoev.ru nxt_string("HTTP/1.1 406 Not Acceptable\r\n"), 651431Sigor@sysoev.ru nxt_string("HTTP/1.1 407 Proxy Authentication Required\r\n"), 652431Sigor@sysoev.ru nxt_string("HTTP/1.1 408 Request Timeout\r\n"), 653431Sigor@sysoev.ru nxt_string("HTTP/1.1 409 Conflict\r\n"), 654431Sigor@sysoev.ru nxt_string("HTTP/1.1 410 Gone\r\n"), 655431Sigor@sysoev.ru nxt_string("HTTP/1.1 411 Length Required\r\n"), 656431Sigor@sysoev.ru nxt_string("HTTP/1.1 412 Precondition Failed\r\n"), 657431Sigor@sysoev.ru nxt_string("HTTP/1.1 413 Payload Too Large\r\n"), 658431Sigor@sysoev.ru nxt_string("HTTP/1.1 414 URI Too Long\r\n"), 659431Sigor@sysoev.ru nxt_string("HTTP/1.1 415 Unsupported Media Type\r\n"), 660431Sigor@sysoev.ru nxt_string("HTTP/1.1 416 Range Not Satisfiable\r\n"), 661431Sigor@sysoev.ru nxt_string("HTTP/1.1 417 Expectation Failed\r\n"), 662431Sigor@sysoev.ru nxt_string("HTTP/1.1 418\r\n"), 663431Sigor@sysoev.ru nxt_string("HTTP/1.1 419\r\n"), 664431Sigor@sysoev.ru nxt_string("HTTP/1.1 420\r\n"), 665431Sigor@sysoev.ru nxt_string("HTTP/1.1 421\r\n"), 666431Sigor@sysoev.ru nxt_string("HTTP/1.1 422\r\n"), 667431Sigor@sysoev.ru nxt_string("HTTP/1.1 423\r\n"), 668431Sigor@sysoev.ru nxt_string("HTTP/1.1 424\r\n"), 669431Sigor@sysoev.ru nxt_string("HTTP/1.1 425\r\n"), 670431Sigor@sysoev.ru nxt_string("HTTP/1.1 426\r\n"), 671431Sigor@sysoev.ru nxt_string("HTTP/1.1 427\r\n"), 672431Sigor@sysoev.ru nxt_string("HTTP/1.1 428\r\n"), 673431Sigor@sysoev.ru nxt_string("HTTP/1.1 429\r\n"), 674431Sigor@sysoev.ru nxt_string("HTTP/1.1 430\r\n"), 675431Sigor@sysoev.ru nxt_string("HTTP/1.1 431 Request Header Fields Too Large\r\n"), 676431Sigor@sysoev.ru }; 677431Sigor@sysoev.ru 678431Sigor@sysoev.ru 679431Sigor@sysoev.ru #define NXT_HTTP_LAST_SERVER_ERROR \ 680431Sigor@sysoev.ru (NXT_HTTP_INTERNAL_SERVER_ERROR + nxt_nitems(nxt_http_server_error) - 1) 681431Sigor@sysoev.ru 682431Sigor@sysoev.ru static const nxt_str_t nxt_http_server_error[] = { 683431Sigor@sysoev.ru nxt_string("HTTP/1.1 500 Internal Server Error\r\n"), 684431Sigor@sysoev.ru nxt_string("HTTP/1.1 501 Not Implemented\r\n"), 685431Sigor@sysoev.ru nxt_string("HTTP/1.1 502 Bad Gateway\r\n"), 686431Sigor@sysoev.ru nxt_string("HTTP/1.1 503 Service Unavailable\r\n"), 687431Sigor@sysoev.ru nxt_string("HTTP/1.1 504 Gateway Timeout\r\n"), 688482Svbart@nginx.com nxt_string("HTTP/1.1 505 HTTP Version Not Supported\r\n"), 689431Sigor@sysoev.ru }; 690431Sigor@sysoev.ru 691431Sigor@sysoev.ru 692431Sigor@sysoev.ru #define UNKNOWN_STATUS_LENGTH (sizeof("HTTP/1.1 65536\r\n") - 1) 693431Sigor@sysoev.ru 694431Sigor@sysoev.ru static void 695431Sigor@sysoev.ru nxt_h1p_request_header_send(nxt_task_t *task, nxt_http_request_t *r) 696431Sigor@sysoev.ru { 697431Sigor@sysoev.ru u_char *p; 698431Sigor@sysoev.ru size_t size; 699431Sigor@sysoev.ru nxt_buf_t *header; 700431Sigor@sysoev.ru nxt_str_t unknown_status; 701431Sigor@sysoev.ru nxt_int_t conn; 702431Sigor@sysoev.ru nxt_uint_t n; 703431Sigor@sysoev.ru nxt_bool_t http11; 704431Sigor@sysoev.ru nxt_conn_t *c; 705431Sigor@sysoev.ru nxt_h1proto_t *h1p; 706431Sigor@sysoev.ru const nxt_str_t *status; 707431Sigor@sysoev.ru nxt_http_field_t *field; 708431Sigor@sysoev.ru nxt_event_engine_t *engine; 709431Sigor@sysoev.ru u_char buf[UNKNOWN_STATUS_LENGTH]; 710431Sigor@sysoev.ru 711431Sigor@sysoev.ru static const char chunked[] = "Transfer-Encoding: chunked\r\n"; 712431Sigor@sysoev.ru 713431Sigor@sysoev.ru static const nxt_str_t connection[2] = { 714431Sigor@sysoev.ru nxt_string("Connection: close\r\n"), 715431Sigor@sysoev.ru nxt_string("Connection: keep-alive\r\n"), 716431Sigor@sysoev.ru }; 717431Sigor@sysoev.ru 718431Sigor@sysoev.ru nxt_debug(task, "h1p request header send"); 719431Sigor@sysoev.ru 720431Sigor@sysoev.ru r->header_sent = 1; 721431Sigor@sysoev.ru h1p = r->proto.h1; 722431Sigor@sysoev.ru n = r->status; 723431Sigor@sysoev.ru 724431Sigor@sysoev.ru if (n >= NXT_HTTP_OK && n <= NXT_HTTP_LAST_SUCCESS) { 725431Sigor@sysoev.ru status = &nxt_http_success[n - NXT_HTTP_OK]; 726431Sigor@sysoev.ru 727431Sigor@sysoev.ru } else if (n >= NXT_HTTP_MULTIPLE_CHOICES 728431Sigor@sysoev.ru && n <= NXT_HTTP_LAST_REDIRECTION) 729431Sigor@sysoev.ru { 730431Sigor@sysoev.ru status = &nxt_http_redirection[n - NXT_HTTP_MULTIPLE_CHOICES]; 731431Sigor@sysoev.ru 732431Sigor@sysoev.ru } else if (n >= NXT_HTTP_BAD_REQUEST && n <= NXT_HTTP_LAST_CLIENT_ERROR) { 733431Sigor@sysoev.ru status = &nxt_http_client_error[n - NXT_HTTP_BAD_REQUEST]; 734431Sigor@sysoev.ru 735431Sigor@sysoev.ru } else if (n >= NXT_HTTP_INTERNAL_SERVER_ERROR 736431Sigor@sysoev.ru && n <= NXT_HTTP_LAST_SERVER_ERROR) 737431Sigor@sysoev.ru { 738431Sigor@sysoev.ru status = &nxt_http_server_error[n - NXT_HTTP_INTERNAL_SERVER_ERROR]; 739431Sigor@sysoev.ru 740431Sigor@sysoev.ru } else { 741431Sigor@sysoev.ru p = nxt_sprintf(buf, buf + UNKNOWN_STATUS_LENGTH, 742431Sigor@sysoev.ru "HTTP/1.1 %03d\r\n", n); 743431Sigor@sysoev.ru 744431Sigor@sysoev.ru unknown_status.length = p - buf; 745431Sigor@sysoev.ru unknown_status.start = buf; 746431Sigor@sysoev.ru status = &unknown_status; 747431Sigor@sysoev.ru } 748431Sigor@sysoev.ru 749450Sigor@sysoev.ru size = status->length; 750450Sigor@sysoev.ru /* Trailing CRLF at the end of header. */ 751450Sigor@sysoev.ru size += sizeof("\r\n") - 1; 752431Sigor@sysoev.ru 753481Svbart@nginx.com http11 = (h1p->parser.version.s.minor != '0'); 754431Sigor@sysoev.ru 755431Sigor@sysoev.ru if (r->resp.content_length == NULL || r->resp.content_length->skip) { 756431Sigor@sysoev.ru if (http11) { 757431Sigor@sysoev.ru h1p->chunked = 1; 758431Sigor@sysoev.ru size += sizeof(chunked) - 1; 759450Sigor@sysoev.ru /* Trailing CRLF will be added by the first chunk header. */ 760450Sigor@sysoev.ru size -= sizeof("\r\n") - 1; 761431Sigor@sysoev.ru 762431Sigor@sysoev.ru } else { 763431Sigor@sysoev.ru h1p->keepalive = 0; 764431Sigor@sysoev.ru } 765431Sigor@sysoev.ru } 766431Sigor@sysoev.ru 767431Sigor@sysoev.ru conn = -1; 768431Sigor@sysoev.ru 769431Sigor@sysoev.ru if (http11 ^ h1p->keepalive) { 770431Sigor@sysoev.ru conn = h1p->keepalive; 771431Sigor@sysoev.ru size += connection[conn].length; 772431Sigor@sysoev.ru } 773431Sigor@sysoev.ru 774431Sigor@sysoev.ru nxt_list_each(field, r->resp.fields) { 775431Sigor@sysoev.ru 776431Sigor@sysoev.ru if (!field->skip) { 777431Sigor@sysoev.ru size += field->name_length + field->value_length; 778431Sigor@sysoev.ru size += sizeof(": \r\n") - 1; 779431Sigor@sysoev.ru } 780431Sigor@sysoev.ru 781431Sigor@sysoev.ru } nxt_list_loop; 782431Sigor@sysoev.ru 783608Sigor@sysoev.ru header = nxt_http_buf_mem(task, r, size); 784431Sigor@sysoev.ru if (nxt_slow_path(header == NULL)) { 785608Sigor@sysoev.ru nxt_h1p_request_error(task, r); 786431Sigor@sysoev.ru return; 787431Sigor@sysoev.ru } 788431Sigor@sysoev.ru 789431Sigor@sysoev.ru p = header->mem.free; 790431Sigor@sysoev.ru 791431Sigor@sysoev.ru p = nxt_cpymem(p, status->start, status->length); 792431Sigor@sysoev.ru 793431Sigor@sysoev.ru nxt_list_each(field, r->resp.fields) { 794431Sigor@sysoev.ru 795431Sigor@sysoev.ru if (!field->skip) { 796431Sigor@sysoev.ru p = nxt_cpymem(p, field->name, field->name_length); 797431Sigor@sysoev.ru *p++ = ':'; *p++ = ' '; 798431Sigor@sysoev.ru p = nxt_cpymem(p, field->value, field->value_length); 799431Sigor@sysoev.ru *p++ = '\r'; *p++ = '\n'; 800431Sigor@sysoev.ru } 801431Sigor@sysoev.ru 802431Sigor@sysoev.ru } nxt_list_loop; 803431Sigor@sysoev.ru 804431Sigor@sysoev.ru if (conn >= 0) { 805431Sigor@sysoev.ru p = nxt_cpymem(p, connection[conn].start, connection[conn].length); 806431Sigor@sysoev.ru } 807431Sigor@sysoev.ru 808431Sigor@sysoev.ru if (h1p->chunked) { 809431Sigor@sysoev.ru p = nxt_cpymem(p, chunked, sizeof(chunked) - 1); 810450Sigor@sysoev.ru /* Trailing CRLF will be added by the first chunk header. */ 811431Sigor@sysoev.ru 812431Sigor@sysoev.ru } else { 813431Sigor@sysoev.ru *p++ = '\r'; *p++ = '\n'; 814431Sigor@sysoev.ru } 815431Sigor@sysoev.ru 816431Sigor@sysoev.ru header->mem.free = p; 817431Sigor@sysoev.ru 818*630Svbart@nginx.com h1p->header_size = nxt_buf_mem_used_size(&header->mem); 819*630Svbart@nginx.com 820431Sigor@sysoev.ru c = h1p->conn; 821431Sigor@sysoev.ru 822431Sigor@sysoev.ru c->write = header; 823431Sigor@sysoev.ru c->write_state = &nxt_h1p_send_state; 824431Sigor@sysoev.ru 825431Sigor@sysoev.ru engine = task->thread->engine; 826431Sigor@sysoev.ru 827431Sigor@sysoev.ru nxt_work_queue_add(&engine->fast_work_queue, r->state->ready_handler, 828431Sigor@sysoev.ru task, r, NULL); 829431Sigor@sysoev.ru 830431Sigor@sysoev.ru nxt_conn_write(engine, c); 831431Sigor@sysoev.ru } 832431Sigor@sysoev.ru 833431Sigor@sysoev.ru 834431Sigor@sysoev.ru static const nxt_conn_state_t nxt_h1p_send_state 835431Sigor@sysoev.ru nxt_aligned(64) = 836431Sigor@sysoev.ru { 837624Sigor@sysoev.ru .ready_handler = nxt_h1p_conn_request_sent, 838624Sigor@sysoev.ru .error_handler = nxt_h1p_conn_request_error, 839431Sigor@sysoev.ru 840626Sigor@sysoev.ru .timer_handler = nxt_h1p_conn_request_send_timeout, 841624Sigor@sysoev.ru .timer_value = nxt_h1p_conn_timeout_value, 842431Sigor@sysoev.ru .timer_data = offsetof(nxt_socket_conf_t, send_timeout), 843431Sigor@sysoev.ru .timer_autoreset = 1, 844431Sigor@sysoev.ru }; 845431Sigor@sysoev.ru 846431Sigor@sysoev.ru 847431Sigor@sysoev.ru static void 848431Sigor@sysoev.ru nxt_h1p_request_send(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *out) 849431Sigor@sysoev.ru { 850431Sigor@sysoev.ru nxt_conn_t *c; 851431Sigor@sysoev.ru 852431Sigor@sysoev.ru nxt_debug(task, "h1p request send"); 853431Sigor@sysoev.ru 854431Sigor@sysoev.ru c = r->proto.h1->conn; 855431Sigor@sysoev.ru 856431Sigor@sysoev.ru if (r->proto.h1->chunked) { 857431Sigor@sysoev.ru out = nxt_h1p_chunk_create(task, r, out); 858431Sigor@sysoev.ru if (nxt_slow_path(out == NULL)) { 859608Sigor@sysoev.ru nxt_h1p_request_error(task, r); 860431Sigor@sysoev.ru return; 861431Sigor@sysoev.ru } 862431Sigor@sysoev.ru } 863431Sigor@sysoev.ru 864431Sigor@sysoev.ru if (c->write == NULL) { 865431Sigor@sysoev.ru c->write = out; 866431Sigor@sysoev.ru c->write_state = &nxt_h1p_send_state; 867431Sigor@sysoev.ru 868431Sigor@sysoev.ru nxt_conn_write(task->thread->engine, c); 869431Sigor@sysoev.ru 870431Sigor@sysoev.ru } else { 871431Sigor@sysoev.ru nxt_buf_chain_add(&c->write, out); 872431Sigor@sysoev.ru } 873431Sigor@sysoev.ru } 874431Sigor@sysoev.ru 875431Sigor@sysoev.ru 876431Sigor@sysoev.ru static nxt_buf_t * 877431Sigor@sysoev.ru nxt_h1p_chunk_create(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *out) 878431Sigor@sysoev.ru { 879483Sigor@sysoev.ru nxt_off_t size; 880431Sigor@sysoev.ru nxt_buf_t *b, **prev, *header, *tail; 881431Sigor@sysoev.ru 882431Sigor@sysoev.ru const size_t chunk_size = 2 * (sizeof("\r\n") - 1) + NXT_OFF_T_HEXLEN; 883431Sigor@sysoev.ru static const char tail_chunk[] = "\r\n0\r\n\r\n"; 884431Sigor@sysoev.ru 885431Sigor@sysoev.ru size = 0; 886431Sigor@sysoev.ru prev = &out; 887431Sigor@sysoev.ru 888431Sigor@sysoev.ru for (b = out; b != NULL; b = b->next) { 889431Sigor@sysoev.ru 890431Sigor@sysoev.ru if (nxt_buf_is_last(b)) { 891608Sigor@sysoev.ru tail = nxt_http_buf_mem(task, r, chunk_size); 892431Sigor@sysoev.ru if (nxt_slow_path(tail == NULL)) { 893431Sigor@sysoev.ru return NULL; 894431Sigor@sysoev.ru } 895431Sigor@sysoev.ru 896431Sigor@sysoev.ru *prev = tail; 897431Sigor@sysoev.ru tail->next = b; 898431Sigor@sysoev.ru /* 899431Sigor@sysoev.ru * The tail_chunk size with trailing zero is 8 bytes, so 900431Sigor@sysoev.ru * memcpy may be inlined with just single 8 byte move operation. 901431Sigor@sysoev.ru */ 902431Sigor@sysoev.ru nxt_memcpy(tail->mem.free, tail_chunk, sizeof(tail_chunk)); 903431Sigor@sysoev.ru tail->mem.free += sizeof(tail_chunk) - 1; 904431Sigor@sysoev.ru 905431Sigor@sysoev.ru break; 906431Sigor@sysoev.ru } 907431Sigor@sysoev.ru 908431Sigor@sysoev.ru size += nxt_buf_used_size(b); 909431Sigor@sysoev.ru prev = &b->next; 910431Sigor@sysoev.ru } 911431Sigor@sysoev.ru 912431Sigor@sysoev.ru if (size == 0) { 913431Sigor@sysoev.ru return out; 914431Sigor@sysoev.ru } 915431Sigor@sysoev.ru 916608Sigor@sysoev.ru header = nxt_http_buf_mem(task, r, chunk_size); 917431Sigor@sysoev.ru if (nxt_slow_path(header == NULL)) { 918431Sigor@sysoev.ru return NULL; 919431Sigor@sysoev.ru } 920431Sigor@sysoev.ru 921431Sigor@sysoev.ru header->next = out; 922431Sigor@sysoev.ru header->mem.free = nxt_sprintf(header->mem.free, header->mem.end, 923431Sigor@sysoev.ru "\r\n%xO\r\n", size); 924431Sigor@sysoev.ru return header; 925431Sigor@sysoev.ru } 926431Sigor@sysoev.ru 927431Sigor@sysoev.ru 928431Sigor@sysoev.ru static void 929624Sigor@sysoev.ru nxt_h1p_conn_request_sent(nxt_task_t *task, void *obj, void *data) 930431Sigor@sysoev.ru { 931431Sigor@sysoev.ru nxt_conn_t *c; 932431Sigor@sysoev.ru nxt_event_engine_t *engine; 933431Sigor@sysoev.ru 934431Sigor@sysoev.ru c = obj; 935431Sigor@sysoev.ru 936624Sigor@sysoev.ru nxt_debug(task, "h1p conn request sent"); 937431Sigor@sysoev.ru 938431Sigor@sysoev.ru engine = task->thread->engine; 939431Sigor@sysoev.ru 940592Sigor@sysoev.ru c->write = nxt_sendbuf_completion(task, &engine->fast_work_queue, c->write); 941592Sigor@sysoev.ru 942431Sigor@sysoev.ru if (c->write != NULL) { 943431Sigor@sysoev.ru nxt_conn_write(engine, c); 944431Sigor@sysoev.ru } 945431Sigor@sysoev.ru } 946431Sigor@sysoev.ru 947431Sigor@sysoev.ru 948*630Svbart@nginx.com static nxt_off_t 949*630Svbart@nginx.com nxt_h1p_request_body_bytes_sent(nxt_task_t *task, nxt_http_proto_t proto) 950*630Svbart@nginx.com { 951*630Svbart@nginx.com nxt_off_t sent; 952*630Svbart@nginx.com nxt_h1proto_t *h1p; 953*630Svbart@nginx.com 954*630Svbart@nginx.com h1p = proto.h1; 955*630Svbart@nginx.com 956*630Svbart@nginx.com sent = h1p->conn->sent - h1p->header_size; 957*630Svbart@nginx.com 958*630Svbart@nginx.com return (sent > 0) ? sent : 0; 959*630Svbart@nginx.com } 960*630Svbart@nginx.com 961*630Svbart@nginx.com 962431Sigor@sysoev.ru static void 963608Sigor@sysoev.ru nxt_h1p_request_discard(nxt_task_t *task, nxt_http_request_t *r, 964608Sigor@sysoev.ru nxt_buf_t *last) 965608Sigor@sysoev.ru { 966608Sigor@sysoev.ru nxt_buf_t *b; 967608Sigor@sysoev.ru nxt_conn_t *c; 968608Sigor@sysoev.ru nxt_h1proto_t *h1p; 969608Sigor@sysoev.ru nxt_work_queue_t *wq; 970608Sigor@sysoev.ru 971608Sigor@sysoev.ru nxt_debug(task, "h1p request discard"); 972608Sigor@sysoev.ru 973608Sigor@sysoev.ru h1p = r->proto.h1; 974608Sigor@sysoev.ru h1p->keepalive = 0; 975608Sigor@sysoev.ru 976608Sigor@sysoev.ru c = h1p->conn; 977608Sigor@sysoev.ru b = c->write; 978608Sigor@sysoev.ru c->write = NULL; 979608Sigor@sysoev.ru 980608Sigor@sysoev.ru wq = &task->thread->engine->fast_work_queue; 981608Sigor@sysoev.ru 982608Sigor@sysoev.ru nxt_sendbuf_drain(task, wq, b); 983608Sigor@sysoev.ru nxt_sendbuf_drain(task, wq, last); 984608Sigor@sysoev.ru } 985608Sigor@sysoev.ru 986608Sigor@sysoev.ru 987608Sigor@sysoev.ru static void 988431Sigor@sysoev.ru nxt_h1p_request_close(nxt_task_t *task, nxt_http_proto_t proto) 989431Sigor@sysoev.ru { 990431Sigor@sysoev.ru nxt_conn_t *c; 991431Sigor@sysoev.ru nxt_h1proto_t *h1p; 992431Sigor@sysoev.ru 993431Sigor@sysoev.ru nxt_debug(task, "h1p request close"); 994431Sigor@sysoev.ru 995431Sigor@sysoev.ru h1p = proto.h1; 996431Sigor@sysoev.ru h1p->request = NULL; 997431Sigor@sysoev.ru 998431Sigor@sysoev.ru c = h1p->conn; 999431Sigor@sysoev.ru 1000431Sigor@sysoev.ru if (h1p->keepalive) { 1001431Sigor@sysoev.ru nxt_h1p_keepalive(task, h1p, c); 1002431Sigor@sysoev.ru 1003431Sigor@sysoev.ru } else { 1004431Sigor@sysoev.ru nxt_h1p_close(task, c); 1005431Sigor@sysoev.ru } 1006431Sigor@sysoev.ru } 1007431Sigor@sysoev.ru 1008431Sigor@sysoev.ru 1009431Sigor@sysoev.ru static void 1010431Sigor@sysoev.ru nxt_h1p_keepalive(nxt_task_t *task, nxt_h1proto_t *h1p, nxt_conn_t *c) 1011431Sigor@sysoev.ru { 1012431Sigor@sysoev.ru size_t size; 1013431Sigor@sysoev.ru nxt_buf_t *in, *b, *next; 1014431Sigor@sysoev.ru 1015431Sigor@sysoev.ru nxt_debug(task, "h1p keepalive"); 1016431Sigor@sysoev.ru 1017436Sigor@sysoev.ru if (!c->tcp_nodelay) { 1018436Sigor@sysoev.ru nxt_conn_tcp_nodelay_on(task, c); 1019436Sigor@sysoev.ru } 1020436Sigor@sysoev.ru 1021431Sigor@sysoev.ru b = h1p->buffers; 1022431Sigor@sysoev.ru 1023452Sigor@sysoev.ru nxt_memzero(h1p, offsetof(nxt_h1proto_t, conn)); 1024431Sigor@sysoev.ru 1025*630Svbart@nginx.com c->sent = 0; 1026*630Svbart@nginx.com 1027431Sigor@sysoev.ru in = c->read; 1028431Sigor@sysoev.ru 1029459Sigor@sysoev.ru if (in == NULL) { 1030459Sigor@sysoev.ru /* A request with large body. */ 1031459Sigor@sysoev.ru in = b; 1032459Sigor@sysoev.ru c->read = in; 1033459Sigor@sysoev.ru 1034459Sigor@sysoev.ru b = in->next; 1035459Sigor@sysoev.ru in->next = NULL; 1036459Sigor@sysoev.ru } 1037459Sigor@sysoev.ru 1038459Sigor@sysoev.ru while (b != NULL) { 1039459Sigor@sysoev.ru next = b->next; 1040459Sigor@sysoev.ru nxt_mp_free(c->mem_pool, b); 1041459Sigor@sysoev.ru b = next; 1042459Sigor@sysoev.ru } 1043459Sigor@sysoev.ru 1044431Sigor@sysoev.ru size = nxt_buf_mem_used_size(&in->mem); 1045431Sigor@sysoev.ru 1046431Sigor@sysoev.ru if (size == 0) { 1047629Sigor@sysoev.ru nxt_mp_free(c->mem_pool, in); 1048431Sigor@sysoev.ru 1049629Sigor@sysoev.ru c->read = NULL; 1050628Sigor@sysoev.ru c->read_state = &nxt_h1p_keepalive_state; 1051431Sigor@sysoev.ru 1052628Sigor@sysoev.ru nxt_conn_read(task->thread->engine, c); 1053431Sigor@sysoev.ru 1054431Sigor@sysoev.ru } else { 1055431Sigor@sysoev.ru nxt_debug(task, "h1p pipelining"); 1056431Sigor@sysoev.ru 1057431Sigor@sysoev.ru nxt_memmove(in->mem.start, in->mem.pos, size); 1058431Sigor@sysoev.ru 1059431Sigor@sysoev.ru in->mem.pos = in->mem.start; 1060431Sigor@sysoev.ru in->mem.free = in->mem.start + size; 1061431Sigor@sysoev.ru 1062627Svbart@nginx.com nxt_h1p_conn_request_init(task, c, c->socket.data); 1063431Sigor@sysoev.ru } 1064431Sigor@sysoev.ru } 1065431Sigor@sysoev.ru 1066431Sigor@sysoev.ru 1067624Sigor@sysoev.ru static const nxt_conn_state_t nxt_h1p_keepalive_state 1068624Sigor@sysoev.ru nxt_aligned(64) = 1069431Sigor@sysoev.ru { 1070628Sigor@sysoev.ru .ready_handler = nxt_h1p_conn_request_init, 1071624Sigor@sysoev.ru .close_handler = nxt_h1p_conn_error, 1072624Sigor@sysoev.ru .error_handler = nxt_h1p_conn_error, 1073624Sigor@sysoev.ru 1074629Sigor@sysoev.ru .io_read_handler = nxt_h1p_conn_io_read_handler, 1075629Sigor@sysoev.ru 1076624Sigor@sysoev.ru .timer_handler = nxt_h1p_conn_timeout, 1077624Sigor@sysoev.ru .timer_value = nxt_h1p_conn_timeout_value, 1078624Sigor@sysoev.ru .timer_data = offsetof(nxt_socket_conf_t, idle_timeout), 1079624Sigor@sysoev.ru }; 1080624Sigor@sysoev.ru 1081624Sigor@sysoev.ru 1082624Sigor@sysoev.ru static void 1083431Sigor@sysoev.ru nxt_h1p_conn_error(nxt_task_t *task, void *obj, void *data) 1084431Sigor@sysoev.ru { 1085624Sigor@sysoev.ru nxt_conn_t *c; 1086431Sigor@sysoev.ru 1087431Sigor@sysoev.ru c = obj; 1088431Sigor@sysoev.ru 1089431Sigor@sysoev.ru nxt_debug(task, "h1p conn error"); 1090431Sigor@sysoev.ru 1091624Sigor@sysoev.ru nxt_h1p_close(task, c); 1092431Sigor@sysoev.ru } 1093431Sigor@sysoev.ru 1094431Sigor@sysoev.ru 1095431Sigor@sysoev.ru static void 1096431Sigor@sysoev.ru nxt_h1p_conn_timeout(nxt_task_t *task, void *obj, void *data) 1097431Sigor@sysoev.ru { 1098431Sigor@sysoev.ru nxt_conn_t *c; 1099431Sigor@sysoev.ru nxt_timer_t *timer; 1100431Sigor@sysoev.ru 1101431Sigor@sysoev.ru timer = obj; 1102431Sigor@sysoev.ru 1103431Sigor@sysoev.ru nxt_debug(task, "h1p conn timeout"); 1104431Sigor@sysoev.ru 1105431Sigor@sysoev.ru c = nxt_read_timer_conn(timer); 1106431Sigor@sysoev.ru 1107624Sigor@sysoev.ru nxt_h1p_close(task, c); 1108624Sigor@sysoev.ru } 1109624Sigor@sysoev.ru 1110624Sigor@sysoev.ru 1111624Sigor@sysoev.ru static void 1112624Sigor@sysoev.ru nxt_h1p_close(nxt_task_t *task, nxt_conn_t *c) 1113624Sigor@sysoev.ru { 1114624Sigor@sysoev.ru nxt_debug(task, "h1p close"); 1115624Sigor@sysoev.ru 1116624Sigor@sysoev.ru c->socket.data = NULL; 1117624Sigor@sysoev.ru 1118624Sigor@sysoev.ru c->write_state = &nxt_router_conn_close_state; 1119624Sigor@sysoev.ru 1120624Sigor@sysoev.ru nxt_conn_close(task->thread->engine, c); 1121624Sigor@sysoev.ru } 1122624Sigor@sysoev.ru 1123624Sigor@sysoev.ru 1124624Sigor@sysoev.ru static void 1125624Sigor@sysoev.ru nxt_h1p_conn_request_error(nxt_task_t *task, void *obj, void *data) 1126624Sigor@sysoev.ru { 1127624Sigor@sysoev.ru nxt_h1proto_t *h1p; 1128624Sigor@sysoev.ru nxt_http_request_t *r; 1129624Sigor@sysoev.ru 1130624Sigor@sysoev.ru h1p = data; 1131624Sigor@sysoev.ru 1132624Sigor@sysoev.ru nxt_debug(task, "h1p conn request error"); 1133624Sigor@sysoev.ru 1134624Sigor@sysoev.ru r = h1p->request; 1135624Sigor@sysoev.ru 1136624Sigor@sysoev.ru if (r->fields == NULL) { 1137624Sigor@sysoev.ru (void) nxt_h1p_header_process(h1p, r); 1138624Sigor@sysoev.ru } 1139624Sigor@sysoev.ru 1140624Sigor@sysoev.ru if (r->status == 0) { 1141624Sigor@sysoev.ru r->status = NXT_HTTP_BAD_REQUEST; 1142624Sigor@sysoev.ru } 1143624Sigor@sysoev.ru 1144624Sigor@sysoev.ru nxt_h1p_request_error(task, r); 1145624Sigor@sysoev.ru } 1146624Sigor@sysoev.ru 1147624Sigor@sysoev.ru 1148624Sigor@sysoev.ru static void 1149624Sigor@sysoev.ru nxt_h1p_conn_request_timeout(nxt_task_t *task, void *obj, void *data) 1150624Sigor@sysoev.ru { 1151624Sigor@sysoev.ru nxt_conn_t *c; 1152624Sigor@sysoev.ru nxt_timer_t *timer; 1153624Sigor@sysoev.ru nxt_h1proto_t *h1p; 1154624Sigor@sysoev.ru nxt_http_request_t *r; 1155624Sigor@sysoev.ru 1156624Sigor@sysoev.ru timer = obj; 1157624Sigor@sysoev.ru 1158624Sigor@sysoev.ru nxt_debug(task, "h1p conn request timeout"); 1159624Sigor@sysoev.ru 1160624Sigor@sysoev.ru c = nxt_read_timer_conn(timer); 1161626Sigor@sysoev.ru /* 1162626Sigor@sysoev.ru * Disable SO_LINGER off during socket closing 1163626Sigor@sysoev.ru * to send "408 Request Timeout" error response. 1164626Sigor@sysoev.ru */ 1165626Sigor@sysoev.ru c->socket.timedout = 0; 1166626Sigor@sysoev.ru 1167624Sigor@sysoev.ru h1p = c->socket.data; 1168624Sigor@sysoev.ru r = h1p->request; 1169624Sigor@sysoev.ru 1170624Sigor@sysoev.ru if (r->fields == NULL) { 1171624Sigor@sysoev.ru (void) nxt_h1p_header_process(h1p, r); 1172624Sigor@sysoev.ru } 1173624Sigor@sysoev.ru 1174626Sigor@sysoev.ru nxt_http_request_error(task, r, NXT_HTTP_REQUEST_TIMEOUT); 1175626Sigor@sysoev.ru } 1176626Sigor@sysoev.ru 1177624Sigor@sysoev.ru 1178626Sigor@sysoev.ru static void 1179626Sigor@sysoev.ru nxt_h1p_conn_request_send_timeout(nxt_task_t *task, void *obj, void *data) 1180626Sigor@sysoev.ru { 1181626Sigor@sysoev.ru nxt_conn_t *c; 1182626Sigor@sysoev.ru nxt_timer_t *timer; 1183626Sigor@sysoev.ru nxt_h1proto_t *h1p; 1184626Sigor@sysoev.ru 1185626Sigor@sysoev.ru timer = obj; 1186626Sigor@sysoev.ru 1187626Sigor@sysoev.ru nxt_debug(task, "h1p conn request send timeout"); 1188626Sigor@sysoev.ru 1189626Sigor@sysoev.ru c = nxt_read_timer_conn(timer); 1190626Sigor@sysoev.ru h1p = c->socket.data; 1191626Sigor@sysoev.ru 1192626Sigor@sysoev.ru nxt_h1p_request_error(task, h1p->request); 1193624Sigor@sysoev.ru } 1194624Sigor@sysoev.ru 1195624Sigor@sysoev.ru 1196624Sigor@sysoev.ru nxt_inline void 1197624Sigor@sysoev.ru nxt_h1p_request_error(nxt_task_t *task, nxt_http_request_t *r) 1198624Sigor@sysoev.ru { 1199624Sigor@sysoev.ru r->state->error_handler(task, r, r->proto.h1); 1200431Sigor@sysoev.ru } 1201431Sigor@sysoev.ru 1202431Sigor@sysoev.ru 1203431Sigor@sysoev.ru static nxt_msec_t 1204624Sigor@sysoev.ru nxt_h1p_conn_timeout_value(nxt_conn_t *c, uintptr_t data) 1205431Sigor@sysoev.ru { 1206431Sigor@sysoev.ru nxt_socket_conf_joint_t *joint; 1207431Sigor@sysoev.ru 1208431Sigor@sysoev.ru joint = c->joint; 1209431Sigor@sysoev.ru 1210431Sigor@sysoev.ru return nxt_value_at(nxt_msec_t, joint->socket_conf, data); 1211431Sigor@sysoev.ru } 1212