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 101183Svbart@nginx.com #define NXT_HTTP_STATIC_BUF_COUNT 2 111183Svbart@nginx.com #define NXT_HTTP_STATIC_BUF_SIZE (128 * 1024) 121183Svbart@nginx.com 131183Svbart@nginx.com 141183Svbart@nginx.com static void nxt_http_static_extract_extension(nxt_str_t *path, 151183Svbart@nginx.com nxt_str_t *extension); 161183Svbart@nginx.com static void nxt_http_static_body_handler(nxt_task_t *task, void *obj, 171183Svbart@nginx.com void *data); 181183Svbart@nginx.com static void nxt_http_static_buf_completion(nxt_task_t *task, void *obj, 191183Svbart@nginx.com void *data); 201183Svbart@nginx.com 211183Svbart@nginx.com static nxt_int_t nxt_http_static_mtypes_hash_test(nxt_lvlhsh_query_t *lhq, 221183Svbart@nginx.com void *data); 231183Svbart@nginx.com static void *nxt_http_static_mtypes_hash_alloc(void *data, size_t size); 241183Svbart@nginx.com static void nxt_http_static_mtypes_hash_free(void *data, void *p); 251183Svbart@nginx.com 261183Svbart@nginx.com 271183Svbart@nginx.com static const nxt_http_request_state_t nxt_http_static_send_state; 281183Svbart@nginx.com 291183Svbart@nginx.com 301183Svbart@nginx.com nxt_http_pass_t * 311183Svbart@nginx.com nxt_http_static_handler(nxt_task_t *task, nxt_http_request_t *r, 321183Svbart@nginx.com nxt_http_pass_t *pass) 331183Svbart@nginx.com { 341183Svbart@nginx.com size_t alloc, encode; 351183Svbart@nginx.com u_char *p; 361183Svbart@nginx.com struct tm tm; 371183Svbart@nginx.com nxt_buf_t *fb; 381183Svbart@nginx.com nxt_int_t ret; 391183Svbart@nginx.com nxt_str_t index, extension, *mtype; 401183Svbart@nginx.com nxt_uint_t level; 411183Svbart@nginx.com nxt_bool_t need_body; 421183Svbart@nginx.com nxt_file_t *f; 431183Svbart@nginx.com nxt_file_info_t fi; 441183Svbart@nginx.com nxt_http_field_t *field; 451183Svbart@nginx.com nxt_http_status_t status; 461183Svbart@nginx.com nxt_router_conf_t *rtcf; 471183Svbart@nginx.com nxt_work_handler_t body_handler; 481183Svbart@nginx.com 491183Svbart@nginx.com if (nxt_slow_path(!nxt_str_eq(r->method, "GET", 3))) { 501183Svbart@nginx.com 511183Svbart@nginx.com if (!nxt_str_eq(r->method, "HEAD", 4)) { 521183Svbart@nginx.com nxt_http_request_error(task, r, NXT_HTTP_METHOD_NOT_ALLOWED); 531183Svbart@nginx.com return NULL; 541183Svbart@nginx.com } 551183Svbart@nginx.com 561183Svbart@nginx.com need_body = 0; 571183Svbart@nginx.com 581183Svbart@nginx.com } else { 591183Svbart@nginx.com need_body = 1; 601183Svbart@nginx.com } 611183Svbart@nginx.com 621183Svbart@nginx.com f = nxt_mp_zget(r->mem_pool, sizeof(nxt_file_t)); 631183Svbart@nginx.com if (nxt_slow_path(f == NULL)) { 641183Svbart@nginx.com goto fail; 651183Svbart@nginx.com } 661183Svbart@nginx.com 671183Svbart@nginx.com f->fd = NXT_FILE_INVALID; 681183Svbart@nginx.com 691183Svbart@nginx.com if (r->path->start[r->path->length - 1] == '/') { 701183Svbart@nginx.com /* TODO: dynamic index setting. */ 711183Svbart@nginx.com nxt_str_set(&index, "index.html"); 721183Svbart@nginx.com nxt_str_set(&extension, ".html"); 731183Svbart@nginx.com 741183Svbart@nginx.com } else { 751183Svbart@nginx.com nxt_str_null(&index); 761183Svbart@nginx.com nxt_str_null(&extension); 771183Svbart@nginx.com } 781183Svbart@nginx.com 791183Svbart@nginx.com alloc = pass->name.length + r->path->length + index.length + 1; 801183Svbart@nginx.com 811183Svbart@nginx.com f->name = nxt_mp_nget(r->mem_pool, alloc); 821183Svbart@nginx.com if (nxt_slow_path(f->name == NULL)) { 831183Svbart@nginx.com goto fail; 841183Svbart@nginx.com } 851183Svbart@nginx.com 861183Svbart@nginx.com p = f->name; 871183Svbart@nginx.com p = nxt_cpymem(p, pass->name.start, pass->name.length); 881183Svbart@nginx.com p = nxt_cpymem(p, r->path->start, r->path->length); 891183Svbart@nginx.com p = nxt_cpymem(p, index.start, index.length); 901183Svbart@nginx.com *p = '\0'; 911183Svbart@nginx.com 921183Svbart@nginx.com ret = nxt_file_open(task, f, NXT_FILE_RDONLY, NXT_FILE_OPEN, 0); 931183Svbart@nginx.com 941183Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 951183Svbart@nginx.com switch (f->error) { 961183Svbart@nginx.com 97*1200Svbart@nginx.com /* 98*1200Svbart@nginx.com * For Unix domain sockets "errno" is set to: 99*1200Svbart@nginx.com * - ENXIO on Linux; 100*1200Svbart@nginx.com * - EOPNOTSUPP on *BSD, MacOSX, and Solaris. 101*1200Svbart@nginx.com */ 102*1200Svbart@nginx.com 1031183Svbart@nginx.com case NXT_ENOENT: 1041183Svbart@nginx.com case NXT_ENOTDIR: 1051183Svbart@nginx.com case NXT_ENAMETOOLONG: 106*1200Svbart@nginx.com #if (NXT_LINUX) 107*1200Svbart@nginx.com case NXT_ENXIO: 108*1200Svbart@nginx.com #else 109*1200Svbart@nginx.com case NXT_EOPNOTSUPP: 110*1200Svbart@nginx.com #endif 1111183Svbart@nginx.com level = NXT_LOG_ERR; 1121183Svbart@nginx.com status = NXT_HTTP_NOT_FOUND; 1131183Svbart@nginx.com break; 1141183Svbart@nginx.com 1151183Svbart@nginx.com case NXT_EACCES: 1161183Svbart@nginx.com level = NXT_LOG_ERR; 1171183Svbart@nginx.com status = NXT_HTTP_FORBIDDEN; 1181183Svbart@nginx.com break; 1191183Svbart@nginx.com 1201183Svbart@nginx.com default: 1211183Svbart@nginx.com level = NXT_LOG_ALERT; 1221183Svbart@nginx.com status = NXT_HTTP_INTERNAL_SERVER_ERROR; 1231183Svbart@nginx.com break; 1241183Svbart@nginx.com } 1251183Svbart@nginx.com 1261183Svbart@nginx.com if (status != NXT_HTTP_NOT_FOUND) { 1271183Svbart@nginx.com nxt_log(task, level, "open(\"%FN\") failed %E", f->name, f->error); 1281183Svbart@nginx.com } 1291183Svbart@nginx.com 1301183Svbart@nginx.com nxt_http_request_error(task, r, status); 1311183Svbart@nginx.com return NULL; 1321183Svbart@nginx.com } 1331183Svbart@nginx.com 1341183Svbart@nginx.com ret = nxt_file_info(f, &fi); 1351183Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 1361183Svbart@nginx.com goto fail; 1371183Svbart@nginx.com } 1381183Svbart@nginx.com 1391183Svbart@nginx.com if (nxt_fast_path(nxt_is_file(&fi))) { 1401183Svbart@nginx.com r->status = NXT_HTTP_OK; 1411183Svbart@nginx.com r->resp.content_length_n = nxt_file_size(&fi); 1421183Svbart@nginx.com 1431183Svbart@nginx.com field = nxt_list_zero_add(r->resp.fields); 1441183Svbart@nginx.com if (nxt_slow_path(field == NULL)) { 1451183Svbart@nginx.com goto fail; 1461183Svbart@nginx.com } 1471183Svbart@nginx.com 1481183Svbart@nginx.com nxt_http_field_name_set(field, "Last-Modified"); 1491183Svbart@nginx.com 1501183Svbart@nginx.com p = nxt_mp_nget(r->mem_pool, NXT_HTTP_DATE_LEN); 1511183Svbart@nginx.com if (nxt_slow_path(p == NULL)) { 1521183Svbart@nginx.com goto fail; 1531183Svbart@nginx.com } 1541183Svbart@nginx.com 1551183Svbart@nginx.com nxt_localtime(nxt_file_mtime(&fi), &tm); 1561183Svbart@nginx.com 1571183Svbart@nginx.com field->value = p; 1581183Svbart@nginx.com field->value_length = nxt_http_date(p, &tm) - p; 1591183Svbart@nginx.com 1601183Svbart@nginx.com field = nxt_list_zero_add(r->resp.fields); 1611183Svbart@nginx.com if (nxt_slow_path(field == NULL)) { 1621183Svbart@nginx.com goto fail; 1631183Svbart@nginx.com } 1641183Svbart@nginx.com 1651183Svbart@nginx.com nxt_http_field_name_set(field, "ETag"); 1661183Svbart@nginx.com 1671183Svbart@nginx.com alloc = NXT_TIME_T_HEXLEN + NXT_OFF_T_HEXLEN + 3; 1681183Svbart@nginx.com 1691183Svbart@nginx.com p = nxt_mp_nget(r->mem_pool, alloc); 1701183Svbart@nginx.com if (nxt_slow_path(p == NULL)) { 1711183Svbart@nginx.com goto fail; 1721183Svbart@nginx.com } 1731183Svbart@nginx.com 1741183Svbart@nginx.com field->value = p; 1751183Svbart@nginx.com field->value_length = nxt_sprintf(p, p + alloc, "\"%xT-%xO\"", 1761183Svbart@nginx.com nxt_file_mtime(&fi), 1771183Svbart@nginx.com nxt_file_size(&fi)) 1781183Svbart@nginx.com - p; 1791183Svbart@nginx.com 1801183Svbart@nginx.com if (extension.start == NULL) { 1811183Svbart@nginx.com nxt_http_static_extract_extension(r->path, &extension); 1821183Svbart@nginx.com } 1831183Svbart@nginx.com 1841183Svbart@nginx.com rtcf = r->conf->socket_conf->router_conf; 1851183Svbart@nginx.com 1861183Svbart@nginx.com mtype = nxt_http_static_mtypes_hash_find(&rtcf->mtypes_hash, 1871183Svbart@nginx.com &extension); 1881183Svbart@nginx.com 1891183Svbart@nginx.com if (mtype != NULL) { 1901183Svbart@nginx.com field = nxt_list_zero_add(r->resp.fields); 1911183Svbart@nginx.com if (nxt_slow_path(field == NULL)) { 1921183Svbart@nginx.com goto fail; 1931183Svbart@nginx.com } 1941183Svbart@nginx.com 1951183Svbart@nginx.com nxt_http_field_name_set(field, "Content-Type"); 1961183Svbart@nginx.com 1971183Svbart@nginx.com field->value = mtype->start; 1981183Svbart@nginx.com field->value_length = mtype->length; 1991183Svbart@nginx.com } 2001183Svbart@nginx.com 2011183Svbart@nginx.com if (need_body && nxt_file_size(&fi) > 0) { 2021183Svbart@nginx.com fb = nxt_mp_zget(r->mem_pool, NXT_BUF_FILE_SIZE); 2031183Svbart@nginx.com if (nxt_slow_path(fb == NULL)) { 2041183Svbart@nginx.com goto fail; 2051183Svbart@nginx.com } 2061183Svbart@nginx.com 2071183Svbart@nginx.com fb->file = f; 2081183Svbart@nginx.com fb->file_end = nxt_file_size(&fi); 2091183Svbart@nginx.com 2101183Svbart@nginx.com r->out = fb; 2111183Svbart@nginx.com 2121183Svbart@nginx.com body_handler = &nxt_http_static_body_handler; 2131183Svbart@nginx.com 2141183Svbart@nginx.com } else { 2151183Svbart@nginx.com nxt_file_close(task, f); 2161183Svbart@nginx.com body_handler = NULL; 2171183Svbart@nginx.com } 2181183Svbart@nginx.com 2191183Svbart@nginx.com } else { 2201183Svbart@nginx.com /* Not a file. */ 2211183Svbart@nginx.com 2221183Svbart@nginx.com nxt_file_close(task, f); 2231183Svbart@nginx.com 2241183Svbart@nginx.com if (nxt_slow_path(!nxt_is_dir(&fi))) { 2251183Svbart@nginx.com nxt_log(task, NXT_LOG_ERR, "\"%FN\" is not a regular file", 2261183Svbart@nginx.com f->name); 2271183Svbart@nginx.com nxt_http_request_error(task, r, NXT_HTTP_NOT_FOUND); 2281183Svbart@nginx.com return NULL; 2291183Svbart@nginx.com } 2301183Svbart@nginx.com 2311198Svbart@nginx.com f = NULL; 2321198Svbart@nginx.com 2331183Svbart@nginx.com r->status = NXT_HTTP_MOVED_PERMANENTLY; 2341183Svbart@nginx.com r->resp.content_length_n = 0; 2351183Svbart@nginx.com 2361183Svbart@nginx.com field = nxt_list_zero_add(r->resp.fields); 2371183Svbart@nginx.com if (nxt_slow_path(field == NULL)) { 2381183Svbart@nginx.com goto fail; 2391183Svbart@nginx.com } 2401183Svbart@nginx.com 2411183Svbart@nginx.com nxt_http_field_name_set(field, "Location"); 2421183Svbart@nginx.com 2431183Svbart@nginx.com encode = nxt_encode_uri(NULL, r->path->start, r->path->length); 2441183Svbart@nginx.com alloc = r->path->length + encode * 2 + 1; 2451183Svbart@nginx.com 2461183Svbart@nginx.com if (r->args->length > 0) { 2471183Svbart@nginx.com alloc += 1 + r->args->length; 2481183Svbart@nginx.com } 2491183Svbart@nginx.com 2501183Svbart@nginx.com p = nxt_mp_nget(r->mem_pool, alloc); 2511183Svbart@nginx.com if (nxt_slow_path(p == NULL)) { 2521183Svbart@nginx.com goto fail; 2531183Svbart@nginx.com } 2541183Svbart@nginx.com 2551183Svbart@nginx.com field->value = p; 2561183Svbart@nginx.com field->value_length = alloc; 2571183Svbart@nginx.com 2581183Svbart@nginx.com if (encode > 0) { 2591183Svbart@nginx.com p = (u_char *) nxt_encode_uri(p, r->path->start, r->path->length); 2601183Svbart@nginx.com 2611183Svbart@nginx.com } else { 2621183Svbart@nginx.com p = nxt_cpymem(p, r->path->start, r->path->length); 2631183Svbart@nginx.com } 2641183Svbart@nginx.com 2651183Svbart@nginx.com *p++ = '/'; 2661183Svbart@nginx.com 2671183Svbart@nginx.com if (r->args->length > 0) { 2681183Svbart@nginx.com *p++ = '?'; 2691183Svbart@nginx.com nxt_memcpy(p, r->args->start, r->args->length); 2701183Svbart@nginx.com } 2711183Svbart@nginx.com 2721183Svbart@nginx.com body_handler = NULL; 2731183Svbart@nginx.com } 2741183Svbart@nginx.com 2751183Svbart@nginx.com nxt_http_request_header_send(task, r, body_handler); 2761183Svbart@nginx.com 2771183Svbart@nginx.com r->state = &nxt_http_static_send_state; 2781183Svbart@nginx.com return NULL; 2791183Svbart@nginx.com 2801183Svbart@nginx.com fail: 2811183Svbart@nginx.com 2821183Svbart@nginx.com nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR); 2831183Svbart@nginx.com 2841183Svbart@nginx.com if (f != NULL && f->fd != NXT_FILE_INVALID) { 2851183Svbart@nginx.com nxt_file_close(task, f); 2861183Svbart@nginx.com } 2871183Svbart@nginx.com 2881183Svbart@nginx.com return NULL; 2891183Svbart@nginx.com } 2901183Svbart@nginx.com 2911183Svbart@nginx.com 2921183Svbart@nginx.com static void 2931183Svbart@nginx.com nxt_http_static_extract_extension(nxt_str_t *path, nxt_str_t *extension) 2941183Svbart@nginx.com { 2951183Svbart@nginx.com u_char ch, *p, *end; 2961183Svbart@nginx.com 2971183Svbart@nginx.com end = path->start + path->length; 2981183Svbart@nginx.com p = end; 2991183Svbart@nginx.com 3001183Svbart@nginx.com for ( ;; ) { 3011183Svbart@nginx.com /* There's always '/' in the beginning of the request path. */ 3021183Svbart@nginx.com 3031183Svbart@nginx.com p--; 3041183Svbart@nginx.com ch = *p; 3051183Svbart@nginx.com 3061183Svbart@nginx.com switch (ch) { 3071183Svbart@nginx.com case '/': 3081183Svbart@nginx.com p++; 3091183Svbart@nginx.com /* Fall through. */ 3101183Svbart@nginx.com case '.': 3111183Svbart@nginx.com extension->length = end - p; 3121183Svbart@nginx.com extension->start = p; 3131183Svbart@nginx.com return; 3141183Svbart@nginx.com } 3151183Svbart@nginx.com } 3161183Svbart@nginx.com } 3171183Svbart@nginx.com 3181183Svbart@nginx.com 3191183Svbart@nginx.com static void 3201183Svbart@nginx.com nxt_http_static_body_handler(nxt_task_t *task, void *obj, void *data) 3211183Svbart@nginx.com { 3221183Svbart@nginx.com size_t alloc; 3231183Svbart@nginx.com nxt_buf_t *fb, *b, **next, *out; 3241183Svbart@nginx.com nxt_off_t rest; 3251183Svbart@nginx.com nxt_int_t n; 3261183Svbart@nginx.com nxt_work_queue_t *wq; 3271183Svbart@nginx.com nxt_http_request_t *r; 3281183Svbart@nginx.com 3291183Svbart@nginx.com r = obj; 3301183Svbart@nginx.com fb = r->out; 3311183Svbart@nginx.com 3321183Svbart@nginx.com rest = fb->file_end - fb->file_pos; 3331183Svbart@nginx.com out = NULL; 3341183Svbart@nginx.com next = &out; 3351183Svbart@nginx.com n = 0; 3361183Svbart@nginx.com 3371183Svbart@nginx.com do { 3381183Svbart@nginx.com alloc = nxt_min(rest, NXT_HTTP_STATIC_BUF_SIZE); 3391183Svbart@nginx.com 3401183Svbart@nginx.com b = nxt_buf_mem_alloc(r->mem_pool, alloc, 0); 3411183Svbart@nginx.com if (nxt_slow_path(b == NULL)) { 3421183Svbart@nginx.com goto fail; 3431183Svbart@nginx.com } 3441183Svbart@nginx.com 3451183Svbart@nginx.com b->completion_handler = nxt_http_static_buf_completion; 3461183Svbart@nginx.com b->parent = r; 3471183Svbart@nginx.com 3481183Svbart@nginx.com nxt_mp_retain(r->mem_pool); 3491183Svbart@nginx.com 3501183Svbart@nginx.com *next = b; 3511183Svbart@nginx.com next = &b->next; 3521183Svbart@nginx.com 3531183Svbart@nginx.com rest -= alloc; 3541183Svbart@nginx.com 3551183Svbart@nginx.com } while (rest > 0 && ++n < NXT_HTTP_STATIC_BUF_COUNT); 3561183Svbart@nginx.com 3571183Svbart@nginx.com wq = &task->thread->engine->fast_work_queue; 3581183Svbart@nginx.com 3591183Svbart@nginx.com nxt_sendbuf_drain(task, wq, out); 3601183Svbart@nginx.com return; 3611183Svbart@nginx.com 3621183Svbart@nginx.com fail: 3631183Svbart@nginx.com 3641183Svbart@nginx.com while (out != NULL) { 3651183Svbart@nginx.com b = out; 3661183Svbart@nginx.com out = b->next; 3671183Svbart@nginx.com 3681183Svbart@nginx.com nxt_mp_free(r->mem_pool, b); 3691183Svbart@nginx.com nxt_mp_release(r->mem_pool); 3701183Svbart@nginx.com } 3711183Svbart@nginx.com } 3721183Svbart@nginx.com 3731183Svbart@nginx.com 3741183Svbart@nginx.com static const nxt_http_request_state_t nxt_http_static_send_state 3751183Svbart@nginx.com nxt_aligned(64) = 3761183Svbart@nginx.com { 3771183Svbart@nginx.com .error_handler = nxt_http_request_error_handler, 3781183Svbart@nginx.com }; 3791183Svbart@nginx.com 3801183Svbart@nginx.com 3811183Svbart@nginx.com static void 3821183Svbart@nginx.com nxt_http_static_buf_completion(nxt_task_t *task, void *obj, void *data) 3831183Svbart@nginx.com { 3841183Svbart@nginx.com ssize_t n, size; 3851183Svbart@nginx.com nxt_buf_t *b, *fb; 3861183Svbart@nginx.com nxt_off_t rest; 3871183Svbart@nginx.com nxt_http_request_t *r; 3881183Svbart@nginx.com 3891183Svbart@nginx.com b = obj; 3901183Svbart@nginx.com r = data; 3911183Svbart@nginx.com fb = r->out; 3921183Svbart@nginx.com 3931183Svbart@nginx.com if (nxt_slow_path(fb == NULL || r->error)) { 3941183Svbart@nginx.com goto clean; 3951183Svbart@nginx.com } 3961183Svbart@nginx.com 3971183Svbart@nginx.com rest = fb->file_end - fb->file_pos; 3981183Svbart@nginx.com size = nxt_buf_mem_size(&b->mem); 3991183Svbart@nginx.com 4001183Svbart@nginx.com size = nxt_min(rest, (nxt_off_t) size); 4011183Svbart@nginx.com 4021183Svbart@nginx.com n = nxt_file_read(fb->file, b->mem.start, size, fb->file_pos); 4031183Svbart@nginx.com 4041183Svbart@nginx.com if (n != size) { 4051183Svbart@nginx.com if (n >= 0) { 4061183Svbart@nginx.com nxt_log(task, NXT_LOG_ERR, "file \"%FN\" has changed " 4071183Svbart@nginx.com "while sending response to a client", fb->file->name); 4081183Svbart@nginx.com } 4091183Svbart@nginx.com 4101183Svbart@nginx.com nxt_http_request_error_handler(task, r, r->proto.any); 4111183Svbart@nginx.com goto clean; 4121183Svbart@nginx.com } 4131183Svbart@nginx.com 4141183Svbart@nginx.com if (n == rest) { 4151183Svbart@nginx.com nxt_file_close(task, fb->file); 4161183Svbart@nginx.com r->out = NULL; 4171183Svbart@nginx.com 4181183Svbart@nginx.com b->next = nxt_http_buf_last(r); 4191183Svbart@nginx.com 4201183Svbart@nginx.com } else { 4211183Svbart@nginx.com fb->file_pos += n; 4221183Svbart@nginx.com b->next = NULL; 4231183Svbart@nginx.com } 4241183Svbart@nginx.com 4251183Svbart@nginx.com b->mem.pos = b->mem.start; 4261183Svbart@nginx.com b->mem.free = b->mem.pos + n; 4271183Svbart@nginx.com 4281183Svbart@nginx.com nxt_http_request_send(task, r, b); 4291183Svbart@nginx.com return; 4301183Svbart@nginx.com 4311183Svbart@nginx.com clean: 4321183Svbart@nginx.com 4331183Svbart@nginx.com nxt_mp_free(r->mem_pool, b); 4341183Svbart@nginx.com nxt_mp_release(r->mem_pool); 4351183Svbart@nginx.com 4361183Svbart@nginx.com if (fb != NULL) { 4371183Svbart@nginx.com nxt_file_close(task, fb->file); 4381183Svbart@nginx.com r->out = NULL; 4391183Svbart@nginx.com } 4401183Svbart@nginx.com } 4411183Svbart@nginx.com 4421183Svbart@nginx.com 4431183Svbart@nginx.com nxt_int_t 4441183Svbart@nginx.com nxt_http_static_mtypes_init(nxt_mp_t *mp, nxt_lvlhsh_t *hash) 4451183Svbart@nginx.com { 4461183Svbart@nginx.com nxt_str_t *type, extension; 4471183Svbart@nginx.com nxt_int_t ret; 4481183Svbart@nginx.com nxt_uint_t i; 4491183Svbart@nginx.com 4501183Svbart@nginx.com static const struct { 4511183Svbart@nginx.com nxt_str_t type; 4521183Svbart@nginx.com const char *extension; 4531183Svbart@nginx.com } default_types[] = { 4541183Svbart@nginx.com 4551183Svbart@nginx.com { nxt_string("text/html"), ".html" }, 4561183Svbart@nginx.com { nxt_string("text/html"), ".htm" }, 4571183Svbart@nginx.com { nxt_string("text/css"), ".css" }, 4581183Svbart@nginx.com 4591183Svbart@nginx.com { nxt_string("image/svg+xml"), ".svg" }, 4601183Svbart@nginx.com { nxt_string("image/svg+xml"), ".svg" }, 4611183Svbart@nginx.com { nxt_string("image/webp"), ".webp" }, 4621183Svbart@nginx.com { nxt_string("image/png"), ".png" }, 4631183Svbart@nginx.com { nxt_string("image/jpeg"), ".jpeg" }, 4641183Svbart@nginx.com { nxt_string("image/jpeg"), ".jpg" }, 4651183Svbart@nginx.com { nxt_string("image/gif"), ".gif" }, 4661183Svbart@nginx.com { nxt_string("image/x-icon"), ".ico" }, 4671183Svbart@nginx.com 4681183Svbart@nginx.com { nxt_string("font/woff"), ".woff" }, 4691183Svbart@nginx.com { nxt_string("font/woff2"), ".woff2" }, 4701183Svbart@nginx.com { nxt_string("font/otf"), ".otf" }, 4711183Svbart@nginx.com { nxt_string("font/ttf"), ".ttf" }, 4721183Svbart@nginx.com 4731183Svbart@nginx.com { nxt_string("text/plain"), ".txt" }, 4741183Svbart@nginx.com { nxt_string("text/markdown"), ".md" }, 4751183Svbart@nginx.com { nxt_string("text/x-rst"), ".rst" }, 4761183Svbart@nginx.com 4771183Svbart@nginx.com { nxt_string("application/javascript"), ".js" }, 4781183Svbart@nginx.com { nxt_string("application/json"), ".json" }, 4791183Svbart@nginx.com { nxt_string("application/xml"), ".xml" }, 4801183Svbart@nginx.com { nxt_string("application/rss+xml"), ".rss" }, 4811183Svbart@nginx.com { nxt_string("application/atom+xml"), ".atom" }, 4821183Svbart@nginx.com { nxt_string("application/pdf"), ".pdf" }, 4831183Svbart@nginx.com 4841183Svbart@nginx.com { nxt_string("application/zip"), ".zip" }, 4851183Svbart@nginx.com 4861183Svbart@nginx.com { nxt_string("audio/mpeg"), ".mp3" }, 4871183Svbart@nginx.com { nxt_string("audio/ogg"), ".ogg" }, 4881183Svbart@nginx.com { nxt_string("audio/midi"), ".midi" }, 4891183Svbart@nginx.com { nxt_string("audio/midi"), ".mid" }, 4901183Svbart@nginx.com { nxt_string("audio/flac"), ".flac" }, 4911183Svbart@nginx.com { nxt_string("audio/aac"), ".aac" }, 4921183Svbart@nginx.com { nxt_string("audio/wav"), ".wav" }, 4931183Svbart@nginx.com 4941183Svbart@nginx.com { nxt_string("video/mpeg"), ".mpeg" }, 4951183Svbart@nginx.com { nxt_string("video/mpeg"), ".mpg" }, 4961183Svbart@nginx.com { nxt_string("video/mp4"), ".mp4" }, 4971183Svbart@nginx.com { nxt_string("video/webm"), ".webm" }, 4981183Svbart@nginx.com { nxt_string("video/x-msvideo"), ".avi" }, 4991183Svbart@nginx.com 5001183Svbart@nginx.com { nxt_string("application/octet-stream"), ".exe" }, 5011183Svbart@nginx.com { nxt_string("application/octet-stream"), ".bin" }, 5021183Svbart@nginx.com { nxt_string("application/octet-stream"), ".dll" }, 5031183Svbart@nginx.com { nxt_string("application/octet-stream"), ".iso" }, 5041183Svbart@nginx.com { nxt_string("application/octet-stream"), ".img" }, 5051183Svbart@nginx.com { nxt_string("application/octet-stream"), ".msi" }, 5061183Svbart@nginx.com 5071183Svbart@nginx.com { nxt_string("application/octet-stream"), ".deb" }, 5081183Svbart@nginx.com { nxt_string("application/octet-stream"), ".rpm" }, 5091183Svbart@nginx.com }; 5101183Svbart@nginx.com 5111183Svbart@nginx.com for (i = 0; i < nxt_nitems(default_types); i++) { 5121183Svbart@nginx.com type = (nxt_str_t *) &default_types[i].type; 5131183Svbart@nginx.com 5141183Svbart@nginx.com extension.start = (u_char *) default_types[i].extension; 5151183Svbart@nginx.com extension.length = nxt_strlen(extension.start); 5161183Svbart@nginx.com 5171183Svbart@nginx.com ret = nxt_http_static_mtypes_hash_add(mp, hash, &extension, type); 5181183Svbart@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 5191183Svbart@nginx.com return NXT_ERROR; 5201183Svbart@nginx.com } 5211183Svbart@nginx.com } 5221183Svbart@nginx.com 5231183Svbart@nginx.com return NXT_OK; 5241183Svbart@nginx.com } 5251183Svbart@nginx.com 5261183Svbart@nginx.com 5271183Svbart@nginx.com static const nxt_lvlhsh_proto_t nxt_http_static_mtypes_hash_proto 5281183Svbart@nginx.com nxt_aligned(64) = 5291183Svbart@nginx.com { 5301183Svbart@nginx.com NXT_LVLHSH_DEFAULT, 5311183Svbart@nginx.com nxt_http_static_mtypes_hash_test, 5321183Svbart@nginx.com nxt_http_static_mtypes_hash_alloc, 5331183Svbart@nginx.com nxt_http_static_mtypes_hash_free, 5341183Svbart@nginx.com }; 5351183Svbart@nginx.com 5361183Svbart@nginx.com 5371183Svbart@nginx.com typedef struct { 5381183Svbart@nginx.com nxt_str_t extension; 5391183Svbart@nginx.com nxt_str_t *type; 5401183Svbart@nginx.com } nxt_http_static_mtype_t; 5411183Svbart@nginx.com 5421183Svbart@nginx.com 5431183Svbart@nginx.com nxt_int_t 5441183Svbart@nginx.com nxt_http_static_mtypes_hash_add(nxt_mp_t *mp, nxt_lvlhsh_t *hash, 5451183Svbart@nginx.com nxt_str_t *extension, nxt_str_t *type) 5461183Svbart@nginx.com { 5471183Svbart@nginx.com nxt_lvlhsh_query_t lhq; 5481183Svbart@nginx.com nxt_http_static_mtype_t *mtype; 5491183Svbart@nginx.com 5501183Svbart@nginx.com mtype = nxt_mp_get(mp, sizeof(nxt_http_static_mtype_t)); 5511183Svbart@nginx.com if (nxt_slow_path(mtype == NULL)) { 5521183Svbart@nginx.com return NXT_ERROR; 5531183Svbart@nginx.com } 5541183Svbart@nginx.com 5551183Svbart@nginx.com mtype->extension = *extension; 5561183Svbart@nginx.com mtype->type = type; 5571183Svbart@nginx.com 5581183Svbart@nginx.com lhq.key = *extension; 5591183Svbart@nginx.com lhq.key_hash = nxt_djb_hash_lowcase(lhq.key.start, lhq.key.length); 5601183Svbart@nginx.com lhq.replace = 1; 5611183Svbart@nginx.com lhq.value = mtype; 5621183Svbart@nginx.com lhq.proto = &nxt_http_static_mtypes_hash_proto; 5631183Svbart@nginx.com lhq.pool = mp; 5641183Svbart@nginx.com 5651183Svbart@nginx.com return nxt_lvlhsh_insert(hash, &lhq); 5661183Svbart@nginx.com } 5671183Svbart@nginx.com 5681183Svbart@nginx.com 5691183Svbart@nginx.com nxt_str_t * 5701183Svbart@nginx.com nxt_http_static_mtypes_hash_find(nxt_lvlhsh_t *hash, nxt_str_t *extension) 5711183Svbart@nginx.com { 5721183Svbart@nginx.com nxt_lvlhsh_query_t lhq; 5731183Svbart@nginx.com nxt_http_static_mtype_t *mtype; 5741183Svbart@nginx.com 5751183Svbart@nginx.com lhq.key = *extension; 5761183Svbart@nginx.com lhq.key_hash = nxt_djb_hash_lowcase(lhq.key.start, lhq.key.length); 5771183Svbart@nginx.com lhq.proto = &nxt_http_static_mtypes_hash_proto; 5781183Svbart@nginx.com 5791183Svbart@nginx.com if (nxt_lvlhsh_find(hash, &lhq) == NXT_OK) { 5801183Svbart@nginx.com mtype = lhq.value; 5811183Svbart@nginx.com return mtype->type; 5821183Svbart@nginx.com } 5831183Svbart@nginx.com 5841183Svbart@nginx.com return NULL; 5851183Svbart@nginx.com } 5861183Svbart@nginx.com 5871183Svbart@nginx.com 5881183Svbart@nginx.com static nxt_int_t 5891183Svbart@nginx.com nxt_http_static_mtypes_hash_test(nxt_lvlhsh_query_t *lhq, void *data) 5901183Svbart@nginx.com { 5911183Svbart@nginx.com nxt_http_static_mtype_t *mtype; 5921183Svbart@nginx.com 5931183Svbart@nginx.com mtype = data; 5941183Svbart@nginx.com 5951183Svbart@nginx.com return nxt_strcasestr_eq(&lhq->key, &mtype->extension) ? NXT_OK 5961183Svbart@nginx.com : NXT_DECLINED; 5971183Svbart@nginx.com } 5981183Svbart@nginx.com 5991183Svbart@nginx.com 6001183Svbart@nginx.com static void * 6011183Svbart@nginx.com nxt_http_static_mtypes_hash_alloc(void *data, size_t size) 6021183Svbart@nginx.com { 6031183Svbart@nginx.com return nxt_mp_align(data, size, size); 6041183Svbart@nginx.com } 6051183Svbart@nginx.com 6061183Svbart@nginx.com 6071183Svbart@nginx.com static void 6081183Svbart@nginx.com nxt_http_static_mtypes_hash_free(void *data, void *p) 6091183Svbart@nginx.com { 6101183Svbart@nginx.com nxt_mp_free(data, p); 6111183Svbart@nginx.com } 612