xref: /unit/src/nxt_http_static.c (revision 2381:a68b5f5bf46c)
11183Svbart@nginx.com 
21183Svbart@nginx.com /*
31183Svbart@nginx.com  * Copyright (C) NGINX, Inc.
41183Svbart@nginx.com  */
51183Svbart@nginx.com 
61183Svbart@nginx.com #include <nxt_router.h>
71183Svbart@nginx.com #include <nxt_http.h>
81183Svbart@nginx.com 
91183Svbart@nginx.com 
101923Sz.hong@f5.com typedef struct {
112246Sz.hong@f5.com     nxt_tstr_t                  *tstr;
121961Sz.hong@f5.com #if (NXT_HAVE_OPENAT2)
131961Sz.hong@f5.com     u_char                      *fname;
141961Sz.hong@f5.com #endif
151961Sz.hong@f5.com     uint8_t                     is_const;  /* 1 bit */
161961Sz.hong@f5.com } nxt_http_static_share_t;
171961Sz.hong@f5.com 
181961Sz.hong@f5.com 
191961Sz.hong@f5.com typedef struct {
201961Sz.hong@f5.com     nxt_uint_t                  nshares;
211961Sz.hong@f5.com     nxt_http_static_share_t     *shares;
222108Salx.manpages@gmail.com     nxt_str_t                   index;
231959Sz.hong@f5.com #if (NXT_HAVE_OPENAT2)
242246Sz.hong@f5.com     nxt_tstr_t                  *chroot;
251959Sz.hong@f5.com     nxt_uint_t                  resolve;
261959Sz.hong@f5.com #endif
271959Sz.hong@f5.com     nxt_http_route_rule_t       *types;
281923Sz.hong@f5.com } nxt_http_static_conf_t;
291923Sz.hong@f5.com 
301923Sz.hong@f5.com 
311959Sz.hong@f5.com typedef struct {
321959Sz.hong@f5.com     nxt_http_action_t           *action;
331960Sz.hong@f5.com     nxt_str_t                   share;
341959Sz.hong@f5.com #if (NXT_HAVE_OPENAT2)
351959Sz.hong@f5.com     nxt_str_t                   chroot;
361959Sz.hong@f5.com #endif
372096Salx.manpages@gmail.com     uint32_t                    share_idx;
381959Sz.hong@f5.com     uint8_t                     need_body;  /* 1 bit */
391959Sz.hong@f5.com } nxt_http_static_ctx_t;
401959Sz.hong@f5.com 
411959Sz.hong@f5.com 
421183Svbart@nginx.com #define NXT_HTTP_STATIC_BUF_COUNT  2
431183Svbart@nginx.com #define NXT_HTTP_STATIC_BUF_SIZE   (128 * 1024)
441183Svbart@nginx.com 
451183Svbart@nginx.com 
461923Sz.hong@f5.com static nxt_http_action_t *nxt_http_static(nxt_task_t *task,
471923Sz.hong@f5.com     nxt_http_request_t *r, nxt_http_action_t *action);
481961Sz.hong@f5.com static void nxt_http_static_iterate(nxt_task_t *task, nxt_http_request_t *r,
491961Sz.hong@f5.com     nxt_http_static_ctx_t *ctx);
501959Sz.hong@f5.com static void nxt_http_static_send_ready(nxt_task_t *task, void *obj, void *data);
512246Sz.hong@f5.com static void nxt_http_static_send_error(nxt_task_t *task, void *obj, void *data);
521961Sz.hong@f5.com static void nxt_http_static_next(nxt_task_t *task, nxt_http_request_t *r,
531961Sz.hong@f5.com     nxt_http_static_ctx_t *ctx, nxt_http_status_t status);
541959Sz.hong@f5.com #if (NXT_HAVE_OPENAT2)
551959Sz.hong@f5.com static u_char *nxt_http_static_chroot_match(u_char *chr, u_char *shr);
561959Sz.hong@f5.com #endif
571183Svbart@nginx.com static void nxt_http_static_extract_extension(nxt_str_t *path,
581923Sz.hong@f5.com     nxt_str_t *exten);
591183Svbart@nginx.com static void nxt_http_static_body_handler(nxt_task_t *task, void *obj,
601183Svbart@nginx.com     void *data);
611183Svbart@nginx.com static void nxt_http_static_buf_completion(nxt_task_t *task, void *obj,
621183Svbart@nginx.com     void *data);
631183Svbart@nginx.com 
641183Svbart@nginx.com static nxt_int_t nxt_http_static_mtypes_hash_test(nxt_lvlhsh_query_t *lhq,
651183Svbart@nginx.com     void *data);
661183Svbart@nginx.com static void *nxt_http_static_mtypes_hash_alloc(void *data, size_t size);
671183Svbart@nginx.com static void nxt_http_static_mtypes_hash_free(void *data, void *p);
681183Svbart@nginx.com 
691183Svbart@nginx.com 
701183Svbart@nginx.com static const nxt_http_request_state_t  nxt_http_static_send_state;
711183Svbart@nginx.com 
721183Svbart@nginx.com 
731923Sz.hong@f5.com nxt_int_t
nxt_http_static_init(nxt_task_t * task,nxt_router_temp_conf_t * tmcf,nxt_http_action_t * action,nxt_http_action_conf_t * acf)741923Sz.hong@f5.com nxt_http_static_init(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
751923Sz.hong@f5.com     nxt_http_action_t *action, nxt_http_action_conf_t *acf)
761923Sz.hong@f5.com {
771961Sz.hong@f5.com     uint32_t                i;
781923Sz.hong@f5.com     nxt_mp_t                *mp;
792108Salx.manpages@gmail.com     nxt_str_t               str, *ret;
802246Sz.hong@f5.com     nxt_tstr_t              *tstr;
811961Sz.hong@f5.com     nxt_conf_value_t        *cv;
822147Sz.hong@f5.com     nxt_router_conf_t       *rtcf;
831923Sz.hong@f5.com     nxt_http_static_conf_t  *conf;
841923Sz.hong@f5.com 
852147Sz.hong@f5.com     rtcf = tmcf->router_conf;
862147Sz.hong@f5.com     mp = rtcf->mem_pool;
871923Sz.hong@f5.com 
881923Sz.hong@f5.com     conf = nxt_mp_zget(mp, sizeof(nxt_http_static_conf_t));
891923Sz.hong@f5.com     if (nxt_slow_path(conf == NULL)) {
901923Sz.hong@f5.com         return NXT_ERROR;
911923Sz.hong@f5.com     }
921923Sz.hong@f5.com 
931923Sz.hong@f5.com     action->handler = nxt_http_static;
941923Sz.hong@f5.com     action->u.conf = conf;
951923Sz.hong@f5.com 
962077Salx.manpages@gmail.com     conf->nshares = nxt_conf_array_elements_count_or_1(acf->share);
971961Sz.hong@f5.com     conf->shares = nxt_mp_zget(mp, sizeof(nxt_http_static_share_t)
981961Sz.hong@f5.com                                    * conf->nshares);
991961Sz.hong@f5.com     if (nxt_slow_path(conf->shares == NULL)) {
1001923Sz.hong@f5.com         return NXT_ERROR;
1011923Sz.hong@f5.com     }
1021923Sz.hong@f5.com 
1032077Salx.manpages@gmail.com     for (i = 0; i < conf->nshares; i++) {
1042077Salx.manpages@gmail.com         cv = nxt_conf_get_array_element_or_itself(acf->share, i);
1052077Salx.manpages@gmail.com         nxt_conf_get_string(cv, &str);
1061961Sz.hong@f5.com 
1072246Sz.hong@f5.com         tstr = nxt_tstr_compile(rtcf->tstr_state, &str, NXT_TSTR_STRZ);
1082246Sz.hong@f5.com         if (nxt_slow_path(tstr == NULL)) {
1091961Sz.hong@f5.com             return NXT_ERROR;
1101961Sz.hong@f5.com         }
1111961Sz.hong@f5.com 
1122246Sz.hong@f5.com         conf->shares[i].tstr = tstr;
1132246Sz.hong@f5.com         conf->shares[i].is_const = nxt_tstr_is_const(tstr);
1141961Sz.hong@f5.com     }
1151959Sz.hong@f5.com 
1162108Salx.manpages@gmail.com     if (acf->index == NULL) {
1172108Salx.manpages@gmail.com         nxt_str_set(&conf->index, "index.html");
1182108Salx.manpages@gmail.com 
1192108Salx.manpages@gmail.com     } else {
1202108Salx.manpages@gmail.com         nxt_conf_get_string(acf->index, &str);
1212108Salx.manpages@gmail.com 
1222108Salx.manpages@gmail.com         ret = nxt_str_dup(mp, &conf->index, &str);
1232108Salx.manpages@gmail.com         if (nxt_slow_path(ret == NULL)) {
1242108Salx.manpages@gmail.com             return NXT_ERROR;
1252108Salx.manpages@gmail.com         }
1262108Salx.manpages@gmail.com     }
1272108Salx.manpages@gmail.com 
1281923Sz.hong@f5.com #if (NXT_HAVE_OPENAT2)
1291923Sz.hong@f5.com     if (acf->chroot.length > 0) {
1301961Sz.hong@f5.com         nxt_str_t   chr, shr;
1311961Sz.hong@f5.com         nxt_bool_t  is_const;
1321923Sz.hong@f5.com 
1332246Sz.hong@f5.com         conf->chroot = nxt_tstr_compile(rtcf->tstr_state, &acf->chroot,
1342246Sz.hong@f5.com                                         NXT_TSTR_STRZ);
1351959Sz.hong@f5.com         if (nxt_slow_path(conf->chroot == NULL)) {
1361923Sz.hong@f5.com             return NXT_ERROR;
1371923Sz.hong@f5.com         }
1381960Sz.hong@f5.com 
1392246Sz.hong@f5.com         is_const = nxt_tstr_is_const(conf->chroot);
1401961Sz.hong@f5.com 
1411961Sz.hong@f5.com         for (i = 0; i < conf->nshares; i++) {
1421961Sz.hong@f5.com             conf->shares[i].is_const &= is_const;
1431960Sz.hong@f5.com 
1441961Sz.hong@f5.com             if (conf->shares[i].is_const) {
1452246Sz.hong@f5.com                 nxt_tstr_str(conf->chroot, &chr);
1462246Sz.hong@f5.com                 nxt_tstr_str(conf->shares[i].tstr, &shr);
1471961Sz.hong@f5.com 
1481961Sz.hong@f5.com                 conf->shares[i].fname = nxt_http_static_chroot_match(chr.start,
1491961Sz.hong@f5.com                                                                      shr.start);
1501961Sz.hong@f5.com             }
1511960Sz.hong@f5.com         }
1521923Sz.hong@f5.com     }
1531923Sz.hong@f5.com 
1541923Sz.hong@f5.com     if (acf->follow_symlinks != NULL
1551923Sz.hong@f5.com         && !nxt_conf_get_boolean(acf->follow_symlinks))
1561923Sz.hong@f5.com     {
1571923Sz.hong@f5.com         conf->resolve |= RESOLVE_NO_SYMLINKS;
1581923Sz.hong@f5.com     }
1591923Sz.hong@f5.com 
1601923Sz.hong@f5.com     if (acf->traverse_mounts != NULL
1611923Sz.hong@f5.com         && !nxt_conf_get_boolean(acf->traverse_mounts))
1621923Sz.hong@f5.com     {
1631923Sz.hong@f5.com         conf->resolve |= RESOLVE_NO_XDEV;
1641923Sz.hong@f5.com     }
1651923Sz.hong@f5.com #endif
1661923Sz.hong@f5.com 
1671923Sz.hong@f5.com     if (acf->types != NULL) {
1681923Sz.hong@f5.com         conf->types = nxt_http_route_types_rule_create(task, mp, acf->types);
1691923Sz.hong@f5.com         if (nxt_slow_path(conf->types == NULL)) {
1701923Sz.hong@f5.com             return NXT_ERROR;
1711923Sz.hong@f5.com         }
1721923Sz.hong@f5.com     }
1731923Sz.hong@f5.com 
1741923Sz.hong@f5.com     if (acf->fallback != NULL) {
1751923Sz.hong@f5.com         action->fallback = nxt_mp_alloc(mp, sizeof(nxt_http_action_t));
1761923Sz.hong@f5.com         if (nxt_slow_path(action->fallback == NULL)) {
1771923Sz.hong@f5.com             return NXT_ERROR;
1781923Sz.hong@f5.com         }
1791923Sz.hong@f5.com 
1801923Sz.hong@f5.com         return nxt_http_action_init(task, tmcf, acf->fallback,
1811923Sz.hong@f5.com                                     action->fallback);
1821923Sz.hong@f5.com     }
1831923Sz.hong@f5.com 
1841923Sz.hong@f5.com     return NXT_OK;
1851923Sz.hong@f5.com }
1861923Sz.hong@f5.com 
1871923Sz.hong@f5.com 
1881923Sz.hong@f5.com static nxt_http_action_t *
nxt_http_static(nxt_task_t * task,nxt_http_request_t * r,nxt_http_action_t * action)1891923Sz.hong@f5.com nxt_http_static(nxt_task_t *task, nxt_http_request_t *r,
1901264Sigor@sysoev.ru     nxt_http_action_t *action)
1911183Svbart@nginx.com {
1921961Sz.hong@f5.com     nxt_bool_t             need_body;
1931961Sz.hong@f5.com     nxt_http_static_ctx_t  *ctx;
1941923Sz.hong@f5.com 
1951183Svbart@nginx.com     if (nxt_slow_path(!nxt_str_eq(r->method, "GET", 3))) {
1961183Svbart@nginx.com 
1971183Svbart@nginx.com         if (!nxt_str_eq(r->method, "HEAD", 4)) {
1981923Sz.hong@f5.com             if (action->fallback != NULL) {
199*2381Salx@nginx.com                 if (nxt_slow_path(r->log_route)) {
200*2381Salx@nginx.com                     nxt_log(task, NXT_LOG_NOTICE, "\"fallback\" taken");
201*2381Salx@nginx.com                 }
2021923Sz.hong@f5.com                 return action->fallback;
2031378Svbart@nginx.com             }
2041378Svbart@nginx.com 
2051183Svbart@nginx.com             nxt_http_request_error(task, r, NXT_HTTP_METHOD_NOT_ALLOWED);
2061183Svbart@nginx.com             return NULL;
2071183Svbart@nginx.com         }
2081183Svbart@nginx.com 
2091183Svbart@nginx.com         need_body = 0;
2101183Svbart@nginx.com 
2111183Svbart@nginx.com     } else {
2121183Svbart@nginx.com         need_body = 1;
2131183Svbart@nginx.com     }
2141183Svbart@nginx.com 
2151961Sz.hong@f5.com     ctx = nxt_mp_zget(r->mem_pool, sizeof(nxt_http_static_ctx_t));
2161961Sz.hong@f5.com     if (nxt_slow_path(ctx == NULL)) {
2171961Sz.hong@f5.com         nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
2181961Sz.hong@f5.com         return NULL;
2191961Sz.hong@f5.com     }
2201961Sz.hong@f5.com 
2211961Sz.hong@f5.com     ctx->action = action;
2221961Sz.hong@f5.com     ctx->need_body = need_body;
2231961Sz.hong@f5.com 
2241961Sz.hong@f5.com     nxt_http_static_iterate(task, r, ctx);
2251961Sz.hong@f5.com 
2261961Sz.hong@f5.com     return NULL;
2271961Sz.hong@f5.com }
2281961Sz.hong@f5.com 
2291961Sz.hong@f5.com 
2301961Sz.hong@f5.com static void
nxt_http_static_iterate(nxt_task_t * task,nxt_http_request_t * r,nxt_http_static_ctx_t * ctx)2311961Sz.hong@f5.com nxt_http_static_iterate(nxt_task_t *task, nxt_http_request_t *r,
2321961Sz.hong@f5.com     nxt_http_static_ctx_t *ctx)
2331961Sz.hong@f5.com {
2341961Sz.hong@f5.com     nxt_int_t                ret;
2352246Sz.hong@f5.com     nxt_router_conf_t        *rtcf;
2361961Sz.hong@f5.com     nxt_http_static_conf_t   *conf;
2371961Sz.hong@f5.com     nxt_http_static_share_t  *share;
2381961Sz.hong@f5.com 
2391961Sz.hong@f5.com     conf = ctx->action->u.conf;
2401961Sz.hong@f5.com 
2412096Salx.manpages@gmail.com     share = &conf->shares[ctx->share_idx];
2421959Sz.hong@f5.com 
2431960Sz.hong@f5.com #if (NXT_DEBUG)
2441960Sz.hong@f5.com     nxt_str_t  shr;
2452108Salx.manpages@gmail.com     nxt_str_t  idx;
2461960Sz.hong@f5.com 
2472246Sz.hong@f5.com     nxt_tstr_str(share->tstr, &shr);
2482108Salx.manpages@gmail.com     idx = conf->index;
2491960Sz.hong@f5.com 
2501960Sz.hong@f5.com #if (NXT_HAVE_OPENAT2)
2511959Sz.hong@f5.com     nxt_str_t  chr;
2521959Sz.hong@f5.com 
2531959Sz.hong@f5.com     if (conf->chroot != NULL) {
2542246Sz.hong@f5.com         nxt_tstr_str(conf->chroot, &chr);
2551959Sz.hong@f5.com 
2561959Sz.hong@f5.com     } else {
2571959Sz.hong@f5.com         nxt_str_set(&chr, "");
2581959Sz.hong@f5.com     }
2591959Sz.hong@f5.com 
2602108Salx.manpages@gmail.com     nxt_debug(task, "http static: \"%V\", index: \"%V\" (chroot: \"%V\")",
2612108Salx.manpages@gmail.com               &shr, &idx, &chr);
2621959Sz.hong@f5.com #else
2632108Salx.manpages@gmail.com     nxt_debug(task, "http static: \"%V\", index: \"%V\"", &shr, &idx);
2641959Sz.hong@f5.com #endif
2651960Sz.hong@f5.com #endif /* NXT_DEBUG */
2661959Sz.hong@f5.com 
2671961Sz.hong@f5.com     if (share->is_const) {
2682246Sz.hong@f5.com         nxt_tstr_str(share->tstr, &ctx->share);
2691960Sz.hong@f5.com 
2701959Sz.hong@f5.com #if (NXT_HAVE_OPENAT2)
2712096Salx.manpages@gmail.com         if (conf->chroot != NULL && ctx->share_idx == 0) {
2722246Sz.hong@f5.com             nxt_tstr_str(conf->chroot, &ctx->chroot);
2731959Sz.hong@f5.com         }
2741959Sz.hong@f5.com #endif
2751959Sz.hong@f5.com 
2761959Sz.hong@f5.com         nxt_http_static_send_ready(task, r, ctx);
2771959Sz.hong@f5.com 
2781959Sz.hong@f5.com     } else {
2792246Sz.hong@f5.com         rtcf = r->conf->socket_conf->router_conf;
2802246Sz.hong@f5.com 
2812246Sz.hong@f5.com         ret = nxt_tstr_query_init(&r->tstr_query, rtcf->tstr_state,
2822247Sz.hong@f5.com                                   &r->tstr_cache, r, r->mem_pool);
2831959Sz.hong@f5.com         if (nxt_slow_path(ret != NXT_OK)) {
2841961Sz.hong@f5.com             nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
2851961Sz.hong@f5.com             return;
2861959Sz.hong@f5.com         }
2871959Sz.hong@f5.com 
2882246Sz.hong@f5.com         nxt_tstr_query(task, r->tstr_query, share->tstr, &ctx->share);
2891960Sz.hong@f5.com 
2901959Sz.hong@f5.com #if (NXT_HAVE_OPENAT2)
2912096Salx.manpages@gmail.com         if (conf->chroot != NULL && ctx->share_idx == 0) {
2922246Sz.hong@f5.com             nxt_tstr_query(task, r->tstr_query, conf->chroot, &ctx->chroot);
2931960Sz.hong@f5.com         }
2941959Sz.hong@f5.com #endif
2951959Sz.hong@f5.com 
2962246Sz.hong@f5.com         nxt_tstr_query_resolve(task, r->tstr_query, ctx,
2972246Sz.hong@f5.com                                nxt_http_static_send_ready,
2982246Sz.hong@f5.com                                nxt_http_static_send_error);
2991961Sz.hong@f5.com      }
3001959Sz.hong@f5.com }
3011959Sz.hong@f5.com 
3021959Sz.hong@f5.com 
3031959Sz.hong@f5.com static void
nxt_http_static_send_ready(nxt_task_t * task,void * obj,void * data)3041959Sz.hong@f5.com nxt_http_static_send_ready(nxt_task_t *task, void *obj, void *data)
3051959Sz.hong@f5.com {
3061959Sz.hong@f5.com     size_t                  length, encode;
3071959Sz.hong@f5.com     u_char                  *p, *fname;
3081959Sz.hong@f5.com     struct tm               tm;
3091959Sz.hong@f5.com     nxt_buf_t               *fb;
3101959Sz.hong@f5.com     nxt_int_t               ret;
3112108Salx.manpages@gmail.com     nxt_str_t               *shr, *index, exten, *mtype;
3121959Sz.hong@f5.com     nxt_uint_t              level;
3131959Sz.hong@f5.com     nxt_file_t              *f, file;
3141959Sz.hong@f5.com     nxt_file_info_t         fi;
3151959Sz.hong@f5.com     nxt_http_field_t        *field;
3161959Sz.hong@f5.com     nxt_http_status_t       status;
3171959Sz.hong@f5.com     nxt_router_conf_t       *rtcf;
3181959Sz.hong@f5.com     nxt_http_action_t       *action;
3191959Sz.hong@f5.com     nxt_http_request_t      *r;
3201959Sz.hong@f5.com     nxt_work_handler_t      body_handler;
3211959Sz.hong@f5.com     nxt_http_static_ctx_t   *ctx;
3221959Sz.hong@f5.com     nxt_http_static_conf_t  *conf;
3231959Sz.hong@f5.com 
3241959Sz.hong@f5.com     r = obj;
3251959Sz.hong@f5.com     ctx = data;
3261959Sz.hong@f5.com     action = ctx->action;
3271959Sz.hong@f5.com     conf = action->u.conf;
3281960Sz.hong@f5.com     rtcf = r->conf->socket_conf->router_conf;
3291183Svbart@nginx.com 
3301855Sz.hong@f5.com     f = NULL;
3311960Sz.hong@f5.com     mtype = NULL;
3321183Svbart@nginx.com 
3331960Sz.hong@f5.com     shr = &ctx->share;
3342108Salx.manpages@gmail.com     index = &conf->index;
3351859So.canty@f5.com 
3361960Sz.hong@f5.com     if (shr->start[shr->length - 1] == '/') {
3372108Salx.manpages@gmail.com         nxt_http_static_extract_extension(index, &exten);
3381859So.canty@f5.com 
3392108Salx.manpages@gmail.com         length = shr->length + index->length;
3401960Sz.hong@f5.com 
3411960Sz.hong@f5.com         fname = nxt_mp_nget(r->mem_pool, length + 1);
3421960Sz.hong@f5.com         if (nxt_slow_path(fname == NULL)) {
3431883So.canty@f5.com             goto fail;
3441883So.canty@f5.com         }
3451883So.canty@f5.com 
3461960Sz.hong@f5.com         p = fname;
3471960Sz.hong@f5.com         p = nxt_cpymem(p, shr->start, shr->length);
3482108Salx.manpages@gmail.com         p = nxt_cpymem(p, index->start, index->length);
3491960Sz.hong@f5.com         *p = '\0';
3501859So.canty@f5.com 
3511960Sz.hong@f5.com     } else {
3521960Sz.hong@f5.com         if (conf->types == NULL) {
3531960Sz.hong@f5.com             nxt_str_null(&exten);
3541960Sz.hong@f5.com 
3551960Sz.hong@f5.com         } else {
3561960Sz.hong@f5.com             nxt_http_static_extract_extension(shr, &exten);
3571960Sz.hong@f5.com             mtype = nxt_http_static_mtype_get(&rtcf->mtypes_hash, &exten);
3581855Sz.hong@f5.com 
3591960Sz.hong@f5.com             ret = nxt_http_route_test_rule(r, conf->types, mtype->start,
3601960Sz.hong@f5.com                                            mtype->length);
3611960Sz.hong@f5.com             if (nxt_slow_path(ret == NXT_ERROR)) {
3621960Sz.hong@f5.com                 goto fail;
3631960Sz.hong@f5.com             }
3641183Svbart@nginx.com 
3651960Sz.hong@f5.com             if (ret == 0) {
3661961Sz.hong@f5.com                 nxt_http_static_next(task, r, ctx, NXT_HTTP_FORBIDDEN);
3671961Sz.hong@f5.com                 return;
3681960Sz.hong@f5.com             }
3691960Sz.hong@f5.com         }
3701960Sz.hong@f5.com 
3711960Sz.hong@f5.com         fname = ctx->share.start;
3721960Sz.hong@f5.com     }
3731183Svbart@nginx.com 
3741855Sz.hong@f5.com     nxt_memzero(&file, sizeof(nxt_file_t));
3751855Sz.hong@f5.com 
3761855Sz.hong@f5.com     file.name = fname;
3771855Sz.hong@f5.com 
3781959Sz.hong@f5.com #if (NXT_HAVE_OPENAT2)
3791959Sz.hong@f5.com     if (conf->resolve != 0 || ctx->chroot.length > 0) {
3801961Sz.hong@f5.com         nxt_str_t                *chr;
3811961Sz.hong@f5.com         nxt_uint_t               resolve;
3821961Sz.hong@f5.com         nxt_http_static_share_t  *share;
3831961Sz.hong@f5.com 
3842096Salx.manpages@gmail.com         share = &conf->shares[ctx->share_idx];
3851855Sz.hong@f5.com 
3861959Sz.hong@f5.com         resolve = conf->resolve;
3871959Sz.hong@f5.com         chr = &ctx->chroot;
3881855Sz.hong@f5.com 
3891959Sz.hong@f5.com         if (chr->length > 0) {
3901959Sz.hong@f5.com             resolve |= RESOLVE_IN_ROOT;
3911855Sz.hong@f5.com 
3921961Sz.hong@f5.com             fname = share->is_const
3931961Sz.hong@f5.com                     ? share->fname
3941960Sz.hong@f5.com                     : nxt_http_static_chroot_match(chr->start, file.name);
3951959Sz.hong@f5.com 
3961959Sz.hong@f5.com             if (fname != NULL) {
3971959Sz.hong@f5.com                 file.name = chr->start;
3981855Sz.hong@f5.com                 ret = nxt_file_open(task, &file, NXT_FILE_SEARCH, NXT_FILE_OPEN,
3991855Sz.hong@f5.com                                     0);
4001855Sz.hong@f5.com 
4011855Sz.hong@f5.com             } else {
4021855Sz.hong@f5.com                 file.error = NXT_EACCES;
4031855Sz.hong@f5.com                 ret = NXT_ERROR;
4041855Sz.hong@f5.com             }
4051855Sz.hong@f5.com 
4061855Sz.hong@f5.com         } else if (fname[0] == '/') {
4071855Sz.hong@f5.com             file.name = (u_char *) "/";
4081855Sz.hong@f5.com             ret = nxt_file_open(task, &file, NXT_FILE_SEARCH, NXT_FILE_OPEN, 0);
4091855Sz.hong@f5.com 
4101855Sz.hong@f5.com         } else {
4111855Sz.hong@f5.com             file.name = (u_char *) ".";
4121855Sz.hong@f5.com             file.fd = AT_FDCWD;
4131855Sz.hong@f5.com             ret = NXT_OK;
4141855Sz.hong@f5.com         }
4151855Sz.hong@f5.com 
4161855Sz.hong@f5.com         if (nxt_fast_path(ret == NXT_OK)) {
4171856Sz.hong@f5.com             nxt_file_t  af;
4181856Sz.hong@f5.com 
4191855Sz.hong@f5.com             af = file;
4201855Sz.hong@f5.com             nxt_memzero(&file, sizeof(nxt_file_t));
4211855Sz.hong@f5.com             file.name = fname;
4221855Sz.hong@f5.com 
4231855Sz.hong@f5.com             ret = nxt_file_openat2(task, &file, NXT_FILE_RDONLY,
4241959Sz.hong@f5.com                                    NXT_FILE_OPEN, 0, af.fd, resolve);
4251855Sz.hong@f5.com 
4261855Sz.hong@f5.com             if (af.fd != AT_FDCWD) {
4271855Sz.hong@f5.com                 nxt_file_close(task, &af);
4281855Sz.hong@f5.com             }
4291855Sz.hong@f5.com         }
4301855Sz.hong@f5.com 
4311855Sz.hong@f5.com     } else {
4321855Sz.hong@f5.com         ret = nxt_file_open(task, &file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 0);
4331855Sz.hong@f5.com     }
4341855Sz.hong@f5.com 
4351855Sz.hong@f5.com #else
4361855Sz.hong@f5.com     ret = nxt_file_open(task, &file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 0);
4371855Sz.hong@f5.com #endif
4381183Svbart@nginx.com 
4391183Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
4401855Sz.hong@f5.com 
4411855Sz.hong@f5.com         switch (file.error) {
4421183Svbart@nginx.com 
4431200Svbart@nginx.com         /*
4441200Svbart@nginx.com          * For Unix domain sockets "errno" is set to:
4451200Svbart@nginx.com          *  - ENXIO on Linux;
4461200Svbart@nginx.com          *  - EOPNOTSUPP on *BSD, MacOSX, and Solaris.
4471200Svbart@nginx.com          */
4481200Svbart@nginx.com 
4491183Svbart@nginx.com         case NXT_ENOENT:
4501183Svbart@nginx.com         case NXT_ENOTDIR:
4511183Svbart@nginx.com         case NXT_ENAMETOOLONG:
4521200Svbart@nginx.com #if (NXT_LINUX)
4531200Svbart@nginx.com         case NXT_ENXIO:
4541200Svbart@nginx.com #else
4551200Svbart@nginx.com         case NXT_EOPNOTSUPP:
4561200Svbart@nginx.com #endif
4571183Svbart@nginx.com             level = NXT_LOG_ERR;
4581183Svbart@nginx.com             status = NXT_HTTP_NOT_FOUND;
4591183Svbart@nginx.com             break;
4601183Svbart@nginx.com 
4611183Svbart@nginx.com         case NXT_EACCES:
4621855Sz.hong@f5.com #if (NXT_HAVE_OPENAT2)
4631855Sz.hong@f5.com         case NXT_ELOOP:
4641855Sz.hong@f5.com         case NXT_EXDEV:
4651855Sz.hong@f5.com #endif
4661183Svbart@nginx.com             level = NXT_LOG_ERR;
4671183Svbart@nginx.com             status = NXT_HTTP_FORBIDDEN;
4681183Svbart@nginx.com             break;
4691183Svbart@nginx.com 
4701183Svbart@nginx.com         default:
4711183Svbart@nginx.com             level = NXT_LOG_ALERT;
4721183Svbart@nginx.com             status = NXT_HTTP_INTERNAL_SERVER_ERROR;
4731183Svbart@nginx.com             break;
4741183Svbart@nginx.com         }
4751183Svbart@nginx.com 
4761183Svbart@nginx.com         if (status != NXT_HTTP_NOT_FOUND) {
4771959Sz.hong@f5.com #if (NXT_HAVE_OPENAT2)
4781959Sz.hong@f5.com             nxt_str_t  *chr = &ctx->chroot;
4791959Sz.hong@f5.com 
4801959Sz.hong@f5.com             if (chr->length > 0) {
4811857Sz.hong@f5.com                 nxt_log(task, level, "opening \"%s\" at \"%V\" failed %E",
4821959Sz.hong@f5.com                         fname, chr, file.error);
4831855Sz.hong@f5.com 
4841855Sz.hong@f5.com             } else {
4851857Sz.hong@f5.com                 nxt_log(task, level, "opening \"%s\" failed %E",
4861855Sz.hong@f5.com                         fname, file.error);
4871855Sz.hong@f5.com             }
4881959Sz.hong@f5.com 
4891959Sz.hong@f5.com #else
4901959Sz.hong@f5.com             nxt_log(task, level, "opening \"%s\" failed %E", fname, file.error);
4911959Sz.hong@f5.com #endif
4921183Svbart@nginx.com         }
4931183Svbart@nginx.com 
4941961Sz.hong@f5.com         if (level == NXT_LOG_ERR) {
4951961Sz.hong@f5.com             nxt_http_static_next(task, r, ctx, status);
4961961Sz.hong@f5.com             return;
4971961Sz.hong@f5.com         }
4981961Sz.hong@f5.com 
4991959Sz.hong@f5.com         goto fail;
5001183Svbart@nginx.com     }
5011183Svbart@nginx.com 
5021855Sz.hong@f5.com     f = nxt_mp_get(r->mem_pool, sizeof(nxt_file_t));
5031855Sz.hong@f5.com     if (nxt_slow_path(f == NULL)) {
5041962Svbart@nginx.com         nxt_file_close(task, &file);
5051855Sz.hong@f5.com         goto fail;
5061855Sz.hong@f5.com     }
5071855Sz.hong@f5.com 
5081855Sz.hong@f5.com     *f = file;
5091855Sz.hong@f5.com 
5101183Svbart@nginx.com     ret = nxt_file_info(f, &fi);
5111183Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
5121183Svbart@nginx.com         goto fail;
5131183Svbart@nginx.com     }
5141183Svbart@nginx.com 
5151183Svbart@nginx.com     if (nxt_fast_path(nxt_is_file(&fi))) {
5161183Svbart@nginx.com         r->status = NXT_HTTP_OK;
5171183Svbart@nginx.com         r->resp.content_length_n = nxt_file_size(&fi);
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, "Last-Modified");
5251183Svbart@nginx.com 
5261183Svbart@nginx.com         p = nxt_mp_nget(r->mem_pool, NXT_HTTP_DATE_LEN);
5271183Svbart@nginx.com         if (nxt_slow_path(p == NULL)) {
5281183Svbart@nginx.com             goto fail;
5291183Svbart@nginx.com         }
5301183Svbart@nginx.com 
5311183Svbart@nginx.com         nxt_localtime(nxt_file_mtime(&fi), &tm);
5321183Svbart@nginx.com 
5331183Svbart@nginx.com         field->value = p;
5341183Svbart@nginx.com         field->value_length = nxt_http_date(p, &tm) - p;
5351183Svbart@nginx.com 
5361183Svbart@nginx.com         field = nxt_list_zero_add(r->resp.fields);
5371183Svbart@nginx.com         if (nxt_slow_path(field == NULL)) {
5381183Svbart@nginx.com             goto fail;
5391183Svbart@nginx.com         }
5401183Svbart@nginx.com 
5411183Svbart@nginx.com         nxt_http_field_name_set(field, "ETag");
5421183Svbart@nginx.com 
5431855Sz.hong@f5.com         length = NXT_TIME_T_HEXLEN + NXT_OFF_T_HEXLEN + 3;
5441183Svbart@nginx.com 
5451855Sz.hong@f5.com         p = nxt_mp_nget(r->mem_pool, length);
5461183Svbart@nginx.com         if (nxt_slow_path(p == NULL)) {
5471183Svbart@nginx.com             goto fail;
5481183Svbart@nginx.com         }
5491183Svbart@nginx.com 
5501183Svbart@nginx.com         field->value = p;
5511855Sz.hong@f5.com         field->value_length = nxt_sprintf(p, p + length, "\"%xT-%xO\"",
5521183Svbart@nginx.com                                           nxt_file_mtime(&fi),
5531183Svbart@nginx.com                                           nxt_file_size(&fi))
5541183Svbart@nginx.com                               - p;
5551183Svbart@nginx.com 
5561923Sz.hong@f5.com         if (exten.start == NULL) {
5571960Sz.hong@f5.com             nxt_http_static_extract_extension(shr, &exten);
5581183Svbart@nginx.com         }
5591183Svbart@nginx.com 
5601859So.canty@f5.com         if (mtype == NULL) {
5611923Sz.hong@f5.com             mtype = nxt_http_static_mtype_get(&rtcf->mtypes_hash, &exten);
5621859So.canty@f5.com         }
5631183Svbart@nginx.com 
5641883So.canty@f5.com         if (mtype->length != 0) {
5651183Svbart@nginx.com             field = nxt_list_zero_add(r->resp.fields);
5661183Svbart@nginx.com             if (nxt_slow_path(field == NULL)) {
5671183Svbart@nginx.com                 goto fail;
5681183Svbart@nginx.com             }
5691183Svbart@nginx.com 
5701183Svbart@nginx.com             nxt_http_field_name_set(field, "Content-Type");
5711183Svbart@nginx.com 
5721183Svbart@nginx.com             field->value = mtype->start;
5731183Svbart@nginx.com             field->value_length = mtype->length;
5741183Svbart@nginx.com         }
5751183Svbart@nginx.com 
5761959Sz.hong@f5.com         if (ctx->need_body && nxt_file_size(&fi) > 0) {
5771183Svbart@nginx.com             fb = nxt_mp_zget(r->mem_pool, NXT_BUF_FILE_SIZE);
5781183Svbart@nginx.com             if (nxt_slow_path(fb == NULL)) {
5791183Svbart@nginx.com                 goto fail;
5801183Svbart@nginx.com             }
5811183Svbart@nginx.com 
5821183Svbart@nginx.com             fb->file = f;
5831183Svbart@nginx.com             fb->file_end = nxt_file_size(&fi);
5841183Svbart@nginx.com 
5851183Svbart@nginx.com             r->out = fb;
5861183Svbart@nginx.com 
5871183Svbart@nginx.com             body_handler = &nxt_http_static_body_handler;
5881183Svbart@nginx.com 
5891183Svbart@nginx.com         } else {
5901183Svbart@nginx.com             nxt_file_close(task, f);
5911183Svbart@nginx.com             body_handler = NULL;
5921183Svbart@nginx.com         }
5931183Svbart@nginx.com 
5941183Svbart@nginx.com     } else {
5951183Svbart@nginx.com         /* Not a file. */
5961961Sz.hong@f5.com         nxt_file_close(task, f);
5971183Svbart@nginx.com 
5982106Salx.manpages@gmail.com         if (nxt_slow_path(!nxt_is_dir(&fi)
5992106Salx.manpages@gmail.com                           || shr->start[shr->length - 1] == '/'))
6002106Salx.manpages@gmail.com         {
6011961Sz.hong@f5.com             nxt_log(task, NXT_LOG_ERR, "\"%FN\" is not a regular file",
6021961Sz.hong@f5.com                     f->name);
6031378Svbart@nginx.com 
6041961Sz.hong@f5.com             nxt_http_static_next(task, r, ctx, NXT_HTTP_NOT_FOUND);
6051961Sz.hong@f5.com             return;
6061183Svbart@nginx.com         }
6071183Svbart@nginx.com 
6081198Svbart@nginx.com         f = NULL;
6091198Svbart@nginx.com 
6101183Svbart@nginx.com         r->status = NXT_HTTP_MOVED_PERMANENTLY;
6111183Svbart@nginx.com         r->resp.content_length_n = 0;
6121183Svbart@nginx.com 
6131183Svbart@nginx.com         field = nxt_list_zero_add(r->resp.fields);
6141183Svbart@nginx.com         if (nxt_slow_path(field == NULL)) {
6151183Svbart@nginx.com             goto fail;
6161183Svbart@nginx.com         }
6171183Svbart@nginx.com 
6181183Svbart@nginx.com         nxt_http_field_name_set(field, "Location");
6191183Svbart@nginx.com 
6201183Svbart@nginx.com         encode = nxt_encode_uri(NULL, r->path->start, r->path->length);
6211855Sz.hong@f5.com         length = r->path->length + encode * 2 + 1;
6221183Svbart@nginx.com 
6231183Svbart@nginx.com         if (r->args->length > 0) {
6241855Sz.hong@f5.com             length += 1 + r->args->length;
6251183Svbart@nginx.com         }
6261183Svbart@nginx.com 
6271855Sz.hong@f5.com         p = nxt_mp_nget(r->mem_pool, length);
6281183Svbart@nginx.com         if (nxt_slow_path(p == NULL)) {
6291183Svbart@nginx.com             goto fail;
6301183Svbart@nginx.com         }
6311183Svbart@nginx.com 
6321183Svbart@nginx.com         field->value = p;
6331855Sz.hong@f5.com         field->value_length = length;
6341183Svbart@nginx.com 
6351183Svbart@nginx.com         if (encode > 0) {
6361183Svbart@nginx.com             p = (u_char *) nxt_encode_uri(p, r->path->start, r->path->length);
6371183Svbart@nginx.com 
6381183Svbart@nginx.com         } else {
6391183Svbart@nginx.com             p = nxt_cpymem(p, r->path->start, r->path->length);
6401183Svbart@nginx.com         }
6411183Svbart@nginx.com 
6421183Svbart@nginx.com         *p++ = '/';
6431183Svbart@nginx.com 
6441183Svbart@nginx.com         if (r->args->length > 0) {
6451183Svbart@nginx.com             *p++ = '?';
6461183Svbart@nginx.com             nxt_memcpy(p, r->args->start, r->args->length);
6471183Svbart@nginx.com         }
6481183Svbart@nginx.com 
6491183Svbart@nginx.com         body_handler = NULL;
6501183Svbart@nginx.com     }
6511183Svbart@nginx.com 
6521270Sigor@sysoev.ru     nxt_http_request_header_send(task, r, body_handler, NULL);
6531183Svbart@nginx.com 
6541183Svbart@nginx.com     r->state = &nxt_http_static_send_state;
6551959Sz.hong@f5.com     return;
6561183Svbart@nginx.com 
6571183Svbart@nginx.com fail:
6581183Svbart@nginx.com 
6591855Sz.hong@f5.com     if (f != NULL) {
6601183Svbart@nginx.com         nxt_file_close(task, f);
6611183Svbart@nginx.com     }
6621183Svbart@nginx.com 
6631961Sz.hong@f5.com     nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
6641959Sz.hong@f5.com }
6651959Sz.hong@f5.com 
6661959Sz.hong@f5.com 
6671959Sz.hong@f5.com static void
nxt_http_static_send_error(nxt_task_t * task,void * obj,void * data)6682246Sz.hong@f5.com nxt_http_static_send_error(nxt_task_t *task, void *obj, void *data)
6691959Sz.hong@f5.com {
6701959Sz.hong@f5.com     nxt_http_request_t  *r;
6711959Sz.hong@f5.com 
6721959Sz.hong@f5.com     r = obj;
6731959Sz.hong@f5.com 
6741959Sz.hong@f5.com     nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
6751183Svbart@nginx.com }
6761183Svbart@nginx.com 
6771183Svbart@nginx.com 
6781961Sz.hong@f5.com static void
nxt_http_static_next(nxt_task_t * task,nxt_http_request_t * r,nxt_http_static_ctx_t * ctx,nxt_http_status_t status)6791961Sz.hong@f5.com nxt_http_static_next(nxt_task_t *task, nxt_http_request_t *r,
6801961Sz.hong@f5.com     nxt_http_static_ctx_t *ctx, nxt_http_status_t status)
6811961Sz.hong@f5.com {
6821961Sz.hong@f5.com     nxt_http_action_t       *action;
6831961Sz.hong@f5.com     nxt_http_static_conf_t  *conf;
6841961Sz.hong@f5.com 
6851961Sz.hong@f5.com     action = ctx->action;
6861961Sz.hong@f5.com     conf = action->u.conf;
6871961Sz.hong@f5.com 
6882096Salx.manpages@gmail.com     ctx->share_idx++;
6891961Sz.hong@f5.com 
6902096Salx.manpages@gmail.com     if (ctx->share_idx < conf->nshares) {
6911961Sz.hong@f5.com         nxt_http_static_iterate(task, r, ctx);
6921961Sz.hong@f5.com         return;
6931961Sz.hong@f5.com     }
6941961Sz.hong@f5.com 
6951961Sz.hong@f5.com     if (action->fallback != NULL) {
696*2381Salx@nginx.com         if (nxt_slow_path(r->log_route)) {
697*2381Salx@nginx.com             nxt_log(task, NXT_LOG_NOTICE, "\"fallback\" taken");
698*2381Salx@nginx.com         }
6991961Sz.hong@f5.com         nxt_http_request_action(task, r, action->fallback);
7001961Sz.hong@f5.com         return;
7011961Sz.hong@f5.com     }
7021961Sz.hong@f5.com 
7031961Sz.hong@f5.com     nxt_http_request_error(task, r, status);
7041961Sz.hong@f5.com }
7051961Sz.hong@f5.com 
7061961Sz.hong@f5.com 
7071959Sz.hong@f5.com #if (NXT_HAVE_OPENAT2)
7081959Sz.hong@f5.com 
7091959Sz.hong@f5.com static u_char *
nxt_http_static_chroot_match(u_char * chr,u_char * shr)7101959Sz.hong@f5.com nxt_http_static_chroot_match(u_char *chr, u_char *shr)
7111959Sz.hong@f5.com {
7121959Sz.hong@f5.com     if (*chr != *shr) {
7131959Sz.hong@f5.com         return NULL;
7141959Sz.hong@f5.com     }
7151959Sz.hong@f5.com 
7161959Sz.hong@f5.com     chr++;
7171959Sz.hong@f5.com     shr++;
7181959Sz.hong@f5.com 
7191959Sz.hong@f5.com     for ( ;; ) {
7201959Sz.hong@f5.com         if (*shr == '\0') {
7211959Sz.hong@f5.com             return NULL;
7221959Sz.hong@f5.com         }
7231959Sz.hong@f5.com 
7241959Sz.hong@f5.com         if (*chr == *shr) {
7251959Sz.hong@f5.com             chr++;
7261959Sz.hong@f5.com             shr++;
7271959Sz.hong@f5.com             continue;
7281959Sz.hong@f5.com         }
7291959Sz.hong@f5.com 
7301959Sz.hong@f5.com         if (*chr == '\0') {
7311959Sz.hong@f5.com             break;
7321959Sz.hong@f5.com         }
7331959Sz.hong@f5.com 
7341959Sz.hong@f5.com         if (*chr == '/') {
7351959Sz.hong@f5.com             if (chr[-1] == '/') {
7361959Sz.hong@f5.com                 chr++;
7371959Sz.hong@f5.com                 continue;
7381959Sz.hong@f5.com             }
7391959Sz.hong@f5.com 
7401959Sz.hong@f5.com         } else if (*shr == '/') {
7411959Sz.hong@f5.com             if (shr[-1] == '/') {
7421959Sz.hong@f5.com                 shr++;
7431959Sz.hong@f5.com                 continue;
7441959Sz.hong@f5.com             }
7451959Sz.hong@f5.com         }
7461959Sz.hong@f5.com 
7471959Sz.hong@f5.com         return NULL;
7481959Sz.hong@f5.com     }
7491959Sz.hong@f5.com 
7501959Sz.hong@f5.com     if (shr[-1] != '/' && *shr != '/') {
7511959Sz.hong@f5.com         return NULL;
7521959Sz.hong@f5.com     }
7531959Sz.hong@f5.com 
7541959Sz.hong@f5.com     while (*shr == '/') {
7551959Sz.hong@f5.com         shr++;
7561959Sz.hong@f5.com     }
7571959Sz.hong@f5.com 
7581959Sz.hong@f5.com     return (*shr != '\0') ? shr : NULL;
7591959Sz.hong@f5.com }
7601959Sz.hong@f5.com 
7611959Sz.hong@f5.com #endif
7621959Sz.hong@f5.com 
7631959Sz.hong@f5.com 
7641183Svbart@nginx.com static void
nxt_http_static_extract_extension(nxt_str_t * path,nxt_str_t * exten)7651923Sz.hong@f5.com nxt_http_static_extract_extension(nxt_str_t *path, nxt_str_t *exten)
7661183Svbart@nginx.com {
7671183Svbart@nginx.com     u_char  ch, *p, *end;
7681183Svbart@nginx.com 
7691183Svbart@nginx.com     end = path->start + path->length;
7701183Svbart@nginx.com     p = end;
7711183Svbart@nginx.com 
7722137Salx.manpages@gmail.com     while (p > path->start) {
7731183Svbart@nginx.com         p--;
7741183Svbart@nginx.com         ch = *p;
7751183Svbart@nginx.com 
7761183Svbart@nginx.com         switch (ch) {
7771183Svbart@nginx.com         case '/':
7781183Svbart@nginx.com             p++;
7791183Svbart@nginx.com             /* Fall through. */
7801183Svbart@nginx.com         case '.':
7812137Salx.manpages@gmail.com             goto extension;
7821183Svbart@nginx.com         }
7831183Svbart@nginx.com     }
7842137Salx.manpages@gmail.com 
7852137Salx.manpages@gmail.com extension:
7862137Salx.manpages@gmail.com 
7872137Salx.manpages@gmail.com     exten->length = end - p;
7882137Salx.manpages@gmail.com     exten->start = p;
7891183Svbart@nginx.com }
7901183Svbart@nginx.com 
7911183Svbart@nginx.com 
7921183Svbart@nginx.com static void
nxt_http_static_body_handler(nxt_task_t * task,void * obj,void * data)7931183Svbart@nginx.com nxt_http_static_body_handler(nxt_task_t *task, void *obj, void *data)
7941183Svbart@nginx.com {
7951183Svbart@nginx.com     size_t              alloc;
7961183Svbart@nginx.com     nxt_buf_t           *fb, *b, **next, *out;
7971183Svbart@nginx.com     nxt_off_t           rest;
7981183Svbart@nginx.com     nxt_int_t           n;
7991183Svbart@nginx.com     nxt_work_queue_t    *wq;
8001183Svbart@nginx.com     nxt_http_request_t  *r;
8011183Svbart@nginx.com 
8021183Svbart@nginx.com     r = obj;
8031183Svbart@nginx.com     fb = r->out;
8041183Svbart@nginx.com 
8051183Svbart@nginx.com     rest = fb->file_end - fb->file_pos;
8061183Svbart@nginx.com     out = NULL;
8071183Svbart@nginx.com     next = &out;
8081183Svbart@nginx.com     n = 0;
8091183Svbart@nginx.com 
8101183Svbart@nginx.com     do {
8111183Svbart@nginx.com         alloc = nxt_min(rest, NXT_HTTP_STATIC_BUF_SIZE);
8121183Svbart@nginx.com 
8131183Svbart@nginx.com         b = nxt_buf_mem_alloc(r->mem_pool, alloc, 0);
8141183Svbart@nginx.com         if (nxt_slow_path(b == NULL)) {
8151183Svbart@nginx.com             goto fail;
8161183Svbart@nginx.com         }
8171183Svbart@nginx.com 
8181183Svbart@nginx.com         b->completion_handler = nxt_http_static_buf_completion;
8191183Svbart@nginx.com         b->parent = r;
8201183Svbart@nginx.com 
8211183Svbart@nginx.com         nxt_mp_retain(r->mem_pool);
8221183Svbart@nginx.com 
8231183Svbart@nginx.com         *next = b;
8241183Svbart@nginx.com         next = &b->next;
8251183Svbart@nginx.com 
8261183Svbart@nginx.com         rest -= alloc;
8271183Svbart@nginx.com 
8281183Svbart@nginx.com     } while (rest > 0 && ++n < NXT_HTTP_STATIC_BUF_COUNT);
8291183Svbart@nginx.com 
8301183Svbart@nginx.com     wq = &task->thread->engine->fast_work_queue;
8311183Svbart@nginx.com 
8321183Svbart@nginx.com     nxt_sendbuf_drain(task, wq, out);
8331183Svbart@nginx.com     return;
8341183Svbart@nginx.com 
8351183Svbart@nginx.com fail:
8361183Svbart@nginx.com 
8371183Svbart@nginx.com     while (out != NULL) {
8381183Svbart@nginx.com         b = out;
8391183Svbart@nginx.com         out = b->next;
8401183Svbart@nginx.com 
8411183Svbart@nginx.com         nxt_mp_free(r->mem_pool, b);
8421183Svbart@nginx.com         nxt_mp_release(r->mem_pool);
8431183Svbart@nginx.com     }
8441183Svbart@nginx.com }
8451183Svbart@nginx.com 
8461183Svbart@nginx.com 
8471183Svbart@nginx.com static const nxt_http_request_state_t  nxt_http_static_send_state
8481183Svbart@nginx.com     nxt_aligned(64) =
8491183Svbart@nginx.com {
8501183Svbart@nginx.com     .error_handler = nxt_http_request_error_handler,
8511183Svbart@nginx.com };
8521183Svbart@nginx.com 
8531183Svbart@nginx.com 
8541183Svbart@nginx.com static void
nxt_http_static_buf_completion(nxt_task_t * task,void * obj,void * data)8551183Svbart@nginx.com nxt_http_static_buf_completion(nxt_task_t *task, void *obj, void *data)
8561183Svbart@nginx.com {
8571183Svbart@nginx.com     ssize_t             n, size;
8581760Smax.romanov@nginx.com     nxt_buf_t           *b, *fb, *next;
8591183Svbart@nginx.com     nxt_off_t           rest;
8601183Svbart@nginx.com     nxt_http_request_t  *r;
8611183Svbart@nginx.com 
8621183Svbart@nginx.com     b = obj;
8631183Svbart@nginx.com     r = data;
8641760Smax.romanov@nginx.com 
8651760Smax.romanov@nginx.com complete_buf:
8661760Smax.romanov@nginx.com 
8671183Svbart@nginx.com     fb = r->out;
8681183Svbart@nginx.com 
8691183Svbart@nginx.com     if (nxt_slow_path(fb == NULL || r->error)) {
8701183Svbart@nginx.com         goto clean;
8711183Svbart@nginx.com     }
8721183Svbart@nginx.com 
8731183Svbart@nginx.com     rest = fb->file_end - fb->file_pos;
8741183Svbart@nginx.com     size = nxt_buf_mem_size(&b->mem);
8751183Svbart@nginx.com 
8761183Svbart@nginx.com     size = nxt_min(rest, (nxt_off_t) size);
8771183Svbart@nginx.com 
8781183Svbart@nginx.com     n = nxt_file_read(fb->file, b->mem.start, size, fb->file_pos);
8791183Svbart@nginx.com 
8801183Svbart@nginx.com     if (n != size) {
8811183Svbart@nginx.com         if (n >= 0) {
8821183Svbart@nginx.com             nxt_log(task, NXT_LOG_ERR, "file \"%FN\" has changed "
8831183Svbart@nginx.com                     "while sending response to a client", fb->file->name);
8841183Svbart@nginx.com         }
8851183Svbart@nginx.com 
8861183Svbart@nginx.com         nxt_http_request_error_handler(task, r, r->proto.any);
8871183Svbart@nginx.com         goto clean;
8881183Svbart@nginx.com     }
8891183Svbart@nginx.com 
8901760Smax.romanov@nginx.com     next = b->next;
8911760Smax.romanov@nginx.com 
8921183Svbart@nginx.com     if (n == rest) {
8931183Svbart@nginx.com         nxt_file_close(task, fb->file);
8941183Svbart@nginx.com         r->out = NULL;
8951183Svbart@nginx.com 
8961183Svbart@nginx.com         b->next = nxt_http_buf_last(r);
8971183Svbart@nginx.com 
8981183Svbart@nginx.com     } else {
8991183Svbart@nginx.com         fb->file_pos += n;
9001183Svbart@nginx.com         b->next = NULL;
9011183Svbart@nginx.com     }
9021183Svbart@nginx.com 
9031183Svbart@nginx.com     b->mem.pos = b->mem.start;
9041183Svbart@nginx.com     b->mem.free = b->mem.pos + n;
9051183Svbart@nginx.com 
9061183Svbart@nginx.com     nxt_http_request_send(task, r, b);
9071760Smax.romanov@nginx.com 
9081760Smax.romanov@nginx.com     if (next != NULL) {
9091760Smax.romanov@nginx.com         b = next;
9101760Smax.romanov@nginx.com         goto complete_buf;
9111760Smax.romanov@nginx.com     }
9121760Smax.romanov@nginx.com 
9131183Svbart@nginx.com     return;
9141183Svbart@nginx.com 
9151183Svbart@nginx.com clean:
9161183Svbart@nginx.com 
9171760Smax.romanov@nginx.com     do {
918