1 2/* 3 * Copyright (C) Igor Sysoev 4 * Copyright (C) NGINX, Inc. 5 */ 6 7#include <nxt_router.h> 8#include <nxt_http.h> 9 10 11static nxt_int_t nxt_http_validate_host(nxt_str_t *host, nxt_mp_t *mp); 12static void nxt_http_request_start(nxt_task_t *task, void *obj, void *data); 13static void nxt_http_request_pass(nxt_task_t *task, void *obj, void *data); 14static void nxt_http_request_mem_buf_completion(nxt_task_t *task, void *obj, 15 void *data); 16static void nxt_http_request_done(nxt_task_t *task, void *obj, void *data); 17static void nxt_http_request_close_handler(nxt_task_t *task, void *obj, 18 void *data); 19 20static u_char *nxt_http_date(u_char *buf, nxt_realtime_t *now, struct tm *tm, 21 size_t size, const char *format); 22 23 24static const nxt_http_request_state_t nxt_http_request_init_state; 25static const nxt_http_request_state_t nxt_http_request_body_state; 26 27 28nxt_time_string_t nxt_http_date_cache = { 29 (nxt_atomic_uint_t) -1, 30 nxt_http_date, 31 "%s, %02d %s %4d %02d:%02d:%02d GMT", 32 nxt_length("Wed, 31 Dec 1986 16:40:00 GMT"), 33 NXT_THREAD_TIME_GMT, 34 NXT_THREAD_TIME_SEC, 35}; 36 37 38nxt_int_t 39nxt_http_init(nxt_task_t *task, nxt_runtime_t *rt) 40{ 41 nxt_int_t ret; 42 43 ret = nxt_h1p_init(task, rt); 44 45 if (ret != NXT_OK) { 46 return ret; 47 } 48 49 return nxt_http_response_hash_init(task, rt); 50} 51 52 53nxt_int_t 54nxt_http_request_host(void *ctx, nxt_http_field_t *field, uintptr_t data) 55{ 56 nxt_int_t ret; 57 nxt_str_t host; 58 nxt_http_request_t *r; 59 60 r = ctx; 61 62 if (nxt_slow_path(r->host.start != NULL)) { 63 return NXT_HTTP_BAD_REQUEST; 64 } 65 66 host.length = field->value_length; 67 host.start = field->value; 68 69 ret = nxt_http_validate_host(&host, r->mem_pool); 70 71 if (nxt_fast_path(ret == NXT_OK)) { 72 r->host = host; 73 } 74 75 return ret; 76} 77 78 79static nxt_int_t 80nxt_http_validate_host(nxt_str_t *host, nxt_mp_t *mp) 81{ 82 u_char *h, ch; 83 size_t i, dot_pos, host_length; 84 nxt_bool_t lowcase; 85 86 enum { 87 sw_usual, 88 sw_literal, 89 sw_rest 90 } state; 91 92 dot_pos = host->length; 93 host_length = host->length; 94 95 h = host->start; 96 97 lowcase = 0; 98 state = sw_usual; 99 100 for (i = 0; i < host->length; i++) { 101 ch = h[i]; 102 103 if (ch > ']') { 104 /* Short path. */ 105 continue; 106 } 107 108 switch (ch) { 109 110 case '.': 111 if (dot_pos == i - 1) { 112 return NXT_HTTP_BAD_REQUEST; 113 } 114 115 dot_pos = i; 116 break; 117 118 case ':': 119 if (state == sw_usual) { 120 host_length = i; 121 state = sw_rest; 122 } 123 124 break; 125 126 case '[': 127 if (i == 0) { 128 state = sw_literal; 129 } 130 131 break; 132 133 case ']': 134 if (state == sw_literal) { 135 host_length = i + 1; 136 state = sw_rest; 137 } 138 139 break; 140 141 case '/': 142 return NXT_HTTP_BAD_REQUEST; 143 144 default: 145 if (ch >= 'A' && ch <= 'Z') { 146 lowcase = 1; 147 } 148 149 break; 150 } 151 } 152 153 if (dot_pos == host_length - 1) { 154 host_length--; 155 } 156 157 host->length = host_length; 158 159 if (lowcase) { 160 host->start = nxt_mp_nget(mp, host_length); 161 if (nxt_slow_path(host->start == NULL)) { 162 return NXT_HTTP_INTERNAL_SERVER_ERROR; 163 } 164 165 nxt_memcpy_lowcase(host->start, h, host_length); 166 } 167 168 return NXT_OK; 169} 170 171 172nxt_int_t 173nxt_http_request_field(void *ctx, nxt_http_field_t *field, uintptr_t offset) 174{ 175 nxt_http_request_t *r; 176 177 r = ctx; 178 179 nxt_value_at(nxt_http_field_t *, r, offset) = field; 180 181 return NXT_OK; 182} 183 184 185nxt_int_t 186nxt_http_request_content_length(void *ctx, nxt_http_field_t *field, 187 uintptr_t data) 188{ 189 nxt_off_t n; 190 nxt_http_request_t *r; 191 192 r = ctx; 193 194 if (nxt_fast_path(r->content_length == NULL)) { 195 r->content_length = field; 196 197 n = nxt_off_t_parse(field->value, field->value_length); 198 199 if (nxt_fast_path(n >= 0)) { 200 r->content_length_n = n; 201 return NXT_OK; 202 } 203 } 204 205 return NXT_HTTP_BAD_REQUEST; 206} 207 208 209nxt_http_request_t * 210nxt_http_request_create(nxt_task_t *task) 211{ 212 nxt_mp_t *mp; 213 nxt_buf_t *last; 214 nxt_http_request_t *r; 215 216 mp = nxt_mp_create(1024, 128, 256, 32); 217 if (nxt_slow_path(mp == NULL)) { 218 return NULL; 219 } 220 221 r = nxt_mp_zget(mp, sizeof(nxt_http_request_t)); 222 if (nxt_slow_path(r == NULL)) { 223 goto fail; 224 } 225 226 r->resp.fields = nxt_list_create(mp, 8, sizeof(nxt_http_field_t)); 227 if (nxt_slow_path(r->resp.fields == NULL)) { 228 goto fail; 229 } 230 231 last = nxt_mp_zget(mp, NXT_BUF_SYNC_SIZE); 232 if (nxt_slow_path(last == NULL)) { 233 goto fail; 234 } 235 236 nxt_buf_set_sync(last); 237 nxt_buf_set_last(last); 238 last->completion_handler = nxt_http_request_done; 239 last->parent = r; 240 r->last = last; 241 242 r->mem_pool = mp; 243 r->content_length_n = -1; 244 r->resp.content_length_n = -1; 245 r->state = &nxt_http_request_init_state; 246 247 return r; 248 249fail: 250 251 nxt_mp_release(mp); 252 253 return NULL; 254} 255 256 257static const nxt_http_request_state_t nxt_http_request_init_state 258 nxt_aligned(64) = 259{ 260 .ready_handler = nxt_http_request_start, 261 .error_handler = nxt_http_request_close_handler, 262}; 263 264 265static void 266nxt_http_request_start(nxt_task_t *task, void *obj, void *data) 267{ 268 nxt_http_request_t *r; 269 270 r = obj; 271 272 r->state = &nxt_http_request_body_state; 273 274 nxt_http_request_read_body(task, r); 275} 276 277 278static const nxt_http_request_state_t nxt_http_request_body_state 279 nxt_aligned(64) = 280{ 281 .ready_handler = nxt_http_request_pass, 282 .error_handler = nxt_http_request_close_handler, 283}; 284 285 286static void 287nxt_http_request_pass(nxt_task_t *task, void *obj, void *data) 288{ 289 nxt_http_pass_t *pass; 290 nxt_http_request_t *r; 291 292 r = obj; 293 294 pass = r->conf->socket_conf->pass; 295 296 if (nxt_slow_path(pass == NULL)) { 297 goto fail; 298 } 299 300 for ( ;; ) { 301 nxt_debug(task, "http request route: %V", &pass->name); 302 303 pass = pass->handler(task, r, pass); 304 if (pass == NULL) { 305 break; 306 } 307 308 if (nxt_slow_path(r->pass_count++ == 255)) { 309 goto fail; 310 } 311 } 312 313 return; 314 315fail: 316 317 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 318} 319 320 321nxt_http_pass_t * 322nxt_http_request_application(nxt_task_t *task, nxt_http_request_t *r, 323 nxt_http_pass_t *pass) 324{ 325 nxt_event_engine_t *engine; 326 327 nxt_debug(task, "http request application"); 328 329 nxt_mp_retain(r->mem_pool); 330 331 engine = task->thread->engine; 332 r->timer.task = &engine->task; 333 r->timer.work_queue = &engine->fast_work_queue; 334 r->timer.log = engine->task.log; 335 r->timer.bias = NXT_TIMER_DEFAULT_BIAS; 336 337 /* 338 * TODO: need an application flag to get local address 339 * required by "SERVER_ADDR" in Pyhton and PHP. Not used in Go. 340 */ 341 nxt_http_request_local_addr(task, r); 342 343 if (r->host.length != 0) { 344 r->server_name = r->host; 345 346 } else { 347 nxt_str_set(&r->server_name, "localhost"); 348 } 349 350 nxt_router_process_http_request(task, r, pass->u.application); 351 352 return NULL; 353} 354 355 356void 357nxt_http_request_read_body(nxt_task_t *task, nxt_http_request_t *r) 358{ 359 if (r->proto.any != NULL) { 360 nxt_http_proto_body_read[r->protocol](task, r); 361 } 362} 363 364 365void 366nxt_http_request_local_addr(nxt_task_t *task, nxt_http_request_t *r) 367{ 368 if (r->proto.any != NULL) { 369 nxt_http_proto_local_addr[r->protocol](task, r); 370 } 371} 372 373 374void 375nxt_http_request_header_send(nxt_task_t *task, nxt_http_request_t *r) 376{ 377 u_char *p, *end; 378 nxt_http_field_t *server, *date, *content_length; 379 380 /* 381 * TODO: "Server", "Date", and "Content-Length" processing should be moved 382 * to the last header filter. 383 */ 384 385 server = nxt_list_zero_add(r->resp.fields); 386 if (nxt_slow_path(server == NULL)) { 387 goto fail; 388 } 389 390 nxt_http_field_set(server, "Server", NXT_SERVER); 391 392 if (r->resp.date == NULL) { 393 date = nxt_list_zero_add(r->resp.fields); 394 if (nxt_slow_path(date == NULL)) { 395 goto fail; 396 } 397 398 nxt_http_field_name_set(date, "Date"); 399 400 p = nxt_mp_nget(r->mem_pool, nxt_http_date_cache.size); 401 if (nxt_slow_path(p == NULL)) { 402 goto fail; 403 } 404 405 (void) nxt_thread_time_string(task->thread, &nxt_http_date_cache, p); 406 407 date->value = p; 408 date->value_length = nxt_http_date_cache.size; 409 410 r->resp.date = date; 411 } 412 413 if (r->resp.content_length_n != -1 414 && (r->resp.content_length == NULL || r->resp.content_length->skip)) 415 { 416 content_length = nxt_list_zero_add(r->resp.fields); 417 if (nxt_slow_path(content_length == NULL)) { 418 goto fail; 419 } 420 421 nxt_http_field_name_set(content_length, "Content-Length"); 422 423 p = nxt_mp_nget(r->mem_pool, NXT_OFF_T_LEN); 424 if (nxt_slow_path(p == NULL)) { 425 goto fail; 426 } 427 428 content_length->value = p; 429 end = nxt_sprintf(p, p + NXT_OFF_T_LEN, "%O", r->resp.content_length_n); 430 content_length->value_length = end - p; 431 432 r->resp.content_length = content_length; 433 } 434 435 if (r->proto.any != NULL) { 436 nxt_http_proto_header_send[r->protocol](task, r); 437 } 438 439 return; 440 441fail: 442 443 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 444} 445 446 447void 448nxt_http_request_send(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *out) 449{ 450 if (r->proto.any != NULL) { 451 nxt_http_proto_send[r->protocol](task, r, out); 452 } 453} 454 455 456nxt_buf_t * 457nxt_http_buf_mem(nxt_task_t *task, nxt_http_request_t *r, size_t size) 458{ 459 nxt_buf_t *b; 460 461 b = nxt_buf_mem_alloc(r->mem_pool, size, 0); 462 if (nxt_fast_path(b != NULL)) { 463 b->completion_handler = nxt_http_request_mem_buf_completion; 464 b->parent = r; 465 nxt_mp_retain(r->mem_pool); 466 467 } else { 468 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 469 } 470 471 return b; 472} 473 474 475static void 476nxt_http_request_mem_buf_completion(nxt_task_t *task, void *obj, void *data) 477{ 478 nxt_buf_t *b; 479 nxt_http_request_t *r; 480 481 b = obj; 482 r = data; 483 484 nxt_mp_free(r->mem_pool, b); 485 486 nxt_mp_release(r->mem_pool); 487} 488 489 490nxt_buf_t * 491nxt_http_buf_last(nxt_http_request_t *r) 492{ 493 nxt_buf_t *last; 494 495 last = r->last; 496 r->last = NULL; 497 498 return last; 499} 500 501 502static void 503nxt_http_request_done(nxt_task_t *task, void *obj, void *data) 504{ 505 nxt_http_request_t *r; 506 507 r = data; 508 509 nxt_debug(task, "http request done"); 510 511 nxt_http_request_close_handler(task, r, r->proto.any); 512} 513 514 515void 516nxt_http_request_error_handler(nxt_task_t *task, void *obj, void *data) 517{ 518 nxt_http_proto_t proto; 519 nxt_http_request_t *r; 520 521 r = obj; 522 proto.any = data; 523 524 nxt_debug(task, "http request error handler"); 525
| 1 2/* 3 * Copyright (C) Igor Sysoev 4 * Copyright (C) NGINX, Inc. 5 */ 6 7#include <nxt_router.h> 8#include <nxt_http.h> 9 10 11static nxt_int_t nxt_http_validate_host(nxt_str_t *host, nxt_mp_t *mp); 12static void nxt_http_request_start(nxt_task_t *task, void *obj, void *data); 13static void nxt_http_request_pass(nxt_task_t *task, void *obj, void *data); 14static void nxt_http_request_mem_buf_completion(nxt_task_t *task, void *obj, 15 void *data); 16static void nxt_http_request_done(nxt_task_t *task, void *obj, void *data); 17static void nxt_http_request_close_handler(nxt_task_t *task, void *obj, 18 void *data); 19 20static u_char *nxt_http_date(u_char *buf, nxt_realtime_t *now, struct tm *tm, 21 size_t size, const char *format); 22 23 24static const nxt_http_request_state_t nxt_http_request_init_state; 25static const nxt_http_request_state_t nxt_http_request_body_state; 26 27 28nxt_time_string_t nxt_http_date_cache = { 29 (nxt_atomic_uint_t) -1, 30 nxt_http_date, 31 "%s, %02d %s %4d %02d:%02d:%02d GMT", 32 nxt_length("Wed, 31 Dec 1986 16:40:00 GMT"), 33 NXT_THREAD_TIME_GMT, 34 NXT_THREAD_TIME_SEC, 35}; 36 37 38nxt_int_t 39nxt_http_init(nxt_task_t *task, nxt_runtime_t *rt) 40{ 41 nxt_int_t ret; 42 43 ret = nxt_h1p_init(task, rt); 44 45 if (ret != NXT_OK) { 46 return ret; 47 } 48 49 return nxt_http_response_hash_init(task, rt); 50} 51 52 53nxt_int_t 54nxt_http_request_host(void *ctx, nxt_http_field_t *field, uintptr_t data) 55{ 56 nxt_int_t ret; 57 nxt_str_t host; 58 nxt_http_request_t *r; 59 60 r = ctx; 61 62 if (nxt_slow_path(r->host.start != NULL)) { 63 return NXT_HTTP_BAD_REQUEST; 64 } 65 66 host.length = field->value_length; 67 host.start = field->value; 68 69 ret = nxt_http_validate_host(&host, r->mem_pool); 70 71 if (nxt_fast_path(ret == NXT_OK)) { 72 r->host = host; 73 } 74 75 return ret; 76} 77 78 79static nxt_int_t 80nxt_http_validate_host(nxt_str_t *host, nxt_mp_t *mp) 81{ 82 u_char *h, ch; 83 size_t i, dot_pos, host_length; 84 nxt_bool_t lowcase; 85 86 enum { 87 sw_usual, 88 sw_literal, 89 sw_rest 90 } state; 91 92 dot_pos = host->length; 93 host_length = host->length; 94 95 h = host->start; 96 97 lowcase = 0; 98 state = sw_usual; 99 100 for (i = 0; i < host->length; i++) { 101 ch = h[i]; 102 103 if (ch > ']') { 104 /* Short path. */ 105 continue; 106 } 107 108 switch (ch) { 109 110 case '.': 111 if (dot_pos == i - 1) { 112 return NXT_HTTP_BAD_REQUEST; 113 } 114 115 dot_pos = i; 116 break; 117 118 case ':': 119 if (state == sw_usual) { 120 host_length = i; 121 state = sw_rest; 122 } 123 124 break; 125 126 case '[': 127 if (i == 0) { 128 state = sw_literal; 129 } 130 131 break; 132 133 case ']': 134 if (state == sw_literal) { 135 host_length = i + 1; 136 state = sw_rest; 137 } 138 139 break; 140 141 case '/': 142 return NXT_HTTP_BAD_REQUEST; 143 144 default: 145 if (ch >= 'A' && ch <= 'Z') { 146 lowcase = 1; 147 } 148 149 break; 150 } 151 } 152 153 if (dot_pos == host_length - 1) { 154 host_length--; 155 } 156 157 host->length = host_length; 158 159 if (lowcase) { 160 host->start = nxt_mp_nget(mp, host_length); 161 if (nxt_slow_path(host->start == NULL)) { 162 return NXT_HTTP_INTERNAL_SERVER_ERROR; 163 } 164 165 nxt_memcpy_lowcase(host->start, h, host_length); 166 } 167 168 return NXT_OK; 169} 170 171 172nxt_int_t 173nxt_http_request_field(void *ctx, nxt_http_field_t *field, uintptr_t offset) 174{ 175 nxt_http_request_t *r; 176 177 r = ctx; 178 179 nxt_value_at(nxt_http_field_t *, r, offset) = field; 180 181 return NXT_OK; 182} 183 184 185nxt_int_t 186nxt_http_request_content_length(void *ctx, nxt_http_field_t *field, 187 uintptr_t data) 188{ 189 nxt_off_t n; 190 nxt_http_request_t *r; 191 192 r = ctx; 193 194 if (nxt_fast_path(r->content_length == NULL)) { 195 r->content_length = field; 196 197 n = nxt_off_t_parse(field->value, field->value_length); 198 199 if (nxt_fast_path(n >= 0)) { 200 r->content_length_n = n; 201 return NXT_OK; 202 } 203 } 204 205 return NXT_HTTP_BAD_REQUEST; 206} 207 208 209nxt_http_request_t * 210nxt_http_request_create(nxt_task_t *task) 211{ 212 nxt_mp_t *mp; 213 nxt_buf_t *last; 214 nxt_http_request_t *r; 215 216 mp = nxt_mp_create(1024, 128, 256, 32); 217 if (nxt_slow_path(mp == NULL)) { 218 return NULL; 219 } 220 221 r = nxt_mp_zget(mp, sizeof(nxt_http_request_t)); 222 if (nxt_slow_path(r == NULL)) { 223 goto fail; 224 } 225 226 r->resp.fields = nxt_list_create(mp, 8, sizeof(nxt_http_field_t)); 227 if (nxt_slow_path(r->resp.fields == NULL)) { 228 goto fail; 229 } 230 231 last = nxt_mp_zget(mp, NXT_BUF_SYNC_SIZE); 232 if (nxt_slow_path(last == NULL)) { 233 goto fail; 234 } 235 236 nxt_buf_set_sync(last); 237 nxt_buf_set_last(last); 238 last->completion_handler = nxt_http_request_done; 239 last->parent = r; 240 r->last = last; 241 242 r->mem_pool = mp; 243 r->content_length_n = -1; 244 r->resp.content_length_n = -1; 245 r->state = &nxt_http_request_init_state; 246 247 return r; 248 249fail: 250 251 nxt_mp_release(mp); 252 253 return NULL; 254} 255 256 257static const nxt_http_request_state_t nxt_http_request_init_state 258 nxt_aligned(64) = 259{ 260 .ready_handler = nxt_http_request_start, 261 .error_handler = nxt_http_request_close_handler, 262}; 263 264 265static void 266nxt_http_request_start(nxt_task_t *task, void *obj, void *data) 267{ 268 nxt_http_request_t *r; 269 270 r = obj; 271 272 r->state = &nxt_http_request_body_state; 273 274 nxt_http_request_read_body(task, r); 275} 276 277 278static const nxt_http_request_state_t nxt_http_request_body_state 279 nxt_aligned(64) = 280{ 281 .ready_handler = nxt_http_request_pass, 282 .error_handler = nxt_http_request_close_handler, 283}; 284 285 286static void 287nxt_http_request_pass(nxt_task_t *task, void *obj, void *data) 288{ 289 nxt_http_pass_t *pass; 290 nxt_http_request_t *r; 291 292 r = obj; 293 294 pass = r->conf->socket_conf->pass; 295 296 if (nxt_slow_path(pass == NULL)) { 297 goto fail; 298 } 299 300 for ( ;; ) { 301 nxt_debug(task, "http request route: %V", &pass->name); 302 303 pass = pass->handler(task, r, pass); 304 if (pass == NULL) { 305 break; 306 } 307 308 if (nxt_slow_path(r->pass_count++ == 255)) { 309 goto fail; 310 } 311 } 312 313 return; 314 315fail: 316 317 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 318} 319 320 321nxt_http_pass_t * 322nxt_http_request_application(nxt_task_t *task, nxt_http_request_t *r, 323 nxt_http_pass_t *pass) 324{ 325 nxt_event_engine_t *engine; 326 327 nxt_debug(task, "http request application"); 328 329 nxt_mp_retain(r->mem_pool); 330 331 engine = task->thread->engine; 332 r->timer.task = &engine->task; 333 r->timer.work_queue = &engine->fast_work_queue; 334 r->timer.log = engine->task.log; 335 r->timer.bias = NXT_TIMER_DEFAULT_BIAS; 336 337 /* 338 * TODO: need an application flag to get local address 339 * required by "SERVER_ADDR" in Pyhton and PHP. Not used in Go. 340 */ 341 nxt_http_request_local_addr(task, r); 342 343 if (r->host.length != 0) { 344 r->server_name = r->host; 345 346 } else { 347 nxt_str_set(&r->server_name, "localhost"); 348 } 349 350 nxt_router_process_http_request(task, r, pass->u.application); 351 352 return NULL; 353} 354 355 356void 357nxt_http_request_read_body(nxt_task_t *task, nxt_http_request_t *r) 358{ 359 if (r->proto.any != NULL) { 360 nxt_http_proto_body_read[r->protocol](task, r); 361 } 362} 363 364 365void 366nxt_http_request_local_addr(nxt_task_t *task, nxt_http_request_t *r) 367{ 368 if (r->proto.any != NULL) { 369 nxt_http_proto_local_addr[r->protocol](task, r); 370 } 371} 372 373 374void 375nxt_http_request_header_send(nxt_task_t *task, nxt_http_request_t *r) 376{ 377 u_char *p, *end; 378 nxt_http_field_t *server, *date, *content_length; 379 380 /* 381 * TODO: "Server", "Date", and "Content-Length" processing should be moved 382 * to the last header filter. 383 */ 384 385 server = nxt_list_zero_add(r->resp.fields); 386 if (nxt_slow_path(server == NULL)) { 387 goto fail; 388 } 389 390 nxt_http_field_set(server, "Server", NXT_SERVER); 391 392 if (r->resp.date == NULL) { 393 date = nxt_list_zero_add(r->resp.fields); 394 if (nxt_slow_path(date == NULL)) { 395 goto fail; 396 } 397 398 nxt_http_field_name_set(date, "Date"); 399 400 p = nxt_mp_nget(r->mem_pool, nxt_http_date_cache.size); 401 if (nxt_slow_path(p == NULL)) { 402 goto fail; 403 } 404 405 (void) nxt_thread_time_string(task->thread, &nxt_http_date_cache, p); 406 407 date->value = p; 408 date->value_length = nxt_http_date_cache.size; 409 410 r->resp.date = date; 411 } 412 413 if (r->resp.content_length_n != -1 414 && (r->resp.content_length == NULL || r->resp.content_length->skip)) 415 { 416 content_length = nxt_list_zero_add(r->resp.fields); 417 if (nxt_slow_path(content_length == NULL)) { 418 goto fail; 419 } 420 421 nxt_http_field_name_set(content_length, "Content-Length"); 422 423 p = nxt_mp_nget(r->mem_pool, NXT_OFF_T_LEN); 424 if (nxt_slow_path(p == NULL)) { 425 goto fail; 426 } 427 428 content_length->value = p; 429 end = nxt_sprintf(p, p + NXT_OFF_T_LEN, "%O", r->resp.content_length_n); 430 content_length->value_length = end - p; 431 432 r->resp.content_length = content_length; 433 } 434 435 if (r->proto.any != NULL) { 436 nxt_http_proto_header_send[r->protocol](task, r); 437 } 438 439 return; 440 441fail: 442 443 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 444} 445 446 447void 448nxt_http_request_send(nxt_task_t *task, nxt_http_request_t *r, nxt_buf_t *out) 449{ 450 if (r->proto.any != NULL) { 451 nxt_http_proto_send[r->protocol](task, r, out); 452 } 453} 454 455 456nxt_buf_t * 457nxt_http_buf_mem(nxt_task_t *task, nxt_http_request_t *r, size_t size) 458{ 459 nxt_buf_t *b; 460 461 b = nxt_buf_mem_alloc(r->mem_pool, size, 0); 462 if (nxt_fast_path(b != NULL)) { 463 b->completion_handler = nxt_http_request_mem_buf_completion; 464 b->parent = r; 465 nxt_mp_retain(r->mem_pool); 466 467 } else { 468 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 469 } 470 471 return b; 472} 473 474 475static void 476nxt_http_request_mem_buf_completion(nxt_task_t *task, void *obj, void *data) 477{ 478 nxt_buf_t *b; 479 nxt_http_request_t *r; 480 481 b = obj; 482 r = data; 483 484 nxt_mp_free(r->mem_pool, b); 485 486 nxt_mp_release(r->mem_pool); 487} 488 489 490nxt_buf_t * 491nxt_http_buf_last(nxt_http_request_t *r) 492{ 493 nxt_buf_t *last; 494 495 last = r->last; 496 r->last = NULL; 497 498 return last; 499} 500 501 502static void 503nxt_http_request_done(nxt_task_t *task, void *obj, void *data) 504{ 505 nxt_http_request_t *r; 506 507 r = data; 508 509 nxt_debug(task, "http request done"); 510 511 nxt_http_request_close_handler(task, r, r->proto.any); 512} 513 514 515void 516nxt_http_request_error_handler(nxt_task_t *task, void *obj, void *data) 517{ 518 nxt_http_proto_t proto; 519 nxt_http_request_t *r; 520 521 r = obj; 522 proto.any = data; 523 524 nxt_debug(task, "http request error handler"); 525
|
526 if (proto.any != NULL) { 527 nxt_http_proto_discard[r->protocol](task, r, nxt_http_buf_last(r)); 528 } 529} 530 531 532static void 533nxt_http_request_close_handler(nxt_task_t *task, void *obj, void *data) 534{ 535 nxt_http_proto_t proto; 536 nxt_http_request_t *r; 537 nxt_http_proto_close_t handler; 538 nxt_socket_conf_joint_t *conf; 539 nxt_router_access_log_t *access_log; 540 541 r = obj; 542 proto.any = data; 543 544 nxt_debug(task, "http request close handler"); 545 546 conf = r->conf; 547 548 if (!r->logged) { 549 r->logged = 1; 550 551 access_log = conf->socket_conf->router_conf->access_log; 552 553 if (access_log != NULL) { 554 access_log->handler(task, r, access_log); 555 } 556 } 557 558 handler = nxt_http_proto_close[r->protocol]; 559 560 r->proto.any = NULL; 561 nxt_mp_release(r->mem_pool); 562 563 if (proto.any != NULL) { 564 handler(task, proto, conf); 565 } 566} 567 568 569static u_char * 570nxt_http_date(u_char *buf, nxt_realtime_t *now, struct tm *tm, size_t size, 571 const char *format) 572{ 573 static const char *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", 574 "Sat" }; 575 576 static const char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", 577 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; 578 579 return nxt_sprintf(buf, buf + size, format, 580 week[tm->tm_wday], tm->tm_mday, 581 month[tm->tm_mon], tm->tm_year + 1900, 582 tm->tm_hour, tm->tm_min, tm->tm_sec); 583}
| 528 if (proto.any != NULL) { 529 nxt_http_proto_discard[r->protocol](task, r, nxt_http_buf_last(r)); 530 } 531} 532 533 534static void 535nxt_http_request_close_handler(nxt_task_t *task, void *obj, void *data) 536{ 537 nxt_http_proto_t proto; 538 nxt_http_request_t *r; 539 nxt_http_proto_close_t handler; 540 nxt_socket_conf_joint_t *conf; 541 nxt_router_access_log_t *access_log; 542 543 r = obj; 544 proto.any = data; 545 546 nxt_debug(task, "http request close handler"); 547 548 conf = r->conf; 549 550 if (!r->logged) { 551 r->logged = 1; 552 553 access_log = conf->socket_conf->router_conf->access_log; 554 555 if (access_log != NULL) { 556 access_log->handler(task, r, access_log); 557 } 558 } 559 560 handler = nxt_http_proto_close[r->protocol]; 561 562 r->proto.any = NULL; 563 nxt_mp_release(r->mem_pool); 564 565 if (proto.any != NULL) { 566 handler(task, proto, conf); 567 } 568} 569 570 571static u_char * 572nxt_http_date(u_char *buf, nxt_realtime_t *now, struct tm *tm, size_t size, 573 const char *format) 574{ 575 static const char *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", 576 "Sat" }; 577 578 static const char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", 579 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; 580 581 return nxt_sprintf(buf, buf + size, format, 582 week[tm->tm_wday], tm->tm_mday, 583 month[tm->tm_mon], tm->tm_year + 1900, 584 tm->tm_hour, tm->tm_min, tm->tm_sec); 585}
|