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