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 { 111961Sz.hong@f5.com nxt_var_t *var; 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; 221959Sz.hong@f5.com #if (NXT_HAVE_OPENAT2) 231959Sz.hong@f5.com nxt_var_t *chroot; 241959Sz.hong@f5.com nxt_uint_t resolve; 251959Sz.hong@f5.com #endif 261959Sz.hong@f5.com nxt_http_route_rule_t *types; 271923Sz.hong@f5.com } nxt_http_static_conf_t; 281923Sz.hong@f5.com 291923Sz.hong@f5.com 301959Sz.hong@f5.com typedef struct { 311959Sz.hong@f5.com nxt_http_action_t *action; 321960Sz.hong@f5.com nxt_str_t share; 331959Sz.hong@f5.com #if (NXT_HAVE_OPENAT2) 341959Sz.hong@f5.com nxt_str_t chroot; 351959Sz.hong@f5.com #endif 361961Sz.hong@f5.com uint32_t index; 371959Sz.hong@f5.com uint8_t need_body; /* 1 bit */ 381959Sz.hong@f5.com } nxt_http_static_ctx_t; 391959Sz.hong@f5.com 401959Sz.hong@f5.com 411183Svbart@nginx.com #define NXT_HTTP_STATIC_BUF_COUNT 2 421183Svbart@nginx.com #define NXT_HTTP_STATIC_BUF_SIZE (128 * 1024) 431183Svbart@nginx.com 441183Svbart@nginx.com 451923Sz.hong@f5.com static nxt_http_action_t *nxt_http_static(nxt_task_t *task, 461923Sz.hong@f5.com nxt_http_request_t *r, nxt_http_action_t *action); 471961Sz.hong@f5.com static void nxt_http_static_iterate(nxt_task_t *task, nxt_http_request_t *r, 481961Sz.hong@f5.com nxt_http_static_ctx_t *ctx); 491959Sz.hong@f5.com static void nxt_http_static_send_ready(nxt_task_t *task, void *obj, void *data); 501959Sz.hong@f5.com static void nxt_http_static_var_error(nxt_task_t *task, void *obj, void *data); 511961Sz.hong@f5.com static void nxt_http_static_next(nxt_task_t *task, nxt_http_request_t *r, 521961Sz.hong@f5.com nxt_http_static_ctx_t *ctx, nxt_http_status_t status); 531959Sz.hong@f5.com #if (NXT_HAVE_OPENAT2) 541959Sz.hong@f5.com static u_char *nxt_http_static_chroot_match(u_char *chr, u_char *shr); 551959Sz.hong@f5.com #endif 561183Svbart@nginx.com static void nxt_http_static_extract_extension(nxt_str_t *path, 571923Sz.hong@f5.com nxt_str_t *exten); 581183Svbart@nginx.com static void nxt_http_static_body_handler(nxt_task_t *task, void *obj, 591183Svbart@nginx.com void *data); 601183Svbart@nginx.com static void nxt_http_static_buf_completion(nxt_task_t *task, void *obj, 611183Svbart@nginx.com void *data); 621183Svbart@nginx.com 631183Svbart@nginx.com static nxt_int_t nxt_http_static_mtypes_hash_test(nxt_lvlhsh_query_t *lhq, 641183Svbart@nginx.com void *data); 651183Svbart@nginx.com static void *nxt_http_static_mtypes_hash_alloc(void *data, size_t size); 661183Svbart@nginx.com static void nxt_http_static_mtypes_hash_free(void *data, void *p); 671183Svbart@nginx.com 681183Svbart@nginx.com 691183Svbart@nginx.com static const nxt_http_request_state_t nxt_http_static_send_state; 701183Svbart@nginx.com 711183Svbart@nginx.com 721923Sz.hong@f5.com nxt_int_t 731923Sz.hong@f5.com nxt_http_static_init(nxt_task_t *task, nxt_router_temp_conf_t *tmcf, 741923Sz.hong@f5.com nxt_http_action_t *action, nxt_http_action_conf_t *acf) 751923Sz.hong@f5.com { 761961Sz.hong@f5.com uint32_t i; 771923Sz.hong@f5.com nxt_mp_t *mp; 781960Sz.hong@f5.com nxt_str_t str; 791961Sz.hong@f5.com nxt_var_t *var; 801961Sz.hong@f5.com nxt_bool_t array; 811961Sz.hong@f5.com nxt_conf_value_t *cv; 821923Sz.hong@f5.com nxt_http_static_conf_t *conf; 831923Sz.hong@f5.com 841923Sz.hong@f5.com mp = tmcf->router_conf->mem_pool; 851923Sz.hong@f5.com 861923Sz.hong@f5.com conf = nxt_mp_zget(mp, sizeof(nxt_http_static_conf_t)); 871923Sz.hong@f5.com if (nxt_slow_path(conf == NULL)) { 881923Sz.hong@f5.com return NXT_ERROR; 891923Sz.hong@f5.com } 901923Sz.hong@f5.com 911923Sz.hong@f5.com action->handler = nxt_http_static; 921923Sz.hong@f5.com action->u.conf = conf; 931923Sz.hong@f5.com 941961Sz.hong@f5.com array = (nxt_conf_type(acf->share) == NXT_CONF_ARRAY); 951961Sz.hong@f5.com conf->nshares = array ? nxt_conf_array_elements_count(acf->share) : 1; 961923Sz.hong@f5.com 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 1031961Sz.hong@f5.com if (array) { 1041961Sz.hong@f5.com for (i = 0; i < conf->nshares; i++) { 1051961Sz.hong@f5.com cv = nxt_conf_get_array_element(acf->share, i); 1061961Sz.hong@f5.com nxt_conf_get_string(cv, &str); 1071961Sz.hong@f5.com 1081961Sz.hong@f5.com var = nxt_var_compile(&str, mp, 1); 1091961Sz.hong@f5.com if (nxt_slow_path(var == NULL)) { 1101961Sz.hong@f5.com return NXT_ERROR; 1111961Sz.hong@f5.com } 1121961Sz.hong@f5.com 1131961Sz.hong@f5.com conf->shares[i].var = var; 1141961Sz.hong@f5.com conf->shares[i].is_const = nxt_var_is_const(var); 1151961Sz.hong@f5.com } 1161961Sz.hong@f5.com 1171961Sz.hong@f5.com } else { 1181961Sz.hong@f5.com nxt_conf_get_string(acf->share, &str); 1191961Sz.hong@f5.com 1201961Sz.hong@f5.com var = nxt_var_compile(&str, mp, 1); 1211961Sz.hong@f5.com if (nxt_slow_path(var == NULL)) { 1221961Sz.hong@f5.com return NXT_ERROR; 1231961Sz.hong@f5.com } 1241961Sz.hong@f5.com 1251961Sz.hong@f5.com conf->shares[0].var = var; 1261961Sz.hong@f5.com conf->shares[0].is_const = nxt_var_is_const(var); 1271961Sz.hong@f5.com } 1281959Sz.hong@f5.com 1291923Sz.hong@f5.com #if (NXT_HAVE_OPENAT2) 1301923Sz.hong@f5.com if (acf->chroot.length > 0) { 1311961Sz.hong@f5.com nxt_str_t chr, shr; 1321961Sz.hong@f5.com nxt_bool_t is_const; 1331923Sz.hong@f5.com 1341959Sz.hong@f5.com conf->chroot = nxt_var_compile(&acf->chroot, mp, 1); 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 1391961Sz.hong@f5.com is_const = nxt_var_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) { 1451961Sz.hong@f5.com nxt_var_raw(conf->chroot, &chr); 1461961Sz.hong@f5.com nxt_var_raw(conf->shares[i].var, &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; 2321961Sz.hong@f5.com nxt_http_static_conf_t *conf; 2331961Sz.hong@f5.com nxt_http_static_share_t *share; 2341961Sz.hong@f5.com 2351961Sz.hong@f5.com conf = ctx->action->u.conf; 2361961Sz.hong@f5.com 2371961Sz.hong@f5.com share = &conf->shares[ctx->index]; 2381959Sz.hong@f5.com 2391960Sz.hong@f5.com #if (NXT_DEBUG) 2401960Sz.hong@f5.com nxt_str_t shr; 2411960Sz.hong@f5.com 2421961Sz.hong@f5.com nxt_var_raw(share->var, &shr); 2431960Sz.hong@f5.com 2441960Sz.hong@f5.com #if (NXT_HAVE_OPENAT2) 2451959Sz.hong@f5.com nxt_str_t chr; 2461959Sz.hong@f5.com 2471959Sz.hong@f5.com if (conf->chroot != NULL) { 2481959Sz.hong@f5.com nxt_var_raw(conf->chroot, &chr); 2491959Sz.hong@f5.com 2501959Sz.hong@f5.com } else { 2511959Sz.hong@f5.com nxt_str_set(&chr, ""); 2521959Sz.hong@f5.com } 2531959Sz.hong@f5.com 2541960Sz.hong@f5.com nxt_debug(task, "http static: \"%V\" (chroot: \"%V\")", &shr, &chr); 2551959Sz.hong@f5.com #else 2561960Sz.hong@f5.com nxt_debug(task, "http static: \"%V\"", &shr); 2571959Sz.hong@f5.com #endif 2581960Sz.hong@f5.com #endif /* NXT_DEBUG */ 2591959Sz.hong@f5.com 2601961Sz.hong@f5.com if (share->is_const) { 2611961Sz.hong@f5.com nxt_var_raw(share->var, &ctx->share); 2621960Sz.hong@f5.com 2631959Sz.hong@f5.com #if (NXT_HAVE_OPENAT2) 2641961Sz.hong@f5.com if (conf->chroot != NULL && ctx->index == 0) { 2651959Sz.hong@f5.com nxt_var_raw(conf->chroot, &ctx->chroot); 2661959Sz.hong@f5.com } 2671959Sz.hong@f5.com #endif 2681959Sz.hong@f5.com 2691959Sz.hong@f5.com nxt_http_static_send_ready(task, r, ctx); 2701959Sz.hong@f5.com 2711959Sz.hong@f5.com } else { 2721959Sz.hong@f5.com ret = nxt_var_query_init(&r->var_query, r, r->mem_pool); 2731959Sz.hong@f5.com if (nxt_slow_path(ret != NXT_OK)) { 2741961Sz.hong@f5.com nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 2751961Sz.hong@f5.com return; 2761959Sz.hong@f5.com } 2771959Sz.hong@f5.com 2781961Sz.hong@f5.com nxt_var_query(task, r->var_query, share->var, &ctx->share); 2791960Sz.hong@f5.com 2801959Sz.hong@f5.com #if (NXT_HAVE_OPENAT2) 2811961Sz.hong@f5.com if (conf->chroot != NULL && ctx->index == 0) { 2821960Sz.hong@f5.com nxt_var_query(task, r->var_query, conf->chroot, &ctx->chroot); 2831960Sz.hong@f5.com } 2841959Sz.hong@f5.com #endif 2851959Sz.hong@f5.com 2861959Sz.hong@f5.com nxt_var_query_resolve(task, r->var_query, ctx, 2871959Sz.hong@f5.com nxt_http_static_send_ready, 2881959Sz.hong@f5.com nxt_http_static_var_error); 2891961Sz.hong@f5.com } 2901959Sz.hong@f5.com } 2911959Sz.hong@f5.com 2921959Sz.hong@f5.com 2931959Sz.hong@f5.com static void 2941959Sz.hong@f5.com nxt_http_static_send_ready(nxt_task_t *task, void *obj, void *data) 2951959Sz.hong@f5.com { 2961959Sz.hong@f5.com size_t length, encode; 2971959Sz.hong@f5.com u_char *p, *fname; 2981959Sz.hong@f5.com struct tm tm; 2991959Sz.hong@f5.com nxt_buf_t *fb; 3001959Sz.hong@f5.com nxt_int_t ret; 3011960Sz.hong@f5.com nxt_str_t *shr, exten, *mtype; 3021959Sz.hong@f5.com nxt_uint_t level; 3031959Sz.hong@f5.com nxt_file_t *f, file; 3041959Sz.hong@f5.com nxt_file_info_t fi; 3051959Sz.hong@f5.com nxt_http_field_t *field; 3061959Sz.hong@f5.com nxt_http_status_t status; 3071959Sz.hong@f5.com nxt_router_conf_t *rtcf; 3081959Sz.hong@f5.com nxt_http_action_t *action; 3091959Sz.hong@f5.com nxt_http_request_t *r; 3101959Sz.hong@f5.com nxt_work_handler_t body_handler; 3111959Sz.hong@f5.com nxt_http_static_ctx_t *ctx; 3121959Sz.hong@f5.com nxt_http_static_conf_t *conf; 3131959Sz.hong@f5.com 3141961Sz.hong@f5.com static const nxt_str_t index = nxt_string("index.html"); 3151960Sz.hong@f5.com 3161959Sz.hong@f5.com r = obj; 3171959Sz.hong@f5.com ctx = data; 3181959Sz.hong@f5.com action = ctx->action; 3191959Sz.hong@f5.com conf = action->u.conf; 3201960Sz.hong@f5.com rtcf = r->conf->socket_conf->router_conf; 3211183Svbart@nginx.com 3221855Sz.hong@f5.com f = NULL; 3231960Sz.hong@f5.com mtype = NULL; 3241959Sz.hong@f5.com status = NXT_HTTP_INTERNAL_SERVER_ERROR; 3251183Svbart@nginx.com 3261960Sz.hong@f5.com shr = &ctx->share; 3271859So.canty@f5.com 3281960Sz.hong@f5.com if (shr->start[shr->length - 1] == '/') { 3291960Sz.hong@f5.com /* TODO: dynamic index setting. */ 3301960Sz.hong@f5.com nxt_str_set(&exten, ".html"); 3311859So.canty@f5.com 3321960Sz.hong@f5.com length = shr->length + index.length; 3331960Sz.hong@f5.com 3341960Sz.hong@f5.com fname = nxt_mp_nget(r->mem_pool, length + 1); 3351960Sz.hong@f5.com if (nxt_slow_path(fname == NULL)) { 3361883So.canty@f5.com goto fail; 3371883So.canty@f5.com } 3381883So.canty@f5.com 3391960Sz.hong@f5.com p = fname; 3401960Sz.hong@f5.com p = nxt_cpymem(p, shr->start, shr->length); 3411960Sz.hong@f5.com p = nxt_cpymem(p, index.start, index.length); 3421960Sz.hong@f5.com *p = '\0'; 3431859So.canty@f5.com 3441960Sz.hong@f5.com } else { 3451960Sz.hong@f5.com if (conf->types == NULL) { 3461960Sz.hong@f5.com nxt_str_null(&exten); 3471960Sz.hong@f5.com 3481960Sz.hong@f5.com } else { 3491960Sz.hong@f5.com nxt_http_static_extract_extension(shr, &exten); 3501960Sz.hong@f5.com mtype = nxt_http_static_mtype_get(&rtcf->mtypes_hash, &exten); 3511855Sz.hong@f5.com 3521960Sz.hong@f5.com ret = nxt_http_route_test_rule(r, conf->types, mtype->start, 3531960Sz.hong@f5.com mtype->length); 3541960Sz.hong@f5.com if (nxt_slow_path(ret == NXT_ERROR)) { 3551960Sz.hong@f5.com goto fail; 3561960Sz.hong@f5.com } 3571183Svbart@nginx.com 3581960Sz.hong@f5.com if (ret == 0) { 3591961Sz.hong@f5.com nxt_http_static_next(task, r, ctx, NXT_HTTP_FORBIDDEN); 3601961Sz.hong@f5.com return; 3611960Sz.hong@f5.com } 3621960Sz.hong@f5.com } 3631960Sz.hong@f5.com 3641960Sz.hong@f5.com fname = ctx->share.start; 3651960Sz.hong@f5.com } 3661183Svbart@nginx.com 3671855Sz.hong@f5.com nxt_memzero(&file, sizeof(nxt_file_t)); 3681855Sz.hong@f5.com 3691855Sz.hong@f5.com file.name = fname; 3701855Sz.hong@f5.com 3711959Sz.hong@f5.com #if (NXT_HAVE_OPENAT2) 3721959Sz.hong@f5.com if (conf->resolve != 0 || ctx->chroot.length > 0) { 3731961Sz.hong@f5.com nxt_str_t *chr; 3741961Sz.hong@f5.com nxt_uint_t resolve; 3751961Sz.hong@f5.com nxt_http_static_share_t *share; 3761961Sz.hong@f5.com 3771961Sz.hong@f5.com share = &conf->shares[ctx->index]; 3781855Sz.hong@f5.com 3791959Sz.hong@f5.com resolve = conf->resolve; 3801959Sz.hong@f5.com chr = &ctx->chroot; 3811855Sz.hong@f5.com 3821959Sz.hong@f5.com if (chr->length > 0) { 3831959Sz.hong@f5.com resolve |= RESOLVE_IN_ROOT; 3841855Sz.hong@f5.com 3851961Sz.hong@f5.com fname = share->is_const 3861961Sz.hong@f5.com ? share->fname 3871960Sz.hong@f5.com : nxt_http_static_chroot_match(chr->start, file.name); 3881959Sz.hong@f5.com 3891959Sz.hong@f5.com if (fname != NULL) { 3901959Sz.hong@f5.com file.name = chr->start; 3911855Sz.hong@f5.com ret = nxt_file_open(task, &file, NXT_FILE_SEARCH, NXT_FILE_OPEN, 3921855Sz.hong@f5.com 0); 3931855Sz.hong@f5.com 3941855Sz.hong@f5.com } else { 3951855Sz.hong@f5.com file.error = NXT_EACCES; 3961855Sz.hong@f5.com ret = NXT_ERROR; 3971855Sz.hong@f5.com } 3981855Sz.hong@f5.com 3991855Sz.hong@f5.com } else if (fname[0] == '/') { 4001855Sz.hong@f5.com file.name = (u_char *) "/"; 4011855Sz.hong@f5.com ret = nxt_file_open(task, &file, NXT_FILE_SEARCH, NXT_FILE_OPEN, 0); 4021855Sz.hong@f5.com 4031855Sz.hong@f5.com } else { 4041855Sz.hong@f5.com file.name = (u_char *) "."; 4051855Sz.hong@f5.com file.fd = AT_FDCWD; 4061855Sz.hong@f5.com ret = NXT_OK; 4071855Sz.hong@f5.com } 4081855Sz.hong@f5.com 4091855Sz.hong@f5.com if (nxt_fast_path(ret == NXT_OK)) { 4101856Sz.hong@f5.com nxt_file_t af; 4111856Sz.hong@f5.com 4121855Sz.hong@f5.com af = file; 4131855Sz.hong@f5.com nxt_memzero(&file, sizeof(nxt_file_t)); 4141855Sz.hong@f5.com file.name = fname; 4151855Sz.hong@f5.com 4161855Sz.hong@f5.com ret = nxt_file_openat2(task, &file, NXT_FILE_RDONLY, 4171959Sz.hong@f5.com NXT_FILE_OPEN, 0, af.fd, resolve); 4181855Sz.hong@f5.com 4191855Sz.hong@f5.com if (af.fd != AT_FDCWD) { 4201855Sz.hong@f5.com nxt_file_close(task, &af); 4211855Sz.hong@f5.com } 4221855Sz.hong@f5.com } 4231855Sz.hong@f5.com 4241855Sz.hong@f5.com } else { 4251855Sz.hong@f5.com ret = nxt_file_open(task, &file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 0); 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 #endif 4311183Svbart@nginx.com 4321183Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 4331855Sz.hong@f5.com 4341855Sz.hong@f5.com switch (file.error) { 4351183Svbart@nginx.com 4361200Svbart@nginx.com /* 4371200Svbart@nginx.com * For Unix domain sockets "errno" is set to: 4381200Svbart@nginx.com * - ENXIO on Linux; 4391200Svbart@nginx.com * - EOPNOTSUPP on *BSD, MacOSX, and Solaris. 4401200Svbart@nginx.com */ 4411200Svbart@nginx.com 4421183Svbart@nginx.com case NXT_ENOENT: 4431183Svbart@nginx.com case NXT_ENOTDIR: 4441183Svbart@nginx.com case NXT_ENAMETOOLONG: 4451200Svbart@nginx.com #if (NXT_LINUX) 4461200Svbart@nginx.com case NXT_ENXIO: 4471200Svbart@nginx.com #else 4481200Svbart@nginx.com case NXT_EOPNOTSUPP: 4491200Svbart@nginx.com #endif 4501183Svbart@nginx.com level = NXT_LOG_ERR; 4511183Svbart@nginx.com status = NXT_HTTP_NOT_FOUND; 4521183Svbart@nginx.com break; 4531183Svbart@nginx.com 4541183Svbart@nginx.com case NXT_EACCES: 4551855Sz.hong@f5.com #if (NXT_HAVE_OPENAT2) 4561855Sz.hong@f5.com case NXT_ELOOP: 4571855Sz.hong@f5.com case NXT_EXDEV: 4581855Sz.hong@f5.com #endif 4591183Svbart@nginx.com level = NXT_LOG_ERR; 4601183Svbart@nginx.com status = NXT_HTTP_FORBIDDEN; 4611183Svbart@nginx.com break; 4621183Svbart@nginx.com 4631183Svbart@nginx.com default: 4641183Svbart@nginx.com level = NXT_LOG_ALERT; 4651183Svbart@nginx.com status = NXT_HTTP_INTERNAL_SERVER_ERROR; 4661183Svbart@nginx.com break; 4671183Svbart@nginx.com } 4681183Svbart@nginx.com 4691183Svbart@nginx.com if (status != NXT_HTTP_NOT_FOUND) { 4701959Sz.hong@f5.com #if (NXT_HAVE_OPENAT2) 4711959Sz.hong@f5.com nxt_str_t *chr = &ctx->chroot; 4721959Sz.hong@f5.com 4731959Sz.hong@f5.com if (chr->length > 0) { 4741857Sz.hong@f5.com nxt_log(task, level, "opening \"%s\" at \"%V\" failed %E", 4751959Sz.hong@f5.com fname, chr, file.error); 4761855Sz.hong@f5.com 4771855Sz.hong@f5.com } else { 4781857Sz.hong@f5.com nxt_log(task, level, "opening \"%s\" failed %E", 4791855Sz.hong@f5.com fname, file.error); 4801855Sz.hong@f5.com } 4811959Sz.hong@f5.com 4821959Sz.hong@f5.com #else 4831959Sz.hong@f5.com nxt_log(task, level, "opening \"%s\" failed %E", fname, file.error); 4841959Sz.hong@f5.com #endif 4851183Svbart@nginx.com } 4861183Svbart@nginx.com 4871961Sz.hong@f5.com if (level == NXT_LOG_ERR) { 4881961Sz.hong@f5.com nxt_http_static_next(task, r, ctx, status); 4891961Sz.hong@f5.com return; 4901961Sz.hong@f5.com } 4911961Sz.hong@f5.com 4921959Sz.hong@f5.com goto fail; 4931183Svbart@nginx.com } 4941183Svbart@nginx.com 4951855Sz.hong@f5.com f = nxt_mp_get(r->mem_pool, sizeof(nxt_file_t)); 4961855Sz.hong@f5.com if (nxt_slow_path(f == NULL)) { 497*1962Svbart@nginx.com nxt_file_close(task, &file); 4981855Sz.hong@f5.com goto fail; 4991855Sz.hong@f5.com } 5001855Sz.hong@f5.com 5011855Sz.hong@f5.com *f = file; 5021855Sz.hong@f5.com 5031183Svbart@nginx.com ret = nxt_file_info(f, &fi); 5041183Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 5051183Svbart@nginx.com goto fail; 5061183Svbart@nginx.com } 5071183Svbart@nginx.com 5081183Svbart@nginx.com if (nxt_fast_path(nxt_is_file(&fi))) { 5091183Svbart@nginx.com r->status = NXT_HTTP_OK; 5101183Svbart@nginx.com r->resp.content_length_n = nxt_file_size(&fi); 5111183Svbart@nginx.com 5121183Svbart@nginx.com field = nxt_list_zero_add(r->resp.fields); 5131183Svbart@nginx.com if (nxt_slow_path(field == NULL)) { 5141183Svbart@nginx.com goto fail; 5151183Svbart@nginx.com } 5161183Svbart@nginx.com 5171183Svbart@nginx.com nxt_http_field_name_set(field, "Last-Modified"); 5181183Svbart@nginx.com 5191183Svbart@nginx.com p = nxt_mp_nget(r->mem_pool, NXT_HTTP_DATE_LEN); 5201183Svbart@nginx.com if (nxt_slow_path(p == NULL)) { 5211183Svbart@nginx.com goto fail; 5221183Svbart@nginx.com } 5231183Svbart@nginx.com 5241183Svbart@nginx.com nxt_localtime(nxt_file_mtime(&fi), &tm); 5251183Svbart@nginx.com 5261183Svbart@nginx.com field->value = p; 5271183Svbart@nginx.com field->value_length = nxt_http_date(p, &tm) - p; 5281183Svbart@nginx.com 5291183Svbart@nginx.com field = nxt_list_zero_add(r->resp.fields); 5301183Svbart@nginx.com if (nxt_slow_path(field == NULL)) { 5311183Svbart@nginx.com goto fail; 5321183Svbart@nginx.com } 5331183Svbart@nginx.com 5341183Svbart@nginx.com nxt_http_field_name_set(field, "ETag"); 5351183Svbart@nginx.com 5361855Sz.hong@f5.com length = NXT_TIME_T_HEXLEN + NXT_OFF_T_HEXLEN + 3; 5371183Svbart@nginx.com 5381855Sz.hong@f5.com p = nxt_mp_nget(r->mem_pool, length); 5391183Svbart@nginx.com if (nxt_slow_path(p == NULL)) { 5401183Svbart@nginx.com goto fail; 5411183Svbart@nginx.com } 5421183Svbart@nginx.com 5431183Svbart@nginx.com field->value = p; 5441855Sz.hong@f5.com field->value_length = nxt_sprintf(p, p + length, "\"%xT-%xO\"", 5451183Svbart@nginx.com nxt_file_mtime(&fi), 5461183Svbart@nginx.com nxt_file_size(&fi)) 5471183Svbart@nginx.com - p; 5481183Svbart@nginx.com 5491923Sz.hong@f5.com if (exten.start == NULL) { 5501960Sz.hong@f5.com nxt_http_static_extract_extension(shr, &exten); 5511183Svbart@nginx.com } 5521183Svbart@nginx.com 5531859So.canty@f5.com if (mtype == NULL) { 5541923Sz.hong@f5.com mtype = nxt_http_static_mtype_get(&rtcf->mtypes_hash, &exten); 5551859So.canty@f5.com } 5561183Svbart@nginx.com 5571883So.canty@f5.com if (mtype->length != 0) { 5581183Svbart@nginx.com field = nxt_list_zero_add(r->resp.fields); 5591183Svbart@nginx.com if (nxt_slow_path(field == NULL)) { 5601183Svbart@nginx.com goto fail; 5611183Svbart@nginx.com } 5621183Svbart@nginx.com 5631183Svbart@nginx.com nxt_http_field_name_set(field, "Content-Type"); 5641183Svbart@nginx.com 5651183Svbart@nginx.com field->value = mtype->start; 5661183Svbart@nginx.com field->value_length = mtype->length; 5671183Svbart@nginx.com } 5681183Svbart@nginx.com 5691959Sz.hong@f5.com if (ctx->need_body && nxt_file_size(&fi) > 0) { 5701183Svbart@nginx.com fb = nxt_mp_zget(r->mem_pool, NXT_BUF_FILE_SIZE); 5711183Svbart@nginx.com if (nxt_slow_path(fb == NULL)) { 5721183Svbart@nginx.com goto fail; 5731183Svbart@nginx.com } 5741183Svbart@nginx.com 5751183Svbart@nginx.com fb->file = f; 5761183Svbart@nginx.com fb->file_end = nxt_file_size(&fi); 5771183Svbart@nginx.com 5781183Svbart@nginx.com r->out = fb; 5791183Svbart@nginx.com 5801183Svbart@nginx.com body_handler = &nxt_http_static_body_handler; 5811183Svbart@nginx.com 5821183Svbart@nginx.com } else { 5831183Svbart@nginx.com nxt_file_close(task, f); 5841183Svbart@nginx.com body_handler = NULL; 5851183Svbart@nginx.com } 5861183Svbart@nginx.com 5871183Svbart@nginx.com } else { 5881183Svbart@nginx.com /* Not a file. */ 5891961Sz.hong@f5.com nxt_file_close(task, f); 5901183Svbart@nginx.com 5911183Svbart@nginx.com if (nxt_slow_path(!nxt_is_dir(&fi))) { 5921961Sz.hong@f5.com nxt_log(task, NXT_LOG_ERR, "\"%FN\" is not a regular file", 5931961Sz.hong@f5.com f->name); 5941378Svbart@nginx.com 5951961Sz.hong@f5.com nxt_http_static_next(task, r, ctx, NXT_HTTP_NOT_FOUND); 5961961Sz.hong@f5.com return; 5971183Svbart@nginx.com } 5981183Svbart@nginx.com 5991198Svbart@nginx.com f = NULL; 6001198Svbart@nginx.com 6011183Svbart@nginx.com r->status = NXT_HTTP_MOVED_PERMANENTLY; 6021183Svbart@nginx.com r->resp.content_length_n = 0; 6031183Svbart@nginx.com 6041183Svbart@nginx.com field = nxt_list_zero_add(r->resp.fields); 6051183Svbart@nginx.com if (nxt_slow_path(field == NULL)) { 6061183Svbart@nginx.com goto fail; 6071183Svbart@nginx.com } 6081183Svbart@nginx.com 6091183Svbart@nginx.com nxt_http_field_name_set(field, "Location"); 6101183Svbart@nginx.com 6111183Svbart@nginx.com encode = nxt_encode_uri(NULL, r->path->start, r->path->length); 6121855Sz.hong@f5.com length = r->path->length + encode * 2 + 1; 6131183Svbart@nginx.com 6141183Svbart@nginx.com if (r->args->length > 0) { 6151855Sz.hong@f5.com length += 1 + r->args->length; 6161183Svbart@nginx.com } 6171183Svbart@nginx.com 6181855Sz.hong@f5.com p = nxt_mp_nget(r->mem_pool, length); 6191183Svbart@nginx.com if (nxt_slow_path(p == NULL)) { 6201183Svbart@nginx.com goto fail; 6211183Svbart@nginx.com } 6221183Svbart@nginx.com 6231183Svbart@nginx.com field->value = p; 6241855Sz.hong@f5.com field->value_length = length; 6251183Svbart@nginx.com 6261183Svbart@nginx.com if (encode > 0) { 6271183Svbart@nginx.com p = (u_char *) nxt_encode_uri(p, r->path->start, r->path->length); 6281183Svbart@nginx.com 6291183Svbart@nginx.com } else { 6301183Svbart@nginx.com p = nxt_cpymem(p, r->path->start, r->path->length); 6311183Svbart@nginx.com } 6321183Svbart@nginx.com 6331183Svbart@nginx.com *p++ = '/'; 6341183Svbart@nginx.com 6351183Svbart@nginx.com if (r->args->length > 0) { 6361183Svbart@nginx.com *p++ = '?'; 6371183Svbart@nginx.com nxt_memcpy(p, r->args->start, r->args->length); 6381183Svbart@nginx.com } 6391183Svbart@nginx.com 6401183Svbart@nginx.com body_handler = NULL; 6411183Svbart@nginx.com } 6421183Svbart@nginx.com 6431270Sigor@sysoev.ru nxt_http_request_header_send(task, r, body_handler, NULL); 6441183Svbart@nginx.com 6451183Svbart@nginx.com r->state = &nxt_http_static_send_state; 6461959Sz.hong@f5.com return; 6471183Svbart@nginx.com 6481183Svbart@nginx.com fail: 6491183Svbart@nginx.com 6501855Sz.hong@f5.com if (f != NULL) { 6511183Svbart@nginx.com nxt_file_close(task, f); 6521183Svbart@nginx.com } 6531183Svbart@nginx.com 6541961Sz.hong@f5.com nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 6551959Sz.hong@f5.com } 6561959Sz.hong@f5.com 6571959Sz.hong@f5.com 6581959Sz.hong@f5.com static void 6591959Sz.hong@f5.com nxt_http_static_var_error(nxt_task_t *task, void *obj, void *data) 6601959Sz.hong@f5.com { 6611959Sz.hong@f5.com nxt_http_request_t *r; 6621959Sz.hong@f5.com 6631959Sz.hong@f5.com r = obj; 6641959Sz.hong@f5.com 6651959Sz.hong@f5.com nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 6661183Svbart@nginx.com } 6671183Svbart@nginx.com 6681183Svbart@nginx.com 6691961Sz.hong@f5.com static void 6701961Sz.hong@f5.com nxt_http_static_next(nxt_task_t *task, nxt_http_request_t *r, 6711961Sz.hong@f5.com nxt_http_static_ctx_t *ctx, nxt_http_status_t status) 6721961Sz.hong@f5.com { 6731961Sz.hong@f5.com nxt_http_action_t *action; 6741961Sz.hong@f5.com nxt_http_static_conf_t *conf; 6751961Sz.hong@f5.com 6761961Sz.hong@f5.com action = ctx->action; 6771961Sz.hong@f5.com conf = action->u.conf; 6781961Sz.hong@f5.com 6791961Sz.hong@f5.com ctx->index++; 6801961Sz.hong@f5.com 6811961Sz.hong@f5.com if (ctx->index < conf->nshares) { 6821961Sz.hong@f5.com nxt_http_static_iterate(task, r, ctx); 6831961Sz.hong@f5.com return; 6841961Sz.hong@f5.com } 6851961Sz.hong@f5.com 6861961Sz.hong@f5.com if (action->fallback != NULL) { 6871961Sz.hong@f5.com nxt_http_request_action(task, r, action->fallback); 6881961Sz.hong@f5.com return; 6891961Sz.hong@f5.com } 6901961Sz.hong@f5.com 6911961Sz.hong@f5.com nxt_http_request_error(task, r, status); 6921961Sz.hong@f5.com } 6931961Sz.hong@f5.com 6941961Sz.hong@f5.com 6951959Sz.hong@f5.com #if (NXT_HAVE_OPENAT2) 6961959Sz.hong@f5.com 6971959Sz.hong@f5.com static u_char * 6981959Sz.hong@f5.com nxt_http_static_chroot_match(u_char *chr, u_char *shr) 6991959Sz.hong@f5.com { 7001959Sz.hong@f5.com if (*chr != *shr) { 7011959Sz.hong@f5.com return NULL; 7021959Sz.hong@f5.com } 7031959Sz.hong@f5.com 7041959Sz.hong@f5.com chr++; 7051959Sz.hong@f5.com shr++; 7061959Sz.hong@f5.com 7071959Sz.hong@f5.com for ( ;; ) { 7081959Sz.hong@f5.com if (*shr == '\0') { 7091959Sz.hong@f5.com return NULL; 7101959Sz.hong@f5.com } 7111959Sz.hong@f5.com 7121959Sz.hong@f5.com if (*chr == *shr) { 7131959Sz.hong@f5.com chr++; 7141959Sz.hong@f5.com shr++; 7151959Sz.hong@f5.com continue; 7161959Sz.hong@f5.com } 7171959Sz.hong@f5.com 7181959Sz.hong@f5.com if (*chr == '\0') { 7191959Sz.hong@f5.com break; 7201959Sz.hong@f5.com } 7211959Sz.hong@f5.com 7221959Sz.hong@f5.com if (*chr == '/') { 7231959Sz.hong@f5.com if (chr[-1] == '/') { 7241959Sz.hong@f5.com chr++; 7251959Sz.hong@f5.com continue; 7261959Sz.hong@f5.com } 7271959Sz.hong@f5.com 7281959Sz.hong@f5.com } else if (*shr == '/') { 7291959Sz.hong@f5.com if (shr[-1] == '/') { 7301959Sz.hong@f5.com shr++; 7311959Sz.hong@f5.com continue; 7321959Sz.hong@f5.com } 7331959Sz.hong@f5.com } 7341959Sz.hong@f5.com 7351959Sz.hong@f5.com return NULL; 7361959Sz.hong@f5.com } 7371959Sz.hong@f5.com 7381959Sz.hong@f5.com if (shr[-1] != '/' && *shr != '/') { 7391959Sz.hong@f5.com return NULL; 7401959Sz.hong@f5.com } 7411959Sz.hong@f5.com 7421959Sz.hong@f5.com while (*shr == '/') { 7431959Sz.hong@f5.com shr++; 7441959Sz.hong@f5.com } 7451959Sz.hong@f5.com 7461959Sz.hong@f5.com return (*shr != '\0') ? shr : NULL; 7471959Sz.hong@f5.com } 7481959Sz.hong@f5.com 7491959Sz.hong@f5.com #endif 7501959Sz.hong@f5.com 7511959Sz.hong@f5.com 7521183Svbart@nginx.com static void 7531923Sz.hong@f5.com nxt_http_static_extract_extension(nxt_str_t *path, nxt_str_t *exten) 7541183Svbart@nginx.com { 7551183Svbart@nginx.com u_char ch, *p, *end; 7561183Svbart@nginx.com 7571183Svbart@nginx.com end = path->start + path->length; 7581183Svbart@nginx.com p = end; 7591183Svbart@nginx.com 7601183Svbart@nginx.com for ( ;; ) { 7611183Svbart@nginx.com /* There's always '/' in the beginning of the request path. */ 7621183Svbart@nginx.com 7631183Svbart@nginx.com p--; 7641183Svbart@nginx.com ch = *p; 7651183Svbart@nginx.com 7661183Svbart@nginx.com switch (ch) { 7671183Svbart@nginx.com case '/': 7681183Svbart@nginx.com p++; 7691183Svbart@nginx.com /* Fall through. */ 7701183Svbart@nginx.com case '.': 7711923Sz.hong@f5.com exten->length = end - p; 7721923Sz.hong@f5.com exten->start = p; 7731183Svbart@nginx.com return; 7741183Svbart@nginx.com } 7751183Svbart@nginx.com } 7761183Svbart@nginx.com } 7771183Svbart@nginx.com 7781183Svbart@nginx.com 7791183Svbart@nginx.com static void 7801183Svbart@nginx.com nxt_http_static_body_handler(nxt_task_t *task, void *obj, void *data) 7811183Svbart@nginx.com { 7821183Svbart@nginx.com size_t alloc; 7831183Svbart@nginx.com nxt_buf_t *fb, *b, **next, *out; 7841183Svbart@nginx.com nxt_off_t rest; 7851183Svbart@nginx.com nxt_int_t n; 7861183Svbart@nginx.com nxt_work_queue_t *wq; 7871183Svbart@nginx.com nxt_http_request_t *r; 7881183Svbart@nginx.com 7891183Svbart@nginx.com r = obj; 7901183Svbart@nginx.com fb = r->out; 7911183Svbart@nginx.com 7921183Svbart@nginx.com rest = fb->file_end - fb->file_pos; 7931183Svbart@nginx.com out = NULL; 7941183Svbart@nginx.com next = &out; 7951183Svbart@nginx.com n = 0; 7961183Svbart@nginx.com 7971183Svbart@nginx.com do { 7981183Svbart@nginx.com alloc = nxt_min(rest, NXT_HTTP_STATIC_BUF_SIZE); 7991183Svbart@nginx.com 8001183Svbart@nginx.com b = nxt_buf_mem_alloc(r->mem_pool, alloc, 0); 8011183Svbart@nginx.com if (nxt_slow_path(b == NULL)) { 8021183Svbart@nginx.com goto fail; 8031183Svbart@nginx.com } 8041183Svbart@nginx.com 8051183Svbart@nginx.com b->completion_handler = nxt_http_static_buf_completion; 8061183Svbart@nginx.com b->parent = r; 8071183Svbart@nginx.com 8081183Svbart@nginx.com nxt_mp_retain(r->mem_pool); 8091183Svbart@nginx.com 8101183Svbart@nginx.com *next = b; 8111183Svbart@nginx.com next = &b->next; 8121183Svbart@nginx.com 8131183Svbart@nginx.com rest -= alloc; 8141183Svbart@nginx.com 8151183Svbart@nginx.com } while (rest > 0 && ++n < NXT_HTTP_STATIC_BUF_COUNT); 8161183Svbart@nginx.com 8171183Svbart@nginx.com wq = &task->thread->engine->fast_work_queue; 8181183Svbart@nginx.com 8191183Svbart@nginx.com nxt_sendbuf_drain(task, wq, out); 8201183Svbart@nginx.com return; 8211183Svbart@nginx.com 8221183Svbart@nginx.com fail: 8231183Svbart@nginx.com 8241183Svbart@nginx.com while (out != NULL) { 8251183Svbart@nginx.com b = out; 8261183Svbart@nginx.com out = b->next; 8271183Svbart@nginx.com 8281183Svbart@nginx.com nxt_mp_free(r->mem_pool, b); 8291183Svbart@nginx.com nxt_mp_release(r->mem_pool); 8301183Svbart@nginx.com } 8311183Svbart@nginx.com } 8321183Svbart@nginx.com 8331183Svbart@nginx.com 8341183Svbart@nginx.com static const nxt_http_request_state_t nxt_http_static_send_state 8351183Svbart@nginx.com nxt_aligned(64) = 8361183Svbart@nginx.com { 8371183Svbart@nginx.com .error_handler = nxt_http_request_error_handler, 8381183Svbart@nginx.com }; 8391183Svbart@nginx.com 8401183Svbart@nginx.com 8411183Svbart@nginx.com static void 8421183Svbart@nginx.com nxt_http_static_buf_completion(nxt_task_t *task, void *obj, void *data) 8431183Svbart@nginx.com { 8441183Svbart@nginx.com ssize_t n, size; 8451760Smax.romanov@nginx.com nxt_buf_t *b, *fb, *next; 8461183Svbart@nginx.com nxt_off_t rest; 8471183Svbart@nginx.com nxt_http_request_t *r; 8481183Svbart@nginx.com 8491183Svbart@nginx.com b = obj; 8501183Svbart@nginx.com r = data; 8511760Smax.romanov@nginx.com 8521760Smax.romanov@nginx.com complete_buf: 8531760Smax.romanov@nginx.com 8541183Svbart@nginx.com fb = r->out; 8551183Svbart@nginx.com 8561183Svbart@nginx.com if (nxt_slow_path(fb == NULL || r->error)) { 8571183Svbart@nginx.com goto clean; 8581183Svbart@nginx.com } 8591183Svbart@nginx.com 8601183Svbart@nginx.com rest = fb->file_end - fb->file_pos; 8611183Svbart@nginx.com size = nxt_buf_mem_size(&b->mem); 8621183Svbart@nginx.com 8631183Svbart@nginx.com size = nxt_min(rest, (nxt_off_t) size); 8641183Svbart@nginx.com 8651183Svbart@nginx.com n = nxt_file_read(fb->file, b->mem.start, size, fb->file_pos); 8661183Svbart@nginx.com 8671183Svbart@nginx.com if (n != size) { 8681183Svbart@nginx.com if (n >= 0) { 8691183Svbart@nginx.com nxt_log(task, NXT_LOG_ERR, "file \"%FN\" has changed " 8701183Svbart@nginx.com "while sending response to a client", fb->file->name); 8711183Svbart@nginx.com } 8721183Svbart@nginx.com 8731183Svbart@nginx.com nxt_http_request_error_handler(task, r, r->proto.any); 8741183Svbart@nginx.com goto clean; 8751183Svbart@nginx.com } 8761183Svbart@nginx.com 8771760Smax.romanov@nginx.com next = b->next; 8781760Smax.romanov@nginx.com 8791183Svbart@nginx.com if (n == rest) { 8801183Svbart@nginx.com nxt_file_close(task, fb->file); 8811183Svbart@nginx.com r->out = NULL; 8821183Svbart@nginx.com 8831183Svbart@nginx.com b->next = nxt_http_buf_last(r); 8841183Svbart@nginx.com 8851183Svbart@nginx.com } else { 8861183Svbart@nginx.com fb->file_pos += n; 8871183Svbart@nginx.com b->next = NULL; 8881183Svbart@nginx.com } 8891183Svbart@nginx.com 8901183Svbart@nginx.com b->mem.pos = b->mem.start; 8911183Svbart@nginx.com b->mem.free = b->mem.pos + n; 8921183Svbart@nginx.com 8931183Svbart@nginx.com nxt_http_request_send(task, r, b); 8941760Smax.romanov@nginx.com 8951760Smax.romanov@nginx.com if (next != NULL) { 8961760Smax.romanov@nginx.com b = next; 8971760Smax.romanov@nginx.com goto complete_buf; 8981760Smax.romanov@nginx.com } 8991760Smax.romanov@nginx.com 9001183Svbart@nginx.com return; 9011183Svbart@nginx.com 9021183Svbart@nginx.com clean: 9031183Svbart@nginx.com 9041760Smax.romanov@nginx.com do { 9051760Smax.romanov@nginx.com next = b->next; 9061760Smax.romanov@nginx.com 9071760Smax.romanov@nginx.com nxt_mp_free(r->mem_pool, b); 9081760Smax.romanov@nginx.com nxt_mp_release(r->mem_pool); 9091760Smax.romanov@nginx.com 9101760Smax.romanov@nginx.com b = next; 9111760Smax.romanov@nginx.com } while (b != NULL); 9121183Svbart@nginx.com 9131183Svbart@nginx.com if (fb != NULL) { 9141183Svbart@nginx.com nxt_file_close(task, fb->file); 9151183Svbart@nginx.com r->out = NULL; 9161183Svbart@nginx.com } 9171183Svbart@nginx.com } 9181183Svbart@nginx.com 9191183Svbart@nginx.com 9201183Svbart@nginx.com nxt_int_t 9211183Svbart@nginx.com nxt_http_static_mtypes_init(nxt_mp_t *mp, nxt_lvlhsh_t *hash) 9221183Svbart@nginx.com { 9231923Sz.hong@f5.com nxt_str_t *type, exten; 9241183Svbart@nginx.com nxt_int_t ret; 9251183Svbart@nginx.com nxt_uint_t i; 9261183Svbart@nginx.com 9271183Svbart@nginx.com static const struct { 9281183Svbart@nginx.com nxt_str_t type; 9291923Sz.hong@f5.com const char *exten; 9301183Svbart@nginx.com } default_types[] = { 9311183Svbart@nginx.com 9321183Svbart@nginx.com { nxt_string("text/html"), ".html" }, 9331183Svbart@nginx.com { nxt_string("text/html"), ".htm" }, 9341183Svbart@nginx.com { nxt_string("text/css"), ".css" }, 9351183Svbart@nginx.com 9361183Svbart@nginx.com { nxt_string("image/svg+xml"), ".svg" }, 9371183Svbart@nginx.com { nxt_string("image/webp"), ".webp" }, 9381183Svbart@nginx.com { nxt_string("image/png"), ".png" }, 9391617Svbart@nginx.com { nxt_string("image/apng"), ".apng" }, 9401183Svbart@nginx.com { nxt_string("image/jpeg"), ".jpeg" }, 9411183Svbart@nginx.com { nxt_string("image/jpeg"), ".jpg" }, 9421183Svbart@nginx.com { nxt_string("image/gif"), ".gif" }, 9431183Svbart@nginx.com { nxt_string("image/x-icon"), ".ico" }, 9441183Svbart@nginx.com 9451617Svbart@nginx.com { nxt_string("image/avif"), ".avif" }, 9461617Svbart@nginx.com { nxt_string("image/avif-sequence"), ".avifs" }, 9471617Svbart@nginx.com 9481183Svbart@nginx.com { nxt_string("font/woff"), ".woff" }, 9491183Svbart@nginx.com { nxt_string("font/woff2"), ".woff2" }, 9501183Svbart@nginx.com { nxt_string("font/otf"), ".otf" }, 9511183Svbart@nginx.com { nxt_string("font/ttf"), ".ttf" }, 9521183Svbart@nginx.com 9531183Svbart@nginx.com { nxt_string("text/plain"), ".txt" }, 9541183Svbart@nginx.com { nxt_string("text/markdown"), ".md" }, 9551183Svbart@nginx.com { nxt_string("text/x-rst"), ".rst" }, 9561183Svbart@nginx.com 9571183Svbart@nginx.com { nxt_string("application/javascript"), ".js" }, 9581183Svbart@nginx.com { nxt_string("application/json"), ".json" }, 9591183Svbart@nginx.com { nxt_string("application/xml"), ".xml" }, 9601183Svbart@nginx.com { nxt_string("application/rss+xml"), ".rss" }, 9611183Svbart@nginx.com { nxt_string("application/atom+xml"), ".atom" }, 9621183Svbart@nginx.com { nxt_string("application/pdf"), ".pdf" }, 9631183Svbart@nginx.com 9641183Svbart@nginx.com { nxt_string("application/zip"), ".zip" }, 9651183Svbart@nginx.com 9661183Svbart@nginx.com { nxt_string("audio/mpeg"), ".mp3" }, 9671183Svbart@nginx.com { nxt_string("audio/ogg"), ".ogg" }, 9681183Svbart@nginx.com { nxt_string("audio/midi"), ".midi" }, 9691183Svbart@nginx.com { nxt_string("audio/midi"), ".mid" }, 9701183Svbart@nginx.com { nxt_string("audio/flac"), ".flac" }, 9711183Svbart@nginx.com { nxt_string("audio/aac"), ".aac" }, 9721183Svbart@nginx.com { nxt_string("audio/wav"), ".wav" }, 9731183Svbart@nginx.com 9741183Svbart@nginx.com { nxt_string("video/mpeg"), ".mpeg" }, 9751183Svbart@nginx.com { nxt_string("video/mpeg"), ".mpg" }, 9761183Svbart@nginx.com { nxt_string("video/mp4"), ".mp4" }, 9771183Svbart@nginx.com { nxt_string("video/webm"), ".webm" }, 9781183Svbart@nginx.com { nxt_string("video/x-msvideo"), ".avi" }, 9791183Svbart@nginx.com 9801183Svbart@nginx.com { nxt_string("application/octet-stream"), ".exe" }, 9811183Svbart@nginx.com { nxt_string("application/octet-stream"), ".bin" }, 9821183Svbart@nginx.com { nxt_string("application/octet-stream"), ".dll" }, 9831183Svbart@nginx.com { nxt_string("application/octet-stream"), ".iso" }, 9841183Svbart@nginx.com { nxt_string("application/octet-stream"), ".img" }, 9851183Svbart@nginx.com { nxt_string("application/octet-stream"), ".msi" }, 9861183Svbart@nginx.com 9871183Svbart@nginx.com { nxt_string("application/octet-stream"), ".deb" }, 9881183Svbart@nginx.com { nxt_string("application/octet-stream"), ".rpm" }, 9891882So.canty@f5.com 9901882So.canty@f5.com { nxt_string("application/x-httpd-php"), ".php" }, 9911183Svbart@nginx.com }; 9921183Svbart@nginx.com 9931183Svbart@nginx.com for (i = 0; i < nxt_nitems(default_types); i++) { 9941183Svbart@nginx.com type = (nxt_str_t *) &default_types[i].type; 9951183Svbart@nginx.com 9961923Sz.hong@f5.com exten.start = (u_char *) default_types[i].exten; 9971923Sz.hong@f5.com exten.length = nxt_strlen(exten.start); 9981183Svbart@nginx.com 9991923Sz.hong@f5.com ret = nxt_http_static_mtypes_hash_add(mp, hash, &exten, type); 10001183Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 10011183Svbart@nginx.com return NXT_ERROR; 10021183Svbart@nginx.com } 10031183Svbart@nginx.com } 10041183Svbart@nginx.com 10051183Svbart@nginx.com return NXT_OK; 10061183Svbart@nginx.com } 10071183Svbart@nginx.com 10081183Svbart@nginx.com 10091183Svbart@nginx.com static const nxt_lvlhsh_proto_t nxt_http_static_mtypes_hash_proto 10101183Svbart@nginx.com nxt_aligned(64) = 10111183Svbart@nginx.com { 10121183Svbart@nginx.com NXT_LVLHSH_DEFAULT, 10131183Svbart@nginx.com nxt_http_static_mtypes_hash_test, 10141183Svbart@nginx.com nxt_http_static_mtypes_hash_alloc, 10151183Svbart@nginx.com nxt_http_static_mtypes_hash_free, 10161183Svbart@nginx.com }; 10171183Svbart@nginx.com 10181183Svbart@nginx.com 10191183Svbart@nginx.com typedef struct { 10201923Sz.hong@f5.com nxt_str_t exten; 10211183Svbart@nginx.com nxt_str_t *type; 10221183Svbart@nginx.com } nxt_http_static_mtype_t; 10231183Svbart@nginx.com 10241183Svbart@nginx.com 10251183Svbart@nginx.com nxt_int_t 10261183Svbart@nginx.com nxt_http_static_mtypes_hash_add(nxt_mp_t *mp, nxt_lvlhsh_t *hash, 10271923Sz.hong@f5.com nxt_str_t *exten, nxt_str_t *type) 10281183Svbart@nginx.com { 10291183Svbart@nginx.com nxt_lvlhsh_query_t lhq; 10301183Svbart@nginx.com nxt_http_static_mtype_t *mtype; 10311183Svbart@nginx.com 10321183Svbart@nginx.com mtype = nxt_mp_get(mp, sizeof(nxt_http_static_mtype_t)); 10331183Svbart@nginx.com if (nxt_slow_path(mtype == NULL)) { 10341183Svbart@nginx.com return NXT_ERROR; 10351183Svbart@nginx.com } 10361183Svbart@nginx.com 10371923Sz.hong@f5.com mtype->exten = *exten; 10381183Svbart@nginx.com mtype->type = type; 10391183Svbart@nginx.com 10401923Sz.hong@f5.com lhq.key = *exten; 10411183Svbart@nginx.com lhq.key_hash = nxt_djb_hash_lowcase(lhq.key.start, lhq.key.length); 10421183Svbart@nginx.com lhq.replace = 1; 10431183Svbart@nginx.com lhq.value = mtype; 10441183Svbart@nginx.com lhq.proto = &nxt_http_static_mtypes_hash_proto; 10451183Svbart@nginx.com lhq.pool = mp; 10461183Svbart@nginx.com 10471183Svbart@nginx.com return nxt_lvlhsh_insert(hash, &lhq); 10481183Svbart@nginx.com } 10491183Svbart@nginx.com 10501183Svbart@nginx.com 10511183Svbart@nginx.com nxt_str_t * 10521923Sz.hong@f5.com nxt_http_static_mtype_get(nxt_lvlhsh_t *hash, nxt_str_t *exten) 10531183Svbart@nginx.com { 10541183Svbart@nginx.com nxt_lvlhsh_query_t lhq; 10551183Svbart@nginx.com nxt_http_static_mtype_t *mtype; 10561183Svbart@nginx.com 10571883So.canty@f5.com static nxt_str_t empty = nxt_string(""); 10581883So.canty@f5.com 10591923Sz.hong@f5.com lhq.key = *exten; 10601183Svbart@nginx.com lhq.key_hash = nxt_djb_hash_lowcase(lhq.key.start, lhq.key.length); 10611183Svbart@nginx.com lhq.proto = &nxt_http_static_mtypes_hash_proto; 10621183Svbart@nginx.com 10631183Svbart@nginx.com if (nxt_lvlhsh_find(hash, &lhq) == NXT_OK) { 10641183Svbart@nginx.com mtype = lhq.value; 10651183Svbart@nginx.com return mtype->type; 10661183Svbart@nginx.com } 10671183Svbart@nginx.com 10681883So.canty@f5.com return ∅ 10691183Svbart@nginx.com } 10701183Svbart@nginx.com 10711183Svbart@nginx.com 10721183Svbart@nginx.com static nxt_int_t 10731183Svbart@nginx.com nxt_http_static_mtypes_hash_test(nxt_lvlhsh_query_t *lhq, void *data) 10741183Svbart@nginx.com { 10751183Svbart@nginx.com nxt_http_static_mtype_t *mtype; 10761183Svbart@nginx.com 10771183Svbart@nginx.com mtype = data; 10781183Svbart@nginx.com 10791923Sz.hong@f5.com return nxt_strcasestr_eq(&lhq->key, &mtype->exten) ? NXT_OK : NXT_DECLINED; 10801183Svbart@nginx.com } 10811183Svbart@nginx.com 10821183Svbart@nginx.com 10831183Svbart@nginx.com static void * 10841183Svbart@nginx.com nxt_http_static_mtypes_hash_alloc(void *data, size_t size) 10851183Svbart@nginx.com { 10861183Svbart@nginx.com return nxt_mp_align(data, size, size); 10871183Svbart@nginx.com } 10881183Svbart@nginx.com 10891183Svbart@nginx.com 10901183Svbart@nginx.com static void 10911183Svbart@nginx.com nxt_http_static_mtypes_hash_free(void *data, void *p) 10921183Svbart@nginx.com { 10931183Svbart@nginx.com nxt_mp_free(data, p); 10941183Svbart@nginx.com } 1095