xref: /unit/src/nxt_http_static.c (revision 1959)
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 {
11*1959Sz.hong@f5.com     nxt_str_t                   share;
12*1959Sz.hong@f5.com #if (NXT_HAVE_OPENAT2)
13*1959Sz.hong@f5.com     nxt_var_t                   *chroot;
14*1959Sz.hong@f5.com     nxt_uint_t                  resolve;
15*1959Sz.hong@f5.com #endif
16*1959Sz.hong@f5.com     nxt_http_route_rule_t       *types;
17*1959Sz.hong@f5.com     uint8_t                     is_const;  /* 1 bit */
181923Sz.hong@f5.com } nxt_http_static_conf_t;
191923Sz.hong@f5.com 
201923Sz.hong@f5.com 
21*1959Sz.hong@f5.com typedef struct {
22*1959Sz.hong@f5.com     nxt_http_action_t           *action;
23*1959Sz.hong@f5.com #if (NXT_HAVE_OPENAT2)
24*1959Sz.hong@f5.com     nxt_str_t                   chroot;
25*1959Sz.hong@f5.com #endif
26*1959Sz.hong@f5.com     uint8_t                     need_body;  /* 1 bit */
27*1959Sz.hong@f5.com } nxt_http_static_ctx_t;
28*1959Sz.hong@f5.com 
29*1959Sz.hong@f5.com 
301183Svbart@nginx.com #define NXT_HTTP_STATIC_BUF_COUNT  2
311183Svbart@nginx.com #define NXT_HTTP_STATIC_BUF_SIZE   (128 * 1024)
321183Svbart@nginx.com 
331183Svbart@nginx.com 
341923Sz.hong@f5.com static nxt_http_action_t *nxt_http_static(nxt_task_t *task,
351923Sz.hong@f5.com     nxt_http_request_t *r, nxt_http_action_t *action);
36*1959Sz.hong@f5.com static void nxt_http_static_send_ready(nxt_task_t *task, void *obj, void *data);
37*1959Sz.hong@f5.com static void nxt_http_static_var_error(nxt_task_t *task, void *obj, void *data);
38*1959Sz.hong@f5.com #if (NXT_HAVE_OPENAT2)
39*1959Sz.hong@f5.com static u_char *nxt_http_static_chroot_match(u_char *chr, u_char *shr);
40*1959Sz.hong@f5.com #endif
411183Svbart@nginx.com static void nxt_http_static_extract_extension(nxt_str_t *path,
421923Sz.hong@f5.com     nxt_str_t *exten);
431183Svbart@nginx.com static void nxt_http_static_body_handler(nxt_task_t *task, void *obj,
441183Svbart@nginx.com     void *data);
451183Svbart@nginx.com static void nxt_http_static_buf_completion(nxt_task_t *task, void *obj,
461183Svbart@nginx.com     void *data);
471183Svbart@nginx.com 
481183Svbart@nginx.com static nxt_int_t nxt_http_static_mtypes_hash_test(nxt_lvlhsh_query_t *lhq,
491183Svbart@nginx.com     void *data);
501183Svbart@nginx.com static void *nxt_http_static_mtypes_hash_alloc(void *data, size_t size);
511183Svbart@nginx.com static void nxt_http_static_mtypes_hash_free(void *data, void *p);
521183Svbart@nginx.com 
531183Svbart@nginx.com 
541183Svbart@nginx.com static const nxt_http_request_state_t  nxt_http_static_send_state;
551183Svbart@nginx.com 
561183Svbart@nginx.com 
571923Sz.hong@f5.com nxt_int_t
581923Sz.hong@f5.com nxt_http_static_init(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
591923Sz.hong@f5.com     nxt_http_action_t *action, nxt_http_action_conf_t *acf)
601923Sz.hong@f5.com {
611923Sz.hong@f5.com     nxt_mp_t                *mp;
621923Sz.hong@f5.com     nxt_str_t               *str, value;
631923Sz.hong@f5.com     nxt_http_static_conf_t  *conf;
641923Sz.hong@f5.com 
651923Sz.hong@f5.com     mp = tmcf->router_conf->mem_pool;
661923Sz.hong@f5.com 
671923Sz.hong@f5.com     conf = nxt_mp_zget(mp, sizeof(nxt_http_static_conf_t));
681923Sz.hong@f5.com     if (nxt_slow_path(conf == NULL)) {
691923Sz.hong@f5.com         return NXT_ERROR;
701923Sz.hong@f5.com     }
711923Sz.hong@f5.com 
721923Sz.hong@f5.com     action->handler = nxt_http_static;
731923Sz.hong@f5.com     action->u.conf = conf;
741923Sz.hong@f5.com 
751923Sz.hong@f5.com     nxt_conf_get_string(acf->share, &value);
761923Sz.hong@f5.com 
771923Sz.hong@f5.com     str = nxt_str_dup(mp, &conf->share, &value);
781923Sz.hong@f5.com     if (nxt_slow_path(str == NULL)) {
791923Sz.hong@f5.com         return NXT_ERROR;
801923Sz.hong@f5.com     }
811923Sz.hong@f5.com 
82*1959Sz.hong@f5.com     conf->is_const = 1;
83*1959Sz.hong@f5.com 
841923Sz.hong@f5.com #if (NXT_HAVE_OPENAT2)
851923Sz.hong@f5.com     if (acf->chroot.length > 0) {
86*1959Sz.hong@f5.com         if (nxt_is_var(&acf->chroot)) {
87*1959Sz.hong@f5.com             conf->is_const = 0;
881923Sz.hong@f5.com         }
891923Sz.hong@f5.com 
90*1959Sz.hong@f5.com         conf->chroot = nxt_var_compile(&acf->chroot, mp, 1);
91*1959Sz.hong@f5.com         if (nxt_slow_path(conf->chroot == NULL)) {
921923Sz.hong@f5.com             return NXT_ERROR;
931923Sz.hong@f5.com         }
941923Sz.hong@f5.com     }
951923Sz.hong@f5.com 
961923Sz.hong@f5.com     if (acf->follow_symlinks != NULL
971923Sz.hong@f5.com         && !nxt_conf_get_boolean(acf->follow_symlinks))
981923Sz.hong@f5.com     {
991923Sz.hong@f5.com         conf->resolve |= RESOLVE_NO_SYMLINKS;
1001923Sz.hong@f5.com     }
1011923Sz.hong@f5.com 
1021923Sz.hong@f5.com     if (acf->traverse_mounts != NULL
1031923Sz.hong@f5.com         && !nxt_conf_get_boolean(acf->traverse_mounts))
1041923Sz.hong@f5.com     {
1051923Sz.hong@f5.com         conf->resolve |= RESOLVE_NO_XDEV;
1061923Sz.hong@f5.com     }
1071923Sz.hong@f5.com #endif
1081923Sz.hong@f5.com 
1091923Sz.hong@f5.com     if (acf->types != NULL) {
1101923Sz.hong@f5.com         conf->types = nxt_http_route_types_rule_create(task, mp, acf->types);
1111923Sz.hong@f5.com         if (nxt_slow_path(conf->types == NULL)) {
1121923Sz.hong@f5.com             return NXT_ERROR;
1131923Sz.hong@f5.com         }
1141923Sz.hong@f5.com     }
1151923Sz.hong@f5.com 
1161923Sz.hong@f5.com     if (acf->fallback != NULL) {
1171923Sz.hong@f5.com         action->fallback = nxt_mp_alloc(mp, sizeof(nxt_http_action_t));
1181923Sz.hong@f5.com         if (nxt_slow_path(action->fallback == NULL)) {
1191923Sz.hong@f5.com             return NXT_ERROR;
1201923Sz.hong@f5.com         }
1211923Sz.hong@f5.com 
1221923Sz.hong@f5.com         return nxt_http_action_init(task, tmcf, acf->fallback,
1231923Sz.hong@f5.com                                     action->fallback);
1241923Sz.hong@f5.com     }
1251923Sz.hong@f5.com 
1261923Sz.hong@f5.com     return NXT_OK;
1271923Sz.hong@f5.com }
1281923Sz.hong@f5.com 
1291923Sz.hong@f5.com 
1301923Sz.hong@f5.com static nxt_http_action_t *
1311923Sz.hong@f5.com nxt_http_static(nxt_task_t *task, nxt_http_request_t *r,
1321264Sigor@sysoev.ru     nxt_http_action_t *action)
1331183Svbart@nginx.com {
1341923Sz.hong@f5.com     nxt_int_t               ret;
1351923Sz.hong@f5.com     nxt_bool_t              need_body;
136*1959Sz.hong@f5.com     nxt_http_static_ctx_t   *ctx;
1371923Sz.hong@f5.com     nxt_http_static_conf_t  *conf;
1381923Sz.hong@f5.com 
1391183Svbart@nginx.com     if (nxt_slow_path(!nxt_str_eq(r->method, "GET", 3))) {
1401183Svbart@nginx.com 
1411183Svbart@nginx.com         if (!nxt_str_eq(r->method, "HEAD", 4)) {
1421923Sz.hong@f5.com             if (action->fallback != NULL) {
1431923Sz.hong@f5.com                 return action->fallback;
1441378Svbart@nginx.com             }
1451378Svbart@nginx.com 
1461183Svbart@nginx.com             nxt_http_request_error(task, r, NXT_HTTP_METHOD_NOT_ALLOWED);
1471183Svbart@nginx.com             return NULL;
1481183Svbart@nginx.com         }
1491183Svbart@nginx.com 
1501183Svbart@nginx.com         need_body = 0;
1511183Svbart@nginx.com 
1521183Svbart@nginx.com     } else {
1531183Svbart@nginx.com         need_body = 1;
1541183Svbart@nginx.com     }
1551183Svbart@nginx.com 
156*1959Sz.hong@f5.com     conf = action->u.conf;
157*1959Sz.hong@f5.com 
158*1959Sz.hong@f5.com #if (NXT_DEBUG && NXT_HAVE_OPENAT2)
159*1959Sz.hong@f5.com     nxt_str_t  chr;
160*1959Sz.hong@f5.com 
161*1959Sz.hong@f5.com     if (conf->chroot != NULL) {
162*1959Sz.hong@f5.com         nxt_var_raw(conf->chroot, &chr);
163*1959Sz.hong@f5.com 
164*1959Sz.hong@f5.com     } else {
165*1959Sz.hong@f5.com         nxt_str_set(&chr, "");
166*1959Sz.hong@f5.com     }
167*1959Sz.hong@f5.com 
168*1959Sz.hong@f5.com     nxt_debug(task, "http static: \"%V\" (chroot: \"%V\")", &conf->share, &chr);
169*1959Sz.hong@f5.com 
170*1959Sz.hong@f5.com #else
171*1959Sz.hong@f5.com     nxt_debug(task, "http static: \"%V\"", &conf->share);
172*1959Sz.hong@f5.com #endif
173*1959Sz.hong@f5.com 
174*1959Sz.hong@f5.com     ctx = nxt_mp_zget(r->mem_pool, sizeof(nxt_http_static_ctx_t));
175*1959Sz.hong@f5.com     if (nxt_slow_path(ctx == NULL)) {
176*1959Sz.hong@f5.com         goto fail;
177*1959Sz.hong@f5.com     }
178*1959Sz.hong@f5.com 
179*1959Sz.hong@f5.com     ctx->action = action;
180*1959Sz.hong@f5.com     ctx->need_body = need_body;
181*1959Sz.hong@f5.com 
182*1959Sz.hong@f5.com     if (conf->is_const) {
183*1959Sz.hong@f5.com #if (NXT_HAVE_OPENAT2)
184*1959Sz.hong@f5.com         if (conf->chroot != NULL) {
185*1959Sz.hong@f5.com             nxt_var_raw(conf->chroot, &ctx->chroot);
186*1959Sz.hong@f5.com         }
187*1959Sz.hong@f5.com #endif
188*1959Sz.hong@f5.com 
189*1959Sz.hong@f5.com         nxt_http_static_send_ready(task, r, ctx);
190*1959Sz.hong@f5.com 
191*1959Sz.hong@f5.com     } else {
192*1959Sz.hong@f5.com         ret = nxt_var_query_init(&r->var_query, r, r->mem_pool);
193*1959Sz.hong@f5.com         if (nxt_slow_path(ret != NXT_OK)) {
194*1959Sz.hong@f5.com             goto fail;
195*1959Sz.hong@f5.com         }
196*1959Sz.hong@f5.com 
197*1959Sz.hong@f5.com #if (NXT_HAVE_OPENAT2)
198*1959Sz.hong@f5.com         nxt_var_query(task, r->var_query, conf->chroot, &ctx->chroot);
199*1959Sz.hong@f5.com #endif
200*1959Sz.hong@f5.com 
201*1959Sz.hong@f5.com         nxt_var_query_resolve(task, r->var_query, ctx,
202*1959Sz.hong@f5.com                               nxt_http_static_send_ready,
203*1959Sz.hong@f5.com                               nxt_http_static_var_error);
204*1959Sz.hong@f5.com     }
205*1959Sz.hong@f5.com 
206*1959Sz.hong@f5.com     return NULL;
207*1959Sz.hong@f5.com 
208*1959Sz.hong@f5.com fail:
209*1959Sz.hong@f5.com 
210*1959Sz.hong@f5.com     nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
211*1959Sz.hong@f5.com     return NULL;
212*1959Sz.hong@f5.com }
213*1959Sz.hong@f5.com 
214*1959Sz.hong@f5.com 
215*1959Sz.hong@f5.com static void
216*1959Sz.hong@f5.com nxt_http_static_send_ready(nxt_task_t *task, void *obj, void *data)
217*1959Sz.hong@f5.com {
218*1959Sz.hong@f5.com     size_t                  length, encode;
219*1959Sz.hong@f5.com     u_char                  *p, *fname;
220*1959Sz.hong@f5.com     struct tm               tm;
221*1959Sz.hong@f5.com     nxt_buf_t               *fb;
222*1959Sz.hong@f5.com     nxt_int_t               ret;
223*1959Sz.hong@f5.com     nxt_str_t               index, exten, *mtype;
224*1959Sz.hong@f5.com     nxt_uint_t              level;
225*1959Sz.hong@f5.com     nxt_file_t              *f, file;
226*1959Sz.hong@f5.com     nxt_file_info_t         fi;
227*1959Sz.hong@f5.com     nxt_http_field_t        *field;
228*1959Sz.hong@f5.com     nxt_http_status_t       status;
229*1959Sz.hong@f5.com     nxt_router_conf_t       *rtcf;
230*1959Sz.hong@f5.com     nxt_http_action_t       *action;
231*1959Sz.hong@f5.com     nxt_http_request_t      *r;
232*1959Sz.hong@f5.com     nxt_work_handler_t      body_handler;
233*1959Sz.hong@f5.com     nxt_http_static_ctx_t   *ctx;
234*1959Sz.hong@f5.com     nxt_http_static_conf_t  *conf;
235*1959Sz.hong@f5.com 
236*1959Sz.hong@f5.com     r = obj;
237*1959Sz.hong@f5.com     ctx = data;
238*1959Sz.hong@f5.com     action = ctx->action;
239*1959Sz.hong@f5.com     conf = action->u.conf;
240*1959Sz.hong@f5.com 
2411183Svbart@nginx.com     if (r->path->start[r->path->length - 1] == '/') {
2421183Svbart@nginx.com         /* TODO: dynamic index setting. */
2431183Svbart@nginx.com         nxt_str_set(&index, "index.html");
2441923Sz.hong@f5.com         nxt_str_set(&exten, ".html");
2451183Svbart@nginx.com 
2461183Svbart@nginx.com     } else {
2471483Svbart@nginx.com         nxt_str_set(&index, "");
2481923Sz.hong@f5.com         nxt_str_null(&exten);
2491183Svbart@nginx.com     }
2501183Svbart@nginx.com 
2511855Sz.hong@f5.com     f = NULL;
252*1959Sz.hong@f5.com     status = NXT_HTTP_INTERNAL_SERVER_ERROR;
2531183Svbart@nginx.com 
2541859So.canty@f5.com     rtcf = r->conf->socket_conf->router_conf;
2551859So.canty@f5.com 
2561859So.canty@f5.com     mtype = NULL;
2571859So.canty@f5.com 
2581923Sz.hong@f5.com     if (conf->types != NULL && exten.start == NULL) {
2591923Sz.hong@f5.com         nxt_http_static_extract_extension(r->path, &exten);
2601923Sz.hong@f5.com         mtype = nxt_http_static_mtype_get(&rtcf->mtypes_hash, &exten);
2611859So.canty@f5.com 
2621923Sz.hong@f5.com         ret = nxt_http_route_test_rule(r, conf->types, mtype->start,
2631923Sz.hong@f5.com                                        mtype->length);
2641883So.canty@f5.com         if (nxt_slow_path(ret == NXT_ERROR)) {
2651883So.canty@f5.com             goto fail;
2661883So.canty@f5.com         }
2671883So.canty@f5.com 
2681883So.canty@f5.com         if (ret == 0) {
269*1959Sz.hong@f5.com             status = NXT_HTTP_FORBIDDEN;
270*1959Sz.hong@f5.com             goto fail;
2711859So.canty@f5.com         }
2721859So.canty@f5.com     }
2731859So.canty@f5.com 
2741923Sz.hong@f5.com     length = conf->share.length + r->path->length + index.length;
2751855Sz.hong@f5.com 
2761855Sz.hong@f5.com     fname = nxt_mp_nget(r->mem_pool, length + 1);
2771855Sz.hong@f5.com     if (nxt_slow_path(fname == NULL)) {
2781183Svbart@nginx.com         goto fail;
2791183Svbart@nginx.com     }
2801183Svbart@nginx.com 
2811855Sz.hong@f5.com     p = fname;
2821923Sz.hong@f5.com     p = nxt_cpymem(p, conf->share.start, conf->share.length);
2831183Svbart@nginx.com     p = nxt_cpymem(p, r->path->start, r->path->length);
2841183Svbart@nginx.com     p = nxt_cpymem(p, index.start, index.length);
2851183Svbart@nginx.com     *p = '\0';
2861183Svbart@nginx.com 
2871855Sz.hong@f5.com     nxt_memzero(&file, sizeof(nxt_file_t));
2881855Sz.hong@f5.com 
2891855Sz.hong@f5.com     file.name = fname;
2901855Sz.hong@f5.com 
291*1959Sz.hong@f5.com #if (NXT_HAVE_OPENAT2)
292*1959Sz.hong@f5.com     if (conf->resolve != 0 || ctx->chroot.length > 0) {
293*1959Sz.hong@f5.com         nxt_str_t   *chr;
294*1959Sz.hong@f5.com         nxt_uint_t  resolve;
2951855Sz.hong@f5.com 
296*1959Sz.hong@f5.com         resolve = conf->resolve;
297*1959Sz.hong@f5.com         chr = &ctx->chroot;
2981855Sz.hong@f5.com 
299*1959Sz.hong@f5.com         if (chr->length > 0) {
300*1959Sz.hong@f5.com             resolve |= RESOLVE_IN_ROOT;
3011855Sz.hong@f5.com 
302*1959Sz.hong@f5.com             fname = nxt_http_static_chroot_match(chr->start, file.name);
303*1959Sz.hong@f5.com 
304*1959Sz.hong@f5.com             if (fname != NULL) {
305*1959Sz.hong@f5.com                 file.name = chr->start;
3061855Sz.hong@f5.com                 ret = nxt_file_open(task, &file, NXT_FILE_SEARCH, NXT_FILE_OPEN,
3071855Sz.hong@f5.com                                     0);
3081855Sz.hong@f5.com 
3091855Sz.hong@f5.com             } else {
3101855Sz.hong@f5.com                 file.error = NXT_EACCES;
3111855Sz.hong@f5.com                 ret = NXT_ERROR;
3121855Sz.hong@f5.com             }
3131855Sz.hong@f5.com 
3141855Sz.hong@f5.com         } else if (fname[0] == '/') {
3151855Sz.hong@f5.com             file.name = (u_char *) "/";
3161855Sz.hong@f5.com             ret = nxt_file_open(task, &file, NXT_FILE_SEARCH, NXT_FILE_OPEN, 0);
3171855Sz.hong@f5.com 
3181855Sz.hong@f5.com         } else {
3191855Sz.hong@f5.com             file.name = (u_char *) ".";
3201855Sz.hong@f5.com             file.fd = AT_FDCWD;
3211855Sz.hong@f5.com             ret = NXT_OK;
3221855Sz.hong@f5.com         }
3231855Sz.hong@f5.com 
3241855Sz.hong@f5.com         if (nxt_fast_path(ret == NXT_OK)) {
3251856Sz.hong@f5.com             nxt_file_t  af;
3261856Sz.hong@f5.com 
3271855Sz.hong@f5.com             af = file;
3281855Sz.hong@f5.com             nxt_memzero(&file, sizeof(nxt_file_t));
3291855Sz.hong@f5.com             file.name = fname;
3301855Sz.hong@f5.com 
3311855Sz.hong@f5.com             ret = nxt_file_openat2(task, &file, NXT_FILE_RDONLY,
332*1959Sz.hong@f5.com                                    NXT_FILE_OPEN, 0, af.fd, resolve);
3331855Sz.hong@f5.com 
3341855Sz.hong@f5.com             if (af.fd != AT_FDCWD) {
3351855Sz.hong@f5.com                 nxt_file_close(task, &af);
3361855Sz.hong@f5.com             }
3371855Sz.hong@f5.com         }
3381855Sz.hong@f5.com 
3391855Sz.hong@f5.com     } else {
3401855Sz.hong@f5.com         ret = nxt_file_open(task, &file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 0);
3411855Sz.hong@f5.com     }
3421855Sz.hong@f5.com 
3431855Sz.hong@f5.com #else
3441855Sz.hong@f5.com     ret = nxt_file_open(task, &file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 0);
3451855Sz.hong@f5.com #endif
3461183Svbart@nginx.com 
3471183Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
3481855Sz.hong@f5.com 
3491855Sz.hong@f5.com         switch (file.error) {
3501183Svbart@nginx.com 
3511200Svbart@nginx.com         /*
3521200Svbart@nginx.com          * For Unix domain sockets "errno" is set to:
3531200Svbart@nginx.com          *  - ENXIO on Linux;
3541200Svbart@nginx.com          *  - EOPNOTSUPP on *BSD, MacOSX, and Solaris.
3551200Svbart@nginx.com          */
3561200Svbart@nginx.com 
3571183Svbart@nginx.com         case NXT_ENOENT:
3581183Svbart@nginx.com         case NXT_ENOTDIR:
3591183Svbart@nginx.com         case NXT_ENAMETOOLONG:
3601200Svbart@nginx.com #if (NXT_LINUX)
3611200Svbart@nginx.com         case NXT_ENXIO:
3621200Svbart@nginx.com #else
3631200Svbart@nginx.com         case NXT_EOPNOTSUPP:
3641200Svbart@nginx.com #endif
3651183Svbart@nginx.com             level = NXT_LOG_ERR;
3661183Svbart@nginx.com             status = NXT_HTTP_NOT_FOUND;
3671183Svbart@nginx.com             break;
3681183Svbart@nginx.com 
3691183Svbart@nginx.com         case NXT_EACCES:
3701855Sz.hong@f5.com #if (NXT_HAVE_OPENAT2)
3711855Sz.hong@f5.com         case NXT_ELOOP:
3721855Sz.hong@f5.com         case NXT_EXDEV:
3731855Sz.hong@f5.com #endif
3741183Svbart@nginx.com             level = NXT_LOG_ERR;
3751183Svbart@nginx.com             status = NXT_HTTP_FORBIDDEN;
3761183Svbart@nginx.com             break;
3771183Svbart@nginx.com 
3781183Svbart@nginx.com         default:
3791183Svbart@nginx.com             level = NXT_LOG_ALERT;
3801183Svbart@nginx.com             status = NXT_HTTP_INTERNAL_SERVER_ERROR;
3811183Svbart@nginx.com             break;
3821183Svbart@nginx.com         }
3831183Svbart@nginx.com 
3841923Sz.hong@f5.com         if (level == NXT_LOG_ERR && action->fallback != NULL) {
385*1959Sz.hong@f5.com             goto fail;
3861378Svbart@nginx.com         }
3871378Svbart@nginx.com 
3881183Svbart@nginx.com         if (status != NXT_HTTP_NOT_FOUND) {
389*1959Sz.hong@f5.com #if (NXT_HAVE_OPENAT2)
390*1959Sz.hong@f5.com             nxt_str_t  *chr = &ctx->chroot;
391*1959Sz.hong@f5.com 
392*1959Sz.hong@f5.com             if (chr->length > 0) {
3931857Sz.hong@f5.com                 nxt_log(task, level, "opening \"%s\" at \"%V\" failed %E",
394*1959Sz.hong@f5.com                         fname, chr, file.error);
3951855Sz.hong@f5.com 
3961855Sz.hong@f5.com             } else {
3971857Sz.hong@f5.com                 nxt_log(task, level, "opening \"%s\" failed %E",
3981855Sz.hong@f5.com                         fname, file.error);
3991855Sz.hong@f5.com             }
400*1959Sz.hong@f5.com 
401*1959Sz.hong@f5.com #else
402*1959Sz.hong@f5.com             nxt_log(task, level, "opening \"%s\" failed %E", fname, file.error);
403*1959Sz.hong@f5.com #endif
4041183Svbart@nginx.com         }
4051183Svbart@nginx.com 
406*1959Sz.hong@f5.com         goto fail;
4071183Svbart@nginx.com     }
4081183Svbart@nginx.com 
4091855Sz.hong@f5.com     f = nxt_mp_get(r->mem_pool, sizeof(nxt_file_t));
4101855Sz.hong@f5.com     if (nxt_slow_path(f == NULL)) {
4111855Sz.hong@f5.com         goto fail;
4121855Sz.hong@f5.com     }
4131855Sz.hong@f5.com 
4141855Sz.hong@f5.com     *f = file;
4151855Sz.hong@f5.com 
4161183Svbart@nginx.com     ret = nxt_file_info(f, &fi);
4171183Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
4181183Svbart@nginx.com         goto fail;
4191183Svbart@nginx.com     }
4201183Svbart@nginx.com 
4211183Svbart@nginx.com     if (nxt_fast_path(nxt_is_file(&fi))) {
4221183Svbart@nginx.com         r->status = NXT_HTTP_OK;
4231183Svbart@nginx.com         r->resp.content_length_n = nxt_file_size(&fi);
4241183Svbart@nginx.com 
4251183Svbart@nginx.com         field = nxt_list_zero_add(r->resp.fields);
4261183Svbart@nginx.com         if (nxt_slow_path(field == NULL)) {
4271183Svbart@nginx.com             goto fail;
4281183Svbart@nginx.com         }
4291183Svbart@nginx.com 
4301183Svbart@nginx.com         nxt_http_field_name_set(field, "Last-Modified");
4311183Svbart@nginx.com 
4321183Svbart@nginx.com         p = nxt_mp_nget(r->mem_pool, NXT_HTTP_DATE_LEN);
4331183Svbart@nginx.com         if (nxt_slow_path(p == NULL)) {
4341183Svbart@nginx.com             goto fail;
4351183Svbart@nginx.com         }
4361183Svbart@nginx.com 
4371183Svbart@nginx.com         nxt_localtime(nxt_file_mtime(&fi), &tm);
4381183Svbart@nginx.com 
4391183Svbart@nginx.com         field->value = p;
4401183Svbart@nginx.com         field->value_length = nxt_http_date(p, &tm) - p;
4411183Svbart@nginx.com 
4421183Svbart@nginx.com         field = nxt_list_zero_add(r->resp.fields);
4431183Svbart@nginx.com         if (nxt_slow_path(field == NULL)) {
4441183Svbart@nginx.com             goto fail;
4451183Svbart@nginx.com         }
4461183Svbart@nginx.com 
4471183Svbart@nginx.com         nxt_http_field_name_set(field, "ETag");
4481183Svbart@nginx.com 
4491855Sz.hong@f5.com         length = NXT_TIME_T_HEXLEN + NXT_OFF_T_HEXLEN + 3;
4501183Svbart@nginx.com 
4511855Sz.hong@f5.com         p = nxt_mp_nget(r->mem_pool, length);
4521183Svbart@nginx.com         if (nxt_slow_path(p == NULL)) {
4531183Svbart@nginx.com             goto fail;
4541183Svbart@nginx.com         }
4551183Svbart@nginx.com 
4561183Svbart@nginx.com         field->value = p;
4571855Sz.hong@f5.com         field->value_length = nxt_sprintf(p, p + length, "\"%xT-%xO\"",
4581183Svbart@nginx.com                                           nxt_file_mtime(&fi),
4591183Svbart@nginx.com                                           nxt_file_size(&fi))
4601183Svbart@nginx.com                               - p;
4611183Svbart@nginx.com 
4621923Sz.hong@f5.com         if (exten.start == NULL) {
4631923Sz.hong@f5.com             nxt_http_static_extract_extension(r->path, &exten);
4641183Svbart@nginx.com         }
4651183Svbart@nginx.com 
4661859So.canty@f5.com         if (mtype == NULL) {
4671923Sz.hong@f5.com             mtype = nxt_http_static_mtype_get(&rtcf->mtypes_hash, &exten);
4681859So.canty@f5.com         }
4691183Svbart@nginx.com 
4701883So.canty@f5.com         if (mtype->length != 0) {
4711183Svbart@nginx.com             field = nxt_list_zero_add(r->resp.fields);
4721183Svbart@nginx.com             if (nxt_slow_path(field == NULL)) {
4731183Svbart@nginx.com                 goto fail;
4741183Svbart@nginx.com             }
4751183Svbart@nginx.com 
4761183Svbart@nginx.com             nxt_http_field_name_set(field, "Content-Type");
4771183Svbart@nginx.com 
4781183Svbart@nginx.com             field->value = mtype->start;
4791183Svbart@nginx.com             field->value_length = mtype->length;
4801183Svbart@nginx.com         }
4811183Svbart@nginx.com 
482*1959Sz.hong@f5.com         if (ctx->need_body && nxt_file_size(&fi) > 0) {
4831183Svbart@nginx.com             fb = nxt_mp_zget(r->mem_pool, NXT_BUF_FILE_SIZE);
4841183Svbart@nginx.com             if (nxt_slow_path(fb == NULL)) {
4851183Svbart@nginx.com                 goto fail;
4861183Svbart@nginx.com             }
4871183Svbart@nginx.com 
4881183Svbart@nginx.com             fb->file = f;
4891183Svbart@nginx.com             fb->file_end = nxt_file_size(&fi);
4901183Svbart@nginx.com 
4911183Svbart@nginx.com             r->out = fb;
4921183Svbart@nginx.com 
4931183Svbart@nginx.com             body_handler = &nxt_http_static_body_handler;
4941183Svbart@nginx.com 
4951183Svbart@nginx.com         } else {
4961183Svbart@nginx.com             nxt_file_close(task, f);
4971183Svbart@nginx.com             body_handler = NULL;
4981183Svbart@nginx.com         }
4991183Svbart@nginx.com 
5001183Svbart@nginx.com     } else {
5011183Svbart@nginx.com         /* Not a file. */
5021183Svbart@nginx.com 
5031183Svbart@nginx.com         if (nxt_slow_path(!nxt_is_dir(&fi))) {
504*1959Sz.hong@f5.com             if (action->fallback == NULL) {
505*1959Sz.hong@f5.com                 nxt_log(task, NXT_LOG_ERR, "\"%FN\" is not a regular file",
506*1959Sz.hong@f5.com                         f->name);
5071378Svbart@nginx.com             }
5081378Svbart@nginx.com 
509*1959Sz.hong@f5.com             status = NXT_HTTP_NOT_FOUND;
510*1959Sz.hong@f5.com             goto fail;
5111183Svbart@nginx.com         }
5121183Svbart@nginx.com 
513*1959Sz.hong@f5.com         nxt_file_close(task, f);
5141198Svbart@nginx.com         f = NULL;
5151198Svbart@nginx.com 
5161183Svbart@nginx.com         r->status = NXT_HTTP_MOVED_PERMANENTLY;
5171183Svbart@nginx.com         r->resp.content_length_n = 0;
5181183Svbart@nginx.com 
5191183Svbart@nginx.com         field = nxt_list_zero_add(r->resp.fields);
5201183Svbart@nginx.com         if (nxt_slow_path(field == NULL)) {
5211183Svbart@nginx.com             goto fail;
5221183Svbart@nginx.com         }
5231183Svbart@nginx.com 
5241183Svbart@nginx.com         nxt_http_field_name_set(field, "Location");
5251183Svbart@nginx.com 
5261183Svbart@nginx.com         encode = nxt_encode_uri(NULL, r->path->start, r->path->length);
5271855Sz.hong@f5.com         length = r->path->length + encode * 2 + 1;
5281183Svbart@nginx.com 
5291183Svbart@nginx.com         if (r->args->length > 0) {
5301855Sz.hong@f5.com             length += 1 + r->args->length;
5311183Svbart@nginx.com         }
5321183Svbart@nginx.com 
5331855Sz.hong@f5.com         p = nxt_mp_nget(r->mem_pool, length);
5341183Svbart@nginx.com         if (nxt_slow_path(p == NULL)) {
5351183Svbart@nginx.com             goto fail;
5361183Svbart@nginx.com         }
5371183Svbart@nginx.com 
5381183Svbart@nginx.com         field->value = p;
5391855Sz.hong@f5.com         field->value_length = length;
5401183Svbart@nginx.com 
5411183Svbart@nginx.com         if (encode > 0) {
5421183Svbart@nginx.com             p = (u_char *) nxt_encode_uri(p, r->path->start, r->path->length);
5431183Svbart@nginx.com 
5441183Svbart@nginx.com         } else {
5451183Svbart@nginx.com             p = nxt_cpymem(p, r->path->start, r->path->length);
5461183Svbart@nginx.com         }
5471183Svbart@nginx.com 
5481183Svbart@nginx.com         *p++ = '/';
5491183Svbart@nginx.com 
5501183Svbart@nginx.com         if (r->args->length > 0) {
5511183Svbart@nginx.com             *p++ = '?';
5521183Svbart@nginx.com             nxt_memcpy(p, r->args->start, r->args->length);
5531183Svbart@nginx.com         }
5541183Svbart@nginx.com 
5551183Svbart@nginx.com         body_handler = NULL;
5561183Svbart@nginx.com     }
5571183Svbart@nginx.com 
5581270Sigor@sysoev.ru     nxt_http_request_header_send(task, r, body_handler, NULL);
5591183Svbart@nginx.com 
5601183Svbart@nginx.com     r->state = &nxt_http_static_send_state;
561*1959Sz.hong@f5.com     return;
5621183Svbart@nginx.com 
5631183Svbart@nginx.com fail:
5641183Svbart@nginx.com 
5651855Sz.hong@f5.com     if (f != NULL) {
5661183Svbart@nginx.com         nxt_file_close(task, f);
5671183Svbart@nginx.com     }
5681183Svbart@nginx.com 
569*1959Sz.hong@f5.com     if (status != NXT_HTTP_INTERNAL_SERVER_ERROR
570*1959Sz.hong@f5.com         && action->fallback != NULL)
571*1959Sz.hong@f5.com     {
572*1959Sz.hong@f5.com         nxt_http_request_action(task, r, action->fallback);
573*1959Sz.hong@f5.com         return;
574*1959Sz.hong@f5.com     }
575*1959Sz.hong@f5.com 
576*1959Sz.hong@f5.com     nxt_http_request_error(task, r, status);
577*1959Sz.hong@f5.com }
578*1959Sz.hong@f5.com 
579*1959Sz.hong@f5.com 
580*1959Sz.hong@f5.com static void
581*1959Sz.hong@f5.com nxt_http_static_var_error(nxt_task_t *task, void *obj, void *data)
582*1959Sz.hong@f5.com {
583*1959Sz.hong@f5.com     nxt_http_request_t  *r;
584*1959Sz.hong@f5.com 
585*1959Sz.hong@f5.com     r = obj;
586*1959Sz.hong@f5.com 
587*1959Sz.hong@f5.com     nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
5881183Svbart@nginx.com }
5891183Svbart@nginx.com 
5901183Svbart@nginx.com 
591*1959Sz.hong@f5.com #if (NXT_HAVE_OPENAT2)
592*1959Sz.hong@f5.com 
593*1959Sz.hong@f5.com static u_char *
594*1959Sz.hong@f5.com nxt_http_static_chroot_match(u_char *chr, u_char *shr)
595*1959Sz.hong@f5.com {
596*1959Sz.hong@f5.com     if (*chr != *shr) {
597*1959Sz.hong@f5.com         return NULL;
598*1959Sz.hong@f5.com     }
599*1959Sz.hong@f5.com 
600*1959Sz.hong@f5.com     chr++;
601*1959Sz.hong@f5.com     shr++;
602*1959Sz.hong@f5.com 
603*1959Sz.hong@f5.com     for ( ;; ) {
604*1959Sz.hong@f5.com         if (*shr == '\0') {
605*1959Sz.hong@f5.com             return NULL;
606*1959Sz.hong@f5.com         }
607*1959Sz.hong@f5.com 
608*1959Sz.hong@f5.com         if (*chr == *shr) {
609*1959Sz.hong@f5.com             chr++;
610*1959Sz.hong@f5.com             shr++;
611*1959Sz.hong@f5.com             continue;
612*1959Sz.hong@f5.com         }
613*1959Sz.hong@f5.com 
614*1959Sz.hong@f5.com         if (*chr == '\0') {
615*1959Sz.hong@f5.com             break;
616*1959Sz.hong@f5.com         }
617*1959Sz.hong@f5.com 
618*1959Sz.hong@f5.com         if (*chr == '/') {
619*1959Sz.hong@f5.com             if (chr[-1] == '/') {
620*1959Sz.hong@f5.com                 chr++;
621*1959Sz.hong@f5.com                 continue;
622*1959Sz.hong@f5.com             }
623*1959Sz.hong@f5.com 
624*1959Sz.hong@f5.com         } else if (*shr == '/') {
625*1959Sz.hong@f5.com             if (shr[-1] == '/') {
626*1959Sz.hong@f5.com                 shr++;
627*1959Sz.hong@f5.com                 continue;
628*1959Sz.hong@f5.com             }
629*1959Sz.hong@f5.com         }
630*1959Sz.hong@f5.com 
631*1959Sz.hong@f5.com         return NULL;
632*1959Sz.hong@f5.com     }
633*1959Sz.hong@f5.com 
634*1959Sz.hong@f5.com     if (shr[-1] != '/' && *shr != '/') {
635*1959Sz.hong@f5.com         return NULL;
636*1959Sz.hong@f5.com     }
637*1959Sz.hong@f5.com 
638*1959Sz.hong@f5.com     while (*shr == '/') {
639*1959Sz.hong@f5.com         shr++;
640*1959Sz.hong@f5.com     }
641*1959Sz.hong@f5.com 
642*1959Sz.hong@f5.com     return (*shr != '\0') ? shr : NULL;
643*1959Sz.hong@f5.com }
644*1959Sz.hong@f5.com 
645*1959Sz.hong@f5.com #endif
646*1959Sz.hong@f5.com 
647*1959Sz.hong@f5.com 
6481183Svbart@nginx.com static void
6491923Sz.hong@f5.com nxt_http_static_extract_extension(nxt_str_t *path, nxt_str_t *exten)
6501183Svbart@nginx.com {
6511183Svbart@nginx.com     u_char  ch, *p, *end;
6521183Svbart@nginx.com 
6531183Svbart@nginx.com     end = path->start + path->length;
6541183Svbart@nginx.com     p = end;
6551183Svbart@nginx.com 
6561183Svbart@nginx.com     for ( ;; ) {
6571183Svbart@nginx.com         /* There's always '/' in the beginning of the request path. */
6581183Svbart@nginx.com 
6591183Svbart@nginx.com         p--;
6601183Svbart@nginx.com         ch = *p;
6611183Svbart@nginx.com 
6621183Svbart@nginx.com         switch (ch) {
6631183Svbart@nginx.com         case '/':
6641183Svbart@nginx.com             p++;
6651183Svbart@nginx.com             /* Fall through. */
6661183Svbart@nginx.com         case '.':
6671923Sz.hong@f5.com             exten->length = end - p;
6681923Sz.hong@f5.com             exten->start = p;
6691183Svbart@nginx.com             return;
6701183Svbart@nginx.com         }
6711183Svbart@nginx.com     }
6721183Svbart@nginx.com }
6731183Svbart@nginx.com 
6741183Svbart@nginx.com 
6751183Svbart@nginx.com static void
6761183Svbart@nginx.com nxt_http_static_body_handler(nxt_task_t *task, void *obj, void *data)
6771183Svbart@nginx.com {
6781183Svbart@nginx.com     size_t              alloc;
6791183Svbart@nginx.com     nxt_buf_t           *fb, *b, **next, *out;
6801183Svbart@nginx.com     nxt_off_t           rest;
6811183Svbart@nginx.com     nxt_int_t           n;
6821183Svbart@nginx.com     nxt_work_queue_t    *wq;
6831183Svbart@nginx.com     nxt_http_request_t  *r;
6841183Svbart@nginx.com 
6851183Svbart@nginx.com     r = obj;
6861183Svbart@nginx.com     fb = r->out;
6871183Svbart@nginx.com 
6881183Svbart@nginx.com     rest = fb->file_end - fb->file_pos;
6891183Svbart@nginx.com     out = NULL;
6901183Svbart@nginx.com     next = &out;
6911183Svbart@nginx.com     n = 0;
6921183Svbart@nginx.com 
6931183Svbart@nginx.com     do {
6941183Svbart@nginx.com         alloc = nxt_min(rest, NXT_HTTP_STATIC_BUF_SIZE);
6951183Svbart@nginx.com 
6961183Svbart@nginx.com         b = nxt_buf_mem_alloc(r->mem_pool, alloc, 0);
6971183Svbart@nginx.com         if (nxt_slow_path(b == NULL)) {
6981183Svbart@nginx.com             goto fail;
6991183Svbart@nginx.com         }
7001183Svbart@nginx.com 
7011183Svbart@nginx.com         b->completion_handler = nxt_http_static_buf_completion;
7021183Svbart@nginx.com         b->parent = r;
7031183Svbart@nginx.com 
7041183Svbart@nginx.com         nxt_mp_retain(r->mem_pool);
7051183Svbart@nginx.com 
7061183Svbart@nginx.com         *next = b;
7071183Svbart@nginx.com         next = &b->next;
7081183Svbart@nginx.com 
7091183Svbart@nginx.com         rest -= alloc;
7101183Svbart@nginx.com 
7111183Svbart@nginx.com     } while (rest > 0 && ++n < NXT_HTTP_STATIC_BUF_COUNT);
7121183Svbart@nginx.com 
7131183Svbart@nginx.com     wq = &task->thread->engine->fast_work_queue;
7141183Svbart@nginx.com 
7151183Svbart@nginx.com     nxt_sendbuf_drain(task, wq, out);
7161183Svbart@nginx.com     return;
7171183Svbart@nginx.com 
7181183Svbart@nginx.com fail:
7191183Svbart@nginx.com 
7201183Svbart@nginx.com     while (out != NULL) {
7211183Svbart@nginx.com         b = out;
7221183Svbart@nginx.com         out = b->next;
7231183Svbart@nginx.com 
7241183Svbart@nginx.com         nxt_mp_free(r->mem_pool, b);
7251183Svbart@nginx.com         nxt_mp_release(r->mem_pool);
7261183Svbart@nginx.com     }
7271183Svbart@nginx.com }
7281183Svbart@nginx.com 
7291183Svbart@nginx.com 
7301183Svbart@nginx.com static const nxt_http_request_state_t  nxt_http_static_send_state
7311183Svbart@nginx.com     nxt_aligned(64) =
7321183Svbart@nginx.com {
7331183Svbart@nginx.com     .error_handler = nxt_http_request_error_handler,
7341183Svbart@nginx.com };
7351183Svbart@nginx.com 
7361183Svbart@nginx.com 
7371183Svbart@nginx.com static void
7381183Svbart@nginx.com nxt_http_static_buf_completion(nxt_task_t *task, void *obj, void *data)
7391183Svbart@nginx.com {
7401183Svbart@nginx.com     ssize_t             n, size;
7411760Smax.romanov@nginx.com     nxt_buf_t           *b, *fb, *next;
7421183Svbart@nginx.com     nxt_off_t           rest;
7431183Svbart@nginx.com     nxt_http_request_t  *r;
7441183Svbart@nginx.com 
7451183Svbart@nginx.com     b = obj;
7461183Svbart@nginx.com     r = data;
7471760Smax.romanov@nginx.com 
7481760Smax.romanov@nginx.com complete_buf:
7491760Smax.romanov@nginx.com 
7501183Svbart@nginx.com     fb = r->out;
7511183Svbart@nginx.com 
7521183Svbart@nginx.com     if (nxt_slow_path(fb == NULL || r->error)) {
7531183Svbart@nginx.com         goto clean;
7541183Svbart@nginx.com     }
7551183Svbart@nginx.com 
7561183Svbart@nginx.com     rest = fb->file_end - fb->file_pos;
7571183Svbart@nginx.com     size = nxt_buf_mem_size(&b->mem);
7581183Svbart@nginx.com 
7591183Svbart@nginx.com     size = nxt_min(rest, (nxt_off_t) size);
7601183Svbart@nginx.com 
7611183Svbart@nginx.com     n = nxt_file_read(fb->file, b->mem.start, size, fb->file_pos);
7621183Svbart@nginx.com 
7631183Svbart@nginx.com     if (n != size) {
7641183Svbart@nginx.com         if (n >= 0) {
7651183Svbart@nginx.com             nxt_log(task, NXT_LOG_ERR, "file \"%FN\" has changed "
7661183Svbart@nginx.com                     "while sending response to a client", fb->file->name);
7671183Svbart@nginx.com         }
7681183Svbart@nginx.com 
7691183Svbart@nginx.com         nxt_http_request_error_handler(task, r, r->proto.any);
7701183Svbart@nginx.com         goto clean;
7711183Svbart@nginx.com     }
7721183Svbart@nginx.com 
7731760Smax.romanov@nginx.com     next = b->next;
7741760Smax.romanov@nginx.com 
7751183Svbart@nginx.com     if (n == rest) {
7761183Svbart@nginx.com         nxt_file_close(task, fb->file);
7771183Svbart@nginx.com         r->out = NULL;
7781183Svbart@nginx.com 
7791183Svbart@nginx.com         b->next = nxt_http_buf_last(r);
7801183Svbart@nginx.com 
7811183Svbart@nginx.com     } else {
7821183Svbart@nginx.com         fb->file_pos += n;
7831183Svbart@nginx.com         b->next = NULL;
7841183Svbart@nginx.com     }
7851183Svbart@nginx.com 
7861183Svbart@nginx.com     b->mem.pos = b->mem.start;
7871183Svbart@nginx.com     b->mem.free = b->mem.pos + n;
7881183Svbart@nginx.com 
7891183Svbart@nginx.com     nxt_http_request_send(task, r, b);
7901760Smax.romanov@nginx.com 
7911760Smax.romanov@nginx.com     if (next != NULL) {
7921760Smax.romanov@nginx.com         b = next;
7931760Smax.romanov@nginx.com         goto complete_buf;
7941760Smax.romanov@nginx.com     }
7951760Smax.romanov@nginx.com 
7961183Svbart@nginx.com     return;
7971183Svbart@nginx.com 
7981183Svbart@nginx.com clean:
7991183Svbart@nginx.com 
8001760Smax.romanov@nginx.com     do {
8011760Smax.romanov@nginx.com         next = b->next;
8021760Smax.romanov@nginx.com 
8031760Smax.romanov@nginx.com         nxt_mp_free(r->mem_pool, b);
8041760Smax.romanov@nginx.com         nxt_mp_release(r->mem_pool);
8051760Smax.romanov@nginx.com 
8061760Smax.romanov@nginx.com         b = next;
8071760Smax.romanov@nginx.com     } while (b != NULL);
8081183Svbart@nginx.com 
8091183Svbart@nginx.com     if (fb != NULL) {
8101183Svbart@nginx.com         nxt_file_close(task, fb->file);
8111183Svbart@nginx.com         r->out = NULL;
8121183Svbart@nginx.com     }
8131183Svbart@nginx.com }
8141183Svbart@nginx.com 
8151183Svbart@nginx.com 
8161183Svbart@nginx.com nxt_int_t
8171183Svbart@nginx.com nxt_http_static_mtypes_init(nxt_mp_t *mp, nxt_lvlhsh_t *hash)
8181183Svbart@nginx.com {
8191923Sz.hong@f5.com     nxt_str_t   *type, exten;
8201183Svbart@nginx.com     nxt_int_t   ret;
8211183Svbart@nginx.com     nxt_uint_t  i;
8221183Svbart@nginx.com 
8231183Svbart@nginx.com     static const struct {
8241183Svbart@nginx.com         nxt_str_t   type;
8251923Sz.hong@f5.com         const char  *exten;
8261183Svbart@nginx.com     } default_types[] = {
8271183Svbart@nginx.com 
8281183Svbart@nginx.com         { nxt_string("text/html"),      ".html"  },
8291183Svbart@nginx.com         { nxt_string("text/html"),      ".htm"   },
8301183Svbart@nginx.com         { nxt_string("text/css"),       ".css"   },
8311183Svbart@nginx.com 
8321183Svbart@nginx.com         { nxt_string("image/svg+xml"),  ".svg"   },
8331183Svbart@nginx.com         { nxt_string("image/webp"),     ".webp"  },
8341183Svbart@nginx.com         { nxt_string("image/png"),      ".png"   },
8351617Svbart@nginx.com         { nxt_string("image/apng"),     ".apng"  },
8361183Svbart@nginx.com         { nxt_string("image/jpeg"),     ".jpeg"  },
8371183Svbart@nginx.com         { nxt_string("image/jpeg"),     ".jpg"   },
8381183Svbart@nginx.com         { nxt_string("image/gif"),      ".gif"   },
8391183Svbart@nginx.com         { nxt_string("image/x-icon"),   ".ico"   },
8401183Svbart@nginx.com 
8411617Svbart@nginx.com         { nxt_string("image/avif"),           ".avif"  },
8421617Svbart@nginx.com         { nxt_string("image/avif-sequence"),  ".avifs" },
8431617Svbart@nginx.com 
8441183Svbart@nginx.com         { nxt_string("font/woff"),      ".woff"  },
8451183Svbart@nginx.com         { nxt_string("font/woff2"),     ".woff2" },
8461183Svbart@nginx.com         { nxt_string("font/otf"),       ".otf"   },
8471183Svbart@nginx.com         { nxt_string("font/ttf"),       ".ttf"   },
8481183Svbart@nginx.com 
8491183Svbart@nginx.com         { nxt_string("text/plain"),     ".txt"   },
8501183Svbart@nginx.com         { nxt_string("text/markdown"),  ".md"    },
8511183Svbart@nginx.com         { nxt_string("text/x-rst"),     ".rst"   },
8521183Svbart@nginx.com 
8531183Svbart@nginx.com         { nxt_string("application/javascript"),  ".js"   },
8541183Svbart@nginx.com         { nxt_string("application/json"),        ".json" },
8551183Svbart@nginx.com         { nxt_string("application/xml"),         ".xml"  },
8561183Svbart@nginx.com         { nxt_string("application/rss+xml"),     ".rss"  },
8571183Svbart@nginx.com         { nxt_string("application/atom+xml"),    ".atom" },
8581183Svbart@nginx.com         { nxt_string("application/pdf"),         ".pdf"  },
8591183Svbart@nginx.com 
8601183Svbart@nginx.com         { nxt_string("application/zip"),         ".zip"  },
8611183Svbart@nginx.com 
8621183Svbart@nginx.com         { nxt_string("audio/mpeg"),       ".mp3"  },
8631183Svbart@nginx.com         { nxt_string("audio/ogg"),        ".ogg"  },
8641183Svbart@nginx.com         { nxt_string("audio/midi"),       ".midi" },
8651183Svbart@nginx.com         { nxt_string("audio/midi"),       ".mid"  },
8661183Svbart@nginx.com         { nxt_string("audio/flac"),       ".flac" },
8671183Svbart@nginx.com         { nxt_string("audio/aac"),        ".aac"  },
8681183Svbart@nginx.com         { nxt_string("audio/wav"),        ".wav"  },
8691183Svbart@nginx.com 
8701183Svbart@nginx.com         { nxt_string("video/mpeg"),       ".mpeg" },
8711183Svbart@nginx.com         { nxt_string("video/mpeg"),       ".mpg"  },
8721183Svbart@nginx.com         { nxt_string("video/mp4"),        ".mp4"  },
8731183Svbart@nginx.com         { nxt_string("video/webm"),       ".webm" },
8741183Svbart@nginx.com         { nxt_string("video/x-msvideo"),  ".avi"  },
8751183Svbart@nginx.com 
8761183Svbart@nginx.com         { nxt_string("application/octet-stream"),  ".exe" },
8771183Svbart@nginx.com         { nxt_string("application/octet-stream"),  ".bin" },
8781183Svbart@nginx.com         { nxt_string("application/octet-stream"),  ".dll" },
8791183Svbart@nginx.com         { nxt_string("application/octet-stream"),  ".iso" },
8801183Svbart@nginx.com         { nxt_string("application/octet-stream"),  ".img" },
8811183Svbart@nginx.com         { nxt_string("application/octet-stream"),  ".msi" },
8821183Svbart@nginx.com 
8831183Svbart@nginx.com         { nxt_string("application/octet-stream"),  ".deb" },
8841183Svbart@nginx.com         { nxt_string("application/octet-stream"),  ".rpm" },
8851882So.canty@f5.com 
8861882So.canty@f5.com         { nxt_string("application/x-httpd-php"),   ".php" },
8871183Svbart@nginx.com     };
8881183Svbart@nginx.com 
8891183Svbart@nginx.com     for (i = 0; i < nxt_nitems(default_types); i++) {
8901183Svbart@nginx.com         type = (nxt_str_t *) &default_types[i].type;
8911183Svbart@nginx.com 
8921923Sz.hong@f5.com         exten.start = (u_char *) default_types[i].exten;
8931923Sz.hong@f5.com         exten.length = nxt_strlen(exten.start);
8941183Svbart@nginx.com 
8951923Sz.hong@f5.com         ret = nxt_http_static_mtypes_hash_add(mp, hash, &exten, type);
8961183Svbart@nginx.com         if (nxt_slow_path(ret != NXT_OK)) {
8971183Svbart@nginx.com             return NXT_ERROR;
8981183Svbart@nginx.com         }
8991183Svbart@nginx.com     }
9001183Svbart@nginx.com 
9011183Svbart@nginx.com     return NXT_OK;
9021183Svbart@nginx.com }
9031183Svbart@nginx.com 
9041183Svbart@nginx.com 
9051183Svbart@nginx.com static const nxt_lvlhsh_proto_t  nxt_http_static_mtypes_hash_proto
9061183Svbart@nginx.com     nxt_aligned(64) =
9071183Svbart@nginx.com {
9081183Svbart@nginx.com     NXT_LVLHSH_DEFAULT,
9091183Svbart@nginx.com     nxt_http_static_mtypes_hash_test,
9101183Svbart@nginx.com     nxt_http_static_mtypes_hash_alloc,
9111183Svbart@nginx.com     nxt_http_static_mtypes_hash_free,
9121183Svbart@nginx.com };
9131183Svbart@nginx.com 
9141183Svbart@nginx.com 
9151183Svbart@nginx.com typedef struct {
9161923Sz.hong@f5.com     nxt_str_t  exten;
9171183Svbart@nginx.com     nxt_str_t  *type;
9181183Svbart@nginx.com } nxt_http_static_mtype_t;
9191183Svbart@nginx.com 
9201183Svbart@nginx.com 
9211183Svbart@nginx.com nxt_int_t
9221183Svbart@nginx.com nxt_http_static_mtypes_hash_add(nxt_mp_t *mp, nxt_lvlhsh_t *hash,
9231923Sz.hong@f5.com     nxt_str_t *exten, nxt_str_t *type)
9241183Svbart@nginx.com {
9251183Svbart@nginx.com     nxt_lvlhsh_query_t       lhq;
9261183Svbart@nginx.com     nxt_http_static_mtype_t  *mtype;
9271183Svbart@nginx.com 
9281183Svbart@nginx.com     mtype = nxt_mp_get(mp, sizeof(nxt_http_static_mtype_t));
9291183Svbart@nginx.com     if (nxt_slow_path(mtype == NULL)) {
9301183Svbart@nginx.com         return NXT_ERROR;
9311183Svbart@nginx.com     }
9321183Svbart@nginx.com 
9331923Sz.hong@f5.com     mtype->exten = *exten;
9341183Svbart@nginx.com     mtype->type = type;
9351183Svbart@nginx.com 
9361923Sz.hong@f5.com     lhq.key = *exten;
9371183Svbart@nginx.com     lhq.key_hash = nxt_djb_hash_lowcase(lhq.key.start, lhq.key.length);
9381183Svbart@nginx.com     lhq.replace = 1;
9391183Svbart@nginx.com     lhq.value = mtype;
9401183Svbart@nginx.com     lhq.proto = &nxt_http_static_mtypes_hash_proto;
9411183Svbart@nginx.com     lhq.pool = mp;
9421183Svbart@nginx.com 
9431183Svbart@nginx.com     return nxt_lvlhsh_insert(hash, &lhq);
9441183Svbart@nginx.com }
9451183Svbart@nginx.com 
9461183Svbart@nginx.com 
9471183Svbart@nginx.com nxt_str_t *
9481923Sz.hong@f5.com nxt_http_static_mtype_get(nxt_lvlhsh_t *hash, nxt_str_t *exten)
9491183Svbart@nginx.com {
9501183Svbart@nginx.com     nxt_lvlhsh_query_t       lhq;
9511183Svbart@nginx.com     nxt_http_static_mtype_t  *mtype;
9521183Svbart@nginx.com 
9531883So.canty@f5.com     static nxt_str_t  empty = nxt_string("");
9541883So.canty@f5.com 
9551923Sz.hong@f5.com     lhq.key = *exten;
9561183Svbart@nginx.com     lhq.key_hash = nxt_djb_hash_lowcase(lhq.key.start, lhq.key.length);
9571183Svbart@nginx.com     lhq.proto = &nxt_http_static_mtypes_hash_proto;
9581183Svbart@nginx.com 
9591183Svbart@nginx.com     if (nxt_lvlhsh_find(hash, &lhq) == NXT_OK) {
9601183Svbart@nginx.com         mtype = lhq.value;
9611183Svbart@nginx.com         return mtype->type;
9621183Svbart@nginx.com     }
9631183Svbart@nginx.com 
9641883So.canty@f5.com     return &empty;
9651183Svbart@nginx.com }
9661183Svbart@nginx.com 
9671183Svbart@nginx.com 
9681183Svbart@nginx.com static nxt_int_t
9691183Svbart@nginx.com nxt_http_static_mtypes_hash_test(nxt_lvlhsh_query_t *lhq, void *data)
9701183Svbart@nginx.com {
9711183Svbart@nginx.com     nxt_http_static_mtype_t  *mtype;
9721183Svbart@nginx.com 
9731183Svbart@nginx.com     mtype = data;
9741183Svbart@nginx.com 
9751923Sz.hong@f5.com     return nxt_strcasestr_eq(&lhq->key, &mtype->exten) ? NXT_OK : NXT_DECLINED;
9761183Svbart@nginx.com }
9771183Svbart@nginx.com 
9781183Svbart@nginx.com 
9791183Svbart@nginx.com static void *
9801183Svbart@nginx.com nxt_http_static_mtypes_hash_alloc(void *data, size_t size)
9811183Svbart@nginx.com {
9821183Svbart@nginx.com     return nxt_mp_align(data, size, size);
9831183Svbart@nginx.com }
9841183Svbart@nginx.com 
9851183Svbart@nginx.com 
9861183Svbart@nginx.com static void
9871183Svbart@nginx.com nxt_http_static_mtypes_hash_free(void *data, void *p)
9881183Svbart@nginx.com {
9891183Svbart@nginx.com     nxt_mp_free(data, p);
9901183Svbart@nginx.com }
991