xref: /unit/src/nxt_http_static.c (revision 2077)
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_conf_value_t        *cv;
811923Sz.hong@f5.com     nxt_http_static_conf_t  *conf;
821923Sz.hong@f5.com 
831923Sz.hong@f5.com     mp = tmcf->router_conf->mem_pool;
841923Sz.hong@f5.com 
851923Sz.hong@f5.com     conf = nxt_mp_zget(mp, sizeof(nxt_http_static_conf_t));
861923Sz.hong@f5.com     if (nxt_slow_path(conf == NULL)) {
871923Sz.hong@f5.com         return NXT_ERROR;
881923Sz.hong@f5.com     }
891923Sz.hong@f5.com 
901923Sz.hong@f5.com     action->handler = nxt_http_static;
911923Sz.hong@f5.com     action->u.conf = conf;
921923Sz.hong@f5.com 
93*2077Salx.manpages@gmail.com     conf->nshares = nxt_conf_array_elements_count_or_1(acf->share);
941961Sz.hong@f5.com     conf->shares = nxt_mp_zget(mp, sizeof(nxt_http_static_share_t)
951961Sz.hong@f5.com                                    * conf->nshares);
961961Sz.hong@f5.com     if (nxt_slow_path(conf->shares == NULL)) {
971923Sz.hong@f5.com         return NXT_ERROR;
981923Sz.hong@f5.com     }
991923Sz.hong@f5.com 
100*2077Salx.manpages@gmail.com     for (i = 0; i < conf->nshares; i++) {
101*2077Salx.manpages@gmail.com         cv = nxt_conf_get_array_element_or_itself(acf->share, i);
102*2077Salx.manpages@gmail.com         nxt_conf_get_string(cv, &str);
1031961Sz.hong@f5.com 
1041961Sz.hong@f5.com         var = nxt_var_compile(&str, mp, 1);
1051961Sz.hong@f5.com         if (nxt_slow_path(var == NULL)) {
1061961Sz.hong@f5.com             return NXT_ERROR;
1071961Sz.hong@f5.com         }
1081961Sz.hong@f5.com 
109*2077Salx.manpages@gmail.com         conf->shares[i].var = var;
110*2077Salx.manpages@gmail.com         conf->shares[i].is_const = nxt_var_is_const(var);
1111961Sz.hong@f5.com     }
1121959Sz.hong@f5.com 
1131923Sz.hong@f5.com #if (NXT_HAVE_OPENAT2)
1141923Sz.hong@f5.com     if (acf->chroot.length > 0) {
1151961Sz.hong@f5.com         nxt_str_t   chr, shr;
1161961Sz.hong@f5.com         nxt_bool_t  is_const;
1171923Sz.hong@f5.com 
1181959Sz.hong@f5.com         conf->chroot = nxt_var_compile(&acf->chroot, mp, 1);
1191959Sz.hong@f5.com         if (nxt_slow_path(conf->chroot == NULL)) {
1201923Sz.hong@f5.com             return NXT_ERROR;
1211923Sz.hong@f5.com         }
1221960Sz.hong@f5.com 
1231961Sz.hong@f5.com         is_const = nxt_var_is_const(conf->chroot);
1241961Sz.hong@f5.com 
1251961Sz.hong@f5.com         for (i = 0; i < conf->nshares; i++) {
1261961Sz.hong@f5.com             conf->shares[i].is_const &= is_const;
1271960Sz.hong@f5.com 
1281961Sz.hong@f5.com             if (conf->shares[i].is_const) {
1291961Sz.hong@f5.com                 nxt_var_raw(conf->chroot, &chr);
1301961Sz.hong@f5.com                 nxt_var_raw(conf->shares[i].var, &shr);
1311961Sz.hong@f5.com 
1321961Sz.hong@f5.com                 conf->shares[i].fname = nxt_http_static_chroot_match(chr.start,
1331961Sz.hong@f5.com                                                                      shr.start);
1341961Sz.hong@f5.com             }
1351960Sz.hong@f5.com         }
1361923Sz.hong@f5.com     }
1371923Sz.hong@f5.com 
1381923Sz.hong@f5.com     if (acf->follow_symlinks != NULL
1391923Sz.hong@f5.com         && !nxt_conf_get_boolean(acf->follow_symlinks))
1401923Sz.hong@f5.com     {
1411923Sz.hong@f5.com         conf->resolve |= RESOLVE_NO_SYMLINKS;
1421923Sz.hong@f5.com     }
1431923Sz.hong@f5.com 
1441923Sz.hong@f5.com     if (acf->traverse_mounts != NULL
1451923Sz.hong@f5.com         && !nxt_conf_get_boolean(acf->traverse_mounts))
1461923Sz.hong@f5.com     {
1471923Sz.hong@f5.com         conf->resolve |= RESOLVE_NO_XDEV;
1481923Sz.hong@f5.com     }
1491923Sz.hong@f5.com #endif
1501923Sz.hong@f5.com 
1511923Sz.hong@f5.com     if (acf->types != NULL) {
1521923Sz.hong@f5.com         conf->types = nxt_http_route_types_rule_create(task, mp, acf->types);
1531923Sz.hong@f5.com         if (nxt_slow_path(conf->types == NULL)) {
1541923Sz.hong@f5.com             return NXT_ERROR;
1551923Sz.hong@f5.com         }
1561923Sz.hong@f5.com     }
1571923Sz.hong@f5.com 
1581923Sz.hong@f5.com     if (acf->fallback != NULL) {
1591923Sz.hong@f5.com         action->fallback = nxt_mp_alloc(mp, sizeof(nxt_http_action_t));
1601923Sz.hong@f5.com         if (nxt_slow_path(action->fallback == NULL)) {
1611923Sz.hong@f5.com             return NXT_ERROR;
1621923Sz.hong@f5.com         }
1631923Sz.hong@f5.com 
1641923Sz.hong@f5.com         return nxt_http_action_init(task, tmcf, acf->fallback,
1651923Sz.hong@f5.com                                     action->fallback);
1661923Sz.hong@f5.com     }
1671923Sz.hong@f5.com 
1681923Sz.hong@f5.com     return NXT_OK;
1691923Sz.hong@f5.com }
1701923Sz.hong@f5.com 
1711923Sz.hong@f5.com 
1721923Sz.hong@f5.com static nxt_http_action_t *
1731923Sz.hong@f5.com nxt_http_static(nxt_task_t *task, nxt_http_request_t *r,
1741264Sigor@sysoev.ru     nxt_http_action_t *action)
1751183Svbart@nginx.com {
1761961Sz.hong@f5.com     nxt_bool_t             need_body;
1771961Sz.hong@f5.com     nxt_http_static_ctx_t  *ctx;
1781923Sz.hong@f5.com 
1791183Svbart@nginx.com     if (nxt_slow_path(!nxt_str_eq(r->method, "GET", 3))) {
1801183Svbart@nginx.com 
1811183Svbart@nginx.com         if (!nxt_str_eq(r->method, "HEAD", 4)) {
1821923Sz.hong@f5.com             if (action->fallback != NULL) {
1831923Sz.hong@f5.com                 return action->fallback;
1841378Svbart@nginx.com             }
1851378Svbart@nginx.com 
1861183Svbart@nginx.com             nxt_http_request_error(task, r, NXT_HTTP_METHOD_NOT_ALLOWED);
1871183Svbart@nginx.com             return NULL;
1881183Svbart@nginx.com         }
1891183Svbart@nginx.com 
1901183Svbart@nginx.com         need_body = 0;
1911183Svbart@nginx.com 
1921183Svbart@nginx.com     } else {
1931183Svbart@nginx.com         need_body = 1;
1941183Svbart@nginx.com     }
1951183Svbart@nginx.com 
1961961Sz.hong@f5.com     ctx = nxt_mp_zget(r->mem_pool, sizeof(nxt_http_static_ctx_t));
1971961Sz.hong@f5.com     if (nxt_slow_path(ctx == NULL)) {
1981961Sz.hong@f5.com         nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
1991961Sz.hong@f5.com         return NULL;
2001961Sz.hong@f5.com     }
2011961Sz.hong@f5.com 
2021961Sz.hong@f5.com     ctx->action = action;
2031961Sz.hong@f5.com     ctx->need_body = need_body;
2041961Sz.hong@f5.com 
2051961Sz.hong@f5.com     nxt_http_static_iterate(task, r, ctx);
2061961Sz.hong@f5.com 
2071961Sz.hong@f5.com     return NULL;
2081961Sz.hong@f5.com }
2091961Sz.hong@f5.com 
2101961Sz.hong@f5.com 
2111961Sz.hong@f5.com static void
2121961Sz.hong@f5.com nxt_http_static_iterate(nxt_task_t *task, nxt_http_request_t *r,
2131961Sz.hong@f5.com     nxt_http_static_ctx_t *ctx)
2141961Sz.hong@f5.com {
2151961Sz.hong@f5.com     nxt_int_t                ret;
2161961Sz.hong@f5.com     nxt_http_static_conf_t   *conf;
2171961Sz.hong@f5.com     nxt_http_static_share_t  *share;
2181961Sz.hong@f5.com 
2191961Sz.hong@f5.com     conf = ctx->action->u.conf;
2201961Sz.hong@f5.com 
2211961Sz.hong@f5.com     share = &conf->shares[ctx->index];
2221959Sz.hong@f5.com 
2231960Sz.hong@f5.com #if (NXT_DEBUG)
2241960Sz.hong@f5.com     nxt_str_t  shr;
2251960Sz.hong@f5.com 
2261961Sz.hong@f5.com     nxt_var_raw(share->var, &shr);
2271960Sz.hong@f5.com 
2281960Sz.hong@f5.com #if (NXT_HAVE_OPENAT2)
2291959Sz.hong@f5.com     nxt_str_t  chr;
2301959Sz.hong@f5.com 
2311959Sz.hong@f5.com     if (conf->chroot != NULL) {
2321959Sz.hong@f5.com         nxt_var_raw(conf->chroot, &chr);
2331959Sz.hong@f5.com 
2341959Sz.hong@f5.com     } else {
2351959Sz.hong@f5.com         nxt_str_set(&chr, "");
2361959Sz.hong@f5.com     }
2371959Sz.hong@f5.com 
2381960Sz.hong@f5.com     nxt_debug(task, "http static: \"%V\" (chroot: \"%V\")", &shr, &chr);
2391959Sz.hong@f5.com #else
2401960Sz.hong@f5.com     nxt_debug(task, "http static: \"%V\"", &shr);
2411959Sz.hong@f5.com #endif
2421960Sz.hong@f5.com #endif /* NXT_DEBUG */
2431959Sz.hong@f5.com 
2441961Sz.hong@f5.com     if (share->is_const) {
2451961Sz.hong@f5.com         nxt_var_raw(share->var, &ctx->share);
2461960Sz.hong@f5.com 
2471959Sz.hong@f5.com #if (NXT_HAVE_OPENAT2)
2481961Sz.hong@f5.com         if (conf->chroot != NULL && ctx->index == 0) {
2491959Sz.hong@f5.com             nxt_var_raw(conf->chroot, &ctx->chroot);
2501959Sz.hong@f5.com         }
2511959Sz.hong@f5.com #endif
2521959Sz.hong@f5.com 
2531959Sz.hong@f5.com         nxt_http_static_send_ready(task, r, ctx);
2541959Sz.hong@f5.com 
2551959Sz.hong@f5.com     } else {
2561959Sz.hong@f5.com         ret = nxt_var_query_init(&r->var_query, r, r->mem_pool);
2571959Sz.hong@f5.com         if (nxt_slow_path(ret != NXT_OK)) {
2581961Sz.hong@f5.com             nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
2591961Sz.hong@f5.com             return;
2601959Sz.hong@f5.com         }
2611959Sz.hong@f5.com 
2621961Sz.hong@f5.com         nxt_var_query(task, r->var_query, share->var, &ctx->share);
2631960Sz.hong@f5.com 
2641959Sz.hong@f5.com #if (NXT_HAVE_OPENAT2)
2651961Sz.hong@f5.com         if (conf->chroot != NULL && ctx->index == 0) {
2661960Sz.hong@f5.com             nxt_var_query(task, r->var_query, conf->chroot, &ctx->chroot);
2671960Sz.hong@f5.com         }
2681959Sz.hong@f5.com #endif
2691959Sz.hong@f5.com 
2701959Sz.hong@f5.com         nxt_var_query_resolve(task, r->var_query, ctx,
2711959Sz.hong@f5.com                               nxt_http_static_send_ready,
2721959Sz.hong@f5.com                               nxt_http_static_var_error);
2731961Sz.hong@f5.com      }
2741959Sz.hong@f5.com }
2751959Sz.hong@f5.com 
2761959Sz.hong@f5.com 
2771959Sz.hong@f5.com static void
2781959Sz.hong@f5.com nxt_http_static_send_ready(nxt_task_t *task, void *obj, void *data)
2791959Sz.hong@f5.com {
2801959Sz.hong@f5.com     size_t                  length, encode;
2811959Sz.hong@f5.com     u_char                  *p, *fname;
2821959Sz.hong@f5.com     struct tm               tm;
2831959Sz.hong@f5.com     nxt_buf_t               *fb;
2841959Sz.hong@f5.com     nxt_int_t               ret;
2851960Sz.hong@f5.com     nxt_str_t               *shr, exten, *mtype;
2861959Sz.hong@f5.com     nxt_uint_t              level;
2871959Sz.hong@f5.com     nxt_file_t              *f, file;
2881959Sz.hong@f5.com     nxt_file_info_t         fi;
2891959Sz.hong@f5.com     nxt_http_field_t        *field;
2901959Sz.hong@f5.com     nxt_http_status_t       status;
2911959Sz.hong@f5.com     nxt_router_conf_t       *rtcf;
2921959Sz.hong@f5.com     nxt_http_action_t       *action;
2931959Sz.hong@f5.com     nxt_http_request_t      *r;
2941959Sz.hong@f5.com     nxt_work_handler_t      body_handler;
2951959Sz.hong@f5.com     nxt_http_static_ctx_t   *ctx;
2961959Sz.hong@f5.com     nxt_http_static_conf_t  *conf;
2971959Sz.hong@f5.com 
2981961Sz.hong@f5.com     static const nxt_str_t  index = nxt_string("index.html");
2991960Sz.hong@f5.com 
3001959Sz.hong@f5.com     r = obj;
3011959Sz.hong@f5.com     ctx = data;
3021959Sz.hong@f5.com     action = ctx->action;
3031959Sz.hong@f5.com     conf = action->u.conf;
3041960Sz.hong@f5.com     rtcf = r->conf->socket_conf->router_conf;
3051183Svbart@nginx.com 
3061855Sz.hong@f5.com     f = NULL;
3071960Sz.hong@f5.com     mtype = NULL;
3081183Svbart@nginx.com 
3091960Sz.hong@f5.com     shr = &ctx->share;
3101859So.canty@f5.com 
3111960Sz.hong@f5.com     if (shr->start[shr->length - 1] == '/') {
3121960Sz.hong@f5.com         /* TODO: dynamic index setting. */
3131960Sz.hong@f5.com         nxt_str_set(&exten, ".html");
3141859So.canty@f5.com 
3151960Sz.hong@f5.com         length = shr->length + index.length;
3161960Sz.hong@f5.com 
3171960Sz.hong@f5.com         fname = nxt_mp_nget(r->mem_pool, length + 1);
3181960Sz.hong@f5.com         if (nxt_slow_path(fname == NULL)) {
3191883So.canty@f5.com             goto fail;
3201883So.canty@f5.com         }
3211883So.canty@f5.com 
3221960Sz.hong@f5.com         p = fname;
3231960Sz.hong@f5.com         p = nxt_cpymem(p, shr->start, shr->length);
3241960Sz.hong@f5.com         p = nxt_cpymem(p, index.start, index.length);
3251960Sz.hong@f5.com         *p = '\0';
3261859So.canty@f5.com 
3271960Sz.hong@f5.com     } else {
3281960Sz.hong@f5.com         if (conf->types == NULL) {
3291960Sz.hong@f5.com             nxt_str_null(&exten);
3301960Sz.hong@f5.com 
3311960Sz.hong@f5.com         } else {
3321960Sz.hong@f5.com             nxt_http_static_extract_extension(shr, &exten);
3331960Sz.hong@f5.com             mtype = nxt_http_static_mtype_get(&rtcf->mtypes_hash, &exten);
3341855Sz.hong@f5.com 
3351960Sz.hong@f5.com             ret = nxt_http_route_test_rule(r, conf->types, mtype->start,
3361960Sz.hong@f5.com                                            mtype->length);
3371960Sz.hong@f5.com             if (nxt_slow_path(ret == NXT_ERROR)) {
3381960Sz.hong@f5.com                 goto fail;
3391960Sz.hong@f5.com             }
3401183Svbart@nginx.com 
3411960Sz.hong@f5.com             if (ret == 0) {
3421961Sz.hong@f5.com                 nxt_http_static_next(task, r, ctx, NXT_HTTP_FORBIDDEN);
3431961Sz.hong@f5.com                 return;
3441960Sz.hong@f5.com             }
3451960Sz.hong@f5.com         }
3461960Sz.hong@f5.com 
3471960Sz.hong@f5.com         fname = ctx->share.start;
3481960Sz.hong@f5.com     }
3491183Svbart@nginx.com 
3501855Sz.hong@f5.com     nxt_memzero(&file, sizeof(nxt_file_t));
3511855Sz.hong@f5.com 
3521855Sz.hong@f5.com     file.name = fname;
3531855Sz.hong@f5.com 
3541959Sz.hong@f5.com #if (NXT_HAVE_OPENAT2)
3551959Sz.hong@f5.com     if (conf->resolve != 0 || ctx->chroot.length > 0) {
3561961Sz.hong@f5.com         nxt_str_t                *chr;
3571961Sz.hong@f5.com         nxt_uint_t               resolve;
3581961Sz.hong@f5.com         nxt_http_static_share_t  *share;
3591961Sz.hong@f5.com 
3601961Sz.hong@f5.com         share = &conf->shares[ctx->index];
3611855Sz.hong@f5.com 
3621959Sz.hong@f5.com         resolve = conf->resolve;
3631959Sz.hong@f5.com         chr = &ctx->chroot;
3641855Sz.hong@f5.com 
3651959Sz.hong@f5.com         if (chr->length > 0) {
3661959Sz.hong@f5.com             resolve |= RESOLVE_IN_ROOT;
3671855Sz.hong@f5.com 
3681961Sz.hong@f5.com             fname = share->is_const
3691961Sz.hong@f5.com                     ? share->fname
3701960Sz.hong@f5.com                     : nxt_http_static_chroot_match(chr->start, file.name);
3711959Sz.hong@f5.com 
3721959Sz.hong@f5.com             if (fname != NULL) {
3731959Sz.hong@f5.com                 file.name = chr->start;
3741855Sz.hong@f5.com                 ret = nxt_file_open(task, &file, NXT_FILE_SEARCH, NXT_FILE_OPEN,
3751855Sz.hong@f5.com                                     0);
3761855Sz.hong@f5.com 
3771855Sz.hong@f5.com             } else {
3781855Sz.hong@f5.com                 file.error = NXT_EACCES;
3791855Sz.hong@f5.com                 ret = NXT_ERROR;
3801855Sz.hong@f5.com             }
3811855Sz.hong@f5.com 
3821855Sz.hong@f5.com         } else if (fname[0] == '/') {
3831855Sz.hong@f5.com             file.name = (u_char *) "/";
3841855Sz.hong@f5.com             ret = nxt_file_open(task, &file, NXT_FILE_SEARCH, NXT_FILE_OPEN, 0);
3851855Sz.hong@f5.com 
3861855Sz.hong@f5.com         } else {
3871855Sz.hong@f5.com             file.name = (u_char *) ".";
3881855Sz.hong@f5.com             file.fd = AT_FDCWD;
3891855Sz.hong@f5.com             ret = NXT_OK;
3901855Sz.hong@f5.com         }
3911855Sz.hong@f5.com 
3921855Sz.hong@f5.com         if (nxt_fast_path(ret == NXT_OK)) {
3931856Sz.hong@f5.com             nxt_file_t  af;
3941856Sz.hong@f5.com 
3951855Sz.hong@f5.com             af = file;
3961855Sz.hong@f5.com             nxt_memzero(&file, sizeof(nxt_file_t));
3971855Sz.hong@f5.com             file.name = fname;
3981855Sz.hong@f5.com 
3991855Sz.hong@f5.com             ret = nxt_file_openat2(task, &file, NXT_FILE_RDONLY,
4001959Sz.hong@f5.com                                    NXT_FILE_OPEN, 0, af.fd, resolve);
4011855Sz.hong@f5.com 
4021855Sz.hong@f5.com             if (af.fd != AT_FDCWD) {
4031855Sz.hong@f5.com                 nxt_file_close(task, &af);
4041855Sz.hong@f5.com             }
4051855Sz.hong@f5.com         }
4061855Sz.hong@f5.com 
4071855Sz.hong@f5.com     } else {
4081855Sz.hong@f5.com         ret = nxt_file_open(task, &file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 0);
4091855Sz.hong@f5.com     }
4101855Sz.hong@f5.com 
4111855Sz.hong@f5.com #else
4121855Sz.hong@f5.com     ret = nxt_file_open(task, &file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 0);
4131855Sz.hong@f5.com #endif
4141183Svbart@nginx.com 
4151183Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
4161855Sz.hong@f5.com 
4171855Sz.hong@f5.com         switch (file.error) {
4181183Svbart@nginx.com 
4191200Svbart@nginx.com         /*
4201200Svbart@nginx.com          * For Unix domain sockets "errno" is set to:
4211200Svbart@nginx.com          *  - ENXIO on Linux;
4221200Svbart@nginx.com          *  - EOPNOTSUPP on *BSD, MacOSX, and Solaris.
4231200Svbart@nginx.com          */
4241200Svbart@nginx.com 
4251183Svbart@nginx.com         case NXT_ENOENT:
4261183Svbart@nginx.com         case NXT_ENOTDIR:
4271183Svbart@nginx.com         case NXT_ENAMETOOLONG:
4281200Svbart@nginx.com #if (NXT_LINUX)
4291200Svbart@nginx.com         case NXT_ENXIO:
4301200Svbart@nginx.com #else
4311200Svbart@nginx.com         case NXT_EOPNOTSUPP:
4321200Svbart@nginx.com #endif
4331183Svbart@nginx.com             level = NXT_LOG_ERR;
4341183Svbart@nginx.com             status = NXT_HTTP_NOT_FOUND;
4351183Svbart@nginx.com             break;
4361183Svbart@nginx.com 
4371183Svbart@nginx.com         case NXT_EACCES:
4381855Sz.hong@f5.com #if (NXT_HAVE_OPENAT2)
4391855Sz.hong@f5.com         case NXT_ELOOP:
4401855Sz.hong@f5.com         case NXT_EXDEV:
4411855Sz.hong@f5.com #endif
4421183Svbart@nginx.com             level = NXT_LOG_ERR;
4431183Svbart@nginx.com             status = NXT_HTTP_FORBIDDEN;
4441183Svbart@nginx.com             break;
4451183Svbart@nginx.com 
4461183Svbart@nginx.com         default:
4471183Svbart@nginx.com             level = NXT_LOG_ALERT;
4481183Svbart@nginx.com             status = NXT_HTTP_INTERNAL_SERVER_ERROR;
4491183Svbart@nginx.com             break;
4501183Svbart@nginx.com         }
4511183Svbart@nginx.com 
4521183Svbart@nginx.com         if (status != NXT_HTTP_NOT_FOUND) {
4531959Sz.hong@f5.com #if (NXT_HAVE_OPENAT2)
4541959Sz.hong@f5.com             nxt_str_t  *chr = &ctx->chroot;
4551959Sz.hong@f5.com 
4561959Sz.hong@f5.com             if (chr->length > 0) {
4571857Sz.hong@f5.com                 nxt_log(task, level, "opening \"%s\" at \"%V\" failed %E",
4581959Sz.hong@f5.com                         fname, chr, file.error);
4591855Sz.hong@f5.com 
4601855Sz.hong@f5.com             } else {
4611857Sz.hong@f5.com                 nxt_log(task, level, "opening \"%s\" failed %E",
4621855Sz.hong@f5.com                         fname, file.error);
4631855Sz.hong@f5.com             }
4641959Sz.hong@f5.com 
4651959Sz.hong@f5.com #else
4661959Sz.hong@f5.com             nxt_log(task, level, "opening \"%s\" failed %E", fname, file.error);
4671959Sz.hong@f5.com #endif
4681183Svbart@nginx.com         }
4691183Svbart@nginx.com 
4701961Sz.hong@f5.com         if (level == NXT_LOG_ERR) {
4711961Sz.hong@f5.com             nxt_http_static_next(task, r, ctx, status);
4721961Sz.hong@f5.com             return;
4731961Sz.hong@f5.com         }
4741961Sz.hong@f5.com 
4751959Sz.hong@f5.com         goto fail;
4761183Svbart@nginx.com     }
4771183Svbart@nginx.com 
4781855Sz.hong@f5.com     f = nxt_mp_get(r->mem_pool, sizeof(nxt_file_t));
4791855Sz.hong@f5.com     if (nxt_slow_path(f == NULL)) {
4801962Svbart@nginx.com         nxt_file_close(task, &file);
4811855Sz.hong@f5.com         goto fail;
4821855Sz.hong@f5.com     }
4831855Sz.hong@f5.com 
4841855Sz.hong@f5.com     *f = file;
4851855Sz.hong@f5.com 
4861183Svbart@nginx.com     ret = nxt_file_info(f, &fi);
4871183Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
4881183Svbart@nginx.com         goto fail;
4891183Svbart@nginx.com     }
4901183Svbart@nginx.com 
4911183Svbart@nginx.com     if (nxt_fast_path(nxt_is_file(&fi))) {
4921183Svbart@nginx.com         r->status = NXT_HTTP_OK;
4931183Svbart@nginx.com         r->resp.content_length_n = nxt_file_size(&fi);
4941183Svbart@nginx.com 
4951183Svbart@nginx.com         field = nxt_list_zero_add(r->resp.fields);
4961183Svbart@nginx.com         if (nxt_slow_path(field == NULL)) {
4971183Svbart@nginx.com             goto fail;
4981183Svbart@nginx.com         }
4991183Svbart@nginx.com 
5001183Svbart@nginx.com         nxt_http_field_name_set(field, "Last-Modified");
5011183Svbart@nginx.com 
5021183Svbart@nginx.com         p = nxt_mp_nget(r->mem_pool, NXT_HTTP_DATE_LEN);
5031183Svbart@nginx.com         if (nxt_slow_path(p == NULL)) {
5041183Svbart@nginx.com             goto fail;
5051183Svbart@nginx.com         }
5061183Svbart@nginx.com 
5071183Svbart@nginx.com         nxt_localtime(nxt_file_mtime(&fi), &tm);
5081183Svbart@nginx.com 
5091183Svbart@nginx.com         field->value = p;
5101183Svbart@nginx.com         field->value_length = nxt_http_date(p, &tm) - p;
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, "ETag");
5181183Svbart@nginx.com 
5191855Sz.hong@f5.com         length = NXT_TIME_T_HEXLEN + NXT_OFF_T_HEXLEN + 3;
5201183Svbart@nginx.com 
5211855Sz.hong@f5.com         p = nxt_mp_nget(r->mem_pool, length);
5221183Svbart@nginx.com         if (nxt_slow_path(p == NULL)) {
5231183Svbart@nginx.com             goto fail;
5241183Svbart@nginx.com         }
5251183Svbart@nginx.com 
5261183Svbart@nginx.com         field->value = p;
5271855Sz.hong@f5.com         field->value_length = nxt_sprintf(p, p + length, "\"%xT-%xO\"",
5281183Svbart@nginx.com                                           nxt_file_mtime(&fi),
5291183Svbart@nginx.com                                           nxt_file_size(&fi))
5301183Svbart@nginx.com                               - p;
5311183Svbart@nginx.com 
5321923Sz.hong@f5.com         if (exten.start == NULL) {
5331960Sz.hong@f5.com             nxt_http_static_extract_extension(shr, &exten);
5341183Svbart@nginx.com         }
5351183Svbart@nginx.com 
5361859So.canty@f5.com         if (mtype == NULL) {
5371923Sz.hong@f5.com             mtype = nxt_http_static_mtype_get(&rtcf->mtypes_hash, &exten);
5381859So.canty@f5.com         }
5391183Svbart@nginx.com 
5401883So.canty@f5.com         if (mtype->length != 0) {
5411183Svbart@nginx.com             field = nxt_list_zero_add(r->resp.fields);
5421183Svbart@nginx.com             if (nxt_slow_path(field == NULL)) {
5431183Svbart@nginx.com                 goto fail;
5441183Svbart@nginx.com             }
5451183Svbart@nginx.com 
5461183Svbart@nginx.com             nxt_http_field_name_set(field, "Content-Type");
5471183Svbart@nginx.com 
5481183Svbart@nginx.com             field->value = mtype->start;
5491183Svbart@nginx.com             field->value_length = mtype->length;
5501183Svbart@nginx.com         }
5511183Svbart@nginx.com 
5521959Sz.hong@f5.com         if (ctx->need_body && nxt_file_size(&fi) > 0) {
5531183Svbart@nginx.com             fb = nxt_mp_zget(r->mem_pool, NXT_BUF_FILE_SIZE);
5541183Svbart@nginx.com             if (nxt_slow_path(fb == NULL)) {
5551183Svbart@nginx.com                 goto fail;
5561183Svbart@nginx.com             }
5571183Svbart@nginx.com 
5581183Svbart@nginx.com             fb->file = f;
5591183Svbart@nginx.com             fb->file_end = nxt_file_size(&fi);
5601183Svbart@nginx.com 
5611183Svbart@nginx.com             r->out = fb;
5621183Svbart@nginx.com 
5631183Svbart@nginx.com             body_handler = &nxt_http_static_body_handler;
5641183Svbart@nginx.com 
5651183Svbart@nginx.com         } else {
5661183Svbart@nginx.com             nxt_file_close(task, f);
5671183Svbart@nginx.com             body_handler = NULL;
5681183Svbart@nginx.com         }
5691183Svbart@nginx.com 
5701183Svbart@nginx.com     } else {
5711183Svbart@nginx.com         /* Not a file. */
5721961Sz.hong@f5.com         nxt_file_close(task, f);
5731183Svbart@nginx.com 
5741183Svbart@nginx.com         if (nxt_slow_path(!nxt_is_dir(&fi))) {
5751961Sz.hong@f5.com             nxt_log(task, NXT_LOG_ERR, "\"%FN\" is not a regular file",
5761961Sz.hong@f5.com                     f->name);
5771378Svbart@nginx.com 
5781961Sz.hong@f5.com             nxt_http_static_next(task, r, ctx, NXT_HTTP_NOT_FOUND);
5791961Sz.hong@f5.com             return;
5801183Svbart@nginx.com         }
5811183Svbart@nginx.com 
5821198Svbart@nginx.com         f = NULL;
5831198Svbart@nginx.com 
5841183Svbart@nginx.com         r->status = NXT_HTTP_MOVED_PERMANENTLY;
5851183Svbart@nginx.com         r->resp.content_length_n = 0;
5861183Svbart@nginx.com 
5871183Svbart@nginx.com         field = nxt_list_zero_add(r->resp.fields);
5881183Svbart@nginx.com         if (nxt_slow_path(field == NULL)) {
5891183Svbart@nginx.com             goto fail;
5901183Svbart@nginx.com         }
5911183Svbart@nginx.com 
5921183Svbart@nginx.com         nxt_http_field_name_set(field, "Location");
5931183Svbart@nginx.com 
5941183Svbart@nginx.com         encode = nxt_encode_uri(NULL, r->path->start, r->path->length);
5951855Sz.hong@f5.com         length = r->path->length + encode * 2 + 1;
5961183Svbart@nginx.com 
5971183Svbart@nginx.com         if (r->args->length > 0) {
5981855Sz.hong@f5.com             length += 1 + r->args->length;
5991183Svbart@nginx.com         }
6001183Svbart@nginx.com 
6011855Sz.hong@f5.com         p = nxt_mp_nget(r->mem_pool, length);
6021183Svbart@nginx.com         if (nxt_slow_path(p == NULL)) {
6031183Svbart@nginx.com             goto fail;
6041183Svbart@nginx.com         }
6051183Svbart@nginx.com 
6061183Svbart@nginx.com         field->value = p;
6071855Sz.hong@f5.com         field->value_length = length;
6081183Svbart@nginx.com 
6091183Svbart@nginx.com         if (encode > 0) {
6101183Svbart@nginx.com             p = (u_char *) nxt_encode_uri(p, r->path->start, r->path->length);
6111183Svbart@nginx.com 
6121183Svbart@nginx.com         } else {
6131183Svbart@nginx.com             p = nxt_cpymem(p, r->path->start, r->path->length);
6141183Svbart@nginx.com         }
6151183Svbart@nginx.com 
6161183Svbart@nginx.com         *p++ = '/';
6171183Svbart@nginx.com 
6181183Svbart@nginx.com         if (r->args->length > 0) {
6191183Svbart@nginx.com             *p++ = '?';
6201183Svbart@nginx.com             nxt_memcpy(p, r->args->start, r->args->length);
6211183Svbart@nginx.com         }
6221183Svbart@nginx.com 
6231183Svbart@nginx.com         body_handler = NULL;
6241183Svbart@nginx.com     }
6251183Svbart@nginx.com 
6261270Sigor@sysoev.ru     nxt_http_request_header_send(task, r, body_handler, NULL);
6271183Svbart@nginx.com 
6281183Svbart@nginx.com     r->state = &nxt_http_static_send_state;
6291959Sz.hong@f5.com     return;
6301183Svbart@nginx.com 
6311183Svbart@nginx.com fail:
6321183Svbart@nginx.com 
6331855Sz.hong@f5.com     if (f != NULL) {
6341183Svbart@nginx.com         nxt_file_close(task, f);
6351183Svbart@nginx.com     }
6361183Svbart@nginx.com 
6371961Sz.hong@f5.com     nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
6381959Sz.hong@f5.com }
6391959Sz.hong@f5.com 
6401959Sz.hong@f5.com 
6411959Sz.hong@f5.com static void
6421959Sz.hong@f5.com nxt_http_static_var_error(nxt_task_t *task, void *obj, void *data)
6431959Sz.hong@f5.com {
6441959Sz.hong@f5.com     nxt_http_request_t  *r;
6451959Sz.hong@f5.com 
6461959Sz.hong@f5.com     r = obj;
6471959Sz.hong@f5.com 
6481959Sz.hong@f5.com     nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
6491183Svbart@nginx.com }
6501183Svbart@nginx.com 
6511183Svbart@nginx.com 
6521961Sz.hong@f5.com static void
6531961Sz.hong@f5.com nxt_http_static_next(nxt_task_t *task, nxt_http_request_t *r,
6541961Sz.hong@f5.com     nxt_http_static_ctx_t *ctx, nxt_http_status_t status)
6551961Sz.hong@f5.com {
6561961Sz.hong@f5.com     nxt_http_action_t       *action;
6571961Sz.hong@f5.com     nxt_http_static_conf_t  *conf;
6581961Sz.hong@f5.com 
6591961Sz.hong@f5.com     action = ctx->action;
6601961Sz.hong@f5.com     conf = action->u.conf;
6611961Sz.hong@f5.com 
6621961Sz.hong@f5.com     ctx->index++;
6631961Sz.hong@f5.com 
6641961Sz.hong@f5.com     if (ctx->index < conf->nshares) {
6651961Sz.hong@f5.com         nxt_http_static_iterate(task, r, ctx);
6661961Sz.hong@f5.com         return;
6671961Sz.hong@f5.com     }
6681961Sz.hong@f5.com 
6691961Sz.hong@f5.com     if (action->fallback != NULL) {
6701961Sz.hong@f5.com         nxt_http_request_action(task, r, action->fallback);
6711961Sz.hong@f5.com         return;
6721961Sz.hong@f5.com     }
6731961Sz.hong@f5.com 
6741961Sz.hong@f5.com     nxt_http_request_error(task, r, status);
6751961Sz.hong@f5.com }
6761961Sz.hong@f5.com 
6771961Sz.hong@f5.com 
6781959Sz.hong@f5.com #if (NXT_HAVE_OPENAT2)
6791959Sz.hong@f5.com 
6801959Sz.hong@f5.com static u_char *
6811959Sz.hong@f5.com nxt_http_static_chroot_match(u_char *chr, u_char *shr)
6821959Sz.hong@f5.com {
6831959Sz.hong@f5.com     if (*chr != *shr) {
6841959Sz.hong@f5.com         return NULL;
6851959Sz.hong@f5.com     }
6861959Sz.hong@f5.com 
6871959Sz.hong@f5.com     chr++;
6881959Sz.hong@f5.com     shr++;
6891959Sz.hong@f5.com 
6901959Sz.hong@f5.com     for ( ;; ) {
6911959Sz.hong@f5.com         if (*shr == '\0') {
6921959Sz.hong@f5.com             return NULL;
6931959Sz.hong@f5.com         }
6941959Sz.hong@f5.com 
6951959Sz.hong@f5.com         if (*chr == *shr) {
6961959Sz.hong@f5.com             chr++;
6971959Sz.hong@f5.com             shr++;
6981959Sz.hong@f5.com             continue;
6991959Sz.hong@f5.com         }
7001959Sz.hong@f5.com 
7011959Sz.hong@f5.com         if (*chr == '\0') {
7021959Sz.hong@f5.com             break;
7031959Sz.hong@f5.com         }
7041959Sz.hong@f5.com 
7051959Sz.hong@f5.com         if (*chr == '/') {
7061959Sz.hong@f5.com             if (chr[-1] == '/') {
7071959Sz.hong@f5.com                 chr++;
7081959Sz.hong@f5.com                 continue;
7091959Sz.hong@f5.com             }
7101959Sz.hong@f5.com 
7111959Sz.hong@f5.com         } else if (*shr == '/') {
7121959Sz.hong@f5.com             if (shr[-1] == '/') {
7131959Sz.hong@f5.com                 shr++;
7141959Sz.hong@f5.com                 continue;
7151959Sz.hong@f5.com             }
7161959Sz.hong@f5.com         }
7171959Sz.hong@f5.com 
7181959Sz.hong@f5.com         return NULL;
7191959Sz.hong@f5.com     }
7201959Sz.hong@f5.com 
7211959Sz.hong@f5.com     if (shr[-1] != '/' && *shr != '/') {
7221959Sz.hong@f5.com         return NULL;
7231959Sz.hong@f5.com     }
7241959Sz.hong@f5.com 
7251959Sz.hong@f5.com     while (*shr == '/') {
7261959Sz.hong@f5.com         shr++;
7271959Sz.hong@f5.com     }
7281959Sz.hong@f5.com 
7291959Sz.hong@f5.com     return (*shr != '\0') ? shr : NULL;
7301959Sz.hong@f5.com }
7311959Sz.hong@f5.com 
7321959Sz.hong@f5.com #endif
7331959Sz.hong@f5.com 
7341959Sz.hong@f5.com 
7351183Svbart@nginx.com static void
7361923Sz.hong@f5.com nxt_http_static_extract_extension(nxt_str_t *path, nxt_str_t *exten)
7371183Svbart@nginx.com {
7381183Svbart@nginx.com     u_char  ch, *p, *end;
7391183Svbart@nginx.com 
7401183Svbart@nginx.com     end = path->start + path->length;
7411183Svbart@nginx.com     p = end;
7421183Svbart@nginx.com 
7431183Svbart@nginx.com     for ( ;; ) {
7441183Svbart@nginx.com         /* There's always '/' in the beginning of the request path. */
7451183Svbart@nginx.com 
7461183Svbart@nginx.com         p--;
7471183Svbart@nginx.com         ch = *p;
7481183Svbart@nginx.com 
7491183Svbart@nginx.com         switch (ch) {
7501183Svbart@nginx.com         case '/':
7511183Svbart@nginx.com             p++;
7521183Svbart@nginx.com             /* Fall through. */
7531183Svbart@nginx.com         case '.':
7541923Sz.hong@f5.com             exten->length = end - p;
7551923Sz.hong@f5.com             exten->start = p;
7561183Svbart@nginx.com             return;
7571183Svbart@nginx.com         }
7581183Svbart@nginx.com     }
7591183Svbart@nginx.com }
7601183Svbart@nginx.com 
7611183Svbart@nginx.com 
7621183Svbart@nginx.com static void
7631183Svbart@nginx.com nxt_http_static_body_handler(nxt_task_t *task, void *obj, void *data)
7641183Svbart@nginx.com {
7651183Svbart@nginx.com     size_t              alloc;
7661183Svbart@nginx.com     nxt_buf_t           *fb, *b, **next, *out;
7671183Svbart@nginx.com     nxt_off_t           rest;
7681183Svbart@nginx.com     nxt_int_t           n;
7691183Svbart@nginx.com     nxt_work_queue_t    *wq;
7701183Svbart@nginx.com     nxt_http_request_t  *r;
7711183Svbart@nginx.com 
7721183Svbart@nginx.com     r = obj;
7731183Svbart@nginx.com     fb = r->out;
7741183Svbart@nginx.com 
7751183Svbart@nginx.com     rest = fb->file_end - fb->file_pos;
7761183Svbart@nginx.com     out = NULL;
7771183Svbart@nginx.com     next = &out;
7781183Svbart@nginx.com     n = 0;
7791183Svbart@nginx.com 
7801183Svbart@nginx.com     do {
7811183Svbart@nginx.com         alloc = nxt_min(rest, NXT_HTTP_STATIC_BUF_SIZE);
7821183Svbart@nginx.com 
7831183Svbart@nginx.com         b = nxt_buf_mem_alloc(r->mem_pool, alloc, 0);
7841183Svbart@nginx.com         if (nxt_slow_path(b == NULL)) {
7851183Svbart@nginx.com             goto fail;
7861183Svbart@nginx.com         }
7871183Svbart@nginx.com 
7881183Svbart@nginx.com         b->completion_handler = nxt_http_static_buf_completion;
7891183Svbart@nginx.com         b->parent = r;
7901183Svbart@nginx.com 
7911183Svbart@nginx.com         nxt_mp_retain(r->mem_pool);
7921183Svbart@nginx.com 
7931183Svbart@nginx.com         *next = b;
7941183Svbart@nginx.com         next = &b->next;
7951183Svbart@nginx.com 
7961183Svbart@nginx.com         rest -= alloc;
7971183Svbart@nginx.com 
7981183Svbart@nginx.com     } while (rest > 0 && ++n < NXT_HTTP_STATIC_BUF_COUNT);
7991183Svbart@nginx.com 
8001183Svbart@nginx.com     wq = &task->thread->engine->fast_work_queue;
8011183Svbart@nginx.com 
8021183Svbart@nginx.com     nxt_sendbuf_drain(task, wq, out);
8031183Svbart@nginx.com     return;
8041183Svbart@nginx.com 
8051183Svbart@nginx.com fail:
8061183Svbart@nginx.com 
8071183Svbart@nginx.com     while (out != NULL) {
8081183Svbart@nginx.com         b = out;
8091183Svbart@nginx.com         out = b->next;
8101183Svbart@nginx.com 
8111183Svbart@nginx.com         nxt_mp_free(r->mem_pool, b);
8121183Svbart@nginx.com         nxt_mp_release(r->mem_pool);
8131183Svbart@nginx.com     }
8141183Svbart@nginx.com }
8151183Svbart@nginx.com 
8161183Svbart@nginx.com 
8171183Svbart@nginx.com static const nxt_http_request_state_t  nxt_http_static_send_state
8181183Svbart@nginx.com     nxt_aligned(64) =
8191183Svbart@nginx.com {
8201183Svbart@nginx.com     .error_handler = nxt_http_request_error_handler,
8211183Svbart@nginx.com };
8221183Svbart@nginx.com 
8231183Svbart@nginx.com 
8241183Svbart@nginx.com static void
8251183Svbart@nginx.com nxt_http_static_buf_completion(nxt_task_t *task, void *obj, void *data)
8261183Svbart@nginx.com {
8271183Svbart@nginx.com     ssize_t             n, size;
8281760Smax.romanov@nginx.com     nxt_buf_t           *b, *fb, *next;
8291183Svbart@nginx.com     nxt_off_t           rest;
8301183Svbart@nginx.com     nxt_http_request_t  *r;
8311183Svbart@nginx.com 
8321183Svbart@nginx.com     b = obj;
8331183Svbart@nginx.com     r = data;
8341760Smax.romanov@nginx.com 
8351760Smax.romanov@nginx.com complete_buf:
8361760Smax.romanov@nginx.com 
8371183Svbart@nginx.com     fb = r->out;
8381183Svbart@nginx.com 
8391183Svbart@nginx.com     if (nxt_slow_path(fb == NULL || r->error)) {
8401183Svbart@nginx.com         goto clean;
8411183Svbart@nginx.com     }
8421183Svbart@nginx.com 
8431183Svbart@nginx.com     rest = fb->file_end - fb->file_pos;
8441183Svbart@nginx.com     size = nxt_buf_mem_size(&b->mem);
8451183Svbart@nginx.com 
8461183Svbart@nginx.com     size = nxt_min(rest, (nxt_off_t) size);
8471183Svbart@nginx.com 
8481183Svbart@nginx.com     n = nxt_file_read(fb->file, b->mem.start, size, fb->file_pos);
8491183Svbart@nginx.com 
8501183Svbart@nginx.com     if (n != size) {
8511183Svbart@nginx.com         if (n >= 0) {
8521183Svbart@nginx.com             nxt_log(task, NXT_LOG_ERR, "file \"%FN\" has changed "
8531183Svbart@nginx.com                     "while sending response to a client", fb->file->name);
8541183Svbart@nginx.com         }
8551183Svbart@nginx.com 
8561183Svbart@nginx.com         nxt_http_request_error_handler(task, r, r->proto.any);
8571183Svbart@nginx.com         goto clean;
8581183Svbart@nginx.com     }
8591183Svbart@nginx.com 
8601760Smax.romanov@nginx.com     next = b->next;
8611760Smax.romanov@nginx.com 
8621183Svbart@nginx.com     if (n == rest) {
8631183Svbart@nginx.com         nxt_file_close(task, fb->file);
8641183Svbart@nginx.com         r->out = NULL;
8651183Svbart@nginx.com 
8661183Svbart@nginx.com         b->next = nxt_http_buf_last(r);
8671183Svbart@nginx.com 
8681183Svbart@nginx.com     } else {
8691183Svbart@nginx.com         fb->file_pos += n;
8701183Svbart@nginx.com         b->next = NULL;
8711183Svbart@nginx.com     }
8721183Svbart@nginx.com 
8731183Svbart@nginx.com     b->mem.pos = b->mem.start;
8741183Svbart@nginx.com     b->mem.free = b->mem.pos + n;
8751183Svbart@nginx.com 
8761183Svbart@nginx.com     nxt_http_request_send(task, r, b);
8771760Smax.romanov@nginx.com 
8781760Smax.romanov@nginx.com     if (next != NULL) {
8791760Smax.romanov@nginx.com         b = next;
8801760Smax.romanov@nginx.com         goto complete_buf;
8811760Smax.romanov@nginx.com     }
8821760Smax.romanov@nginx.com 
8831183Svbart@nginx.com     return;
8841183Svbart@nginx.com 
8851183Svbart@nginx.com clean:
8861183Svbart@nginx.com 
8871760Smax.romanov@nginx.com     do {
8881760Smax.romanov@nginx.com         next = b->next;
8891760Smax.romanov@nginx.com 
8901760Smax.romanov@nginx.com         nxt_mp_free(r->mem_pool, b);
8911760Smax.romanov@nginx.com         nxt_mp_release(r->mem_pool);
8921760Smax.romanov@nginx.com 
8931760Smax.romanov@nginx.com         b = next;
8941760Smax.romanov@nginx.com     } while (b != NULL);
8951183Svbart@nginx.com 
8961183Svbart@nginx.com     if (fb != NULL) {
8971183Svbart@nginx.com         nxt_file_close(task, fb->file);
8981183Svbart@nginx.com         r->out = NULL;
8991183Svbart@nginx.com     }
9001183Svbart@nginx.com }
9011183Svbart@nginx.com 
9021183Svbart@nginx.com 
9031183Svbart@nginx.com nxt_int_t
9041183Svbart@nginx.com nxt_http_static_mtypes_init(nxt_mp_t *mp, nxt_lvlhsh_t *hash)
9051183Svbart@nginx.com {
9061923Sz.hong@f5.com     nxt_str_t   *type, exten;
9071183Svbart@nginx.com     nxt_int_t   ret;
9081183Svbart@nginx.com     nxt_uint_t  i;
9091183Svbart@nginx.com 
9101183Svbart@nginx.com     static const struct {
9111183Svbart@nginx.com         nxt_str_t   type;
9121923Sz.hong@f5.com         const char  *exten;
9131183Svbart@nginx.com     } default_types[] = {
9141183Svbart@nginx.com 
9151183Svbart@nginx.com         { nxt_string("text/html"),      ".html"  },
9161183Svbart@nginx.com         { nxt_string("text/html"),      ".htm"   },
9171183Svbart@nginx.com         { nxt_string("text/css"),       ".css"   },
9181183Svbart@nginx.com 
9191183Svbart@nginx.com         { nxt_string("image/svg+xml"),  ".svg"   },
9201183Svbart@nginx.com         { nxt_string("image/webp"),     ".webp"  },
9211183Svbart@nginx.com         { nxt_string("image/png"),      ".png"   },
9221617Svbart@nginx.com         { nxt_string("image/apng"),     ".apng"  },
9231183Svbart@nginx.com         { nxt_string("image/jpeg"),     ".jpeg"  },
9241183Svbart@nginx.com         { nxt_string("image/jpeg"),     ".jpg"   },
9251183Svbart@nginx.com         { nxt_string("image/gif"),      ".gif"   },
9261183Svbart@nginx.com         { nxt_string("image/x-icon"),   ".ico"   },
9271183Svbart@nginx.com 
9281617Svbart@nginx.com         { nxt_string("image/avif"),           ".avif"  },
9291617Svbart@nginx.com         { nxt_string("image/avif-sequence"),  ".avifs" },
9301617Svbart@nginx.com 
9311183Svbart@nginx.com         { nxt_string("font/woff"),      ".woff"  },
9321183Svbart@nginx.com         { nxt_string("font/woff2"),     ".woff2" },
9331183Svbart@nginx.com         { nxt_string("font/otf"),       ".otf"   },
9341183Svbart@nginx.com         { nxt_string("font/ttf"),       ".ttf"   },
9351183Svbart@nginx.com 
9361183Svbart@nginx.com         { nxt_string("text/plain"),     ".txt"   },
9371183Svbart@nginx.com         { nxt_string("text/markdown"),  ".md"    },
9381183Svbart@nginx.com         { nxt_string("text/x-rst"),     ".rst"   },
9391183Svbart@nginx.com 
9401183Svbart@nginx.com         { nxt_string("application/javascript"),  ".js"   },
9411183Svbart@nginx.com         { nxt_string("application/json"),        ".json" },
9421183Svbart@nginx.com         { nxt_string("application/xml"),         ".xml"  },
9431183Svbart@nginx.com         { nxt_string("application/rss+xml"),     ".rss"  },
9441183Svbart@nginx.com         { nxt_string("application/atom+xml"),    ".atom" },
9451183Svbart@nginx.com         { nxt_string("application/pdf"),         ".pdf"  },
9461183Svbart@nginx.com 
9471183Svbart@nginx.com         { nxt_string("application/zip"),         ".zip"  },
9481183Svbart@nginx.com 
9491183Svbart@nginx.com         { nxt_string("audio/mpeg"),       ".mp3"  },
9501183Svbart@nginx.com         { nxt_string("audio/ogg"),        ".ogg"  },
9511183Svbart@nginx.com         { nxt_string("audio/midi"),       ".midi" },
9521183Svbart@nginx.com         { nxt_string("audio/midi"),       ".mid"  },
9531183Svbart@nginx.com         { nxt_string("audio/flac"),       ".flac" },
9541183Svbart@nginx.com         { nxt_string("audio/aac"),        ".aac"  },
9551183Svbart@nginx.com         { nxt_string("audio/wav"),        ".wav"  },
9561183Svbart@nginx.com 
9571183Svbart@nginx.com         { nxt_string("video/mpeg"),       ".mpeg" },
9581183Svbart@nginx.com         { nxt_string("video/mpeg"),       ".mpg"  },
9591183Svbart@nginx.com         { nxt_string("video/mp4"),        ".mp4"  },
9601183Svbart@nginx.com         { nxt_string("video/webm"),       ".webm" },
9611183Svbart@nginx.com         { nxt_string("video/x-msvideo"),  ".avi"  },
9621183Svbart@nginx.com 
9631183Svbart@nginx.com         { nxt_string("application/octet-stream"),  ".exe" },
9641183Svbart@nginx.com         { nxt_string("application/octet-stream"),  ".bin" },
9651183Svbart@nginx.com         { nxt_string("application/octet-stream"),  ".dll" },
9661183Svbart@nginx.com         { nxt_string("application/octet-stream"),  ".iso" },
9671183Svbart@nginx.com         { nxt_string("application/octet-stream"),  ".img" },
9681183Svbart@nginx.com         { nxt_string("application/octet-stream"),  ".msi" },
9691183Svbart@nginx.com 
9701183Svbart@nginx.com         { nxt_string("application/octet-stream"),  ".deb" },
9711183Svbart@nginx.com         { nxt_string("application/octet-stream"),  ".rpm" },
9721882So.canty@f5.com 
9731882So.canty@f5.com         { nxt_string("application/x-httpd-php"),   ".php" },
9741183Svbart@nginx.com     };
9751183Svbart@nginx.com 
9761183Svbart@nginx.com     for (i = 0; i < nxt_nitems(default_types); i++) {
9771183Svbart@nginx.com         type = (nxt_str_t *) &default_types[i].type;
9781183Svbart@nginx.com 
9791923Sz.hong@f5.com         exten.start = (u_char *) default_types[i].exten;
9801923Sz.hong@f5.com         exten.length = nxt_strlen(exten.start);
9811183Svbart@nginx.com 
9821923Sz.hong@f5.com         ret = nxt_http_static_mtypes_hash_add(mp, hash, &exten, type);
9831183Svbart@nginx.com         if (nxt_slow_path(ret != NXT_OK)) {
9841183Svbart@nginx.com             return NXT_ERROR;
9851183Svbart@nginx.com         }
9861183Svbart@nginx.com     }
9871183Svbart@nginx.com 
9881183Svbart@nginx.com     return NXT_OK;
9891183Svbart@nginx.com }
9901183Svbart@nginx.com 
9911183Svbart@nginx.com 
9921183Svbart@nginx.com static const nxt_lvlhsh_proto_t  nxt_http_static_mtypes_hash_proto
9931183Svbart@nginx.com     nxt_aligned(64) =
9941183Svbart@nginx.com {
9951183Svbart@nginx.com     NXT_LVLHSH_DEFAULT,
9961183Svbart@nginx.com     nxt_http_static_mtypes_hash_test,
9971183Svbart@nginx.com     nxt_http_static_mtypes_hash_alloc,
9981183Svbart@nginx.com     nxt_http_static_mtypes_hash_free,
9991183Svbart@nginx.com };
10001183Svbart@nginx.com 
10011183Svbart@nginx.com 
10021183Svbart@nginx.com typedef struct {
10031923Sz.hong@f5.com     nxt_str_t  exten;
10041183Svbart@nginx.com     nxt_str_t  *type;
10051183Svbart@nginx.com } nxt_http_static_mtype_t;
10061183Svbart@nginx.com 
10071183Svbart@nginx.com 
10081183Svbart@nginx.com nxt_int_t
10091183Svbart@nginx.com nxt_http_static_mtypes_hash_add(nxt_mp_t *mp, nxt_lvlhsh_t *hash,
10101923Sz.hong@f5.com     nxt_str_t *exten, nxt_str_t *type)
10111183Svbart@nginx.com {
10121183Svbart@nginx.com     nxt_lvlhsh_query_t       lhq;
10131183Svbart@nginx.com     nxt_http_static_mtype_t  *mtype;
10141183Svbart@nginx.com 
10151183Svbart@nginx.com     mtype = nxt_mp_get(mp, sizeof(nxt_http_static_mtype_t));
10161183Svbart@nginx.com     if (nxt_slow_path(mtype == NULL)) {
10171183Svbart@nginx.com         return NXT_ERROR;
10181183Svbart@nginx.com     }
10191183Svbart@nginx.com 
10201923Sz.hong@f5.com     mtype->exten = *exten;
10211183Svbart@nginx.com     mtype->type = type;
10221183Svbart@nginx.com 
10231923Sz.hong@f5.com     lhq.key = *exten;
10241183Svbart@nginx.com     lhq.key_hash = nxt_djb_hash_lowcase(lhq.key.start, lhq.key.length);
10251183Svbart@nginx.com     lhq.replace = 1;
10261183Svbart@nginx.com     lhq.value = mtype;
10271183Svbart@nginx.com     lhq.proto = &nxt_http_static_mtypes_hash_proto;
10281183Svbart@nginx.com     lhq.pool = mp;
10291183Svbart@nginx.com 
10301183Svbart@nginx.com     return nxt_lvlhsh_insert(hash, &lhq);
10311183Svbart@nginx.com }
10321183Svbart@nginx.com 
10331183Svbart@nginx.com 
10341183Svbart@nginx.com nxt_str_t *
10351923Sz.hong@f5.com nxt_http_static_mtype_get(nxt_lvlhsh_t *hash, nxt_str_t *exten)
10361183Svbart@nginx.com {
10371183Svbart@nginx.com     nxt_lvlhsh_query_t       lhq;
10381183Svbart@nginx.com     nxt_http_static_mtype_t  *mtype;
10391183Svbart@nginx.com 
10401883So.canty@f5.com     static nxt_str_t  empty = nxt_string("");
10411883So.canty@f5.com 
10421923Sz.hong@f5.com     lhq.key = *exten;
10431183Svbart@nginx.com     lhq.key_hash = nxt_djb_hash_lowcase(lhq.key.start, lhq.key.length);
10441183Svbart@nginx.com     lhq.proto = &nxt_http_static_mtypes_hash_proto;
10451183Svbart@nginx.com 
10461183Svbart@nginx.com     if (nxt_lvlhsh_find(hash, &lhq) == NXT_OK) {
10471183Svbart@nginx.com         mtype = lhq.value;
10481183Svbart@nginx.com         return mtype->type;
10491183Svbart@nginx.com     }
10501183Svbart@nginx.com 
10511883So.canty@f5.com     return &empty;
10521183Svbart@nginx.com }
10531183Svbart@nginx.com 
10541183Svbart@nginx.com 
10551183Svbart@nginx.com static nxt_int_t
10561183Svbart@nginx.com nxt_http_static_mtypes_hash_test(nxt_lvlhsh_query_t *lhq, void *data)
10571183Svbart@nginx.com {
10581183Svbart@nginx.com     nxt_http_static_mtype_t  *mtype;
10591183Svbart@nginx.com 
10601183Svbart@nginx.com     mtype = data;
10611183Svbart@nginx.com 
10621923Sz.hong@f5.com     return nxt_strcasestr_eq(&lhq->key, &mtype->exten) ? NXT_OK : NXT_DECLINED;
10631183Svbart@nginx.com }
10641183Svbart@nginx.com 
10651183Svbart@nginx.com 
10661183Svbart@nginx.com static void *
10671183Svbart@nginx.com nxt_http_static_mtypes_hash_alloc(void *data, size_t size)
10681183Svbart@nginx.com {
10691183Svbart@nginx.com     return nxt_mp_align(data, size, size);
10701183Svbart@nginx.com }
10711183Svbart@nginx.com 
10721183Svbart@nginx.com 
10731183Svbart@nginx.com static void
10741183Svbart@nginx.com nxt_http_static_mtypes_hash_free(void *data, void *p)
10751183Svbart@nginx.com {
10761183Svbart@nginx.com     nxt_mp_free(data, p);
10771183Svbart@nginx.com }
1078