11183Svbart@nginx.com 21183Svbart@nginx.com /* 31183Svbart@nginx.com * Copyright (C) NGINX, Inc. 41183Svbart@nginx.com */ 51183Svbart@nginx.com 61183Svbart@nginx.com #include <nxt_router.h> 71183Svbart@nginx.com #include <nxt_http.h> 81183Svbart@nginx.com 91183Svbart@nginx.com 101923Sz.hong@f5.com typedef struct { 112246Sz.hong@f5.com nxt_tstr_t *tstr; 121961Sz.hong@f5.com #if (NXT_HAVE_OPENAT2) 131961Sz.hong@f5.com u_char *fname; 141961Sz.hong@f5.com #endif 151961Sz.hong@f5.com uint8_t is_const; /* 1 bit */ 161961Sz.hong@f5.com } nxt_http_static_share_t; 171961Sz.hong@f5.com 181961Sz.hong@f5.com 191961Sz.hong@f5.com typedef struct { 201961Sz.hong@f5.com nxt_uint_t nshares; 211961Sz.hong@f5.com nxt_http_static_share_t *shares; 222108Salx.manpages@gmail.com nxt_str_t index; 231959Sz.hong@f5.com #if (NXT_HAVE_OPENAT2) 242246Sz.hong@f5.com nxt_tstr_t *chroot; 251959Sz.hong@f5.com nxt_uint_t resolve; 261959Sz.hong@f5.com #endif 271959Sz.hong@f5.com nxt_http_route_rule_t *types; 281923Sz.hong@f5.com } nxt_http_static_conf_t; 291923Sz.hong@f5.com 301923Sz.hong@f5.com 311959Sz.hong@f5.com typedef struct { 321959Sz.hong@f5.com nxt_http_action_t *action; 331960Sz.hong@f5.com nxt_str_t share; 341959Sz.hong@f5.com #if (NXT_HAVE_OPENAT2) 351959Sz.hong@f5.com nxt_str_t chroot; 361959Sz.hong@f5.com #endif 372096Salx.manpages@gmail.com uint32_t share_idx; 381959Sz.hong@f5.com uint8_t need_body; /* 1 bit */ 391959Sz.hong@f5.com } nxt_http_static_ctx_t; 401959Sz.hong@f5.com 411959Sz.hong@f5.com 421183Svbart@nginx.com #define NXT_HTTP_STATIC_BUF_COUNT 2 431183Svbart@nginx.com #define NXT_HTTP_STATIC_BUF_SIZE (128 * 1024) 441183Svbart@nginx.com 451183Svbart@nginx.com 461923Sz.hong@f5.com static nxt_http_action_t *nxt_http_static(nxt_task_t *task, 471923Sz.hong@f5.com nxt_http_request_t *r, nxt_http_action_t *action); 481961Sz.hong@f5.com static void nxt_http_static_iterate(nxt_task_t *task, nxt_http_request_t *r, 491961Sz.hong@f5.com nxt_http_static_ctx_t *ctx); 501959Sz.hong@f5.com static void nxt_http_static_send_ready(nxt_task_t *task, void *obj, void *data); 512246Sz.hong@f5.com static void nxt_http_static_send_error(nxt_task_t *task, void *obj, void *data); 521961Sz.hong@f5.com static void nxt_http_static_next(nxt_task_t *task, nxt_http_request_t *r, 531961Sz.hong@f5.com nxt_http_static_ctx_t *ctx, nxt_http_status_t status); 541959Sz.hong@f5.com #if (NXT_HAVE_OPENAT2) 551959Sz.hong@f5.com static u_char *nxt_http_static_chroot_match(u_char *chr, u_char *shr); 561959Sz.hong@f5.com #endif 571183Svbart@nginx.com static void nxt_http_static_extract_extension(nxt_str_t *path, 581923Sz.hong@f5.com nxt_str_t *exten); 591183Svbart@nginx.com static void nxt_http_static_body_handler(nxt_task_t *task, void *obj, 601183Svbart@nginx.com void *data); 611183Svbart@nginx.com static void nxt_http_static_buf_completion(nxt_task_t *task, void *obj, 621183Svbart@nginx.com void *data); 631183Svbart@nginx.com 641183Svbart@nginx.com static nxt_int_t nxt_http_static_mtypes_hash_test(nxt_lvlhsh_query_t *lhq, 651183Svbart@nginx.com void *data); 661183Svbart@nginx.com static void *nxt_http_static_mtypes_hash_alloc(void *data, size_t size); 671183Svbart@nginx.com static void nxt_http_static_mtypes_hash_free(void *data, void *p); 681183Svbart@nginx.com 691183Svbart@nginx.com 701183Svbart@nginx.com static const nxt_http_request_state_t nxt_http_static_send_state; 711183Svbart@nginx.com 721183Svbart@nginx.com 731923Sz.hong@f5.com nxt_int_t 741923Sz.hong@f5.com nxt_http_static_init(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 751923Sz.hong@f5.com nxt_http_action_t *action, nxt_http_action_conf_t *acf) 761923Sz.hong@f5.com { 771961Sz.hong@f5.com uint32_t i; 781923Sz.hong@f5.com nxt_mp_t *mp; 792108Salx.manpages@gmail.com nxt_str_t str, *ret; 802246Sz.hong@f5.com nxt_tstr_t *tstr; 811961Sz.hong@f5.com nxt_conf_value_t *cv; 822147Sz.hong@f5.com nxt_router_conf_t *rtcf; 831923Sz.hong@f5.com nxt_http_static_conf_t *conf; 841923Sz.hong@f5.com 852147Sz.hong@f5.com rtcf = tmcf->router_conf; 862147Sz.hong@f5.com mp = rtcf->mem_pool; 871923Sz.hong@f5.com 881923Sz.hong@f5.com conf = nxt_mp_zget(mp, sizeof(nxt_http_static_conf_t)); 891923Sz.hong@f5.com if (nxt_slow_path(conf == NULL)) { 901923Sz.hong@f5.com return NXT_ERROR; 911923Sz.hong@f5.com } 921923Sz.hong@f5.com 931923Sz.hong@f5.com action->handler = nxt_http_static; 941923Sz.hong@f5.com action->u.conf = conf; 951923Sz.hong@f5.com 962077Salx.manpages@gmail.com conf->nshares = nxt_conf_array_elements_count_or_1(acf->share); 971961Sz.hong@f5.com conf->shares = nxt_mp_zget(mp, sizeof(nxt_http_static_share_t) 981961Sz.hong@f5.com * conf->nshares); 991961Sz.hong@f5.com if (nxt_slow_path(conf->shares == NULL)) { 1001923Sz.hong@f5.com return NXT_ERROR; 1011923Sz.hong@f5.com } 1021923Sz.hong@f5.com 1032077Salx.manpages@gmail.com for (i = 0; i < conf->nshares; i++) { 1042077Salx.manpages@gmail.com cv = nxt_conf_get_array_element_or_itself(acf->share, i); 1052077Salx.manpages@gmail.com nxt_conf_get_string(cv, &str); 1061961Sz.hong@f5.com 1072246Sz.hong@f5.com tstr = nxt_tstr_compile(rtcf->tstr_state, &str, NXT_TSTR_STRZ); 1082246Sz.hong@f5.com if (nxt_slow_path(tstr == NULL)) { 1091961Sz.hong@f5.com return NXT_ERROR; 1101961Sz.hong@f5.com } 1111961Sz.hong@f5.com 1122246Sz.hong@f5.com conf->shares[i].tstr = tstr; 1132246Sz.hong@f5.com conf->shares[i].is_const = nxt_tstr_is_const(tstr); 1141961Sz.hong@f5.com } 1151959Sz.hong@f5.com 1162108Salx.manpages@gmail.com if (acf->index == NULL) { 1172108Salx.manpages@gmail.com nxt_str_set(&conf->index, "index.html"); 1182108Salx.manpages@gmail.com 1192108Salx.manpages@gmail.com } else { 1202108Salx.manpages@gmail.com nxt_conf_get_string(acf->index, &str); 1212108Salx.manpages@gmail.com 1222108Salx.manpages@gmail.com ret = nxt_str_dup(mp, &conf->index, &str); 1232108Salx.manpages@gmail.com if (nxt_slow_path(ret == NULL)) { 1242108Salx.manpages@gmail.com return NXT_ERROR; 1252108Salx.manpages@gmail.com } 1262108Salx.manpages@gmail.com } 1272108Salx.manpages@gmail.com 1281923Sz.hong@f5.com #if (NXT_HAVE_OPENAT2) 1291923Sz.hong@f5.com if (acf->chroot.length > 0) { 1301961Sz.hong@f5.com nxt_str_t chr, shr; 1311961Sz.hong@f5.com nxt_bool_t is_const; 1321923Sz.hong@f5.com 1332246Sz.hong@f5.com conf->chroot = nxt_tstr_compile(rtcf->tstr_state, &acf->chroot, 1342246Sz.hong@f5.com NXT_TSTR_STRZ); 1351959Sz.hong@f5.com if (nxt_slow_path(conf->chroot == NULL)) { 1361923Sz.hong@f5.com return NXT_ERROR; 1371923Sz.hong@f5.com } 1381960Sz.hong@f5.com 1392246Sz.hong@f5.com is_const = nxt_tstr_is_const(conf->chroot); 1401961Sz.hong@f5.com 1411961Sz.hong@f5.com for (i = 0; i < conf->nshares; i++) { 1421961Sz.hong@f5.com conf->shares[i].is_const &= is_const; 1431960Sz.hong@f5.com 1441961Sz.hong@f5.com if (conf->shares[i].is_const) { 1452246Sz.hong@f5.com nxt_tstr_str(conf->chroot, &chr); 1462246Sz.hong@f5.com nxt_tstr_str(conf->shares[i].tstr, &shr); 1471961Sz.hong@f5.com 1481961Sz.hong@f5.com conf->shares[i].fname = nxt_http_static_chroot_match(chr.start, 1491961Sz.hong@f5.com shr.start); 1501961Sz.hong@f5.com } 1511960Sz.hong@f5.com } 1521923Sz.hong@f5.com } 1531923Sz.hong@f5.com 1541923Sz.hong@f5.com if (acf->follow_symlinks != NULL 1551923Sz.hong@f5.com && !nxt_conf_get_boolean(acf->follow_symlinks)) 1561923Sz.hong@f5.com { 1571923Sz.hong@f5.com conf->resolve |= RESOLVE_NO_SYMLINKS; 1581923Sz.hong@f5.com } 1591923Sz.hong@f5.com 1601923Sz.hong@f5.com if (acf->traverse_mounts != NULL 1611923Sz.hong@f5.com && !nxt_conf_get_boolean(acf->traverse_mounts)) 1621923Sz.hong@f5.com { 1631923Sz.hong@f5.com conf->resolve |= RESOLVE_NO_XDEV; 1641923Sz.hong@f5.com } 1651923Sz.hong@f5.com #endif 1661923Sz.hong@f5.com 1671923Sz.hong@f5.com if (acf->types != NULL) { 1681923Sz.hong@f5.com conf->types = nxt_http_route_types_rule_create(task, mp, acf->types); 1691923Sz.hong@f5.com if (nxt_slow_path(conf->types == NULL)) { 1701923Sz.hong@f5.com return NXT_ERROR; 1711923Sz.hong@f5.com } 1721923Sz.hong@f5.com } 1731923Sz.hong@f5.com 1741923Sz.hong@f5.com if (acf->fallback != NULL) { 1751923Sz.hong@f5.com action->fallback = nxt_mp_alloc(mp, sizeof(nxt_http_action_t)); 1761923Sz.hong@f5.com if (nxt_slow_path(action->fallback == NULL)) { 1771923Sz.hong@f5.com return NXT_ERROR; 1781923Sz.hong@f5.com } 1791923Sz.hong@f5.com 1801923Sz.hong@f5.com return nxt_http_action_init(task, tmcf, acf->fallback, 1811923Sz.hong@f5.com action->fallback); 1821923Sz.hong@f5.com } 1831923Sz.hong@f5.com 1841923Sz.hong@f5.com return NXT_OK; 1851923Sz.hong@f5.com } 1861923Sz.hong@f5.com 1871923Sz.hong@f5.com 1881923Sz.hong@f5.com static nxt_http_action_t * 1891923Sz.hong@f5.com nxt_http_static(nxt_task_t *task, nxt_http_request_t *r, 1901264Sigor@sysoev.ru nxt_http_action_t *action) 1911183Svbart@nginx.com { 1921961Sz.hong@f5.com nxt_bool_t need_body; 1931961Sz.hong@f5.com nxt_http_static_ctx_t *ctx; 1941923Sz.hong@f5.com 1951183Svbart@nginx.com if (nxt_slow_path(!nxt_str_eq(r->method, "GET", 3))) { 1961183Svbart@nginx.com 1971183Svbart@nginx.com if (!nxt_str_eq(r->method, "HEAD", 4)) { 1981923Sz.hong@f5.com if (action->fallback != NULL) { 1991923Sz.hong@f5.com return action->fallback; 2001378Svbart@nginx.com } 2011378Svbart@nginx.com 2021183Svbart@nginx.com nxt_http_request_error(task, r, NXT_HTTP_METHOD_NOT_ALLOWED); 2031183Svbart@nginx.com return NULL; 2041183Svbart@nginx.com } 2051183Svbart@nginx.com 2061183Svbart@nginx.com need_body = 0; 2071183Svbart@nginx.com 2081183Svbart@nginx.com } else { 2091183Svbart@nginx.com need_body = 1; 2101183Svbart@nginx.com } 2111183Svbart@nginx.com 2121961Sz.hong@f5.com ctx = nxt_mp_zget(r->mem_pool, sizeof(nxt_http_static_ctx_t)); 2131961Sz.hong@f5.com if (nxt_slow_path(ctx == NULL)) { 2141961Sz.hong@f5.com nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 2151961Sz.hong@f5.com return NULL; 2161961Sz.hong@f5.com } 2171961Sz.hong@f5.com 2181961Sz.hong@f5.com ctx->action = action; 2191961Sz.hong@f5.com ctx->need_body = need_body; 2201961Sz.hong@f5.com 2211961Sz.hong@f5.com nxt_http_static_iterate(task, r, ctx); 2221961Sz.hong@f5.com 2231961Sz.hong@f5.com return NULL; 2241961Sz.hong@f5.com } 2251961Sz.hong@f5.com 2261961Sz.hong@f5.com 2271961Sz.hong@f5.com static void 2281961Sz.hong@f5.com nxt_http_static_iterate(nxt_task_t *task, nxt_http_request_t *r, 2291961Sz.hong@f5.com nxt_http_static_ctx_t *ctx) 2301961Sz.hong@f5.com { 2311961Sz.hong@f5.com nxt_int_t ret; 2322246Sz.hong@f5.com nxt_router_conf_t *rtcf; 2331961Sz.hong@f5.com nxt_http_static_conf_t *conf; 2341961Sz.hong@f5.com nxt_http_static_share_t *share; 2351961Sz.hong@f5.com 2361961Sz.hong@f5.com conf = ctx->action->u.conf; 2371961Sz.hong@f5.com 2382096Salx.manpages@gmail.com share = &conf->shares[ctx->share_idx]; 2391959Sz.hong@f5.com 2401960Sz.hong@f5.com #if (NXT_DEBUG) 2411960Sz.hong@f5.com nxt_str_t shr; 2422108Salx.manpages@gmail.com nxt_str_t idx; 2431960Sz.hong@f5.com 2442246Sz.hong@f5.com nxt_tstr_str(share->tstr, &shr); 2452108Salx.manpages@gmail.com idx = conf->index; 2461960Sz.hong@f5.com 2471960Sz.hong@f5.com #if (NXT_HAVE_OPENAT2) 2481959Sz.hong@f5.com nxt_str_t chr; 2491959Sz.hong@f5.com 2501959Sz.hong@f5.com if (conf->chroot != NULL) { 2512246Sz.hong@f5.com nxt_tstr_str(conf->chroot, &chr); 2521959Sz.hong@f5.com 2531959Sz.hong@f5.com } else { 2541959Sz.hong@f5.com nxt_str_set(&chr, ""); 2551959Sz.hong@f5.com } 2561959Sz.hong@f5.com 2572108Salx.manpages@gmail.com nxt_debug(task, "http static: \"%V\", index: \"%V\" (chroot: \"%V\")", 2582108Salx.manpages@gmail.com &shr, &idx, &chr); 2591959Sz.hong@f5.com #else 2602108Salx.manpages@gmail.com nxt_debug(task, "http static: \"%V\", index: \"%V\"", &shr, &idx); 2611959Sz.hong@f5.com #endif 2621960Sz.hong@f5.com #endif /* NXT_DEBUG */ 2631959Sz.hong@f5.com 2641961Sz.hong@f5.com if (share->is_const) { 2652246Sz.hong@f5.com nxt_tstr_str(share->tstr, &ctx->share); 2661960Sz.hong@f5.com 2671959Sz.hong@f5.com #if (NXT_HAVE_OPENAT2) 2682096Salx.manpages@gmail.com if (conf->chroot != NULL && ctx->share_idx == 0) { 2692246Sz.hong@f5.com nxt_tstr_str(conf->chroot, &ctx->chroot); 2701959Sz.hong@f5.com } 2711959Sz.hong@f5.com #endif 2721959Sz.hong@f5.com 2731959Sz.hong@f5.com nxt_http_static_send_ready(task, r, ctx); 2741959Sz.hong@f5.com 2751959Sz.hong@f5.com } else { 2762246Sz.hong@f5.com rtcf = r->conf->socket_conf->router_conf; 2772246Sz.hong@f5.com 2782246Sz.hong@f5.com ret = nxt_tstr_query_init(&r->tstr_query, rtcf->tstr_state, 279*2247Sz.hong@f5.com &r->tstr_cache, r, r->mem_pool); 2801959Sz.hong@f5.com if (nxt_slow_path(ret != NXT_OK)) { 2811961Sz.hong@f5.com nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 2821961Sz.hong@f5.com return; 2831959Sz.hong@f5.com } 2841959Sz.hong@f5.com 2852246Sz.hong@f5.com nxt_tstr_query(task, r->tstr_query, share->tstr, &ctx->share); 2861960Sz.hong@f5.com 2871959Sz.hong@f5.com #if (NXT_HAVE_OPENAT2) 2882096Salx.manpages@gmail.com if (conf->chroot != NULL && ctx->share_idx == 0) { 2892246Sz.hong@f5.com nxt_tstr_query(task, r->tstr_query, conf->chroot, &ctx->chroot); 2901960Sz.hong@f5.com } 2911959Sz.hong@f5.com #endif 2921959Sz.hong@f5.com 2932246Sz.hong@f5.com nxt_tstr_query_resolve(task, r->tstr_query, ctx, 2942246Sz.hong@f5.com nxt_http_static_send_ready, 2952246Sz.hong@f5.com nxt_http_static_send_error); 2961961Sz.hong@f5.com } 2971959Sz.hong@f5.com } 2981959Sz.hong@f5.com 2991959Sz.hong@f5.com 3001959Sz.hong@f5.com static void 3011959Sz.hong@f5.com nxt_http_static_send_ready(nxt_task_t *task, void *obj, void *data) 3021959Sz.hong@f5.com { 3031959Sz.hong@f5.com size_t length, encode; 3041959Sz.hong@f5.com u_char *p, *fname; 3051959Sz.hong@f5.com struct tm tm; 3061959Sz.hong@f5.com nxt_buf_t *fb; 3071959Sz.hong@f5.com nxt_int_t ret; 3082108Salx.manpages@gmail.com nxt_str_t *shr, *index, exten, *mtype; 3091959Sz.hong@f5.com nxt_uint_t level; 3101959Sz.hong@f5.com nxt_file_t *f, file; 3111959Sz.hong@f5.com nxt_file_info_t fi; 3121959Sz.hong@f5.com nxt_http_field_t *field; 3131959Sz.hong@f5.com nxt_http_status_t status; 3141959Sz.hong@f5.com nxt_router_conf_t *rtcf; 3151959Sz.hong@f5.com nxt_http_action_t *action; 3161959Sz.hong@f5.com nxt_http_request_t *r; 3171959Sz.hong@f5.com nxt_work_handler_t body_handler; 3181959Sz.hong@f5.com nxt_http_static_ctx_t *ctx; 3191959Sz.hong@f5.com nxt_http_static_conf_t *conf; 3201959Sz.hong@f5.com 3211959Sz.hong@f5.com r = obj; 3221959Sz.hong@f5.com ctx = data; 3231959Sz.hong@f5.com action = ctx->action; 3241959Sz.hong@f5.com conf = action->u.conf; 3251960Sz.hong@f5.com rtcf = r->conf->socket_conf->router_conf; 3261183Svbart@nginx.com 3271855Sz.hong@f5.com f = NULL; 3281960Sz.hong@f5.com mtype = NULL; 3291183Svbart@nginx.com 3301960Sz.hong@f5.com shr = &ctx->share; 3312108Salx.manpages@gmail.com index = &conf->index; 3321859So.canty@f5.com 3331960Sz.hong@f5.com if (shr->start[shr->length - 1] == '/') { 3342108Salx.manpages@gmail.com nxt_http_static_extract_extension(index, &exten); 3351859So.canty@f5.com 3362108Salx.manpages@gmail.com length = shr->length + index->length; 3371960Sz.hong@f5.com 3381960Sz.hong@f5.com fname = nxt_mp_nget(r->mem_pool, length + 1); 3391960Sz.hong@f5.com if (nxt_slow_path(fname == NULL)) { 3401883So.canty@f5.com goto fail; 3411883So.canty@f5.com } 3421883So.canty@f5.com 3431960Sz.hong@f5.com p = fname; 3441960Sz.hong@f5.com p = nxt_cpymem(p, shr->start, shr->length); 3452108Salx.manpages@gmail.com p = nxt_cpymem(p, index->start, index->length); 3461960Sz.hong@f5.com *p = '\0'; 3471859So.canty@f5.com 3481960Sz.hong@f5.com } else { 3491960Sz.hong@f5.com if (conf->types == NULL) { 3501960Sz.hong@f5.com nxt_str_null(&exten); 3511960Sz.hong@f5.com 3521960Sz.hong@f5.com } else { 3531960Sz.hong@f5.com nxt_http_static_extract_extension(shr, &exten); 3541960Sz.hong@f5.com mtype = nxt_http_static_mtype_get(&rtcf->mtypes_hash, &exten); 3551855Sz.hong@f5.com 3561960Sz.hong@f5.com ret = nxt_http_route_test_rule(r, conf->types, mtype->start, 3571960Sz.hong@f5.com mtype->length); 3581960Sz.hong@f5.com if (nxt_slow_path(ret == NXT_ERROR)) { 3591960Sz.hong@f5.com goto fail; 3601960Sz.hong@f5.com } 3611183Svbart@nginx.com 3621960Sz.hong@f5.com if (ret == 0) { 3631961Sz.hong@f5.com nxt_http_static_next(task, r, ctx, NXT_HTTP_FORBIDDEN); 3641961Sz.hong@f5.com return; 3651960Sz.hong@f5.com } 3661960Sz.hong@f5.com } 3671960Sz.hong@f5.com 3681960Sz.hong@f5.com fname = ctx->share.start; 3691960Sz.hong@f5.com } 3701183Svbart@nginx.com 3711855Sz.hong@f5.com nxt_memzero(&file, sizeof(nxt_file_t)); 3721855Sz.hong@f5.com 3731855Sz.hong@f5.com file.name = fname; 3741855Sz.hong@f5.com 3751959Sz.hong@f5.com #if (NXT_HAVE_OPENAT2) 3761959Sz.hong@f5.com if (conf->resolve != 0 || ctx->chroot.length > 0) { 3771961Sz.hong@f5.com nxt_str_t *chr; 3781961Sz.hong@f5.com nxt_uint_t resolve; 3791961Sz.hong@f5.com nxt_http_static_share_t *share; 3801961Sz.hong@f5.com 3812096Salx.manpages@gmail.com share = &conf->shares[ctx->share_idx]; 3821855Sz.hong@f5.com 3831959Sz.hong@f5.com resolve = conf->resolve; 3841959Sz.hong@f5.com chr = &ctx->chroot; 3851855Sz.hong@f5.com 3861959Sz.hong@f5.com if (chr->length > 0) { 3871959Sz.hong@f5.com resolve |= RESOLVE_IN_ROOT; 3881855Sz.hong@f5.com 3891961Sz.hong@f5.com fname = share->is_const 3901961Sz.hong@f5.com ? share->fname 3911960Sz.hong@f5.com : nxt_http_static_chroot_match(chr->start, file.name); 3921959Sz.hong@f5.com 3931959Sz.hong@f5.com if (fname != NULL) { 3941959Sz.hong@f5.com file.name = chr->start; 3951855Sz.hong@f5.com ret = nxt_file_open(task, &file, NXT_FILE_SEARCH, NXT_FILE_OPEN, 3961855Sz.hong@f5.com 0); 3971855Sz.hong@f5.com 3981855Sz.hong@f5.com } else { 3991855Sz.hong@f5.com file.error = NXT_EACCES; 4001855Sz.hong@f5.com ret = NXT_ERROR; 4011855Sz.hong@f5.com } 4021855Sz.hong@f5.com 4031855Sz.hong@f5.com } else if (fname[0] == '/') { 4041855Sz.hong@f5.com file.name = (u_char *) "/"; 4051855Sz.hong@f5.com ret = nxt_file_open(task, &file, NXT_FILE_SEARCH, NXT_FILE_OPEN, 0); 4061855Sz.hong@f5.com 4071855Sz.hong@f5.com } else { 4081855Sz.hong@f5.com file.name = (u_char *) "."; 4091855Sz.hong@f5.com file.fd = AT_FDCWD; 4101855Sz.hong@f5.com ret = NXT_OK; 4111855Sz.hong@f5.com } 4121855Sz.hong@f5.com 4131855Sz.hong@f5.com if (nxt_fast_path(ret == NXT_OK)) { 4141856Sz.hong@f5.com nxt_file_t af; 4151856Sz.hong@f5.com 4161855Sz.hong@f5.com af = file; 4171855Sz.hong@f5.com nxt_memzero(&file, sizeof(nxt_file_t)); 4181855Sz.hong@f5.com file.name = fname; 4191855Sz.hong@f5.com 4201855Sz.hong@f5.com ret = nxt_file_openat2(task, &file, NXT_FILE_RDONLY, 4211959Sz.hong@f5.com NXT_FILE_OPEN, 0, af.fd, resolve); 4221855Sz.hong@f5.com 4231855Sz.hong@f5.com if (af.fd != AT_FDCWD) { 4241855Sz.hong@f5.com nxt_file_close(task, &af); 4251855Sz.hong@f5.com } 4261855Sz.hong@f5.com } 4271855Sz.hong@f5.com 4281855Sz.hong@f5.com } else { 4291855Sz.hong@f5.com ret = nxt_file_open(task, &file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 0); 4301855Sz.hong@f5.com } 4311855Sz.hong@f5.com 4321855Sz.hong@f5.com #else 4331855Sz.hong@f5.com ret = nxt_file_open(task, &file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 0); 4341855Sz.hong@f5.com #endif 4351183Svbart@nginx.com 4361183Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 4371855Sz.hong@f5.com 4381855Sz.hong@f5.com switch (file.error) { 4391183Svbart@nginx.com 4401200Svbart@nginx.com /* 4411200Svbart@nginx.com * For Unix domain sockets "errno" is set to: 4421200Svbart@nginx.com * - ENXIO on Linux; 4431200Svbart@nginx.com * - EOPNOTSUPP on *BSD, MacOSX, and Solaris. 4441200Svbart@nginx.com */ 4451200Svbart@nginx.com 4461183Svbart@nginx.com case NXT_ENOENT: 4471183Svbart@nginx.com case NXT_ENOTDIR: 4481183Svbart@nginx.com case NXT_ENAMETOOLONG: 4491200Svbart@nginx.com #if (NXT_LINUX) 4501200Svbart@nginx.com case NXT_ENXIO: 4511200Svbart@nginx.com #else 4521200Svbart@nginx.com case NXT_EOPNOTSUPP: 4531200Svbart@nginx.com #endif 4541183Svbart@nginx.com level = NXT_LOG_ERR; 4551183Svbart@nginx.com status = NXT_HTTP_NOT_FOUND; 4561183Svbart@nginx.com break; 4571183Svbart@nginx.com 4581183Svbart@nginx.com case NXT_EACCES: 4591855Sz.hong@f5.com #if (NXT_HAVE_OPENAT2) 4601855Sz.hong@f5.com case NXT_ELOOP: 4611855Sz.hong@f5.com case NXT_EXDEV: 4621855Sz.hong@f5.com #endif 4631183Svbart@nginx.com level = NXT_LOG_ERR; 4641183Svbart@nginx.com status = NXT_HTTP_FORBIDDEN; 4651183Svbart@nginx.com break; 4661183Svbart@nginx.com 4671183Svbart@nginx.com default: 4681183Svbart@nginx.com level = NXT_LOG_ALERT; 4691183Svbart@nginx.com status = NXT_HTTP_INTERNAL_SERVER_ERROR; 4701183Svbart@nginx.com break; 4711183Svbart@nginx.com } 4721183Svbart@nginx.com 4731183Svbart@nginx.com if (status != NXT_HTTP_NOT_FOUND) { 4741959Sz.hong@f5.com #if (NXT_HAVE_OPENAT2) 4751959Sz.hong@f5.com nxt_str_t *chr = &ctx->chroot; 4761959Sz.hong@f5.com 4771959Sz.hong@f5.com if (chr->length > 0) { 4781857Sz.hong@f5.com nxt_log(task, level, "opening \"%s\" at \"%V\" failed %E", 4791959Sz.hong@f5.com fname, chr, file.error); 4801855Sz.hong@f5.com 4811855Sz.hong@f5.com } else { 4821857Sz.hong@f5.com nxt_log(task, level, "opening \"%s\" failed %E", 4831855Sz.hong@f5.com fname, file.error); 4841855Sz.hong@f5.com } 4851959Sz.hong@f5.com 4861959Sz.hong@f5.com #else 4871959Sz.hong@f5.com nxt_log(task, level, "opening \"%s\" failed %E", fname, file.error); 4881959Sz.hong@f5.com #endif 4891183Svbart@nginx.com } 4901183Svbart@nginx.com 4911961Sz.hong@f5.com if (level == NXT_LOG_ERR) { 4921961Sz.hong@f5.com nxt_http_static_next(task, r, ctx, status); 4931961Sz.hong@f5.com return; 4941961Sz.hong@f5.com } 4951961Sz.hong@f5.com 4961959Sz.hong@f5.com goto fail; 4971183Svbart@nginx.com } 4981183Svbart@nginx.com 4991855Sz.hong@f5.com f = nxt_mp_get(r->mem_pool, sizeof(nxt_file_t)); 5001855Sz.hong@f5.com if (nxt_slow_path(f == NULL)) { 5011962Svbart@nginx.com nxt_file_close(task, &file); 5021855Sz.hong@f5.com goto fail; 5031855Sz.hong@f5.com } 5041855Sz.hong@f5.com 5051855Sz.hong@f5.com *f = file; 5061855Sz.hong@f5.com 5071183Svbart@nginx.com ret = nxt_file_info(f, &fi); 5081183Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 5091183Svbart@nginx.com goto fail; 5101183Svbart@nginx.com } 5111183Svbart@nginx.com 5121183Svbart@nginx.com if (nxt_fast_path(nxt_is_file(&fi))) { 5131183Svbart@nginx.com r->status = NXT_HTTP_OK; 5141183Svbart@nginx.com r->resp.content_length_n = nxt_file_size(&fi); 5151183Svbart@nginx.com 5161183Svbart@nginx.com field = nxt_list_zero_add(r->resp.fields); 5171183Svbart@nginx.com if (nxt_slow_path(field == NULL)) { 5181183Svbart@nginx.com goto fail; 5191183Svbart@nginx.com } 5201183Svbart@nginx.com 5211183Svbart@nginx.com nxt_http_field_name_set(field, "Last-Modified"); 5221183Svbart@nginx.com 5231183Svbart@nginx.com p = nxt_mp_nget(r->mem_pool, NXT_HTTP_DATE_LEN); 5241183Svbart@nginx.com if (nxt_slow_path(p == NULL)) { 5251183Svbart@nginx.com goto fail; 5261183Svbart@nginx.com } 5271183Svbart@nginx.com 5281183Svbart@nginx.com nxt_localtime(nxt_file_mtime(&fi), &tm); 5291183Svbart@nginx.com 5301183Svbart@nginx.com field->value = p; 5311183Svbart@nginx.com field->value_length = nxt_http_date(p, &tm) - p; 5321183Svbart@nginx.com 5331183Svbart@nginx.com field = nxt_list_zero_add(r->resp.fields); 5341183Svbart@nginx.com if (nxt_slow_path(field == NULL)) { 5351183Svbart@nginx.com goto fail; 5361183Svbart@nginx.com } 5371183Svbart@nginx.com 5381183Svbart@nginx.com nxt_http_field_name_set(field, "ETag"); 5391183Svbart@nginx.com 5401855Sz.hong@f5.com length = NXT_TIME_T_HEXLEN + NXT_OFF_T_HEXLEN + 3; 5411183Svbart@nginx.com 5421855Sz.hong@f5.com p = nxt_mp_nget(r->mem_pool, length); 5431183Svbart@nginx.com if (nxt_slow_path(p == NULL)) { 5441183Svbart@nginx.com goto fail; 5451183Svbart@nginx.com } 5461183Svbart@nginx.com 5471183Svbart@nginx.com field->value = p; 5481855Sz.hong@f5.com field->value_length = nxt_sprintf(p, p + length, "\"%xT-%xO\"", 5491183Svbart@nginx.com nxt_file_mtime(&fi), 5501183Svbart@nginx.com nxt_file_size(&fi)) 5511183Svbart@nginx.com - p; 5521183Svbart@nginx.com 5531923Sz.hong@f5.com if (exten.start == NULL) { 5541960Sz.hong@f5.com nxt_http_static_extract_extension(shr, &exten); 5551183Svbart@nginx.com } 5561183Svbart@nginx.com 5571859So.canty@f5.com if (mtype == NULL) { 5581923Sz.hong@f5.com mtype = nxt_http_static_mtype_get(&rtcf->mtypes_hash, &exten); 5591859So.canty@f5.com } 5601183Svbart@nginx.com 5611883So.canty@f5.com if (mtype->length != 0) { 5621183Svbart@nginx.com field = nxt_list_zero_add(r->resp.fields); 5631183Svbart@nginx.com if (nxt_slow_path(field == NULL)) { 5641183Svbart@nginx.com goto fail; 5651183Svbart@nginx.com } 5661183Svbart@nginx.com 5671183Svbart@nginx.com nxt_http_field_name_set(field, "Content-Type"); 5681183Svbart@nginx.com 5691183Svbart@nginx.com field->value = mtype->start; 5701183Svbart@nginx.com field->value_length = mtype->length; 5711183Svbart@nginx.com } 5721183Svbart@nginx.com 5731959Sz.hong@f5.com if (ctx->need_body && nxt_file_size(&fi) > 0) { 5741183Svbart@nginx.com fb = nxt_mp_zget(r->mem_pool, NXT_BUF_FILE_SIZE); 5751183Svbart@nginx.com if (nxt_slow_path(fb == NULL)) { 5761183Svbart@nginx.com goto fail; 5771183Svbart@nginx.com } 5781183Svbart@nginx.com 5791183Svbart@nginx.com fb->file = f; 5801183Svbart@nginx.com fb->file_end = nxt_file_size(&fi); 5811183Svbart@nginx.com 5821183Svbart@nginx.com r->out = fb; 5831183Svbart@nginx.com 5841183Svbart@nginx.com body_handler = &nxt_http_static_body_handler; 5851183Svbart@nginx.com 5861183Svbart@nginx.com } else { 5871183Svbart@nginx.com nxt_file_close(task, f); 5881183Svbart@nginx.com body_handler = NULL; 5891183Svbart@nginx.com } 5901183Svbart@nginx.com 5911183Svbart@nginx.com } else { 5921183Svbart@nginx.com /* Not a file. */ 5931961Sz.hong@f5.com nxt_file_close(task, f); 5941183Svbart@nginx.com 5952106Salx.manpages@gmail.com if (nxt_slow_path(!nxt_is_dir(&fi) 5962106Salx.manpages@gmail.com || shr->start[shr->length - 1] == '/')) 5972106Salx.manpages@gmail.com { 5981961Sz.hong@f5.com nxt_log(task, NXT_LOG_ERR, "\"%FN\" is not a regular file", 5991961Sz.hong@f5.com f->name); 6001378Svbart@nginx.com 6011961Sz.hong@f5.com nxt_http_static_next(task, r, ctx, NXT_HTTP_NOT_FOUND); 6021961Sz.hong@f5.com return; 6031183Svbart@nginx.com } 6041183Svbart@nginx.com 6051198Svbart@nginx.com f = NULL; 6061198Svbart@nginx.com 6071183Svbart@nginx.com r->status = NXT_HTTP_MOVED_PERMANENTLY; 6081183Svbart@nginx.com r->resp.content_length_n = 0; 6091183Svbart@nginx.com 6101183Svbart@nginx.com field = nxt_list_zero_add(r->resp.fields); 6111183Svbart@nginx.com if (nxt_slow_path(field == NULL)) { 6121183Svbart@nginx.com goto fail; 6131183Svbart@nginx.com } 6141183Svbart@nginx.com 6151183Svbart@nginx.com nxt_http_field_name_set(field, "Location"); 6161183Svbart@nginx.com 6171183Svbart@nginx.com encode = nxt_encode_uri(NULL, r->path->start, r->path->length); 6181855Sz.hong@f5.com length = r->path->length + encode * 2 + 1; 6191183Svbart@nginx.com 6201183Svbart@nginx.com if (r->args->length > 0) { 6211855Sz.hong@f5.com length += 1 + r->args->length; 6221183Svbart@nginx.com } 6231183Svbart@nginx.com 6241855Sz.hong@f5.com p = nxt_mp_nget(r->mem_pool, length); 6251183Svbart@nginx.com if (nxt_slow_path(p == NULL)) { 6261183Svbart@nginx.com goto fail; 6271183Svbart@nginx.com } 6281183Svbart@nginx.com 6291183Svbart@nginx.com field->value = p; 6301855Sz.hong@f5.com field->value_length = length; 6311183Svbart@nginx.com 6321183Svbart@nginx.com if (encode > 0) { 6331183Svbart@nginx.com p = (u_char *) nxt_encode_uri(p, r->path->start, r->path->length); 6341183Svbart@nginx.com 6351183Svbart@nginx.com } else { 6361183Svbart@nginx.com p = nxt_cpymem(p, r->path->start, r->path->length); 6371183Svbart@nginx.com } 6381183Svbart@nginx.com 6391183Svbart@nginx.com *p++ = '/'; 6401183Svbart@nginx.com 6411183Svbart@nginx.com if (r->args->length > 0) { 6421183Svbart@nginx.com *p++ = '?'; 6431183Svbart@nginx.com nxt_memcpy(p, r->args->start, r->args->length); 6441183Svbart@nginx.com } 6451183Svbart@nginx.com 6461183Svbart@nginx.com body_handler = NULL; 6471183Svbart@nginx.com } 6481183Svbart@nginx.com 6491270Sigor@sysoev.ru nxt_http_request_header_send(task, r, body_handler, NULL); 6501183Svbart@nginx.com 6511183Svbart@nginx.com r->state = &nxt_http_static_send_state; 6521959Sz.hong@f5.com return; 6531183Svbart@nginx.com 6541183Svbart@nginx.com fail: 6551183Svbart@nginx.com 6561855Sz.hong@f5.com if (f != NULL) { 6571183Svbart@nginx.com nxt_file_close(task, f); 6581183Svbart@nginx.com } 6591183Svbart@nginx.com 6601961Sz.hong@f5.com nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 6611959Sz.hong@f5.com } 6621959Sz.hong@f5.com 6631959Sz.hong@f5.com 6641959Sz.hong@f5.com static void 6652246Sz.hong@f5.com nxt_http_static_send_error(nxt_task_t *task, void *obj, void *data) 6661959Sz.hong@f5.com { 6671959Sz.hong@f5.com nxt_http_request_t *r; 6681959Sz.hong@f5.com 6691959Sz.hong@f5.com r = obj; 6701959Sz.hong@f5.com 6711959Sz.hong@f5.com nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 6721183Svbart@nginx.com } 6731183Svbart@nginx.com 6741183Svbart@nginx.com 6751961Sz.hong@f5.com static void 6761961Sz.hong@f5.com nxt_http_static_next(nxt_task_t *task, nxt_http_request_t *r, 6771961Sz.hong@f5.com nxt_http_static_ctx_t *ctx, nxt_http_status_t status) 6781961Sz.hong@f5.com { 6791961Sz.hong@f5.com nxt_http_action_t *action; 6801961Sz.hong@f5.com nxt_http_static_conf_t *conf; 6811961Sz.hong@f5.com 6821961Sz.hong@f5.com action = ctx->action; 6831961Sz.hong@f5.com conf = action->u.conf; 6841961Sz.hong@f5.com 6852096Salx.manpages@gmail.com ctx->share_idx++; 6861961Sz.hong@f5.com 6872096Salx.manpages@gmail.com if (ctx->share_idx < conf->nshares) { 6881961Sz.hong@f5.com nxt_http_static_iterate(task, r, ctx); 6891961Sz.hong@f5.com return; 6901961Sz.hong@f5.com } 6911961Sz.hong@f5.com 6921961Sz.hong@f5.com if (action->fallback != NULL) { 6931961Sz.hong@f5.com nxt_http_request_action(task, r, action->fallback); 6941961Sz.hong@f5.com return; 6951961Sz.hong@f5.com } 6961961Sz.hong@f5.com 6971961Sz.hong@f5.com nxt_http_request_error(task, r, status); 6981961Sz.hong@f5.com } 6991961Sz.hong@f5.com 7001961Sz.hong@f5.com 7011959Sz.hong@f5.com #if (NXT_HAVE_OPENAT2) 7021959Sz.hong@f5.com 7031959Sz.hong@f5.com static u_char * 7041959Sz.hong@f5.com nxt_http_static_chroot_match(u_char *chr, u_char *shr) 7051959Sz.hong@f5.com { 7061959Sz.hong@f5.com if (*chr != *shr) { 7071959Sz.hong@f5.com return NULL; 7081959Sz.hong@f5.com } 7091959Sz.hong@f5.com 7101959Sz.hong@f5.com chr++; 7111959Sz.hong@f5.com shr++; 7121959Sz.hong@f5.com 7131959Sz.hong@f5.com for ( ;; ) { 7141959Sz.hong@f5.com if (*shr == '\0') { 7151959Sz.hong@f5.com return NULL; 7161959Sz.hong@f5.com } 7171959Sz.hong@f5.com 7181959Sz.hong@f5.com if (*chr == *shr) { 7191959Sz.hong@f5.com chr++; 7201959Sz.hong@f5.com shr++; 7211959Sz.hong@f5.com continue; 7221959Sz.hong@f5.com } 7231959Sz.hong@f5.com 7241959Sz.hong@f5.com if (*chr == '\0') { 7251959Sz.hong@f5.com break; 7261959Sz.hong@f5.com } 7271959Sz.hong@f5.com 7281959Sz.hong@f5.com if (*chr == '/') { 7291959Sz.hong@f5.com if (chr[-1] == '/') { 7301959Sz.hong@f5.com chr++; 7311959Sz.hong@f5.com continue; 7321959Sz.hong@f5.com } 7331959Sz.hong@f5.com 7341959Sz.hong@f5.com } else if (*shr == '/') { 7351959Sz.hong@f5.com if (shr[-1] == '/') { 7361959Sz.hong@f5.com shr++; 7371959Sz.hong@f5.com continue; 7381959Sz.hong@f5.com } 7391959Sz.hong@f5.com } 7401959Sz.hong@f5.com 7411959Sz.hong@f5.com return NULL; 7421959Sz.hong@f5.com } 7431959Sz.hong@f5.com 7441959Sz.hong@f5.com if (shr[-1] != '/' && *shr != '/') { 7451959Sz.hong@f5.com return NULL; 7461959Sz.hong@f5.com } 7471959Sz.hong@f5.com 7481959Sz.hong@f5.com while (*shr == '/') { 7491959Sz.hong@f5.com shr++; 7501959Sz.hong@f5.com } 7511959Sz.hong@f5.com 7521959Sz.hong@f5.com return (*shr != '\0') ? shr : NULL; 7531959Sz.hong@f5.com } 7541959Sz.hong@f5.com 7551959Sz.hong@f5.com #endif 7561959Sz.hong@f5.com 7571959Sz.hong@f5.com 7581183Svbart@nginx.com static void 7591923Sz.hong@f5.com nxt_http_static_extract_extension(nxt_str_t *path, nxt_str_t *exten) 7601183Svbart@nginx.com { 7611183Svbart@nginx.com u_char ch, *p, *end; 7621183Svbart@nginx.com 7631183Svbart@nginx.com end = path->start + path->length; 7641183Svbart@nginx.com p = end; 7651183Svbart@nginx.com 7662137Salx.manpages@gmail.com while (p > path->start) { 7671183Svbart@nginx.com p--; 7681183Svbart@nginx.com ch = *p; 7691183Svbart@nginx.com 7701183Svbart@nginx.com switch (ch) { 7711183Svbart@nginx.com case '/': 7721183Svbart@nginx.com p++; 7731183Svbart@nginx.com /* Fall through. */ 7741183Svbart@nginx.com case '.': 7752137Salx.manpages@gmail.com goto extension; 7761183Svbart@nginx.com } 7771183Svbart@nginx.com } 7782137Salx.manpages@gmail.com 7792137Salx.manpages@gmail.com extension: 7802137Salx.manpages@gmail.com 7812137Salx.manpages@gmail.com exten->length = end - p; 7822137Salx.manpages@gmail.com exten->start = p; 7831183Svbart@nginx.com } 7841183Svbart@nginx.com 7851183Svbart@nginx.com 7861183Svbart@nginx.com static void 7871183Svbart@nginx.com nxt_http_static_body_handler(nxt_task_t *task, void *obj, void *data) 7881183Svbart@nginx.com { 7891183Svbart@nginx.com size_t alloc; 7901183Svbart@nginx.com nxt_buf_t *fb, *b, **next, *out; 7911183Svbart@nginx.com nxt_off_t rest; 7921183Svbart@nginx.com nxt_int_t n; 7931183Svbart@nginx.com nxt_work_queue_t *wq; 7941183Svbart@nginx.com nxt_http_request_t *r; 7951183Svbart@nginx.com 7961183Svbart@nginx.com r = obj; 7971183Svbart@nginx.com fb = r->out; 7981183Svbart@nginx.com 7991183Svbart@nginx.com rest = fb->file_end - fb->file_pos; 8001183Svbart@nginx.com out = NULL; 8011183Svbart@nginx.com next = &out; 8021183Svbart@nginx.com n = 0; 8031183Svbart@nginx.com 8041183Svbart@nginx.com do { 8051183Svbart@nginx.com alloc = nxt_min(rest, NXT_HTTP_STATIC_BUF_SIZE); 8061183Svbart@nginx.com 8071183Svbart@nginx.com b = nxt_buf_mem_alloc(r->mem_pool, alloc, 0); 8081183Svbart@nginx.com if (nxt_slow_path(b == NULL)) { 8091183Svbart@nginx.com goto fail; 8101183Svbart@nginx.com } 8111183Svbart@nginx.com 8121183Svbart@nginx.com b->completion_handler = nxt_http_static_buf_completion; 8131183Svbart@nginx.com b->parent = r; 8141183Svbart@nginx.com 8151183Svbart@nginx.com nxt_mp_retain(r->mem_pool); 8161183Svbart@nginx.com 8171183Svbart@nginx.com *next = b; 8181183Svbart@nginx.com next = &b->next; 8191183Svbart@nginx.com 8201183Svbart@nginx.com rest -= alloc; 8211183Svbart@nginx.com 8221183Svbart@nginx.com } while (rest > 0 && ++n < NXT_HTTP_STATIC_BUF_COUNT); 8231183Svbart@nginx.com 8241183Svbart@nginx.com wq = &task->thread->engine->fast_work_queue; 8251183Svbart@nginx.com 8261183Svbart@nginx.com nxt_sendbuf_drain(task, wq, out); 8271183Svbart@nginx.com return; 8281183Svbart@nginx.com 8291183Svbart@nginx.com fail: 8301183Svbart@nginx.com 8311183Svbart@nginx.com while (out != NULL) { 8321183Svbart@nginx.com b = out; 8331183Svbart@nginx.com out = b->next; 8341183Svbart@nginx.com 8351183Svbart@nginx.com nxt_mp_free(r->mem_pool, b); 8361183Svbart@nginx.com nxt_mp_release(r->mem_pool); 8371183Svbart@nginx.com } 8381183Svbart@nginx.com } 8391183Svbart@nginx.com 8401183Svbart@nginx.com 8411183Svbart@nginx.com static const nxt_http_request_state_t nxt_http_static_send_state 8421183Svbart@nginx.com nxt_aligned(64) = 8431183Svbart@nginx.com { 8441183Svbart@nginx.com .error_handler = nxt_http_request_error_handler, 8451183Svbart@nginx.com }; 8461183Svbart@nginx.com 8471183Svbart@nginx.com 8481183Svbart@nginx.com static void 8491183Svbart@nginx.com nxt_http_static_buf_completion(nxt_task_t *task, void *obj, void *data) 8501183Svbart@nginx.com { 8511183Svbart@nginx.com ssize_t n, size; 8521760Smax.romanov@nginx.com nxt_buf_t *b, *fb, *next; 8531183Svbart@nginx.com nxt_off_t rest; 8541183Svbart@nginx.com nxt_http_request_t *r; 8551183Svbart@nginx.com 8561183Svbart@nginx.com b = obj; 8571183Svbart@nginx.com r = data; 8581760Smax.romanov@nginx.com 8591760Smax.romanov@nginx.com complete_buf: 8601760Smax.romanov@nginx.com 8611183Svbart@nginx.com fb = r->out; 8621183Svbart@nginx.com 8631183Svbart@nginx.com if (nxt_slow_path(fb == NULL || r->error)) { 8641183Svbart@nginx.com goto clean; 8651183Svbart@nginx.com } 8661183Svbart@nginx.com 8671183Svbart@nginx.com rest = fb->file_end - fb->file_pos; 8681183Svbart@nginx.com size = nxt_buf_mem_size(&b->mem); 8691183Svbart@nginx.com 8701183Svbart@nginx.com size = nxt_min(rest, (nxt_off_t) size); 8711183Svbart@nginx.com 8721183Svbart@nginx.com n = nxt_file_read(fb->file, b->mem.start, size, fb->file_pos); 8731183Svbart@nginx.com 8741183Svbart@nginx.com if (n != size) { 8751183Svbart@nginx.com if (n >= 0) { 8761183Svbart@nginx.com nxt_log(task, NXT_LOG_ERR, "file \"%FN\" has changed " 8771183Svbart@nginx.com "while sending response to a client", fb->file->name); 8781183Svbart@nginx.com } 8791183Svbart@nginx.com 8801183Svbart@nginx.com nxt_http_request_error_handler(task, r, r->proto.any); 8811183Svbart@nginx.com goto clean; 8821183Svbart@nginx.com } 8831183Svbart@nginx.com 8841760Smax.romanov@nginx.com next = b->next; 8851760Smax.romanov@nginx.com 8861183Svbart@nginx.com if (n == rest) { 8871183Svbart@nginx.com nxt_file_close(task, fb->file); 8881183Svbart@nginx.com r->out = NULL; 8891183Svbart@nginx.com 8901183Svbart@nginx.com b->next = nxt_http_buf_last(r); 8911183Svbart@nginx.com 8921183Svbart@nginx.com } else { 8931183Svbart@nginx.com fb->file_pos += n; 8941183Svbart@nginx.com b->next = NULL; 8951183Svbart@nginx.com } 8961183Svbart@nginx.com 8971183Svbart@nginx.com b->mem.pos = b->mem.start; 8981183Svbart@nginx.com b->mem.free = b->mem.pos + n; 8991183Svbart@nginx.com 9001183Svbart@nginx.com nxt_http_request_send(task, r, b); 9011760Smax.romanov@nginx.com 9021760Smax.romanov@nginx.com if (next != NULL) { 9031760Smax.romanov@nginx.com b = next; 9041760Smax.romanov@nginx.com goto complete_buf; 9051760Smax.romanov@nginx.com } 9061760Smax.romanov@nginx.com 9071183Svbart@nginx.com return; 9081183Svbart@nginx.com 9091183Svbart@nginx.com clean: 9101183Svbart@nginx.com 9111760Smax.romanov@nginx.com do { 9121760Smax.romanov@nginx.com next = b->next; 9131760Smax.romanov@nginx.com 9141760Smax.romanov@nginx.com nxt_mp_free(r->mem_pool, b); 9151760Smax.romanov@nginx.com nxt_mp_release(r->mem_pool); 9161760Smax.romanov@nginx.com 9171760Smax.romanov@nginx.com b = next; 9181760Smax.romanov@nginx.com } while (b != NULL); 9191183Svbart@nginx.com 9201183Svbart@nginx.com if (fb != NULL) { 9211183Svbart@nginx.com nxt_file_close(task, fb->file); 9221183Svbart@nginx.com r->out = NULL; 9231183Svbart@nginx.com } 9241183Svbart@nginx.com } 9251183Svbart@nginx.com 9261183Svbart@nginx.com 9271183Svbart@nginx.com nxt_int_t 9281183Svbart@nginx.com nxt_http_static_mtypes_init(nxt_mp_t *mp, nxt_lvlhsh_t *hash) 9291183Svbart@nginx.com { 9301923Sz.hong@f5.com nxt_str_t *type, exten; 9311183Svbart@nginx.com nxt_int_t ret; 9321183Svbart@nginx.com nxt_uint_t i; 9331183Svbart@nginx.com 9341183Svbart@nginx.com static const struct { 9351183Svbart@nginx.com nxt_str_t type; 9361923Sz.hong@f5.com const char *exten; 9371183Svbart@nginx.com } default_types[] = { 9381183Svbart@nginx.com 9391183Svbart@nginx.com { nxt_string("text/html"), ".html" }, 9401183Svbart@nginx.com { nxt_string("text/html"), ".htm" }, 9411183Svbart@nginx.com { nxt_string("text/css"), ".css" }, 9421183Svbart@nginx.com 9431183Svbart@nginx.com { nxt_string("image/svg+xml"), ".svg" }, 9441183Svbart@nginx.com { nxt_string("image/webp"), ".webp" }, 9451183Svbart@nginx.com { nxt_string("image/png"), ".png" }, 9461617Svbart@nginx.com { nxt_string("image/apng"), ".apng" }, 9471183Svbart@nginx.com { nxt_string("image/jpeg"), ".jpeg" }, 9481183Svbart@nginx.com { nxt_string("image/jpeg"), ".jpg" }, 9491183Svbart@nginx.com { nxt_string("image/gif"), ".gif" }, 9501183Svbart@nginx.com { nxt_string("image/x-icon"), ".ico" }, 9511183Svbart@nginx.com 9521617Svbart@nginx.com { nxt_string("image/avif"), ".avif" }, 9531617Svbart@nginx.com { nxt_string("image/avif-sequence"), ".avifs" }, 9541617Svbart@nginx.com 9551183Svbart@nginx.com { nxt_string("font/woff"), ".woff" }, 9561183Svbart@nginx.com { nxt_string("font/woff2"), ".woff2" }, 9571183Svbart@nginx.com { nxt_string("font/otf"), ".otf" }, 9581183Svbart@nginx.com { nxt_string("font/ttf"), ".ttf" }, 9591183Svbart@nginx.com 9601183Svbart@nginx.com { nxt_string("text/plain"), ".txt" }, 9611183Svbart@nginx.com { nxt_string("text/markdown"), ".md" }, 9621183Svbart@nginx.com { nxt_string("text/x-rst"), ".rst" }, 9631183Svbart@nginx.com 9641183Svbart@nginx.com { nxt_string("application/javascript"), ".js" }, 9651183Svbart@nginx.com { nxt_string("application/json"), ".json" }, 9661183Svbart@nginx.com { nxt_string("application/xml"), ".xml" }, 9671183Svbart@nginx.com { nxt_string("application/rss+xml"), ".rss" }, 9681183Svbart@nginx.com { nxt_string("application/atom+xml"), ".atom" }, 9691183Svbart@nginx.com { nxt_string("application/pdf"), ".pdf" }, 9701183Svbart@nginx.com 9711183Svbart@nginx.com { nxt_string("application/zip"), ".zip" }, 9721183Svbart@nginx.com 9731183Svbart@nginx.com { nxt_string("audio/mpeg"), ".mp3" }, 9741183Svbart@nginx.com { nxt_string("audio/ogg"), ".ogg" }, 9751183Svbart@nginx.com { nxt_string("audio/midi"), ".midi" }, 9761183Svbart@nginx.com { nxt_string("audio/midi"), ".mid" }, 9771183Svbart@nginx.com { nxt_string("audio/flac"), ".flac" }, 9781183Svbart@nginx.com { nxt_string("audio/aac"), ".aac" }, 9791183Svbart@nginx.com { nxt_string("audio/wav"), ".wav" }, 9801183Svbart@nginx.com 9811183Svbart@nginx.com { nxt_string("video/mpeg"), ".mpeg" }, 9821183Svbart@nginx.com { nxt_string("video/mpeg"), ".mpg" }, 9831183Svbart@nginx.com { nxt_string("video/mp4"), ".mp4" }, 9841183Svbart@nginx.com { nxt_string("video/webm"), ".webm" }, 9851183Svbart@nginx.com { nxt_string("video/x-msvideo"), ".avi" }, 9861183Svbart@nginx.com 9871183Svbart@nginx.com { nxt_string("application/octet-stream"), ".exe" }, 9881183Svbart@nginx.com { nxt_string("application/octet-stream"), ".bin" }, 9891183Svbart@nginx.com { nxt_string("application/octet-stream"), ".dll" }, 9901183Svbart@nginx.com { nxt_string("application/octet-stream"), ".iso" }, 9911183Svbart@nginx.com { nxt_string("application/octet-stream"), ".img" }, 9921183Svbart@nginx.com { nxt_string("application/octet-stream"), ".msi" }, 9931183Svbart@nginx.com 9941183Svbart@nginx.com { nxt_string("application/octet-stream"), ".deb" }, 9951183Svbart@nginx.com { nxt_string("application/octet-stream"), ".rpm" }, 9961882So.canty@f5.com 9971882So.canty@f5.com { nxt_string("application/x-httpd-php"), ".php" }, 9981183Svbart@nginx.com }; 9991183Svbart@nginx.com 10001183Svbart@nginx.com for (i = 0; i < nxt_nitems(default_types); i++) { 10011183Svbart@nginx.com type = (nxt_str_t *) &default_types[i].type; 10021183Svbart@nginx.com 10031923Sz.hong@f5.com exten.start = (u_char *) default_types[i].exten; 10041923Sz.hong@f5.com exten.length = nxt_strlen(exten.start); 10051183Svbart@nginx.com 10061923Sz.hong@f5.com ret = nxt_http_static_mtypes_hash_add(mp, hash, &exten, type); 10071183Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 10081183Svbart@nginx.com return NXT_ERROR; 10091183Svbart@nginx.com } 10101183Svbart@nginx.com } 10111183Svbart@nginx.com 10121183Svbart@nginx.com return NXT_OK; 10131183Svbart@nginx.com } 10141183Svbart@nginx.com 10151183Svbart@nginx.com 10161183Svbart@nginx.com static const nxt_lvlhsh_proto_t nxt_http_static_mtypes_hash_proto 10171183Svbart@nginx.com nxt_aligned(64) = 10181183Svbart@nginx.com { 10191183Svbart@nginx.com NXT_LVLHSH_DEFAULT, 10201183Svbart@nginx.com nxt_http_static_mtypes_hash_test, 10211183Svbart@nginx.com nxt_http_static_mtypes_hash_alloc, 10221183Svbart@nginx.com nxt_http_static_mtypes_hash_free, 10231183Svbart@nginx.com }; 10241183Svbart@nginx.com 10251183Svbart@nginx.com 10261183Svbart@nginx.com typedef struct { 10271923Sz.hong@f5.com nxt_str_t exten; 10281183Svbart@nginx.com nxt_str_t *type; 10291183Svbart@nginx.com } nxt_http_static_mtype_t; 10301183Svbart@nginx.com 10311183Svbart@nginx.com 10321183Svbart@nginx.com nxt_int_t 10331183Svbart@nginx.com nxt_http_static_mtypes_hash_add(nxt_mp_t *mp, nxt_lvlhsh_t *hash, 10342139Sandrew@digital-domain.net const nxt_str_t *exten, nxt_str_t *type) 10351183Svbart@nginx.com { 10361183Svbart@nginx.com nxt_lvlhsh_query_t lhq; 10371183Svbart@nginx.com nxt_http_static_mtype_t *mtype; 10381183Svbart@nginx.com 10391183Svbart@nginx.com mtype = nxt_mp_get(mp, sizeof(nxt_http_static_mtype_t)); 10401183Svbart@nginx.com if (nxt_slow_path(mtype == NULL)) { 10411183Svbart@nginx.com return NXT_ERROR; 10421183Svbart@nginx.com } 10431183Svbart@nginx.com 10441923Sz.hong@f5.com mtype->exten = *exten; 10451183Svbart@nginx.com mtype->type = type; 10461183Svbart@nginx.com 10471923Sz.hong@f5.com lhq.key = *exten; 10481183Svbart@nginx.com lhq.key_hash = nxt_djb_hash_lowcase(lhq.key.start, lhq.key.length); 10491183Svbart@nginx.com lhq.replace = 1; 10501183Svbart@nginx.com lhq.value = mtype; 10511183Svbart@nginx.com lhq.proto = &nxt_http_static_mtypes_hash_proto; 10521183Svbart@nginx.com lhq.pool = mp; 10531183Svbart@nginx.com 10541183Svbart@nginx.com return nxt_lvlhsh_insert(hash, &lhq); 10551183Svbart@nginx.com } 10561183Svbart@nginx.com 10571183Svbart@nginx.com 10581183Svbart@nginx.com nxt_str_t * 10592139Sandrew@digital-domain.net nxt_http_static_mtype_get(nxt_lvlhsh_t *hash, const nxt_str_t *exten) 10601183Svbart@nginx.com { 10611183Svbart@nginx.com nxt_lvlhsh_query_t lhq; 10621183Svbart@nginx.com nxt_http_static_mtype_t *mtype; 10631183Svbart@nginx.com 10641883So.canty@f5.com static nxt_str_t empty = nxt_string(""); 10651883So.canty@f5.com 10661923Sz.hong@f5.com lhq.key = *exten; 10671183Svbart@nginx.com lhq.key_hash = nxt_djb_hash_lowcase(lhq.key.start, lhq.key.length); 10681183Svbart@nginx.com lhq.proto = &nxt_http_static_mtypes_hash_proto; 10691183Svbart@nginx.com 10701183Svbart@nginx.com if (nxt_lvlhsh_find(hash, &lhq) == NXT_OK) { 10711183Svbart@nginx.com mtype = lhq.value; 10721183Svbart@nginx.com return mtype->type; 10731183Svbart@nginx.com } 10741183Svbart@nginx.com 10751883So.canty@f5.com return ∅ 10761183Svbart@nginx.com } 10771183Svbart@nginx.com 10781183Svbart@nginx.com 10791183Svbart@nginx.com static nxt_int_t 10801183Svbart@nginx.com nxt_http_static_mtypes_hash_test(nxt_lvlhsh_query_t *lhq, void *data) 10811183Svbart@nginx.com { 10821183Svbart@nginx.com nxt_http_static_mtype_t *mtype; 10831183Svbart@nginx.com 10841183Svbart@nginx.com mtype = data; 10851183Svbart@nginx.com 10861923Sz.hong@f5.com return nxt_strcasestr_eq(&lhq->key, &mtype->exten) ? NXT_OK : NXT_DECLINED; 10871183Svbart@nginx.com } 10881183Svbart@nginx.com 10891183Svbart@nginx.com 10901183Svbart@nginx.com static void * 10911183Svbart@nginx.com nxt_http_static_mtypes_hash_alloc(void *data, size_t size) 10921183Svbart@nginx.com { 10931183Svbart@nginx.com return nxt_mp_align(data, size, size); 10941183Svbart@nginx.com } 10951183Svbart@nginx.com 10961183Svbart@nginx.com 10971183Svbart@nginx.com static void 10981183Svbart@nginx.com nxt_http_static_mtypes_hash_free(void *data, void *p) 10991183Svbart@nginx.com { 11001183Svbart@nginx.com nxt_mp_free(data, p); 11011183Svbart@nginx.com } 1102