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