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 11431Sigor@sysoev.ru static void nxt_http_request_start(nxt_task_t *task, void *obj, void *data); 12431Sigor@sysoev.ru static void nxt_http_app_request(nxt_task_t *task, void *obj, void *data); 13431Sigor@sysoev.ru static void nxt_http_request_done(nxt_task_t *task, void *obj, void *data); 14431Sigor@sysoev.ru 15431Sigor@sysoev.ru 16431Sigor@sysoev.ru static const nxt_http_request_state_t nxt_http_request_init_state; 17431Sigor@sysoev.ru static const nxt_http_request_state_t nxt_http_request_body_state; 18431Sigor@sysoev.ru 19431Sigor@sysoev.ru 20431Sigor@sysoev.ru nxt_int_t 21431Sigor@sysoev.ru nxt_http_init(nxt_task_t *task, nxt_runtime_t *rt) 22431Sigor@sysoev.ru { 23431Sigor@sysoev.ru nxt_int_t ret; 24431Sigor@sysoev.ru 25431Sigor@sysoev.ru ret = nxt_h1p_init(task, rt); 26431Sigor@sysoev.ru 27431Sigor@sysoev.ru if (ret != NXT_OK) { 28431Sigor@sysoev.ru return ret; 29431Sigor@sysoev.ru } 30431Sigor@sysoev.ru 31431Sigor@sysoev.ru return nxt_http_response_hash_init(task, rt); 32431Sigor@sysoev.ru } 33431Sigor@sysoev.ru 34431Sigor@sysoev.ru 35431Sigor@sysoev.ru nxt_int_t 36431Sigor@sysoev.ru nxt_http_request_host(void *ctx, nxt_http_field_t *field, uintptr_t data) 37431Sigor@sysoev.ru { 38431Sigor@sysoev.ru nxt_http_request_t *r; 39431Sigor@sysoev.ru 40431Sigor@sysoev.ru r = ctx; 41431Sigor@sysoev.ru 42431Sigor@sysoev.ru /* TODO: validate host. */ 43431Sigor@sysoev.ru 44431Sigor@sysoev.ru r->host = field; 45431Sigor@sysoev.ru 46431Sigor@sysoev.ru return NXT_OK; 47431Sigor@sysoev.ru } 48431Sigor@sysoev.ru 49431Sigor@sysoev.ru 50431Sigor@sysoev.ru nxt_int_t 51431Sigor@sysoev.ru nxt_http_request_field(void *ctx, nxt_http_field_t *field, uintptr_t offset) 52431Sigor@sysoev.ru { 53431Sigor@sysoev.ru nxt_http_request_t *r; 54431Sigor@sysoev.ru 55431Sigor@sysoev.ru r = ctx; 56431Sigor@sysoev.ru 57431Sigor@sysoev.ru nxt_value_at(nxt_http_field_t *, r, offset) = field; 58431Sigor@sysoev.ru 59431Sigor@sysoev.ru return NXT_OK; 60431Sigor@sysoev.ru } 61431Sigor@sysoev.ru 62431Sigor@sysoev.ru 63431Sigor@sysoev.ru nxt_int_t 64431Sigor@sysoev.ru nxt_http_request_content_length(void *ctx, nxt_http_field_t *field, 65431Sigor@sysoev.ru uintptr_t data) 66431Sigor@sysoev.ru { 67431Sigor@sysoev.ru nxt_http_request_t *r; 68431Sigor@sysoev.ru 69431Sigor@sysoev.ru r = ctx; 70431Sigor@sysoev.ru 71431Sigor@sysoev.ru r->content_length = field; 72431Sigor@sysoev.ru r->content_length_n = nxt_off_t_parse(field->value, field->value_length); 73431Sigor@sysoev.ru 74431Sigor@sysoev.ru return NXT_OK; 75431Sigor@sysoev.ru } 76431Sigor@sysoev.ru 77431Sigor@sysoev.ru 78431Sigor@sysoev.ru nxt_http_request_t * 79431Sigor@sysoev.ru nxt_http_request_create(nxt_task_t *task) 80431Sigor@sysoev.ru { 81431Sigor@sysoev.ru nxt_mp_t *mp; 82431Sigor@sysoev.ru nxt_http_request_t *r; 83431Sigor@sysoev.ru 84431Sigor@sysoev.ru mp = nxt_mp_create(1024, 128, 256, 32); 85431Sigor@sysoev.ru if (nxt_slow_path(mp == NULL)) { 86431Sigor@sysoev.ru return NULL; 87431Sigor@sysoev.ru } 88431Sigor@sysoev.ru 89431Sigor@sysoev.ru r = nxt_mp_zget(mp, sizeof(nxt_http_request_t)); 90431Sigor@sysoev.ru if (nxt_slow_path(r == NULL)) { 91431Sigor@sysoev.ru goto fail; 92431Sigor@sysoev.ru } 93431Sigor@sysoev.ru 94431Sigor@sysoev.ru r->resp.fields = nxt_list_create(mp, 8, sizeof(nxt_http_field_t)); 95*451Sigor@sysoev.ru if (nxt_slow_path(r->resp.fields == NULL)) { 96431Sigor@sysoev.ru goto fail; 97431Sigor@sysoev.ru } 98431Sigor@sysoev.ru 99431Sigor@sysoev.ru r->mem_pool = mp; 100431Sigor@sysoev.ru r->content_length_n = -1; 101431Sigor@sysoev.ru r->resp.content_length_n = -1; 102431Sigor@sysoev.ru r->state = &nxt_http_request_init_state; 103431Sigor@sysoev.ru 104431Sigor@sysoev.ru return r; 105431Sigor@sysoev.ru 106431Sigor@sysoev.ru fail: 107431Sigor@sysoev.ru 108431Sigor@sysoev.ru nxt_mp_release(mp); 109431Sigor@sysoev.ru return NULL; 110431Sigor@sysoev.ru } 111431Sigor@sysoev.ru 112431Sigor@sysoev.ru 113431Sigor@sysoev.ru static const nxt_http_request_state_t nxt_http_request_init_state 114431Sigor@sysoev.ru nxt_aligned(64) = 115431Sigor@sysoev.ru { 116431Sigor@sysoev.ru .ready_handler = nxt_http_request_start, 117431Sigor@sysoev.ru .error_handler = nxt_http_request_close_handler, 118431Sigor@sysoev.ru }; 119431Sigor@sysoev.ru 120431Sigor@sysoev.ru 121431Sigor@sysoev.ru static void 122431Sigor@sysoev.ru nxt_http_request_start(nxt_task_t *task, void *obj, void *data) 123431Sigor@sysoev.ru { 124431Sigor@sysoev.ru nxt_http_request_t *r; 125431Sigor@sysoev.ru 126431Sigor@sysoev.ru r = obj; 127431Sigor@sysoev.ru 128431Sigor@sysoev.ru r->state = &nxt_http_request_body_state; 129431Sigor@sysoev.ru 130431Sigor@sysoev.ru nxt_http_request_read_body(task, r); 131431Sigor@sysoev.ru } 132431Sigor@sysoev.ru 133431Sigor@sysoev.ru 134431Sigor@sysoev.ru static const nxt_http_request_state_t nxt_http_request_body_state 135431Sigor@sysoev.ru nxt_aligned(64) = 136431Sigor@sysoev.ru { 137431Sigor@sysoev.ru .ready_handler = nxt_http_app_request, 138431Sigor@sysoev.ru .error_handler = nxt_http_request_close_handler, 139431Sigor@sysoev.ru }; 140431Sigor@sysoev.ru 141431Sigor@sysoev.ru 142431Sigor@sysoev.ru static void 143431Sigor@sysoev.ru nxt_http_app_request(nxt_task_t *task, void *obj, void *data) 144431Sigor@sysoev.ru { 145431Sigor@sysoev.ru nxt_int_t ret; 146431Sigor@sysoev.ru nxt_event_engine_t *engine; 147431Sigor@sysoev.ru nxt_http_request_t *r; 148431Sigor@sysoev.ru nxt_app_parse_ctx_t *ar; 149431Sigor@sysoev.ru 150431Sigor@sysoev.ru r = obj; 151431Sigor@sysoev.ru 152431Sigor@sysoev.ru ar = nxt_mp_zget(r->mem_pool, sizeof(nxt_app_parse_ctx_t)); 153431Sigor@sysoev.ru if (nxt_slow_path(ar == NULL)) { 154431Sigor@sysoev.ru nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 155431Sigor@sysoev.ru return; 156431Sigor@sysoev.ru } 157431Sigor@sysoev.ru 158431Sigor@sysoev.ru ar->request = r; 159431Sigor@sysoev.ru ar->mem_pool = r->mem_pool; 160431Sigor@sysoev.ru nxt_mp_retain(r->mem_pool); 161431Sigor@sysoev.ru 162431Sigor@sysoev.ru // STUB 163431Sigor@sysoev.ru engine = task->thread->engine; 164431Sigor@sysoev.ru ar->timer.task = &engine->task; 165431Sigor@sysoev.ru ar->timer.work_queue = &engine->fast_work_queue; 166431Sigor@sysoev.ru ar->timer.log = engine->task.log; 167431Sigor@sysoev.ru ar->timer.precision = NXT_TIMER_DEFAULT_PRECISION; 168431Sigor@sysoev.ru 169431Sigor@sysoev.ru ar->r.remote.start = nxt_sockaddr_address(r->remote); 170431Sigor@sysoev.ru ar->r.remote.length = r->remote->address_length; 171431Sigor@sysoev.ru 172431Sigor@sysoev.ru /* 173431Sigor@sysoev.ru * TODO: need an application flag to get local address 174431Sigor@sysoev.ru * required by "SERVER_ADDR" in Pyhton and PHP. Not used in Go. 175431Sigor@sysoev.ru */ 176431Sigor@sysoev.ru nxt_http_request_local_addr(task, r); 177431Sigor@sysoev.ru 178431Sigor@sysoev.ru if (nxt_fast_path(r->local != NULL)) { 179431Sigor@sysoev.ru ar->r.local.start = nxt_sockaddr_address(r->local); 180431Sigor@sysoev.ru ar->r.local.length = r->local->address_length; 181431Sigor@sysoev.ru } 182431Sigor@sysoev.ru 183431Sigor@sysoev.ru ar->r.header.fields = r->fields; 184431Sigor@sysoev.ru ar->r.header.done = 1; 185431Sigor@sysoev.ru ar->r.header.version = r->version; 186431Sigor@sysoev.ru 187431Sigor@sysoev.ru if (r->method != NULL) { 188431Sigor@sysoev.ru ar->r.header.method = *r->method; 189431Sigor@sysoev.ru } 190431Sigor@sysoev.ru 191431Sigor@sysoev.ru ar->r.header.target = r->target; 192431Sigor@sysoev.ru 193431Sigor@sysoev.ru if (r->path != NULL) { 194431Sigor@sysoev.ru ar->r.header.path = *r->path; 195431Sigor@sysoev.ru } 196431Sigor@sysoev.ru 197431Sigor@sysoev.ru if (r->args != NULL) { 198431Sigor@sysoev.ru ar->r.header.query = *r->args; 199431Sigor@sysoev.ru } 200431Sigor@sysoev.ru 201431Sigor@sysoev.ru if (r->host != NULL) { 202431Sigor@sysoev.ru ar->r.header.host.length = r->host->value_length; 203431Sigor@sysoev.ru ar->r.header.host.start = r->host->value; 204431Sigor@sysoev.ru } 205431Sigor@sysoev.ru 206431Sigor@sysoev.ru if (r->content_type != NULL) { 207431Sigor@sysoev.ru ar->r.header.content_type.length = r->content_type->value_length; 208431Sigor@sysoev.ru ar->r.header.content_type.start = r->content_type->value; 209431Sigor@sysoev.ru } 210431Sigor@sysoev.ru 211431Sigor@sysoev.ru if (r->content_length != NULL) { 212431Sigor@sysoev.ru ar->r.header.content_length.length = r->content_length->value_length; 213431Sigor@sysoev.ru ar->r.header.content_length.start = r->content_length->value; 214431Sigor@sysoev.ru } 215431Sigor@sysoev.ru 216431Sigor@sysoev.ru if (r->cookie != NULL) { 217431Sigor@sysoev.ru ar->r.header.cookie.length = r->cookie->value_length; 218431Sigor@sysoev.ru ar->r.header.cookie.start = r->cookie->value; 219431Sigor@sysoev.ru } 220431Sigor@sysoev.ru 221431Sigor@sysoev.ru ar->r.body.done = 1; 222431Sigor@sysoev.ru 223431Sigor@sysoev.ru ret = nxt_http_parse_request_init(&ar->resp_parser, r->mem_pool); 224431Sigor@sysoev.ru if (nxt_slow_path(ret != NXT_OK)) { 225431Sigor@sysoev.ru nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 226431Sigor@sysoev.ru return; 227431Sigor@sysoev.ru } 228431Sigor@sysoev.ru 229431Sigor@sysoev.ru nxt_router_process_http_request(task, ar); 230431Sigor@sysoev.ru } 231431Sigor@sysoev.ru 232431Sigor@sysoev.ru 233431Sigor@sysoev.ru void 234431Sigor@sysoev.ru nxt_http_request_read_body(nxt_task_t *task, nxt_http_request_t *r) 235431Sigor@sysoev.ru { 236431Sigor@sysoev.ru if (r->proto.any != NULL) { 237431Sigor@sysoev.ru nxt_http_proto_body_read[r->protocol](task, r); 238431Sigor@sysoev.ru } 239431Sigor@sysoev.ru } 240431Sigor@sysoev.ru 241431Sigor@sysoev.ru 242431Sigor@sysoev.ru void 243431Sigor@sysoev.ru nxt_http_request_local_addr(nxt_task_t *task, nxt_http_request_t *r) 244431Sigor@sysoev.ru { 245431Sigor@sysoev.ru if (r->proto.any != NULL) { 246431Sigor@sysoev.ru nxt_http_proto_local_addr[r->protocol](task, r); 247431Sigor@sysoev.ru } 248431Sigor@sysoev.ru } 249431Sigor@sysoev.ru 250431Sigor@sysoev.ru 251431Sigor@sysoev.ru void 252431Sigor@sysoev.ru nxt_http_request_header_send(nxt_task_t *task, nxt_http_request_t *r) 253431Sigor@sysoev.ru { 254431Sigor@sysoev.ru u_char *p, *end; 255431Sigor@sysoev.ru nxt_http_field_t *server, *content_length; 256431Sigor@sysoev.ru 257431Sigor@sysoev.ru /* 258431Sigor@sysoev.ru * TODO: "Server" and "Content-Length" processing should be moved 259431Sigor@sysoev.ru * to the last header filter. 260431Sigor@sysoev.ru */ 261431Sigor@sysoev.ru 262431Sigor@sysoev.ru server = nxt_list_zero_add(r->resp.fields); 263431Sigor@sysoev.ru if (nxt_slow_path(server == NULL)) { 264431Sigor@sysoev.ru goto fail; 265431Sigor@sysoev.ru } 266431Sigor@sysoev.ru 267431Sigor@sysoev.ru nxt_http_field_set(server, "Server", "unit/" NXT_VERSION); 268431Sigor@sysoev.ru 269431Sigor@sysoev.ru if (r->resp.content_length_n != -1 270431Sigor@sysoev.ru && (r->resp.content_length == NULL || r->resp.content_length->skip)) 271431Sigor@sysoev.ru { 272431Sigor@sysoev.ru content_length = nxt_list_zero_add(r->resp.fields); 273431Sigor@sysoev.ru if (nxt_slow_path(content_length == NULL)) { 274431Sigor@sysoev.ru goto fail; 275431Sigor@sysoev.ru } 276431Sigor@sysoev.ru 277431Sigor@sysoev.ru nxt_http_field_name_set(content_length, "Content-Length"); 278431Sigor@sysoev.ru 279431Sigor@sysoev.ru p = nxt_mp_nget(r->mem_pool, NXT_OFF_T_LEN); 280431Sigor@sysoev.ru if (nxt_slow_path(p == NULL)) { 281431Sigor@sysoev.ru goto fail; 282431Sigor@sysoev.ru } 283431Sigor@sysoev.ru 284431Sigor@sysoev.ru content_length->value = p; 285431Sigor@sysoev.ru end = nxt_sprintf(p, p + NXT_OFF_T_LEN, "%O", r->resp.content_length_n); 286431Sigor@sysoev.ru content_length->value_length = end - p; 287431Sigor@sysoev.ru 288431Sigor@sysoev.ru r->resp.content_length = content_length; 289431Sigor@sysoev.ru } 290431Sigor@sysoev.ru 291431Sigor@sysoev.ru if (r->proto.any != NULL) { 292431Sigor@sysoev.ru nxt_http_proto_header_send[r->protocol](task, r); 293431Sigor@sysoev.ru } 294431Sigor@sysoev.ru 295431Sigor@sysoev.ru return; 296431Sigor@sysoev.ru 297431Sigor@sysoev.ru fail: 298431Sigor@sysoev.ru 299431Sigor@sysoev.ru nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 300431Sigor@sysoev.ru } 301431Sigor@sysoev.ru 302431Sigor@sysoev.ru 303431Sigor@sysoev.ru void 304431Sigor@sysoev.ru nxt_http_request_send(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *out) 305431Sigor@sysoev.ru { 306431Sigor@sysoev.ru if (r->proto.any != NULL) { 307431Sigor@sysoev.ru nxt_http_proto_send[r->protocol](task, r, out); 308431Sigor@sysoev.ru } 309431Sigor@sysoev.ru } 310431Sigor@sysoev.ru 311431Sigor@sysoev.ru 312431Sigor@sysoev.ru nxt_buf_t * 313431Sigor@sysoev.ru nxt_http_request_last_buffer(nxt_task_t *task, nxt_http_request_t *r) 314431Sigor@sysoev.ru { 315431Sigor@sysoev.ru nxt_buf_t *b; 316431Sigor@sysoev.ru 317431Sigor@sysoev.ru b = nxt_buf_mem_alloc(r->mem_pool, 0, 0); 318431Sigor@sysoev.ru 319431Sigor@sysoev.ru if (nxt_fast_path(b != NULL)) { 320431Sigor@sysoev.ru nxt_buf_set_sync(b); 321431Sigor@sysoev.ru nxt_buf_set_last(b); 322431Sigor@sysoev.ru b->completion_handler = nxt_http_request_done; 323431Sigor@sysoev.ru b->parent = r; 324431Sigor@sysoev.ru 325431Sigor@sysoev.ru } else { 326431Sigor@sysoev.ru nxt_http_request_release(task, r); 327431Sigor@sysoev.ru } 328431Sigor@sysoev.ru 329431Sigor@sysoev.ru return b; 330431Sigor@sysoev.ru } 331431Sigor@sysoev.ru 332431Sigor@sysoev.ru 333431Sigor@sysoev.ru static void 334431Sigor@sysoev.ru nxt_http_request_done(nxt_task_t *task, void *obj, void *data) 335431Sigor@sysoev.ru { 336431Sigor@sysoev.ru nxt_http_request_t *r; 337431Sigor@sysoev.ru 338431Sigor@sysoev.ru r = data; 339431Sigor@sysoev.ru 340431Sigor@sysoev.ru nxt_debug(task, "http request done"); 341431Sigor@sysoev.ru 342431Sigor@sysoev.ru nxt_http_request_close_handler(task, r, r->proto.any); 343431Sigor@sysoev.ru } 344431Sigor@sysoev.ru 345431Sigor@sysoev.ru 346431Sigor@sysoev.ru void 347431Sigor@sysoev.ru nxt_http_request_release(nxt_task_t *task, nxt_http_request_t *r) 348431Sigor@sysoev.ru { 349431Sigor@sysoev.ru nxt_debug(task, "http request release"); 350431Sigor@sysoev.ru 351431Sigor@sysoev.ru nxt_work_queue_add(&task->thread->engine->fast_work_queue, 352431Sigor@sysoev.ru nxt_http_request_close_handler, task, r, r->proto.any); 353431Sigor@sysoev.ru } 354431Sigor@sysoev.ru 355431Sigor@sysoev.ru 356431Sigor@sysoev.ru void 357431Sigor@sysoev.ru nxt_http_request_close_handler(nxt_task_t *task, void *obj, void *data) 358431Sigor@sysoev.ru { 359431Sigor@sysoev.ru nxt_http_proto_t proto; 360431Sigor@sysoev.ru nxt_http_request_t *r; 361431Sigor@sysoev.ru nxt_http_proto_close_t handler; 362431Sigor@sysoev.ru 363431Sigor@sysoev.ru r = obj; 364431Sigor@sysoev.ru proto.any = data; 365431Sigor@sysoev.ru 366431Sigor@sysoev.ru nxt_debug(task, "http request close handler"); 367431Sigor@sysoev.ru 368431Sigor@sysoev.ru if (!r->logged) { 369431Sigor@sysoev.ru r->logged = 1; 370431Sigor@sysoev.ru // STUB 371431Sigor@sysoev.ru nxt_debug(task, "http request log: \"%*s \"%V %V %V\" %d\"", 372431Sigor@sysoev.ru r->remote->address_length, nxt_sockaddr_address(r->remote), 373431Sigor@sysoev.ru r->method, &r->target, &r->version, r->status); 374431Sigor@sysoev.ru } 375431Sigor@sysoev.ru 376431Sigor@sysoev.ru handler = nxt_http_proto_close[r->protocol]; 377431Sigor@sysoev.ru 378431Sigor@sysoev.ru r->proto.any = NULL; 379431Sigor@sysoev.ru nxt_mp_release(r->mem_pool); 380431Sigor@sysoev.ru 381431Sigor@sysoev.ru if (proto.any != NULL) { 382431Sigor@sysoev.ru handler(task, proto); 383431Sigor@sysoev.ru } 384431Sigor@sysoev.ru } 385