Deleted
Added
nxt_http_static.c (1923:9f268a8a1a2f) | nxt_http_static.c (1959:45b25ffb2e8c) |
---|---|
1 2/* 3 * Copyright (C) NGINX, Inc. 4 */ 5 6#include <nxt_router.h> 7#include <nxt_http.h> 8 9 10typedef struct { | 1 2/* 3 * Copyright (C) NGINX, Inc. 4 */ 5 6#include <nxt_router.h> 7#include <nxt_http.h> 8 9 10typedef struct { |
11 nxt_str_t share; 12 nxt_str_t chroot; 13 nxt_uint_t resolve; 14 nxt_http_route_rule_t *types; | 11 nxt_str_t share; 12#if (NXT_HAVE_OPENAT2) 13 nxt_var_t *chroot; 14 nxt_uint_t resolve; 15#endif 16 nxt_http_route_rule_t *types; 17 uint8_t is_const; /* 1 bit */ |
15} nxt_http_static_conf_t; 16 17 | 18} nxt_http_static_conf_t; 19 20 |
21typedef struct { 22 nxt_http_action_t *action; 23#if (NXT_HAVE_OPENAT2) 24 nxt_str_t chroot; 25#endif 26 uint8_t need_body; /* 1 bit */ 27} nxt_http_static_ctx_t; 28 29 |
|
18#define NXT_HTTP_STATIC_BUF_COUNT 2 19#define NXT_HTTP_STATIC_BUF_SIZE (128 * 1024) 20 21 22static nxt_http_action_t *nxt_http_static(nxt_task_t *task, 23 nxt_http_request_t *r, nxt_http_action_t *action); | 30#define NXT_HTTP_STATIC_BUF_COUNT 2 31#define NXT_HTTP_STATIC_BUF_SIZE (128 * 1024) 32 33 34static nxt_http_action_t *nxt_http_static(nxt_task_t *task, 35 nxt_http_request_t *r, nxt_http_action_t *action); |
36static void nxt_http_static_send_ready(nxt_task_t *task, void *obj, void *data); 37static void nxt_http_static_var_error(nxt_task_t *task, void *obj, void *data); 38#if (NXT_HAVE_OPENAT2) 39static u_char *nxt_http_static_chroot_match(u_char *chr, u_char *shr); 40#endif |
|
24static void nxt_http_static_extract_extension(nxt_str_t *path, 25 nxt_str_t *exten); 26static void nxt_http_static_body_handler(nxt_task_t *task, void *obj, 27 void *data); 28static void nxt_http_static_buf_completion(nxt_task_t *task, void *obj, 29 void *data); 30 31static nxt_int_t nxt_http_static_mtypes_hash_test(nxt_lvlhsh_query_t *lhq, --- 25 unchanged lines hidden (view full) --- 57 58 nxt_conf_get_string(acf->share, &value); 59 60 str = nxt_str_dup(mp, &conf->share, &value); 61 if (nxt_slow_path(str == NULL)) { 62 return NXT_ERROR; 63 } 64 | 41static void nxt_http_static_extract_extension(nxt_str_t *path, 42 nxt_str_t *exten); 43static void nxt_http_static_body_handler(nxt_task_t *task, void *obj, 44 void *data); 45static void nxt_http_static_buf_completion(nxt_task_t *task, void *obj, 46 void *data); 47 48static nxt_int_t nxt_http_static_mtypes_hash_test(nxt_lvlhsh_query_t *lhq, --- 25 unchanged lines hidden (view full) --- 74 75 nxt_conf_get_string(acf->share, &value); 76 77 str = nxt_str_dup(mp, &conf->share, &value); 78 if (nxt_slow_path(str == NULL)) { 79 return NXT_ERROR; 80 } 81 |
82 conf->is_const = 1; 83 |
|
65#if (NXT_HAVE_OPENAT2) 66 if (acf->chroot.length > 0) { | 84#if (NXT_HAVE_OPENAT2) 85 if (acf->chroot.length > 0) { |
67 u_char *p; 68 nxt_str_t slash; 69 70 if (acf->chroot.start[acf->chroot.length - 1] != '/') { 71 nxt_str_set(&slash, "/"); 72 73 } else { 74 nxt_str_set(&slash, ""); | 86 if (nxt_is_var(&acf->chroot)) { 87 conf->is_const = 0; |
75 } 76 | 88 } 89 |
77 value.length = acf->chroot.length + slash.length; 78 79 value.start = nxt_mp_alloc(mp, value.length + 1); 80 if (nxt_slow_path(value.start == NULL)) { | 90 conf->chroot = nxt_var_compile(&acf->chroot, mp, 1); 91 if (nxt_slow_path(conf->chroot == NULL)) { |
81 return NXT_ERROR; 82 } | 92 return NXT_ERROR; 93 } |
83 84 p = value.start; 85 p = nxt_cpymem(p, acf->chroot.start, acf->chroot.length); 86 p = nxt_cpymem(p, slash.start, slash.length); 87 *p = '\0'; 88 89 conf->chroot = value; 90 conf->resolve |= RESOLVE_IN_ROOT; | |
91 } 92 93 if (acf->follow_symlinks != NULL 94 && !nxt_conf_get_boolean(acf->follow_symlinks)) 95 { 96 conf->resolve |= RESOLVE_NO_SYMLINKS; 97 } 98 --- 24 unchanged lines hidden (view full) --- 123 return NXT_OK; 124} 125 126 127static nxt_http_action_t * 128nxt_http_static(nxt_task_t *task, nxt_http_request_t *r, 129 nxt_http_action_t *action) 130{ | 94 } 95 96 if (acf->follow_symlinks != NULL 97 && !nxt_conf_get_boolean(acf->follow_symlinks)) 98 { 99 conf->resolve |= RESOLVE_NO_SYMLINKS; 100 } 101 --- 24 unchanged lines hidden (view full) --- 126 return NXT_OK; 127} 128 129 130static nxt_http_action_t * 131nxt_http_static(nxt_task_t *task, nxt_http_request_t *r, 132 nxt_http_action_t *action) 133{ |
131 size_t length, encode; 132 u_char *p, *fname; 133 struct tm tm; 134 nxt_buf_t *fb; | |
135 nxt_int_t ret; | 134 nxt_int_t ret; |
136 nxt_str_t index, exten, *mtype, *chroot; 137 nxt_uint_t level; | |
138 nxt_bool_t need_body; | 135 nxt_bool_t need_body; |
139 nxt_file_t *f, file; 140 nxt_file_info_t fi; 141 nxt_http_field_t *field; 142 nxt_http_status_t status; 143 nxt_router_conf_t *rtcf; 144 nxt_work_handler_t body_handler; | 136 nxt_http_static_ctx_t *ctx; |
145 nxt_http_static_conf_t *conf; 146 | 137 nxt_http_static_conf_t *conf; 138 |
147 conf = action->u.conf; 148 149 nxt_debug(task, "http static: \"%V\"", &conf->share); 150 | |
151 if (nxt_slow_path(!nxt_str_eq(r->method, "GET", 3))) { 152 153 if (!nxt_str_eq(r->method, "HEAD", 4)) { 154 if (action->fallback != NULL) { 155 return action->fallback; 156 } 157 158 nxt_http_request_error(task, r, NXT_HTTP_METHOD_NOT_ALLOWED); 159 return NULL; 160 } 161 162 need_body = 0; 163 164 } else { 165 need_body = 1; 166 } 167 | 139 if (nxt_slow_path(!nxt_str_eq(r->method, "GET", 3))) { 140 141 if (!nxt_str_eq(r->method, "HEAD", 4)) { 142 if (action->fallback != NULL) { 143 return action->fallback; 144 } 145 146 nxt_http_request_error(task, r, NXT_HTTP_METHOD_NOT_ALLOWED); 147 return NULL; 148 } 149 150 need_body = 0; 151 152 } else { 153 need_body = 1; 154 } 155 |
156 conf = action->u.conf; 157 158#if (NXT_DEBUG && NXT_HAVE_OPENAT2) 159 nxt_str_t chr; 160 161 if (conf->chroot != NULL) { 162 nxt_var_raw(conf->chroot, &chr); 163 164 } else { 165 nxt_str_set(&chr, ""); 166 } 167 168 nxt_debug(task, "http static: \"%V\" (chroot: \"%V\")", &conf->share, &chr); 169 170#else 171 nxt_debug(task, "http static: \"%V\"", &conf->share); 172#endif 173 174 ctx = nxt_mp_zget(r->mem_pool, sizeof(nxt_http_static_ctx_t)); 175 if (nxt_slow_path(ctx == NULL)) { 176 goto fail; 177 } 178 179 ctx->action = action; 180 ctx->need_body = need_body; 181 182 if (conf->is_const) { 183#if (NXT_HAVE_OPENAT2) 184 if (conf->chroot != NULL) { 185 nxt_var_raw(conf->chroot, &ctx->chroot); 186 } 187#endif 188 189 nxt_http_static_send_ready(task, r, ctx); 190 191 } else { 192 ret = nxt_var_query_init(&r->var_query, r, r->mem_pool); 193 if (nxt_slow_path(ret != NXT_OK)) { 194 goto fail; 195 } 196 197#if (NXT_HAVE_OPENAT2) 198 nxt_var_query(task, r->var_query, conf->chroot, &ctx->chroot); 199#endif 200 201 nxt_var_query_resolve(task, r->var_query, ctx, 202 nxt_http_static_send_ready, 203 nxt_http_static_var_error); 204 } 205 206 return NULL; 207 208fail: 209 210 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 211 return NULL; 212} 213 214 215static void 216nxt_http_static_send_ready(nxt_task_t *task, void *obj, void *data) 217{ 218 size_t length, encode; 219 u_char *p, *fname; 220 struct tm tm; 221 nxt_buf_t *fb; 222 nxt_int_t ret; 223 nxt_str_t index, exten, *mtype; 224 nxt_uint_t level; 225 nxt_file_t *f, file; 226 nxt_file_info_t fi; 227 nxt_http_field_t *field; 228 nxt_http_status_t status; 229 nxt_router_conf_t *rtcf; 230 nxt_http_action_t *action; 231 nxt_http_request_t *r; 232 nxt_work_handler_t body_handler; 233 nxt_http_static_ctx_t *ctx; 234 nxt_http_static_conf_t *conf; 235 236 r = obj; 237 ctx = data; 238 action = ctx->action; 239 conf = action->u.conf; 240 |
|
168 if (r->path->start[r->path->length - 1] == '/') { 169 /* TODO: dynamic index setting. */ 170 nxt_str_set(&index, "index.html"); 171 nxt_str_set(&exten, ".html"); 172 173 } else { 174 nxt_str_set(&index, ""); 175 nxt_str_null(&exten); 176 } 177 178 f = NULL; | 241 if (r->path->start[r->path->length - 1] == '/') { 242 /* TODO: dynamic index setting. */ 243 nxt_str_set(&index, "index.html"); 244 nxt_str_set(&exten, ".html"); 245 246 } else { 247 nxt_str_set(&index, ""); 248 nxt_str_null(&exten); 249 } 250 251 f = NULL; |
252 status = NXT_HTTP_INTERNAL_SERVER_ERROR; |
|
179 180 rtcf = r->conf->socket_conf->router_conf; 181 182 mtype = NULL; 183 184 if (conf->types != NULL && exten.start == NULL) { 185 nxt_http_static_extract_extension(r->path, &exten); 186 mtype = nxt_http_static_mtype_get(&rtcf->mtypes_hash, &exten); 187 188 ret = nxt_http_route_test_rule(r, conf->types, mtype->start, 189 mtype->length); 190 if (nxt_slow_path(ret == NXT_ERROR)) { 191 goto fail; 192 } 193 194 if (ret == 0) { | 253 254 rtcf = r->conf->socket_conf->router_conf; 255 256 mtype = NULL; 257 258 if (conf->types != NULL && exten.start == NULL) { 259 nxt_http_static_extract_extension(r->path, &exten); 260 mtype = nxt_http_static_mtype_get(&rtcf->mtypes_hash, &exten); 261 262 ret = nxt_http_route_test_rule(r, conf->types, mtype->start, 263 mtype->length); 264 if (nxt_slow_path(ret == NXT_ERROR)) { 265 goto fail; 266 } 267 268 if (ret == 0) { |
195 if (action->fallback != NULL) { 196 return action->fallback; 197 } 198 199 nxt_http_request_error(task, r, NXT_HTTP_FORBIDDEN); 200 return NULL; | 269 status = NXT_HTTP_FORBIDDEN; 270 goto fail; |
201 } 202 } 203 204 length = conf->share.length + r->path->length + index.length; 205 206 fname = nxt_mp_nget(r->mem_pool, length + 1); 207 if (nxt_slow_path(fname == NULL)) { 208 goto fail; --- 4 unchanged lines hidden (view full) --- 213 p = nxt_cpymem(p, r->path->start, r->path->length); 214 p = nxt_cpymem(p, index.start, index.length); 215 *p = '\0'; 216 217 nxt_memzero(&file, sizeof(nxt_file_t)); 218 219 file.name = fname; 220 | 271 } 272 } 273 274 length = conf->share.length + r->path->length + index.length; 275 276 fname = nxt_mp_nget(r->mem_pool, length + 1); 277 if (nxt_slow_path(fname == NULL)) { 278 goto fail; --- 4 unchanged lines hidden (view full) --- 283 p = nxt_cpymem(p, r->path->start, r->path->length); 284 p = nxt_cpymem(p, index.start, index.length); 285 *p = '\0'; 286 287 nxt_memzero(&file, sizeof(nxt_file_t)); 288 289 file.name = fname; 290 |
221 chroot = &conf->chroot; 222 | |
223#if (NXT_HAVE_OPENAT2) | 291#if (NXT_HAVE_OPENAT2) |
224 if (conf->resolve != 0) { | 292 if (conf->resolve != 0 || ctx->chroot.length > 0) { 293 nxt_str_t *chr; 294 nxt_uint_t resolve; |
225 | 295 |
226 if (chroot->length > 0) { 227 file.name = chroot->start; | 296 resolve = conf->resolve; 297 chr = &ctx->chroot; |
228 | 298 |
229 if (length > chroot->length 230 && nxt_memcmp(fname, chroot->start, chroot->length) == 0) 231 { 232 fname += chroot->length; | 299 if (chr->length > 0) { 300 resolve |= RESOLVE_IN_ROOT; 301 302 fname = nxt_http_static_chroot_match(chr->start, file.name); 303 304 if (fname != NULL) { 305 file.name = chr->start; |
233 ret = nxt_file_open(task, &file, NXT_FILE_SEARCH, NXT_FILE_OPEN, 234 0); 235 236 } else { 237 file.error = NXT_EACCES; 238 ret = NXT_ERROR; 239 } 240 --- 10 unchanged lines hidden (view full) --- 251 if (nxt_fast_path(ret == NXT_OK)) { 252 nxt_file_t af; 253 254 af = file; 255 nxt_memzero(&file, sizeof(nxt_file_t)); 256 file.name = fname; 257 258 ret = nxt_file_openat2(task, &file, NXT_FILE_RDONLY, | 306 ret = nxt_file_open(task, &file, NXT_FILE_SEARCH, NXT_FILE_OPEN, 307 0); 308 309 } else { 310 file.error = NXT_EACCES; 311 ret = NXT_ERROR; 312 } 313 --- 10 unchanged lines hidden (view full) --- 324 if (nxt_fast_path(ret == NXT_OK)) { 325 nxt_file_t af; 326 327 af = file; 328 nxt_memzero(&file, sizeof(nxt_file_t)); 329 file.name = fname; 330 331 ret = nxt_file_openat2(task, &file, NXT_FILE_RDONLY, |
259 NXT_FILE_OPEN, 0, af.fd, conf->resolve); | 332 NXT_FILE_OPEN, 0, af.fd, resolve); |
260 261 if (af.fd != AT_FDCWD) { 262 nxt_file_close(task, &af); 263 } 264 } 265 266 } else { 267 ret = nxt_file_open(task, &file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 0); --- 36 unchanged lines hidden (view full) --- 304 305 default: 306 level = NXT_LOG_ALERT; 307 status = NXT_HTTP_INTERNAL_SERVER_ERROR; 308 break; 309 } 310 311 if (level == NXT_LOG_ERR && action->fallback != NULL) { | 333 334 if (af.fd != AT_FDCWD) { 335 nxt_file_close(task, &af); 336 } 337 } 338 339 } else { 340 ret = nxt_file_open(task, &file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 0); --- 36 unchanged lines hidden (view full) --- 377 378 default: 379 level = NXT_LOG_ALERT; 380 status = NXT_HTTP_INTERNAL_SERVER_ERROR; 381 break; 382 } 383 384 if (level == NXT_LOG_ERR && action->fallback != NULL) { |
312 return action->fallback; | 385 goto fail; |
313 } 314 315 if (status != NXT_HTTP_NOT_FOUND) { | 386 } 387 388 if (status != NXT_HTTP_NOT_FOUND) { |
316 if (chroot->length > 0) { | 389#if (NXT_HAVE_OPENAT2) 390 nxt_str_t *chr = &ctx->chroot; 391 392 if (chr->length > 0) { |
317 nxt_log(task, level, "opening \"%s\" at \"%V\" failed %E", | 393 nxt_log(task, level, "opening \"%s\" at \"%V\" failed %E", |
318 fname, chroot, file.error); | 394 fname, chr, file.error); |
319 320 } else { 321 nxt_log(task, level, "opening \"%s\" failed %E", 322 fname, file.error); 323 } | 395 396 } else { 397 nxt_log(task, level, "opening \"%s\" failed %E", 398 fname, file.error); 399 } |
400 401#else 402 nxt_log(task, level, "opening \"%s\" failed %E", fname, file.error); 403#endif |
|
324 } 325 | 404 } 405 |
326 nxt_http_request_error(task, r, status); 327 return NULL; | 406 goto fail; |
328 } 329 330 f = nxt_mp_get(r->mem_pool, sizeof(nxt_file_t)); 331 if (nxt_slow_path(f == NULL)) { 332 goto fail; 333 } 334 335 *f = file; --- 59 unchanged lines hidden (view full) --- 395 } 396 397 nxt_http_field_name_set(field, "Content-Type"); 398 399 field->value = mtype->start; 400 field->value_length = mtype->length; 401 } 402 | 407 } 408 409 f = nxt_mp_get(r->mem_pool, sizeof(nxt_file_t)); 410 if (nxt_slow_path(f == NULL)) { 411 goto fail; 412 } 413 414 *f = file; --- 59 unchanged lines hidden (view full) --- 474 } 475 476 nxt_http_field_name_set(field, "Content-Type"); 477 478 field->value = mtype->start; 479 field->value_length = mtype->length; 480 } 481 |
403 if (need_body && nxt_file_size(&fi) > 0) { | 482 if (ctx->need_body && nxt_file_size(&fi) > 0) { |
404 fb = nxt_mp_zget(r->mem_pool, NXT_BUF_FILE_SIZE); 405 if (nxt_slow_path(fb == NULL)) { 406 goto fail; 407 } 408 409 fb->file = f; 410 fb->file_end = nxt_file_size(&fi); 411 --- 4 unchanged lines hidden (view full) --- 416 } else { 417 nxt_file_close(task, f); 418 body_handler = NULL; 419 } 420 421 } else { 422 /* Not a file. */ 423 | 483 fb = nxt_mp_zget(r->mem_pool, NXT_BUF_FILE_SIZE); 484 if (nxt_slow_path(fb == NULL)) { 485 goto fail; 486 } 487 488 fb->file = f; 489 fb->file_end = nxt_file_size(&fi); 490 --- 4 unchanged lines hidden (view full) --- 495 } else { 496 nxt_file_close(task, f); 497 body_handler = NULL; 498 } 499 500 } else { 501 /* Not a file. */ 502 |
424 nxt_file_close(task, f); 425 | |
426 if (nxt_slow_path(!nxt_is_dir(&fi))) { | 503 if (nxt_slow_path(!nxt_is_dir(&fi))) { |
427 if (action->fallback != NULL) { 428 return action->fallback; | 504 if (action->fallback == NULL) { 505 nxt_log(task, NXT_LOG_ERR, "\"%FN\" is not a regular file", 506 f->name); |
429 } 430 | 507 } 508 |
431 nxt_log(task, NXT_LOG_ERR, "\"%FN\" is not a regular file", 432 f->name); 433 434 nxt_http_request_error(task, r, NXT_HTTP_NOT_FOUND); 435 return NULL; | 509 status = NXT_HTTP_NOT_FOUND; 510 goto fail; |
436 } 437 | 511 } 512 |
513 nxt_file_close(task, f); |
|
438 f = NULL; 439 440 r->status = NXT_HTTP_MOVED_PERMANENTLY; 441 r->resp.content_length_n = 0; 442 443 field = nxt_list_zero_add(r->resp.fields); 444 if (nxt_slow_path(field == NULL)) { 445 goto fail; --- 31 unchanged lines hidden (view full) --- 477 } 478 479 body_handler = NULL; 480 } 481 482 nxt_http_request_header_send(task, r, body_handler, NULL); 483 484 r->state = &nxt_http_static_send_state; | 514 f = NULL; 515 516 r->status = NXT_HTTP_MOVED_PERMANENTLY; 517 r->resp.content_length_n = 0; 518 519 field = nxt_list_zero_add(r->resp.fields); 520 if (nxt_slow_path(field == NULL)) { 521 goto fail; --- 31 unchanged lines hidden (view full) --- 553 } 554 555 body_handler = NULL; 556 } 557 558 nxt_http_request_header_send(task, r, body_handler, NULL); 559 560 r->state = &nxt_http_static_send_state; |
485 return NULL; | 561 return; |
486 487fail: 488 | 562 563fail: 564 |
489 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 490 | |
491 if (f != NULL) { 492 nxt_file_close(task, f); 493 } 494 | 565 if (f != NULL) { 566 nxt_file_close(task, f); 567 } 568 |
495 return NULL; | 569 if (status != NXT_HTTP_INTERNAL_SERVER_ERROR 570 && action->fallback != NULL) 571 { 572 nxt_http_request_action(task, r, action->fallback); 573 return; 574 } 575 576 nxt_http_request_error(task, r, status); |
496} 497 498 499static void | 577} 578 579 580static void |
581nxt_http_static_var_error(nxt_task_t *task, void *obj, void *data) 582{ 583 nxt_http_request_t *r; 584 585 r = obj; 586 587 nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 588} 589 590 591#if (NXT_HAVE_OPENAT2) 592 593static u_char * 594nxt_http_static_chroot_match(u_char *chr, u_char *shr) 595{ 596 if (*chr != *shr) { 597 return NULL; 598 } 599 600 chr++; 601 shr++; 602 603 for ( ;; ) { 604 if (*shr == '\0') { 605 return NULL; 606 } 607 608 if (*chr == *shr) { 609 chr++; 610 shr++; 611 continue; 612 } 613 614 if (*chr == '\0') { 615 break; 616 } 617 618 if (*chr == '/') { 619 if (chr[-1] == '/') { 620 chr++; 621 continue; 622 } 623 624 } else if (*shr == '/') { 625 if (shr[-1] == '/') { 626 shr++; 627 continue; 628 } 629 } 630 631 return NULL; 632 } 633 634 if (shr[-1] != '/' && *shr != '/') { 635 return NULL; 636 } 637 638 while (*shr == '/') { 639 shr++; 640 } 641 642 return (*shr != '\0') ? shr : NULL; 643} 644 645#endif 646 647 648static void |
|
500nxt_http_static_extract_extension(nxt_str_t *path, nxt_str_t *exten) 501{ 502 u_char ch, *p, *end; 503 504 end = path->start + path->length; 505 p = end; 506 507 for ( ;; ) { --- 334 unchanged lines hidden --- | 649nxt_http_static_extract_extension(nxt_str_t *path, nxt_str_t *exten) 650{ 651 u_char ch, *p, *end; 652 653 end = path->start + path->length; 654 p = end; 655 656 for ( ;; ) { --- 334 unchanged lines hidden --- |