static ngx_int_t ngx_http_mp4frag_handler(ngx_http_request_t *r) { ngx_int_t rc; ngx_chain_t out; u_char *resp_body; ngx_buf_t *resp; char *lastslash; char *mediafilename; u_char *last; size_t root; ngx_str_t path; ngx_str_t index_map = ngx_null_string; const u_char *indexptr; ngx_str_t mediafile_map = ngx_null_string; unsigned medianum, fragnum; uint16_t nmedia; ngx_str_t videocodecdata, audiocodecdata; uint32_t mediaoffset, fragments_offset; uint16_t mediafilenamelen; uint16_t nsamples, nfragments; uint32_t totalsize; unsigned int iii; ngx_table_elt_t *self; if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) { return NGX_HTTP_NOT_ALLOWED; } if ( (rc = ngx_http_discard_request_body(r)) != NGX_OK ) { return rc; } if ( (self = ngx_list_push(&r->headers_out.headers)) == NULL ) { ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "Insufficient memory for ngx_list_push"); return NGX_ERROR; } self->hash = 1; ngx_str_set(&self->key, "X-Mp4frag-Version"); ngx_str_set(&self->value, VERSION); last = ngx_http_map_uri_to_path(r, &path, &root, 0); ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "path=%s", path.data); lastslash = strrchr((char*)path.data, '/'); if ( lastslash ) { path.len = lastslash - (char*)path.data; } /* определить путь к файлу индекса и номер фрагмента: */ *lastslash++ = 0; // uri - dirname, lastslash - basename if ( memcmp(lastslash, "Seg1-Frag", 9) != 0 ) { return NGX_HTTP_NOT_FOUND; } fragnum = atoi(lastslash + 9); lastslash = strrchr((char*)path.data, '/'); if ( !lastslash ) { return NGX_HTTP_NOT_FOUND; } medianum = atoi(lastslash + 1); memcpy(lastslash + 1, "index", 6); ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "index_path=%s", path.data); if ( (rc = make_mapping((const char *)path.data, &index_map, r)) != NGX_OK ) { return rc; } indexptr = index_map.data; #define CHECKMAP(nbytes) do { if (indexptr + nbytes >= index_map.data + index_map.len) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "index underrun, offset 0x%0x", nbytes); goto GENERAL_ERROR;} } while(0) CHECKMAP(10); /* 8 for signature and 2 for media count */ if ( memcmp(index_map.data, "mp4frag", 7) != 0 || index_map.data[7] /* version */ > 2 ) { free_mapping(&index_map); ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Bad index format in %s", path.data); goto GENERAL_ERROR; } indexptr += 8; nmedia = get16(indexptr); if ( medianum >= nmedia ) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "No media #%d in %s, total %d media", medianum, path.data, nmedia); goto GENERAL_ERROR; } indexptr += 2; CHECKMAP(nmedia * 4); mediaoffset = get32(indexptr + medianum * 4); if ( mediaoffset >= index_map.len ) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "short index in %s", path.data); goto GENERAL_ERROR; } indexptr = index_map.data; CHECKMAP(mediaoffset); indexptr = index_map.data + mediaoffset; CHECKMAP(2); mediafilenamelen = get16(indexptr); indexptr += 2; CHECKMAP(mediafilenamelen); if ( index_map.data[7] == 1 ) { if ( (mediafilename = ngx_pcalloc(r->pool, mediafilenamelen + 1)) == NULL ) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Insufficient memory"); goto GENERAL_ERROR; } memcpy(mediafilename, (const char *)indexptr, mediafilenamelen); mediafilename[mediafilenamelen] = 0; } else /* index_map.data[7] == 2 */ { mediafilename = (char *)indexptr; } indexptr += mediafilenamelen; CHECKMAP(2); videocodecdata.len = get16(indexptr); indexptr += 2; CHECKMAP(videocodecdata.len); videocodecdata.data = (u_char*)indexptr; indexptr += videocodecdata.len; CHECKMAP(2); audiocodecdata.len = get16(indexptr); indexptr += 2; CHECKMAP(audiocodecdata.len); audiocodecdata.data = (u_char*)indexptr; indexptr += audiocodecdata.len; /* number of fragments in the media */ CHECKMAP(2); nfragments = get16(indexptr); if ( fragnum > nfragments || fragnum < 1 ) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "No fragment #%d in media #%d in file %s", fragnum, medianum, path.data); goto NOT_FOUND; } indexptr += 2; CHECKMAP(nfragments * 4); fragments_offset = get32(indexptr + (fragnum - 1) * 4); indexptr = index_map.data; CHECKMAP(fragments_offset); indexptr += fragments_offset; CHECKMAP(6); /* first entry should present anyway */ nsamples = get16(indexptr); if ( nsamples < 1 ) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Number of samples is 0 for media #%d, fragment #%d, index %s", medianum, fragnum, path.data); goto GENERAL_ERROR; } /* total fragment size in bytes: */ totalsize = get32(indexptr + 2); ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "nsamples=%d, totalsize=%d", nsamples, totalsize); indexptr += 6; /* allocate memory for response */ if ( (resp_body = ngx_pcalloc(r->pool, totalsize)) == NULL ) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Insufficient memory"); goto GENERAL_ERROR; } if ( (resp = ngx_pcalloc(r->pool, sizeof(ngx_buf_t))) == NULL ) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Insufficient memory"); goto GENERAL_ERROR; } out.buf = resp; out.next = NULL; resp->pos = resp_body; resp->last = resp_body + totalsize; resp->memory = 1; resp->last_buf = 1; if ( make_mapping(mediafilename, &mediafile_map, r) != NGX_OK ) goto GENERAL_ERROR; /* generate the fragment */ write32(resp_body, totalsize); memcpy(resp_body + 4, "mdat", 4); CHECKMAP(16 * nsamples - 1); /* check if the last byte still inside the index */ /* fragment timestamp is equal to first sample timestamp */ resp_body = write_fragment_prefix(resp_body + 8, &videocodecdata, &audiocodecdata, get32(indexptr + 8)); for ( iii = 0; iii < nsamples; ++iii ) { uint32_t offset = get32(indexptr); uint32_t size = get32(indexptr + 4); uint32_t timestamp = get32(indexptr + 8); uint32_t composition_offset = get24(indexptr + 12); uint8_t flags = indexptr[15]; indexptr += 16; if ( flags ) { resp_body = write_video_packet(resp_body, flags & 2, 0, composition_offset, timestamp, mediafile_map.data + offset, size); } else { resp_body = write_audio_packet(resp_body, 0, timestamp, mediafile_map.data + offset, size); } } free_mapping(&index_map); free_mapping(&mediafile_map); if ( resp_body != resp->last ) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "response buffer overrun"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = totalsize; rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only || r->method == NGX_HTTP_HEAD) { return rc; } /* send the buffer chain of your response */ return ngx_http_output_filter(r, &out); GENERAL_ERROR: free_mapping(&index_map); free_mapping(&mediafile_map); return NGX_HTTP_INTERNAL_SERVER_ERROR; NOT_FOUND: free_mapping(&index_map); free_mapping(&mediafile_map); return NGX_HTTP_NOT_FOUND; }
/****************************************************************** index指令的理解,当访问某个目录时未指定文件,如果此location 设置了index指令,将返回index指令设置的页面 ******************************************************************/ static ngx_int_t ngx_http_index_handler(ngx_http_request_t *r) { u_char *p, *name; size_t len, root, reserve, allocated; ngx_int_t rc; ngx_str_t path, uri; ngx_uint_t i, dir_tested; ngx_http_index_t *index; ngx_open_file_info_t of; ngx_http_script_code_pt code; ngx_http_script_engine_t e; ngx_http_core_loc_conf_t *clcf; ngx_http_index_loc_conf_t *ilcf; ngx_http_script_len_code_pt lcode; if (r->uri.data[r->uri.len - 1] != '/') { // uri不是“/”结尾时,说明uri中最后指定了文件,index和autoindex模块将不处理,交由static模块处理 return NGX_DECLINED; } if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_POST))) { return NGX_DECLINED; } // 这里获取的r->loc_conf可能是server层的也有可能是location层的,需要检查是否有匹配到配置文件中的Location ilcf = ngx_http_get_module_loc_conf(r, ngx_http_index_module); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); allocated = 0; root = 0; dir_tested = 0; name = NULL; /* suppress MSVC warning */ path.data = NULL; index = ilcf->indices->elts; for (i = 0; i < ilcf->indices->nelts; i++) { // 遍历index指令指定的每个参数 if (index[i].lengths == NULL) { // index指令参数中没有使用变量时 if (index[i].name.data[0] == '/') { // index指定的参数以"/"开始的, 将产生内部重定向。 return ngx_http_internal_redirect(r, &index[i].name, &r->args); } reserve = ilcf->max_index_len; len = index[i].name.len; } else { // index指令参数使用了变量 // 计算index指令参数指定的变量+常量字符串的长度 ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); e.ip = index[i].lengths->elts; e.request = r; e.flushed = 1; /* 1 is for terminating '\0' as in static names */ len = 1; while (*(uintptr_t *) e.ip) { lcode = *(ngx_http_script_len_code_pt *) e.ip; len += lcode(&e); } /* 16 bytes are preallocation */ reserve = len + 16; } if (reserve > allocated) { name = ngx_http_map_uri_to_path(r, &path, &root, reserve); if (name == NULL) { return NGX_ERROR; } allocated = path.data + path.len - name; // ??? } if (index[i].values == NULL) { /* index[i].name.len includes the terminating '\0' */ ngx_memcpy(name, index[i].name.data, index[i].name.len); // 拷贝index指令指定的参数(e.g. "/usr/local/nginx/html/index1/index.html") path.len = (name + index[i].name.len - 1) - path.data; } else { e.ip = index[i].values->elts; e.pos = name; while (*(uintptr_t *) e.ip) { code = *(ngx_http_script_code_pt *) e.ip; code((ngx_http_script_engine_t *) &e); } if (*name == '/') { uri.len = len - 1; uri.data = name; return ngx_http_internal_redirect(r, &uri, &r->args); } path.len = e.pos - path.data; *e.pos = '\0'; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "open index \"%V\"", &path); ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.read_ahead = clcf->read_ahead; of.directio = clcf->directio; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.test_only = 1; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, of.err, "%s \"%s\" failed", of.failed, path.data); if (of.err == 0) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } #if (NGX_HAVE_OPENAT) if (of.err == NGX_EMLINK || of.err == NGX_ELOOP) { return NGX_HTTP_FORBIDDEN; } #endif if (of.err == NGX_ENOTDIR || of.err == NGX_ENAMETOOLONG || of.err == NGX_EACCES) { return ngx_http_index_error(r, clcf, path.data, of.err); } if (!dir_tested) { rc = ngx_http_index_test_dir(r, clcf, path.data, name - 1); if (rc != NGX_OK) { return rc; } dir_tested = 1; } if (of.err == NGX_ENOENT) { continue; } ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err, "%s \"%s\" failed", of.failed, path.data); return NGX_HTTP_INTERNAL_SERVER_ERROR; } uri.len = r->uri.len + len - 1; if (!clcf->alias) { uri.data = path.data + root; } else { uri.data = ngx_pnalloc(r->pool, uri.len); if (uri.data == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } p = ngx_copy(uri.data, r->uri.data, r->uri.len); ngx_memcpy(p, name, len - 1); } return ngx_http_internal_redirect(r, &uri, &r->args); }// End for return NGX_DECLINED; }
static ngx_int_t ngx_http_index_handler(ngx_http_request_t *r) { u_char *p, *name; size_t len, root, reserve, allocated; ngx_int_t rc; ngx_str_t path, uri; ngx_uint_t i, dir_tested; ngx_http_index_t *index; ngx_open_file_info_t of; ngx_http_script_code_pt code; ngx_http_script_engine_t e; ngx_http_core_loc_conf_t *clcf; ngx_http_index_loc_conf_t *ilcf; ngx_http_script_len_code_pt lcode; if (r->uri.data[r->uri.len - 1] != '/') { return NGX_DECLINED; } if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_POST))) { return NGX_DECLINED; } ilcf = ngx_http_get_module_loc_conf(r, ngx_http_index_module); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); allocated = 0; root = 0; dir_tested = 0; name = NULL; /* suppress MSVC warning */ path.data = NULL; index = ilcf->indices->elts; for (i = 0; i < ilcf->indices->nelts; i++) { if (index[i].lengths == NULL) { if (index[i].name.data[0] == '/') { return ngx_http_internal_redirect(r, &index[i].name, &r->args); } reserve = ilcf->max_index_len; len = index[i].name.len; } else { ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); e.ip = index[i].lengths->elts; e.request = r; e.flushed = 1; /* 1 is for terminating '\0' as in static names */ len = 1; while (*(uintptr_t *) e.ip) { lcode = *(ngx_http_script_len_code_pt *) e.ip; len += lcode(&e); } /* 16 bytes are preallocation */ reserve = len + 16; } if (reserve > allocated) { name = ngx_http_map_uri_to_path(r, &path, &root, reserve); if (name == NULL) { return NGX_ERROR; } allocated = path.data + path.len - name; } if (index[i].values == NULL) { /* index[i].name.len includes the terminating '\0' */ ngx_memcpy(name, index[i].name.data, index[i].name.len); path.len = (name + index[i].name.len - 1) - path.data; } else { e.ip = index[i].values->elts; e.pos = name; while (*(uintptr_t *) e.ip) { code = *(ngx_http_script_code_pt *) e.ip; code((ngx_http_script_engine_t *) &e); } if (*name == '/') { uri.len = len - 1; uri.data = name; return ngx_http_internal_redirect(r, &uri, &r->args); } path.len = e.pos - path.data; *e.pos = '\0'; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "open index \"%V\"", &path); ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.read_ahead = clcf->read_ahead; of.directio = clcf->directio; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.test_only = 1; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, of.err, "%s \"%s\" failed", of.failed, path.data); if (of.err == 0) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (of.err == NGX_ENOTDIR || of.err == NGX_ENAMETOOLONG || of.err == NGX_EACCES) { return ngx_http_index_error(r, clcf, path.data, of.err); } if (!dir_tested) { rc = ngx_http_index_test_dir(r, clcf, path.data, name - 1); if (rc != NGX_OK) { return rc; } dir_tested = 1; } if (of.err == NGX_ENOENT) { continue; } ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err, "%s \"%s\" failed", of.failed, path.data); return NGX_HTTP_INTERNAL_SERVER_ERROR; } uri.len = r->uri.len + len - 1; if (!clcf->alias) { uri.data = path.data + root; } else { uri.data = ngx_pnalloc(r->pool, uri.len); if (uri.data == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } p = ngx_copy(uri.data, r->uri.data, r->uri.len); ngx_memcpy(p, name, len - 1); } return ngx_http_internal_redirect(r, &uri, &r->args); } return NGX_DECLINED; }
static ngx_int_t ngx_http_autoindex_handler(ngx_http_request_t *r) { u_char *last, *filename, scale; off_t length; size_t len, utf_len, allocated, root; ngx_tm_t tm; ngx_err_t err; ngx_buf_t *b; ngx_int_t rc, size; ngx_str_t path; ngx_dir_t dir; ngx_uint_t i, level, utf8; ngx_pool_t *pool; ngx_time_t *tp; ngx_chain_t out; ngx_array_t entries; ngx_http_autoindex_entry_t *entry; ngx_http_autoindex_loc_conf_t *alcf; static char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; if (r->uri.data[r->uri.len - 1] != '/') { return NGX_DECLINED; } if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) { return NGX_DECLINED; } alcf = ngx_http_get_module_loc_conf(r, ngx_http_autoindex_module); if (!alcf->enable) { return NGX_DECLINED; } /* NGX_DIR_MASK_LEN is lesser than NGX_HTTP_AUTOINDEX_PREALLOCATE */ last = ngx_http_map_uri_to_path(r, &path, &root, NGX_HTTP_AUTOINDEX_PREALLOCATE); if (last == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } allocated = path.len; path.len = last - path.data; if (path.len > 1) { path.len--; } path.data[path.len] = '\0'; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http autoindex: \"%s\"", path.data); if (ngx_open_dir(&path, &dir) == NGX_ERROR) { err = ngx_errno; if (err == NGX_ENOENT || err == NGX_ENOTDIR || err == NGX_ENAMETOOLONG) { level = NGX_LOG_ERR; rc = NGX_HTTP_NOT_FOUND; } else if (err == NGX_EACCES) { level = NGX_LOG_ERR; rc = NGX_HTTP_FORBIDDEN; } else { level = NGX_LOG_CRIT; rc = NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_log_error(level, r->connection->log, err, ngx_open_dir_n " \"%s\" failed", path.data); return rc; } #if (NGX_SUPPRESS_WARN) /* MSVC thinks 'entries' may be used without having been initialized */ ngx_memzero(&entries, sizeof(ngx_array_t)); #endif /* TODO: pool should be temporary pool */ pool = r->pool; if (ngx_array_init(&entries, pool, 40, sizeof(ngx_http_autoindex_entry_t)) != NGX_OK) { return ngx_http_autoindex_error(r, &dir, &path); } r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_type_len = sizeof("text/html") - 1; ngx_str_set(&r->headers_out.content_type, "text/html"); rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { if (ngx_close_dir(&dir) == NGX_ERROR) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, ngx_close_dir_n " \"%V\" failed", &path); } return rc; } filename = path.data; filename[path.len] = '/'; if (r->headers_out.charset.len == 5 && ngx_strncasecmp(r->headers_out.charset.data, (u_char *) "utf-8", 5) == 0) { utf8 = 1; } else { utf8 = 0; } for ( ;; ) { ngx_set_errno(0); if (ngx_read_dir(&dir) == NGX_ERROR) { err = ngx_errno; if (err != NGX_ENOMOREFILES) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, ngx_read_dir_n " \"%V\" failed", &path); return ngx_http_autoindex_error(r, &dir, &path); } break; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http autoindex file: \"%s\"", ngx_de_name(&dir)); len = ngx_de_namelen(&dir); if (ngx_de_name(&dir)[0] == '.') { continue; } if (!dir.valid_info) { /* 1 byte for '/' and 1 byte for terminating '\0' */ if (path.len + 1 + len + 1 > allocated) { allocated = path.len + 1 + len + 1 + NGX_HTTP_AUTOINDEX_PREALLOCATE; filename = ngx_pnalloc(pool, allocated); if (filename == NULL) { return ngx_http_autoindex_error(r, &dir, &path); } last = ngx_cpystrn(filename, path.data, path.len + 1); *last++ = '/'; } ngx_cpystrn(last, ngx_de_name(&dir), len + 1); if (ngx_de_info(filename, &dir) == NGX_FILE_ERROR) { err = ngx_errno; if (err != NGX_ENOENT) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, ngx_de_info_n " \"%s\" failed", filename); if (err == NGX_EACCES) { continue; } return ngx_http_autoindex_error(r, &dir, &path); } if (ngx_de_link_info(filename, &dir) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, ngx_de_link_info_n " \"%s\" failed", filename); return ngx_http_autoindex_error(r, &dir, &path); } } } entry = ngx_array_push(&entries); if (entry == NULL) { return ngx_http_autoindex_error(r, &dir, &path); } entry->name.len = len; entry->name.data = ngx_pnalloc(pool, len + 1); if (entry->name.data == NULL) { return ngx_http_autoindex_error(r, &dir, &path); } ngx_cpystrn(entry->name.data, ngx_de_name(&dir), len + 1); entry->escape = 2 * ngx_escape_uri(NULL, ngx_de_name(&dir), len, NGX_ESCAPE_HTML); if (utf8) { entry->utf_len = ngx_utf8_length(entry->name.data, entry->name.len); } else { entry->utf_len = len; } entry->colon = (ngx_strchr(entry->name.data, ':') != NULL); entry->dir = ngx_de_is_dir(&dir); entry->mtime = ngx_de_mtime(&dir); entry->size = ngx_de_size(&dir); } if (ngx_close_dir(&dir) == NGX_ERROR) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, ngx_close_dir_n " \"%s\" failed", &path); } len = sizeof(title) - 1 + r->uri.len + sizeof(header) - 1 + r->uri.len + sizeof("</h1>") - 1 + sizeof("<hr><pre><a href=\"../\">../</a>" CRLF) - 1 + sizeof("</pre><hr>") - 1 + sizeof(tail) - 1; entry = entries.elts; for (i = 0; i < entries.nelts; i++) { len += sizeof("<a href=\"") - 1 + entry[i].name.len + entry[i].escape + 1 /* 1 is for "/" */ + sizeof("\">") - 1 + entry[i].name.len - entry[i].utf_len + entry[i].colon * 2 + NGX_HTTP_AUTOINDEX_NAME_LEN + sizeof(">") - 2 + sizeof("</a>") - 1 + sizeof(" 28-Sep-1970 12:00 ") - 1 + 20 /* the file size */ + 2; } b = ngx_create_temp_buf(r->pool, len); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (entries.nelts > 1) { ngx_qsort(entry, (size_t) entries.nelts, sizeof(ngx_http_autoindex_entry_t), ngx_http_autoindex_cmp_entries); } b->last = ngx_cpymem(b->last, title, sizeof(title) - 1); b->last = ngx_cpymem(b->last, r->uri.data, r->uri.len); b->last = ngx_cpymem(b->last, header, sizeof(header) - 1); b->last = ngx_cpymem(b->last, r->uri.data, r->uri.len); b->last = ngx_cpymem(b->last, "</h1>", sizeof("</h1>") - 1); b->last = ngx_cpymem(b->last, "<hr><pre><a href=\"../\">../</a>" CRLF, sizeof("<hr><pre><a href=\"../\">../</a>" CRLF) - 1); tp = ngx_timeofday(); for (i = 0; i < entries.nelts; i++) { b->last = ngx_cpymem(b->last, "<a href=\"", sizeof("<a href=\"") - 1); if (entry[i].colon) { *b->last++ = '.'; *b->last++ = '/'; } if (entry[i].escape) { ngx_escape_uri(b->last, entry[i].name.data, entry[i].name.len, NGX_ESCAPE_HTML); b->last += entry[i].name.len + entry[i].escape; } else { b->last = ngx_cpymem(b->last, entry[i].name.data, entry[i].name.len); } if (entry[i].dir) { *b->last++ = '/'; } *b->last++ = '"'; *b->last++ = '>'; len = entry[i].utf_len; if (entry[i].name.len != len) { if (len > NGX_HTTP_AUTOINDEX_NAME_LEN) { utf_len = NGX_HTTP_AUTOINDEX_NAME_LEN - 3 + 1; } else { utf_len = NGX_HTTP_AUTOINDEX_NAME_LEN + 1; } b->last = ngx_utf8_cpystrn(b->last, entry[i].name.data, utf_len, entry[i].name.len + 1); last = b->last; } else { b->last = ngx_cpystrn(b->last, entry[i].name.data, NGX_HTTP_AUTOINDEX_NAME_LEN + 1); last = b->last - 3; } if (len > NGX_HTTP_AUTOINDEX_NAME_LEN) { b->last = ngx_cpymem(last, "..></a>", sizeof("..></a>") - 1); } else { if (entry[i].dir && NGX_HTTP_AUTOINDEX_NAME_LEN - len > 0) { *b->last++ = '/'; len++; } b->last = ngx_cpymem(b->last, "</a>", sizeof("</a>") - 1); ngx_memset(b->last, ' ', NGX_HTTP_AUTOINDEX_NAME_LEN - len); b->last += NGX_HTTP_AUTOINDEX_NAME_LEN - len; } *b->last++ = ' '; ngx_gmtime(entry[i].mtime + tp->gmtoff * 60 * alcf->localtime, &tm); b->last = ngx_sprintf(b->last, "%02d-%s-%d %02d:%02d ", tm.ngx_tm_mday, months[tm.ngx_tm_mon - 1], tm.ngx_tm_year, tm.ngx_tm_hour, tm.ngx_tm_min); if (alcf->exact_size) { if (entry[i].dir) { b->last = ngx_cpymem(b->last, " -", sizeof(" -") - 1); } else { b->last = ngx_sprintf(b->last, "%19O", entry[i].size); } } else { if (entry[i].dir) { b->last = ngx_cpymem(b->last, " -", sizeof(" -") - 1); } else { length = entry[i].size; if (length > 1024 * 1024 * 1024 - 1) { size = (ngx_int_t) (length / (1024 * 1024 * 1024)); if ((length % (1024 * 1024 * 1024)) > (1024 * 1024 * 1024 / 2 - 1)) { size++; } scale = 'G'; } else if (length > 1024 * 1024 - 1) { size = (ngx_int_t) (length / (1024 * 1024)); if ((length % (1024 * 1024)) > (1024 * 1024 / 2 - 1)) { size++; } scale = 'M'; } else if (length > 9999) { size = (ngx_int_t) (length / 1024); if (length % 1024 > 511) { size++; } scale = 'K'; } else { size = (ngx_int_t) length; scale = '\0'; } if (scale) { b->last = ngx_sprintf(b->last, "%6i%c", size, scale); } else { b->last = ngx_sprintf(b->last, " %6i", size); } } } *b->last++ = CR; *b->last++ = LF; } /* TODO: free temporary pool */ b->last = ngx_cpymem(b->last, "</pre><hr>", sizeof("</pre><hr>") - 1); b->last = ngx_cpymem(b->last, tail, sizeof(tail) - 1); if (r == r->main) { b->last_buf = 1; } b->last_in_chain = 1; out.buf = b; out.next = NULL; return ngx_http_output_filter(r, &out); }
static ngx_int_t ngx_http_static_handler(ngx_http_request_t *r) { u_char *last, *location; size_t root, len; ngx_str_t path; ngx_int_t rc; ngx_uint_t level; ngx_log_t *log; ngx_buf_t *b; ngx_chain_t out; ngx_open_file_info_t of; ngx_http_core_loc_conf_t *clcf; if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_POST))) { return NGX_HTTP_NOT_ALLOWED; } if (r->uri.data[r->uri.len - 1] == '/') { return NGX_DECLINED; } log = r->connection->log; /* * ngx_http_map_uri_to_path() allocates memory for terminating '\0' * so we do not need to reserve memory for '/' for possible redirect */ last = ngx_http_map_uri_to_path(r, &path, &root, 0); if (last == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } path.len = last - path.data; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http filename: \"%s\"", path.data); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.read_ahead = clcf->read_ahead; of.directio = clcf->directio; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; #if (NGX_HAVE_OPENAT) of.disable_symlinks = clcf->disable_symlinks; #endif if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) { switch (of.err) { case 0: return NGX_HTTP_INTERNAL_SERVER_ERROR; case NGX_ENOENT: case NGX_ENOTDIR: case NGX_ENAMETOOLONG: level = NGX_LOG_ERR; rc = NGX_HTTP_NOT_FOUND; break; case NGX_EACCES: #if (NGX_HAVE_OPENAT) case NGX_EMLINK: case NGX_ELOOP: #endif level = NGX_LOG_ERR; rc = NGX_HTTP_FORBIDDEN; break; default: level = NGX_LOG_CRIT; rc = NGX_HTTP_INTERNAL_SERVER_ERROR; break; } if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) { ngx_log_error(level, log, of.err, "%s \"%s\" failed", of.failed, path.data); } return rc; } r->root_tested = !r->error_page; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", of.fd); if (of.is_dir) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http dir"); ngx_http_clear_location(r); r->headers_out.location = ngx_palloc(r->pool, sizeof(ngx_table_elt_t)); if (r->headers_out.location == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } len = r->uri.len + 1; if (!clcf->alias && clcf->root_lengths == NULL && r->args.len == 0) { location = path.data + clcf->root.len; *last = '/'; } else { if (r->args.len) { len += r->args.len + 1; } location = ngx_pnalloc(r->pool, len); if (location == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } last = ngx_copy(location, r->uri.data, r->uri.len); *last = '/'; if (r->args.len) { *++last = '?'; ngx_memcpy(++last, r->args.data, r->args.len); } } /* * we do not need to set the r->headers_out.location->hash and * r->headers_out.location->key fields */ r->headers_out.location->value.len = len; r->headers_out.location->value.data = location; return NGX_HTTP_MOVED_PERMANENTLY; } #if !(NGX_WIN32) /* the not regular files are probably Unix specific */ if (!of.is_file) { ngx_log_error(NGX_LOG_CRIT, log, 0, "\"%s\" is not a regular file", path.data); return NGX_HTTP_NOT_FOUND; } #endif if (r->method & NGX_HTTP_POST) { return NGX_HTTP_NOT_ALLOWED; } rc = ngx_http_discard_request_body(r); if (rc != NGX_OK) { return rc; } log->action = "sending response to client"; r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = of.size; r->headers_out.last_modified_time = of.mtime; if (ngx_http_set_content_type(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (r != r->main && of.size == 0) { return ngx_http_send_header(r); } r->allow_ranges = 1; /* we need to allocate all before the header would be sent */ b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)); if (b->file == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } b->file_pos = 0; b->file_last = of.size; b->in_file = b->file_last ? 1: 0; b->last_buf = (r == r->main) ? 1: 0; b->last_in_chain = 1; b->file->fd = of.fd; b->file->name = path; b->file->log = log; b->file->directio = of.is_directio; out.buf = b; out.next = NULL; return ngx_http_output_filter(r, &out); }
static ngx_inline ngx_int_t make_content_buf( ngx_http_request_t *r, ngx_buf_t **pb, ngx_http_fancyindex_loc_conf_t *alcf) { ngx_http_fancyindex_entry_t *entry; off_t length; size_t len, root, copy, allocated; u_char *filename, *last, scale; ngx_tm_t tm; ngx_array_t entries; ngx_time_t *tp; ngx_uint_t i; ngx_int_t size; ngx_str_t path; ngx_dir_t dir; ngx_buf_t *b; static char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", }; /* * NGX_DIR_MASK_LEN is lesser than NGX_HTTP_FANCYINDEX_PREALLOCATE */ if ((last = ngx_http_map_uri_to_path(r, &path, &root, NGX_HTTP_FANCYINDEX_PREALLOCATE)) == NULL) return NGX_HTTP_INTERNAL_SERVER_ERROR; allocated = path.len; path.len = last - path.data - 1; path.data[path.len] = '\0'; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http fancyindex: \"%s\"", path.data); if (ngx_open_dir(&path, &dir) == NGX_ERROR) { ngx_int_t rc, err = ngx_errno; ngx_uint_t level; if (err == NGX_ENOENT || err == NGX_ENOTDIR || err == NGX_ENAMETOOLONG) { level = NGX_LOG_ERR; rc = NGX_HTTP_NOT_FOUND; } else if (err == NGX_EACCES) { level = NGX_LOG_ERR; rc = NGX_HTTP_FORBIDDEN; } else { level = NGX_LOG_CRIT; rc = NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_log_error(level, r->connection->log, err, ngx_open_dir_n " \"%s\" failed", path.data); return rc; } #if (NGX_SUPPRESS_WARN) /* MSVC thinks 'entries' may be used without having been initialized */ ngx_memzero(&entries, sizeof(ngx_array_t)); #endif /* NGX_SUPPRESS_WARN */ if (ngx_array_init(&entries, r->pool, 40, sizeof(ngx_http_fancyindex_entry_t)) != NGX_OK) return ngx_http_fancyindex_error(r, &dir, &path); filename = path.data; filename[path.len] = '/'; /* Read directory entries and their associated information. */ for (;;) { ngx_set_errno(0); if (ngx_read_dir(&dir) == NGX_ERROR) { ngx_int_t err = ngx_errno; if (err != NGX_ENOMOREFILES) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, ngx_read_dir_n " \"%V\" failed", &path); return ngx_http_fancyindex_error(r, &dir, &path); } break; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http fancyindex file: \"%s\"", ngx_de_name(&dir)); len = ngx_de_namelen(&dir); if (ngx_de_name(&dir)[0] == '.') continue; #if NGX_PCRE { ngx_str_t str = { len, ngx_de_name(&dir) }; if (alcf->ignore && ngx_regex_exec_array(alcf->ignore, &str, r->connection->log) != NGX_DECLINED) { continue; } } #else /* !NGX_PCRE */ if (alcf->ignore) { u_int match_found = 0; ngx_str_t *s = alcf->ignore->elts; for (i = 0; i < alcf->ignore->nelts; i++, s++) { if (ngx_strcmp(ngx_de_name(&dir), s->data) == 0) { match_found = 1; break; } } if (match_found) { continue; } } #endif /* NGX_PCRE */ if (!dir.valid_info) { /* 1 byte for '/' and 1 byte for terminating '\0' */ if (path.len + 1 + len + 1 > allocated) { allocated = path.len + 1 + len + 1 + NGX_HTTP_FANCYINDEX_PREALLOCATE; if ((filename = ngx_palloc(r->pool, allocated)) == NULL) return ngx_http_fancyindex_error(r, &dir, &path); last = ngx_cpystrn(filename, path.data, path.len + 1); *last++ = '/'; } ngx_cpystrn(last, ngx_de_name(&dir), len + 1); if (ngx_de_info(filename, &dir) == NGX_FILE_ERROR) { ngx_int_t err = ngx_errno; if (err != NGX_ENOENT) { ngx_log_error(NGX_LOG_ERR, r->connection->log, err, ngx_de_info_n " \"%s\" failed", filename); continue; } if (ngx_de_link_info(filename, &dir) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, ngx_de_link_info_n " \"%s\" failed", filename); return ngx_http_fancyindex_error(r, &dir, &path); } } } if ((entry = ngx_array_push(&entries)) == NULL) return ngx_http_fancyindex_error(r, &dir, &path); entry->name.len = len; entry->name.data = ngx_palloc(r->pool, len + 1); if (entry->name.data == NULL) return ngx_http_fancyindex_error(r, &dir, &path); ngx_cpystrn(entry->name.data, ngx_de_name(&dir), len + 1); entry->escape = 2 * ngx_fancyindex_escape_uri(NULL, ngx_de_name(&dir), len); entry->dir = ngx_de_is_dir(&dir); entry->mtime = ngx_de_mtime(&dir); entry->size = ngx_de_size(&dir); entry->utf_len = (r->headers_out.charset.len == 5 && ngx_strncasecmp(r->headers_out.charset.data, (u_char*) "utf-8", 5) == 0) ? ngx_utf8_length(entry->name.data, entry->name.len) : len; } if (ngx_close_dir(&dir) == NGX_ERROR) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, ngx_close_dir_n " \"%s\" failed", &path); } /* * Calculate needed buffer length. */ len = r->uri.len + ngx_sizeof_ssz(t05_body2) + ngx_sizeof_ssz(t06_list1) + ngx_sizeof_ssz(t07_list2) ; entry = entries.elts; for (i = 0; i < entries.nelts; i++) { /* * Genearated table rows are as follows, unneeded whitespace * is stripped out: * * <tr class="X"> * <td><a href="U">fname</a></td> * <td>size</td><td>date</td> * </tr> */ len += ngx_sizeof_ssz("<tr class=\"X\"><td><a href=\"") + entry[i].name.len + entry[i].escape /* Escaped URL */ + ngx_sizeof_ssz("\">") + entry[i].name.len + entry[i].utf_len + NGX_HTTP_FANCYINDEX_NAME_LEN + ngx_sizeof_ssz(">") + ngx_sizeof_ssz("</a></td><td>") + 20 /* File size */ + ngx_sizeof_ssz("</td><td>") + ngx_sizeof_ssz(" 28-Sep-1970 12:00 ") + ngx_sizeof_ssz("</td></tr>\n") + 2 /* CR LF */ ; } if ((b = ngx_create_temp_buf(r->pool, len)) == NULL) return NGX_HTTP_INTERNAL_SERVER_ERROR; /* Sort entries, if needed */ if (entries.nelts > 1) { ngx_qsort(entry, (size_t) entries.nelts, sizeof(ngx_http_fancyindex_entry_t), ngx_http_fancyindex_cmp_entries); } b->last = ngx_cpymem_str(b->last, r->uri); b->last = ngx_cpymem_ssz(b->last, t05_body2); b->last = ngx_cpymem_ssz(b->last, t06_list1); tp = ngx_timeofday(); for (i = 0; i < entries.nelts; i++) { static const char _evenodd[] = { 'e', 'o' }; b->last = ngx_cpymem_ssz(b->last, "<tr class=\""); *b->last++ = _evenodd[i & 0x01]; /* * Alternative implementation: * *b->last++ = (i & 0x01) ? 'e' : 'o'; */ b->last = ngx_cpymem_ssz(b->last, "\"><td><a href=\""); if (entry[i].escape) { ngx_fancyindex_escape_uri(b->last, entry[i].name.data, entry[i].name.len); b->last += entry[i].name.len + entry[i].escape; } else { b->last = ngx_cpymem_str(b->last, entry[i].name); } if (entry[i].dir) { *b->last++ = '/'; } *b->last++ = '"'; *b->last++ = '>'; len = entry[i].utf_len; if (entry[i].name.len - len) { if (len > NGX_HTTP_FANCYINDEX_NAME_LEN) { copy = NGX_HTTP_FANCYINDEX_NAME_LEN - 3 + 1; } else { copy = NGX_HTTP_FANCYINDEX_NAME_LEN + 1; } b->last = ngx_utf8_cpystrn(b->last, entry[i].name.data, copy, entry[i].name.len); last = b->last; } else { b->last = ngx_cpystrn(b->last, entry[i].name.data, NGX_HTTP_FANCYINDEX_NAME_LEN + 1); last = b->last - 3; } if (len > NGX_HTTP_FANCYINDEX_NAME_LEN) { b->last = ngx_cpymem_ssz(last, "..></a></td><td>"); } else { if (entry[i].dir && NGX_HTTP_FANCYINDEX_NAME_LEN - len > 0) { *b->last++ = '/'; len++; } b->last = ngx_cpymem_ssz(b->last, "</a></td><td>"); } if (alcf->exact_size) { if (entry[i].dir) { *b->last++ = '-'; } else { b->last = ngx_sprintf(b->last, "%19O", entry[i].size); } } else { if (entry[i].dir) { *b->last++ = '-'; } else { length = entry[i].size; if (length > 1024 * 1024 * 1024 - 1) { size = (ngx_int_t) (length / (1024 * 1024 * 1024)); if ((length % (1024 * 1024 * 1024)) > (1024 * 1024 * 1024 / 2 - 1)) { size++; } scale = 'G'; } else if (length > 1024 * 1024 - 1) { size = (ngx_int_t) (length / (1024 * 1024)); if ((length % (1024 * 1024)) > (1024 * 1024 / 2 - 1)) { size++; } scale = 'M'; } else if (length > 9999) { size = (ngx_int_t) (length / 1024); if (length % 1024 > 511) { size++; } scale = 'K'; } else { size = (ngx_int_t) length; scale = '\0'; } if (scale) { b->last = ngx_sprintf(b->last, "%6i%c", size, scale); } else { b->last = ngx_sprintf(b->last, " %6i", size); } } } ngx_gmtime(entry[i].mtime + tp->gmtoff * 60 * alcf->localtime, &tm); b->last = ngx_sprintf(b->last, "</td><td>%02d-%s-%d %02d:%02d</td></tr>", tm.ngx_tm_mday, months[tm.ngx_tm_mon - 1], tm.ngx_tm_year, tm.ngx_tm_hour, tm.ngx_tm_min); *b->last++ = CR; *b->last++ = LF; } /* Output table bottom */ b->last = ngx_cpymem_ssz(b->last, t07_list2); *pb = b; return NGX_OK; }
static ngx_int_t ngx_streaming_handler(ngx_http_request_t *r) { size_t root; ngx_int_t rc; ngx_uint_t level; ngx_str_t path; ngx_open_file_info_t of; ngx_http_core_loc_conf_t *clcf; if(!(r->method & (NGX_HTTP_GET | NGX_HTTP_HEAD))) return NGX_HTTP_NOT_ALLOWED; if(r->uri.data[r->uri.len - 1] == '/') return NGX_DECLINED; rc = ngx_http_discard_request_body(r); if(rc != NGX_OK) return rc; mp4_split_options_t *options = mp4_split_options_init(r); if(r->args.len && !mp4_split_options_set(r, options, (const char *)r->args.data, r->args.len)) { mp4_split_options_exit(r, options); return NGX_DECLINED; } if(!options) return NGX_DECLINED; if(!ngx_http_map_uri_to_path(r, &path, &root, 1)) { mp4_split_options_exit(r, options); return NGX_HTTP_INTERNAL_SERVER_ERROR; } u_int m3u8 = 0; struct bucket_t *bucket = bucket_init(r); int result = 0; { if(ngx_strstr(path.data, "m3u8")) m3u8 = 1; char *ext = strrchr((const char *)path.data, '.'); strcpy(ext, ".mp4"); path.len = ((u_char *)ext - path.data) + 4; // ngx_open_and_stat_file in ngx_open_cached_file expects the name to be zero-terminated. path.data[path.len] = '\0'; } ngx_log_t *nlog = r->connection->log; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, nlog, 0, "http mp4 filename: \"%s\"", path.data); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.read_ahead = clcf->read_ahead; of.directio = NGX_MAX_OFF_T_VALUE; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; if(ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) { mp4_split_options_exit(r, options); switch(of.err) { case 0: return NGX_HTTP_INTERNAL_SERVER_ERROR; case NGX_ENOENT: case NGX_ENOTDIR: case NGX_ENAMETOOLONG: level = NGX_LOG_ERR; rc = NGX_HTTP_NOT_FOUND; break; case NGX_EACCES: level = NGX_LOG_ERR; rc = NGX_HTTP_FORBIDDEN; break; default: level = NGX_LOG_CRIT; rc = NGX_HTTP_INTERNAL_SERVER_ERROR; break; } if(rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) { ngx_log_error(level, nlog, of.err, ngx_open_file_n " \"%s\" failed", path.data); } return rc; } if(!of.is_file) { mp4_split_options_exit(r, options); if(ngx_close_file(of.fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, nlog, ngx_errno, ngx_close_file_n " \"%s\" failed", path.data); } return NGX_DECLINED; } ngx_file_t *file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)); if(file == NULL) { mp4_split_options_exit(r, options); return NGX_HTTP_INTERNAL_SERVER_ERROR; } file->fd = of.fd; file->name = path; file->log = nlog; mp4_context_t *mp4_context = mp4_open(r, file, of.size, MP4_OPEN_MOOV); if(!mp4_context) { mp4_split_options_exit(r, options); ngx_log_error(NGX_LOG_ALERT, nlog, ngx_errno, "mp4_open failed"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } mp4_context->root = root; if(m3u8) { if((result = mp4_create_m3u8(mp4_context, bucket))) { char action[50]; sprintf(action, "ios_playlist&segments=%d", result); view_count(mp4_context, (char *)path.data, options ? options->hash : NULL, action); } r->allow_ranges = 0; } else { result = output_ts(mp4_context, bucket, options); if(!options || !result) { mp4_close(mp4_context); ngx_log_error(NGX_LOG_ALERT, nlog, ngx_errno, "output_ts failed"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } char action[50] = "ios_view"; view_count(mp4_context, (char *)path.data, options->hash, action); r->allow_ranges = 1; } mp4_close(mp4_context); mp4_split_options_exit(r, options); result = result == 0 ? 415 : 200; r->root_tested = !r->error_page; if(result && bucket) { nlog->action = "sending mp4 to client"; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, nlog, 0, "content_length: %d", bucket->content_length); r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = bucket->content_length; r->headers_out.last_modified_time = of.mtime; if (ngx_http_set_content_type(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } //ngx_table_elt_t *h = ngx_list_push(&r->headers_out.headers); //if(h == NULL) return NGX_HTTP_INTERNAL_SERVER_ERROR; //h->hash = 1; //h->key.len = sizeof(X_MOD_HLS_KEY) - 1; //h->key.data = (u_char *)X_MOD_HLS_KEY; //h->value.len = sizeof(X_MOD_HLS_VERSION) - 1; //h->value.data = (u_char *)X_MOD_HLS_VERSION; rc = ngx_http_send_header(r); if(rc == NGX_ERROR || rc > NGX_OK || r->header_only) { ngx_log_error(NGX_LOG_ALERT, nlog, ngx_errno, ngx_close_file_n "ngx_http_send_header failed"); return rc; } return ngx_http_output_filter(r, bucket->first); } else return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE; }
static ssize_t ngx_http_log_script_write(ngx_http_request_t *r, ngx_http_log_script_t *script, u_char **name, u_char *buf, size_t len) { syslog(LOG_INFO, "[%s:%s:%d]", __FILE__, __func__, __LINE__); size_t root; ssize_t n; ngx_str_t log, path; ngx_open_file_info_t of; ngx_http_log_loc_conf_t *llcf; ngx_http_core_loc_conf_t *clcf; clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (!r->root_tested) { /* test root directory existence */ if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) { /* simulate successful logging */ return len; } path.data[root] = '\0'; ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.test_dir = 1; of.test_only = 1; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) { /* simulate successful logging */ return len; } if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) { if (of.err == 0) { /* simulate successful logging */ return len; } ngx_log_error(NGX_LOG_ERR, r->connection->log, of.err, "testing \"%s\" existence failed", path.data); /* simulate successful logging */ return len; } if (!of.is_dir) { ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_ENOTDIR, "testing \"%s\" existence failed", path.data); /* simulate successful logging */ return len; } } if (ngx_http_script_run(r, &log, script->lengths->elts, 1, script->values->elts) == NULL) { /* simulate successful logging */ return len; } log.data[log.len - 1] = '\0'; *name = log.data; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http log \"%s\"", log.data); llcf = ngx_http_get_module_loc_conf(r, ngx_http_log_module); ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.log = 1; of.valid = llcf->open_file_cache_valid; of.min_uses = llcf->open_file_cache_min_uses; of.directio = NGX_OPEN_FILE_DIRECTIO_OFF; if (ngx_http_set_disable_symlinks(r, clcf, &log, &of) != NGX_OK) { /* simulate successful logging */ return len; } if (ngx_open_cached_file(llcf->open_file_cache, &log, &of, r->pool) != NGX_OK) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, "%s \"%s\" failed", of.failed, log.data); /* simulate successful logging */ return len; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http log #%d", of.fd); n = ngx_write_fd(of.fd, buf, len); return n; }
static ngx_inline ngx_int_t ngx_http_modsecurity_load_request(ngx_http_request_t *r) { ngx_http_modsecurity_ctx_t *ctx; request_rec *req; ngx_str_t str; size_t root; ngx_str_t path; ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity); req = ctx->req; /* request line */ req->method = (char *)ngx_pstrdup0(r->pool, &r->method_name); /* TODO: how to use ap_method_number_of ? * req->method_number = ap_method_number_of(req->method); */ req->method_number = ngx_http_modsecurity_method_number(r->method); /* ngx_http_map_uri_to_path() allocates memory for terminating '\0' */ if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) { return NGX_ERROR; } req->filename = (char *) path.data; req->path_info = req->filename; req->args = (char *)ngx_pstrdup0(r->pool, &r->args); req->proto_num = r->http_major *1000 + r->http_minor; req->protocol = (char *)ngx_pstrdup0(r->pool, &r->http_protocol); req->request_time = apr_time_make(r->start_sec, r->start_msec); req->the_request = (char *)ngx_pstrdup0(r->pool, &r->request_line); req->unparsed_uri = (char *)ngx_pstrdup0(r->pool, &r->unparsed_uri); req->uri = (char *)ngx_pstrdup0(r->pool, &r->uri); req->parsed_uri.scheme = "http"; #if (NGX_HTTP_SSL) if (r->connection->ssl) { req->parsed_uri.scheme = "https"; } #endif req->parsed_uri.path = (char *)ngx_pstrdup0(r->pool, &r->uri); req->parsed_uri.is_initialized = 1; str.data = r->port_start; str.len = r->port_end - r->port_start; req->parsed_uri.port = ngx_atoi(str.data, str.len); req->parsed_uri.port_str = (char *)ngx_pstrdup0(r->pool, &str); req->parsed_uri.query = r->args.len ? req->args : NULL; req->parsed_uri.dns_looked_up = 0; req->parsed_uri.dns_resolved = 0; // req->parsed_uri.password = (char *)ngx_pstrdup0(r->pool, &r->headers_in.passwd); // req->parsed_uri.user = (char *)ngx_pstrdup0(r->pool, &r->headers_in.user); req->parsed_uri.fragment = (char *)ngx_pstrdup0(r->pool, &r->exten); req->hostname = (char *)ngx_pstrdup0(r->pool, (ngx_str_t *)&ngx_cycle->hostname); req->header_only = r->header_only ? r->header_only : (r->method == NGX_HTTP_HEAD); return NGX_OK; }
static ngx_int_t ngx_http_dav_ext_send_propfind(ngx_http_request_t *r) { size_t root; ngx_str_t path, spath, suri; ngx_chain_t *l = NULL, **ll = &l; DIR *dir; int depth; struct dirent *de; size_t len; ngx_http_variable_value_t vv; ngx_str_t depth_name = ngx_string("depth"); u_char *p; if (ngx_http_variable_unknown_header(&vv, &depth_name, &r->headers_in.headers.part, 0) == NGX_OK && vv.valid) { if (vv.len == sizeof("infinity") -1 && !ngx_strncasecmp(vv.data, (u_char*)"infinity", vv.len)) { depth = DAV_EXT_INFINITY; } else { depth = ngx_atoi(vv.data, vv.len); } } else { depth = DAV_EXT_INFINITY; } p = ngx_http_map_uri_to_path(r, &path, &root, 0); if (p == NULL || !path.len) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "dav_ext error mapping uri to path"); return NGX_ERROR; } path.len = p - path.data; *p = 0; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http propfind path: \"%V\"", &path); NGX_HTTP_DAV_EXT_OUTL( "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" "<D:multistatus xmlns:D=\"DAV:\">\n" ); ngx_http_dav_ext_flush(r, ll); ngx_http_dav_ext_send_propfind_item(r, (char*)path.data, &r->uri); if (depth) { /* treat infinite depth as 1 for performance reasons */ if ((dir = opendir((char*)path.data))) { while((de = readdir(dir))) { if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) { continue; } len = strlen(de->d_name); ngx_http_dav_ext_make_child(r->pool, &path, (u_char*)de->d_name, len, &spath); ngx_http_dav_ext_make_child(r->pool, &r->uri, (u_char*)de->d_name, len, &suri); ngx_http_dav_ext_send_propfind_item(r, (char*)spath.data, &suri); } closedir(dir); } } NGX_HTTP_DAV_EXT_OUTL( "</D:multistatus>\n" ); if (*ll && (*ll)->buf) { (*ll)->buf->last_buf = 1; } ngx_http_dav_ext_flush(r, ll); return NGX_OK; }
static ngx_int_t ngx_http_f4fhds_handler(ngx_http_request_t *r) { ngx_int_t rc; ngx_chain_t out; u_char *resp_body; ngx_buf_t *resp; char *lastslash; char *segsuffix; size_t root; ngx_str_t path; ngx_str_t index_map = ngx_null_string; ngx_str_t mediafile_map = ngx_null_string; unsigned fragnum; uint32_t totalsize; ngx_table_elt_t *self; unsigned afraentries; unsigned g_afraentries, g_entry_size = 0; unsigned globaltable_offset; unsigned long long afraoffset = 0, offsetfromafra = 0; unsigned entryindex = 0; if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) { return NGX_HTTP_NOT_ALLOWED; } if ( (rc = ngx_http_discard_request_body(r)) != NGX_OK ) { return rc; } if ( (self = ngx_list_push(&r->headers_out.headers)) == NULL ) { ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "Insufficient memory for ngx_list_push"); return NGX_ERROR; } self->hash = 1; ngx_str_set(&self->key, "X-Inventos-F4FHDS-Version"); ngx_str_set(&self->value, VERSION); ngx_http_map_uri_to_path(r, &path, &root, 0); ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "path=%s", path.data); lastslash = strrchr((char*)path.data, '/'); ++lastslash; segsuffix = (char *)memmem(lastslash, path.len - (lastslash - (char *)path.data), "Seg1-Frag", 9); if ( segsuffix == NULL ) { return NGX_HTTP_NOT_FOUND; } segsuffix += 4; /* "Seg1" */ fragnum = atoi(segsuffix + /* "-Frag" */ 5); if ( fragnum < 1 ) { return NGX_HTTP_NOT_FOUND; } memcpy(segsuffix, ".f4x", 4); path.len = segsuffix - (char*)path.data + 4; segsuffix[4] = 0; ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "f4x_path=%s", path.data); if ( (rc = make_mapping((const char *)path.data, &index_map, r)) != NGX_OK ) { return rc; } if ( index_map.len < 8 ) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Wrong f4x afra size: %d in %s", index_map.len, path.data); goto GENERAL_ERROR; } if ( memcmp(index_map.data + 4, "afra", 4) != 0 ) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Wrong f4x format: %s", path.data); goto GENERAL_ERROR; } if ( getboxlen(index_map.data) != index_map.len ) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Wrong f4x prefix size: %d in %s", get32(index_map.data), path.data); goto GENERAL_ERROR; } if ( (index_map.data[12] & 0x20) == 0 ) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Global entries are not present in %s", path.data); goto GENERAL_ERROR; } afraentries = get32(index_map.data + 17); globaltable_offset = 17 + 4 + afraentries * (8 /* time */ + ((index_map.data[12] & 0x40) ? 8 : 4)) + 4; if ( index_map.len < globaltable_offset ) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Index file too short: %s", path.data); goto GENERAL_ERROR; } g_afraentries = get32(index_map.data + globaltable_offset - 4); switch ( index_map.data[12] & 0xc0 ) { case 0xc0: g_entry_size = 32; break; case 0x80: g_entry_size = 24; break; case 0x40: g_entry_size = 28; break; case 0: g_entry_size = 20; break; } ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "globaltable_offset=%d, afraentries=%d, g_afraentries=%d, entrysize=%d", globaltable_offset, afraentries, g_afraentries, g_entry_size ); if ( index_map.len < globaltable_offset + g_afraentries * g_entry_size ) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Index file too short: %s, len=%d, need=%d, globaltable_offset=%d, afraentries=%d, g_afraentries=%d, entrysize=%d", path.data, index_map.len, globaltable_offset + g_afraentries * g_entry_size, globaltable_offset, afraentries, g_afraentries, g_entry_size ); goto GENERAL_ERROR; } #define FIND_SEGMENT(SEGSIZE, FRAGSIZE, AOSIZE, OFASIZE) \ for ( entryindex = 0; entryindex < g_afraentries; ++entryindex ) { \ u_char *pentry = index_map.data + globaltable_offset + entryindex * g_entry_size; \ unsigned segment = get##SEGSIZE (pentry + 8); \ unsigned fragment = get##FRAGSIZE (pentry + 8 + SEGSIZE/8); \ if ( segment == 1 && fragment == fragnum ) { \ afraoffset = get##AOSIZE (pentry + 8 + SEGSIZE/8 + FRAGSIZE/8); \ offsetfromafra = get##OFASIZE (pentry + 8 + SEGSIZE/8 + FRAGSIZE/8 + AOSIZE/8); \ break; \ } \ } switch ( index_map.data[12] & 0xc0 ) { case 0xc0: FIND_SEGMENT(32, 32, 64, 64); break; case 0x80: FIND_SEGMENT(32, 32, 32, 32); break; case 0x40: FIND_SEGMENT(16, 16, 64, 64); break; case 0: FIND_SEGMENT(16, 16, 32, 32); break; } if ( entryindex == g_afraentries ) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Fragment #%d not found in %s, g_afraentries=%d", fragnum, path.data, g_afraentries); goto NOT_FOUND; } if ( offsetfromafra != 0 ) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "OffsetFromAfra=%llu not supported, %s", offsetfromafra, path.data); goto GENERAL_ERROR; } memcpy(segsuffix, ".f4f", 4); if ( (rc = make_mapping((const char *)path.data, &mediafile_map, r)) != NGX_OK ) { return rc; } if ( mediafile_map.len < afraoffset + 8 ) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Mediafile is too short: %s", path.data); goto GENERAL_ERROR; } { const u_char *afra = mediafile_map.data + afraoffset; unsigned long long afralen = getboxlen(afra); const u_char *abst = afra + afralen; unsigned long long abstlen = getboxlen(abst); const u_char *moof = abst + abstlen; unsigned long long mooflen = getboxlen(moof); const u_char *mdat = moof + mooflen; unsigned long long mdatlen = getboxlen(mdat); totalsize = afralen + abstlen + mooflen + mdatlen; if ( (resp_body = ngx_pcalloc(r->pool, totalsize)) == NULL ) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Insufficient memory"); goto GENERAL_ERROR; } memcpy(resp_body, afra, totalsize); } if ( (resp = ngx_pcalloc(r->pool, sizeof(ngx_buf_t))) == NULL ) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Insufficient memory"); goto GENERAL_ERROR; } out.buf = resp; out.next = NULL; resp->pos = resp_body; resp->last = resp_body + totalsize; resp->memory = 1; resp->last_buf = 1; free_mapping(&index_map); free_mapping(&mediafile_map); r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = totalsize; rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only || r->method == NGX_HTTP_HEAD) { return rc; } return ngx_http_output_filter(r, &out); GENERAL_ERROR: free_mapping(&index_map); free_mapping(&mediafile_map); return NGX_HTTP_INTERNAL_SERVER_ERROR; NOT_FOUND: free_mapping(&index_map); free_mapping(&mediafile_map); return NGX_HTTP_NOT_FOUND; }
static ngx_int_t ngx_estreaming_handler(ngx_http_request_t * r) { size_t root; ngx_int_t rc; ngx_uint_t level; ngx_str_t path; ngx_open_file_info_t of; ngx_http_core_loc_conf_t *clcf; video_buffer *destination; if (!(r->method & (NGX_HTTP_GET | NGX_HTTP_HEAD))) return NGX_HTTP_NOT_ALLOWED; if (r->uri.data[r->uri.len - 1] == '/') return NGX_DECLINED; rc = ngx_http_discard_request_body(r); if (rc != NGX_OK) return rc; mp4_split_options_t * options = mp4_split_options_init(r); if (!ngx_http_map_uri_to_path(r, &path, &root, 1)) { mp4_split_options_exit(r, options); return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (r->args.len && !mp4_split_options_set(r, options, (const char *) r->args.data, r->args.len)) { mp4_split_options_exit(r, options); return NGX_DECLINED; } if (!options) return NGX_DECLINED; ngx_log_t * nlog = r->connection->log; struct bucket_t * bucket = bucket_init(r); int result = 0; u_int m3u8 = 0, len_ = 0; int64_t duration = 0; if (ngx_memcmp(r->exten.data, "mp4", r->exten.len) == 0) { return ngx_http_mp4_handler(r); } else if (ngx_memcmp(r->exten.data, "m3u8", r->exten.len) == 0) { m3u8 = 1; } else if (ngx_memcmp(r->exten.data, "len", r->exten.len) == 0) {// this is for length request len_ = 1; } else if (ngx_memcmp(r->exten.data, "ts", r->exten.len) == 0) { // don't do anything } else { return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE; } // change file name to mp4 // in order to lookup file in filesystem char *ext = strrchr((const char *) path.data, '.'); strcpy(ext, ".mp4"); path.len = ((u_char *) ext - path.data) + 4; path.data[path.len] = '\0'; clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ngx_memzero(&of, sizeof (ngx_open_file_info_t)); of.read_ahead = clcf->read_ahead; of.directio = NGX_MAX_OFF_T_VALUE; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) { mp4_split_options_exit(r, options); switch (of.err) { case 0: return NGX_HTTP_INTERNAL_SERVER_ERROR; case NGX_ENOENT: case NGX_ENOTDIR: case NGX_ENAMETOOLONG: level = NGX_LOG_ERR; rc = NGX_HTTP_NOT_FOUND; break; case NGX_EACCES: level = NGX_LOG_ERR; rc = NGX_HTTP_FORBIDDEN; break; default: level = NGX_LOG_CRIT; rc = NGX_HTTP_INTERNAL_SERVER_ERROR; break; } if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) { ngx_log_error(level, nlog, of.err, ngx_open_file_n " \"%s\" failed", path.data); } return rc; } if (!of.is_file) { mp4_split_options_exit(r, options); if (ngx_close_file(of.fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, nlog, ngx_errno, ngx_close_file_n " \"%s\" failed", path.data); } return NGX_DECLINED; } /* move atom to beginning of file if it's in the last*/ hls_conf_t *mlcf; mlcf = ngx_http_get_module_loc_conf(r, ngx_http_estreaming_module); if (mlcf->mp4_enhance == 1) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "examine mp4 filename: \"%V\"", &path); if (ngx_http_enable_fast_start(&path, of.fd, r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } } ngx_file_t *file = ngx_pcalloc(r->pool, sizeof (ngx_file_t)); if (file == NULL) { mp4_split_options_exit(r, options); return NGX_HTTP_INTERNAL_SERVER_ERROR; } file->fd = of.fd; file->name = path; file->log = nlog; mp4_context_t *mp4_context = mp4_open(r, file, of.size, MP4_OPEN_MOOV); if (!mp4_context) { mp4_split_options_exit(r, options); ngx_log_error(NGX_LOG_ALERT, nlog, ngx_errno, "mp4_open failed"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } mp4_context->root = root; if (m3u8 || len_) { int ret, video_width = 0; // only request for master playlist need to use ffmpeg api to open video // this takes time and cpu, we should avoid it as much as possible if ((m3u8) && (options->adbr || options->org)) goto no_ffmpeg; AVFormatContext *fmt_ctx = NULL; unsigned int i; av_register_all(); if ((ret = avformat_open_input(&fmt_ctx, (const char*) path.data, NULL, NULL)) < 0) { mp4_split_options_exit(r, options); mp4_close(mp4_context); if (fmt_ctx) avformat_close_input(&fmt_ctx); return NGX_HTTP_INTERNAL_SERVER_ERROR; } if ((ret = avformat_find_stream_info(fmt_ctx, NULL)) < 0) { if (fmt_ctx) avformat_close_input(&fmt_ctx); mp4_close(mp4_context); mp4_split_options_exit(r, options); av_log(NULL, AV_LOG_ERROR, "Cannot find stream information\n"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (len_) { duration = fmt_ctx->duration; u_char *buffer = (u_char *) ngx_palloc(mp4_context->r->pool, 10 * sizeof (char)); u_char * p = buffer; if (buffer == NULL) { mp4_split_options_exit(r, options); mp4_close(mp4_context); if (fmt_ctx) avformat_close_input(&fmt_ctx); return NGX_HTTP_INTERNAL_SERVER_ERROR; } // this is stolen from ffmpeg source code if (duration != AV_NOPTS_VALUE) { duration = duration + 5000; int secs; secs = duration / AV_TIME_BASE; p = ngx_sprintf(p, "%02d\n", secs); } else { p = ngx_sprintf(p, "N/A\n"); } bucket_insert(bucket, buffer, p - buffer); ngx_pfree(mp4_context->r->pool, buffer); if (fmt_ctx) avformat_close_input(&fmt_ctx); r->allow_ranges = 0; result = 1; goto response; } else { for (i = 0; i < fmt_ctx->nb_streams; i++) { AVStream *stream; AVCodecContext *codec_ctx; stream = fmt_ctx->streams[i]; codec_ctx = stream->codec; if (codec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) { av_log(NULL, AV_LOG_ERROR, "source video w:%d", codec_ctx->width); if (video_width == 0) { video_width = codec_ctx->width; } else if ((video_width != 0) && (video_width < codec_ctx->width)) { // has 2 video streams video_width = codec_ctx->width; } else break; } } avformat_close_input(&fmt_ctx); } // finish getting video width no_ffmpeg: if ((result = mp4_create_m3u8(mp4_context, bucket, options, video_width))) { char action[50]; sprintf(action, "ios_playlist&segments=%d", result); view_count(mp4_context, (char *) path.data, options ? options->hash : NULL, action); } r->allow_ranges = 0; } else { result = output_ts(mp4_context, bucket, options); if (!options || !result) { mp4_close(mp4_context); ngx_log_error(NGX_LOG_ALERT, nlog, ngx_errno, "output_ts failed"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (options->adbr) { destination = ngx_pcalloc(r->pool, sizeof (video_buffer)); destination->data = NULL; destination->len = 0; destination->pool = r->pool; if (ngx_estreaming_adaptive_bitrate(r, bucket->first, destination, options) == NGX_OK) { ngx_buf_t *b = ngx_pcalloc(r->pool, sizeof (ngx_buf_t)); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } bucket->first->buf = b; bucket->first->next = NULL; b->pos = destination->data; b->last = destination->data + (destination->len * sizeof (unsigned char)); b->memory = 1; b->last_buf = 1; bucket->content_length = destination->len; } ngx_pfree(r->pool, destination); } char action[50] = "ios_view"; view_count(mp4_context, (char *) path.data, options->hash, action); r->allow_ranges = 1; } response: mp4_close(mp4_context); mp4_split_options_exit(r, options); result = result == 0 ? 415 : 200; r->root_tested = !r->error_page; if (result && bucket) { nlog->action = "sending mp4 to client"; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, nlog, 0, "content_length: %d", bucket->content_length); if (bucket->content_length == 0) return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE; r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = bucket->content_length; r->headers_out.last_modified_time = of.mtime; if (m3u8) { r->headers_out.content_type.len = sizeof ("application/vnd.apple.mpegurl") - 1; r->headers_out.content_type.data = (u_char *) "application/vnd.apple.mpegurl"; } else if (len_) { r->headers_out.content_type.len = sizeof ("text/html") - 1; r->headers_out.content_type.data = (u_char *) "text/html"; } else { r->headers_out.content_type.len = sizeof ("video/MP2T") - 1; r->headers_out.content_type.data = (u_char *) "video/MP2T"; } rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { ngx_log_error(NGX_LOG_ALERT, nlog, ngx_errno, ngx_close_file_n "ngx_http_send_header failed"); return rc; } return ngx_http_output_filter(r, bucket->first); } else return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE; }
static ngx_inline ngx_int_t ngx_http_modsecurity_load_request(ngx_http_request_t *r) { ngx_http_modsecurity_ctx_t *ctx; request_rec *req; size_t root; ngx_str_t path; ngx_uint_t port; struct sockaddr_in *sin; #if (NGX_HAVE_INET6) struct sockaddr_in6 *sin6; #endif ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity); req = ctx->req; /* request line */ req->method = (char *)ngx_pstrdup0(r->pool, &r->method_name); /* TODO: how to use ap_method_number_of ? * req->method_number = ap_method_number_of(req->method); */ req->method_number = ngx_http_modsecurity_method_number(r->method); /* ngx_http_map_uri_to_path() allocates memory for terminating '\0' */ if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) { return NGX_ERROR; } req->filename = (char *) path.data; req->path_info = req->filename; req->args = (char *)ngx_pstrdup0(r->pool, &r->args); req->proto_num = r->http_major *1000 + r->http_minor; req->protocol = (char *)ngx_pstrdup0(r->pool, &r->http_protocol); req->request_time = apr_time_make(r->start_sec, r->start_msec); req->the_request = (char *)ngx_pstrdup0(r->pool, &r->request_line); req->unparsed_uri = (char *)ngx_pstrdup0(r->pool, &r->unparsed_uri); req->uri = (char *)ngx_pstrdup0(r->pool, &r->uri); req->parsed_uri.scheme = "http"; #if (NGX_HTTP_SSL) if (r->connection->ssl) { req->parsed_uri.scheme = "https"; } #endif req->parsed_uri.path = (char *)ngx_pstrdup0(r->pool, &r->uri); req->parsed_uri.is_initialized = 1; switch (r->connection->local_sockaddr->sa_family) { #if (NGX_HAVE_INET6) case AF_INET6: sin6 = (struct sockaddr_in6 *) r->connection->local_sockaddr; port = ntohs(sin6->sin6_port); break; #endif #if (NGX_HAVE_UNIX_DOMAIN) case AF_UNIX: port = 0; break; #endif default: /* AF_INET */ sin = (struct sockaddr_in *) r->connection->local_sockaddr; port = ntohs(sin->sin_port); break; } req->parsed_uri.port = port; req->parsed_uri.port_str = ngx_pnalloc(r->pool, sizeof("65535")); (void) ngx_sprintf((u_char *)req->parsed_uri.port_str, "%ui%c", port, '\0'); req->parsed_uri.query = r->args.len ? req->args : NULL; req->parsed_uri.dns_looked_up = 0; req->parsed_uri.dns_resolved = 0; // req->parsed_uri.password = (char *)ngx_pstrdup0(r->pool, &r->headers_in.passwd); // req->parsed_uri.user = (char *)ngx_pstrdup0(r->pool, &r->headers_in.user); req->parsed_uri.fragment = (char *)ngx_pstrdup0(r->pool, &r->exten); req->hostname = (char *)ngx_pstrdup0(r->pool, (ngx_str_t *)&ngx_cycle->hostname); req->header_only = r->header_only ? r->header_only : (r->method == NGX_HTTP_HEAD); return NGX_OK; }
//ngx_http_static_module模块主要是在nginx系统中查找uri指定文件是否存在,存在则直接返回给客户端 static ngx_int_t ngx_http_static_handler(ngx_http_request_t *r) {//注意:ngx_http_static_handler如果uri不是以/结尾返回,ngx_http_index_handler不以/结尾返回 //ngx_http_static_handler ngx_http_index_handler每次都要获取缓存信息stat信息,因此每次获取很可能是上一次stat执行的时候获取的信息,除非缓存过期 u_char *last, *location; size_t root, len; ngx_str_t path; ngx_int_t rc; ngx_uint_t level; ngx_log_t *log; ngx_buf_t *b; ngx_chain_t out; ngx_open_file_info_t of; ngx_http_core_loc_conf_t *clcf; if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_POST))) { return NGX_HTTP_NOT_ALLOWED; } if (r->uri.data[r->uri.len - 1] == '/') { //注意:ngx_http_static_handler如果uri不是以/结尾返回,ngx_http_index_handler不以/结尾返回 return NGX_DECLINED; } log = r->connection->log; /* * ngx_http_map_uri_to_path() allocates memory for terminating '\0' * so we do not need to reserve memory for '/' for possible redirect */ last = ngx_http_map_uri_to_path(r, &path, &root, 0); //通过r->uri获取整个路径或者文件绝对路径 if (last == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } path.len = last - path.data; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http filename: \"%s\"", path.data); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.read_ahead = clcf->read_ahead; of.directio = clcf->directio; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) { switch (of.err) { case 0: return NGX_HTTP_INTERNAL_SERVER_ERROR; case NGX_ENOENT: case NGX_ENOTDIR: case NGX_ENAMETOOLONG: level = NGX_LOG_ERR; rc = NGX_HTTP_NOT_FOUND; break; case NGX_EACCES: #if (NGX_HAVE_OPENAT) case NGX_EMLINK: case NGX_ELOOP: #endif level = NGX_LOG_ERR; rc = NGX_HTTP_FORBIDDEN; break; default: level = NGX_LOG_CRIT; rc = NGX_HTTP_INTERNAL_SERVER_ERROR; break; } /* 如果文件不存在,则返回出去后会结束请求 2016/02/16 10:27:36[ ngx_http_static_handler, 139] [error] 19131#19131: *1 open() "/var/yyz/www/ttt/xx.html" failed (2: No such file or directory), client: 10.2.13.167, server: localhost, request: "GET / HTTP/1.1", host: "10.2.13.167" 2016/02/16 10:27:36[ ngx_http_finalize_request, 2598] [debug] 19131#19131: *1 http finalize request rc: 404, "/ttt/xx.html?" a:1, c:2 */ if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) { ngx_log_error(level, log, of.err, "%s \"%s\" failed", of.failed, path.data); } return rc; } r->root_tested = !r->error_page; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", of.fd); if (of.is_dir) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http dir"); ngx_http_clear_location(r); r->headers_out.location = ngx_palloc(r->pool, sizeof(ngx_table_elt_t)); if (r->headers_out.location == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } len = r->uri.len + 1; if (!clcf->alias && clcf->root_lengths == NULL && r->args.len == 0) { location = path.data + clcf->root.len; *last = '/'; } else { if (r->args.len) { len += r->args.len + 1; } location = ngx_pnalloc(r->pool, len); if (location == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } last = ngx_copy(location, r->uri.data, r->uri.len); *last = '/'; if (r->args.len) { *++last = '?'; ngx_memcpy(++last, r->args.data, r->args.len); } } /* * we do not need to set the r->headers_out.location->hash and * r->headers_out.location->key fields */ r->headers_out.location->value.len = len; r->headers_out.location->value.data = location; return NGX_HTTP_MOVED_PERMANENTLY; } #if !(NGX_WIN32) /* the not regular files are probably Unix specific */ if (!of.is_file) { ngx_log_error(NGX_LOG_CRIT, log, 0, "\"%s\" is not a regular file", path.data); return NGX_HTTP_NOT_FOUND; } #endif if (r->method & NGX_HTTP_POST) { return NGX_HTTP_NOT_ALLOWED; } rc = ngx_http_discard_request_body(r); if (rc != NGX_OK) { return rc; } log->action = "sending response to client"; r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = of.size; r->headers_out.last_modified_time = of.mtime; //文件最后被修改的时间 if (ngx_http_set_etag(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (ngx_http_set_content_type(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (r != r->main && of.size == 0) { return ngx_http_send_header(r); } r->allow_ranges = 1; /* we need to allocate all before the header would be sent */ b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)); if (b->file == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } b->file_pos = 0; b->file_last = of.size; b->in_file = b->file_last ? 1: 0; b->last_buf = (r == r->main) ? 1: 0; b->last_in_chain = 1; b->file->fd = of.fd; b->file->name = path; b->file->log = log; b->file->directio = of.is_directio; //注意这里如果文件大小大于direction设置,则置1,后面会使能direct I/O方式,见ngx_directio_on out.buf = b; out.next = NULL; return ngx_http_output_filter(r, &out); }
static ngx_int_t ngx_http_ts_split_handler(ngx_http_request_t *r) { u_char *last; size_t root; ngx_str_t path, index_path, media_path; ngx_str_t first, second, media_name; ngx_int_t rc, media_seq; ngx_uint_t media_begin, media_len; ngx_uint_t level; ngx_buf_t *b; ngx_chain_t out; ngx_open_file_info_t of; ngx_log_t *log; ngx_http_core_loc_conf_t *clcf; if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_POST))) { return NGX_HTTP_NOT_ALLOWED; } if (r->uri.data[r->uri.len - 1] == '/') { return NGX_DECLINED; } ngx_str_null(&media_name); ngx_str_null(&second); log = r->connection->log; /* * ngx_http_map_uri_to_path() allocates memory for terminating '\0' * so we do not need to reserve memory for '/' for possible redirect */ last = ngx_http_map_uri_to_path(r, &path, &root, 0); if (last == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } path.len = last - path.data; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http filename: \"%s\"", path.data); ngx_http_ts_split_rpartition(&path, &first, &second, '/'); index_path.len = first.len + sizeof("index.m3u8") + 1; index_path.data = ngx_palloc(r->pool, index_path.len); ngx_snprintf(index_path.data, index_path.len, "%V/index.m3u8", &first); index_path.data[index_path.len-1] = '\0'; media_name = ngx_http_ts_split_get_media_name(&second); media_path.len = first.len + 5 + media_name.len; media_path.data = ngx_palloc(r->pool, media_path.len); ngx_snprintf(media_path.data, media_path.len, "%V/%V.ts", &first, &media_name); media_path.data[media_path.len-1] = '\0'; media_seq = ngx_http_ts_split_get_media_seq(&second); media_begin = 0; media_len = 0; if (ngx_http_ts_split_index_info(r, &index_path, media_seq, &media_begin, &media_len) != NGX_OK) { return NGX_ERROR; } clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.read_ahead = clcf->read_ahead; of.directio = clcf->directio; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; if (ngx_http_set_disable_symlinks(r, clcf, &media_path, &of) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (ngx_open_cached_file(clcf->open_file_cache, &media_path, &of, r->pool) != NGX_OK) { switch (of.err) { case 0: return NGX_HTTP_INTERNAL_SERVER_ERROR; case NGX_ENOENT: case NGX_ENOTDIR: case NGX_ENAMETOOLONG: level = NGX_LOG_ERR; rc = NGX_HTTP_NOT_FOUND; break; case NGX_EACCES: #if (NGX_HAVE_OPENAT) case NGX_EMLINK: case NGX_ELOOP: #endif level = NGX_LOG_ERR; rc = NGX_HTTP_FORBIDDEN; break; default: level = NGX_LOG_CRIT; rc = NGX_HTTP_INTERNAL_SERVER_ERROR; break; } if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) { ngx_log_error(level, log, of.err, "%s \"%s\" failed", of.failed, media_path.data); } return rc; } r->root_tested = !r->error_page; #if !(NGX_WIN32) /* the not regular files are probably Unix specific */ if (!of.is_file) { ngx_log_error(NGX_LOG_CRIT, log, 0, "\"%s\" is not a regular file", path.data); return NGX_HTTP_NOT_FOUND; } #endif if (r->method & NGX_HTTP_POST) { return NGX_HTTP_NOT_ALLOWED; } rc = ngx_http_discard_request_body(r); if (rc != NGX_OK) { return rc; } log->action = "sending response to client"; r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = media_len; if (ngx_http_set_etag(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (ngx_http_set_content_type(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (r != r->main && of.size == 0) { return ngx_http_send_header(r); } /* we need to allocate all before the header would be sent */ b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)); if (b->file == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } b->file_pos = media_begin; b->file_last = media_begin + media_len; b->in_file = b->file_last ? 1: 0; b->last_buf = (r == r->main) ? 1: 0; b->last_in_chain = 1; b->file->fd = of.fd; b->file->name = media_path; b->file->log = log; b->file->directio = of.is_directio; out.buf = b; out.next = NULL; return ngx_http_output_filter(r, &out); }
static ngx_int_t ngx_http_slice_handler(ngx_http_request_t *r) { u_char *last; off_t begin, end, len; size_t root; ngx_int_t rc; ngx_uint_t level, i; ngx_str_t path, value; ngx_log_t *log; ngx_buf_t *b; ngx_chain_t out[3]; ngx_open_file_info_t of; ngx_http_core_loc_conf_t *clcf; ngx_http_slice_loc_conf_t *slcf; if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) { return NGX_HTTP_NOT_ALLOWED; } if (r->uri.data[r->uri.len - 1] == '/') { return NGX_DECLINED; } slcf = ngx_http_get_module_loc_conf(r, ngx_http_slice_module); rc = ngx_http_discard_request_body(r); if (rc != NGX_OK) { return rc; } last = ngx_http_map_uri_to_path(r, &path, &root, 0); if (last == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } log = r->connection->log; path.len = last - path.data; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http slice filename: \"%V\"", &path); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.read_ahead = clcf->read_ahead; of.directio = clcf->directio; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) { switch (of.err) { case 0: return NGX_HTTP_INTERNAL_SERVER_ERROR; case NGX_ENOENT: case NGX_ENOTDIR: case NGX_ENAMETOOLONG: level = NGX_LOG_ERR; rc = NGX_HTTP_NOT_FOUND; break; case NGX_EACCES: level = NGX_LOG_ERR; rc = NGX_HTTP_FORBIDDEN; break; default: level = NGX_LOG_CRIT; rc = NGX_HTTP_INTERNAL_SERVER_ERROR; break; } if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) { ngx_log_error(level, log, of.err, "%s \"%s\" failed", of.failed, path.data); } return rc; } if (!of.is_file) { if (ngx_close_file(of.fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, ngx_close_file_n " \"%s\" failed", path.data); } return NGX_DECLINED; } r->root_tested = !r->error_page; begin = 0; end = of.size; if (r->args.len) { if (ngx_http_arg(r, slcf->begin.data, slcf->begin.len, &value) == NGX_OK) { begin = ngx_atoof(value.data, value.len); if (begin == NGX_ERROR || begin >= of.size) { begin = 0; } } if (ngx_http_arg(r, slcf->end.data, slcf->end.len, &value) == NGX_OK) { end = ngx_atoof(value.data, value.len); if (end == NGX_ERROR || end >= of.size) { end = of.size; } } } end = end < begin ? of.size : end; len = (end == begin) ? 0 : ((end - begin) + ((begin == 0 && slcf->header_first) ? slcf->header.len : 0) + ((end == of.size && slcf->footer_last) ? slcf->footer.len : 0)); log->action = "sending slice to client"; r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = len; r->headers_out.last_modified_time = of.mtime; if (ngx_http_set_content_type(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (len == 0) { r->header_only = 1; return ngx_http_send_header(r); } /* * add header when the first header is not denied */ if (slcf->header.len && !(begin == 0 && !slcf->header_first)) { b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b->pos = slcf->header.data; b->last = slcf->header.data + slcf->header.len; b->memory = 1; out[0].buf = b; out[0].next = &out[1]; i = 0; } else { i = 1; } b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)); if (b->file == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } r->allow_ranges = 1; rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } b->file_pos = begin; b->file_last = end; b->in_file = b->file_last ? 1: 0; b->last_buf = 1; b->last_in_chain = 1; b->file->fd = of.fd; b->file->name = path; b->file->log = log; b->file->directio = of.is_directio; out[1].buf = b; out[1].next = NULL; /* * add footer when the last footer is not denied */ if (slcf->footer.len && !(end == of.size && !slcf->footer_last)) { b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b->pos = slcf->footer.data; b->last = slcf->footer.data + slcf->footer.len; b->memory = 1; b->last_buf = 1; b->last_in_chain = 1; out[2].buf = b; out[2].next = NULL; out[1].buf->last_buf = 0; out[1].buf->last_in_chain = 0; out[1].next = &out[2]; } return ngx_http_output_filter(r, &out[i]); }
ngx_int_t passenger_content_handler(ngx_http_request_t *r) { ngx_int_t rc; ngx_http_upstream_t *u; passenger_loc_conf_t *slcf; ngx_str_t path, base_uri; u_char *path_last, *end; u_char root_path_str[NGX_MAX_PATH + 1]; ngx_str_t root_path; size_t root_len, len; u_char page_cache_file_str[NGX_MAX_PATH + 1]; ngx_str_t page_cache_file; passenger_context_t *context; PP_Error error; if (passenger_main_conf.root_dir.len == 0) { return NGX_DECLINED; } else if (r->subrequest_in_memory) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "ngx_http_passenger_module does not support " "subrequest in memory"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } slcf = ngx_http_get_module_loc_conf(r, ngx_http_passenger_module); /* Let the next content handler take care of this request if Phusion * Passenger is disabled for this URL. */ if (!slcf->enabled) { return NGX_DECLINED; } /* Let the next content handler take care of this request if this URL * maps to an existing file. */ path_last = ngx_http_map_uri_to_path(r, &path, &root_len, 0); if (path_last != NULL && file_exists(path.data, 0)) { return NGX_DECLINED; } /* Create a string containing the root path. This path already * contains a trailing slash. */ end = ngx_copy(root_path_str, path.data, root_len); *end = '\0'; root_path.data = root_path_str; root_path.len = root_len; context = ngx_pcalloc(r->pool, sizeof(passenger_context_t)); if (context == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_http_set_ctx(r, context, ngx_http_passenger_module); /* Find the base URI for this web application, if any. */ if (find_base_uri(r, slcf, &base_uri)) { /* Store the found base URI into context->public_dir. We infer that * the 'public' directory of the web app equals document root + base URI. */ if (slcf->document_root.data != NULL) { len = slcf->document_root.len + 1; context->public_dir.data = ngx_palloc(r->pool, sizeof(u_char) * len); end = ngx_copy(context->public_dir.data, slcf->document_root.data, slcf->document_root.len); } else { len = root_path.len + base_uri.len + 1; context->public_dir.data = ngx_palloc(r->pool, sizeof(u_char) * len); end = ngx_copy(context->public_dir.data, root_path.data, root_path.len); end = ngx_copy(end, base_uri.data, base_uri.len); } *end = '\0'; context->public_dir.len = len - 1; context->base_uri = base_uri; } else { /* No base URI directives are applicable for this request. So assume that * the web application's public directory is the document root. * context->base_uri is now a NULL string. */ len = sizeof(u_char *) * (root_path.len + 1); context->public_dir.data = ngx_palloc(r->pool, len); end = ngx_copy(context->public_dir.data, root_path.data, root_path.len); *end = '\0'; context->public_dir.len = root_path.len; } /* If there's a corresponding page cache file for this URL, then serve that * file instead. */ page_cache_file.data = page_cache_file_str; page_cache_file.len = sizeof(page_cache_file_str); if (map_uri_to_page_cache_file(r, &context->public_dir, path.data, path_last - path.data, &page_cache_file)) { return passenger_static_content_handler(r, &page_cache_file); } if (slcf->app_type.data == NULL) { pp_error_init(&error); if (slcf->app_root.data == NULL) { context->app_type = pp_app_type_detector_check_document_root( pp_app_type_detector, (const char *) context->public_dir.data, context->public_dir.len, context->base_uri.len != 0, &error); } else { context->app_type = pp_app_type_detector_check_app_root( pp_app_type_detector, (const char *) slcf->app_root.data, slcf->app_root.len, &error); } if (context->app_type == PAT_NONE) { return NGX_DECLINED; } else if (context->app_type == PAT_ERROR) { if (error.errnoCode == EACCES) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "%s; This error means that the Nginx worker process (PID %d, " "running as UID %d) does not have permission to access this file. " "Please read the manual to learn how to fix this problem: " "section 'Troubleshooting' -> 'Upon accessing the web app, Nginx " "reports a \"Permission denied\" error'; Extra info", error.message, (int) getpid(), (int) getuid()); } else { ngx_log_error(NGX_LOG_ALERT, r->connection->log, (error.errnoCode == PP_NO_ERRNO) ? 0 : error.errnoCode, "%s", error.message); } pp_error_destroy(&error); return NGX_HTTP_INTERNAL_SERVER_ERROR; } } else { context->app_type = pp_get_app_type2((const char *) slcf->app_type.data, slcf->app_type.len); if (context->app_type == PAT_NONE) { return NGX_DECLINED; } } /* Setup upstream stuff and prepare sending the request to the HelperAgent. */ if (ngx_http_upstream_create(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } u = r->upstream; u->schema = pp_schema_string; u->output.tag = (ngx_buf_tag_t) &ngx_http_passenger_module; set_upstream_server_address(u, &slcf->upstream_config); u->conf = &slcf->upstream_config; #if (NGX_HTTP_CACHE) u->create_key = create_key; #endif u->create_request = create_request; u->reinit_request = reinit_request; u->process_header = process_status_line; u->abort_request = abort_request; u->finalize_request = finalize_request; r->state = 0; u->buffering = slcf->upstream_config.buffering; u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t)); if (u->pipe == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } u->pipe->input_filter = ngx_event_pipe_copy_input_filter; u->pipe->input_ctx = r; rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init); fix_peer_address(r); if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; } return NGX_DONE; }
ngx_int_t passenger_content_handler(ngx_http_request_t *r) { ngx_int_t rc; ngx_http_upstream_t *u; passenger_loc_conf_t *slcf; ngx_str_t path, base_uri; u_char *path_last, *end; u_char root_path_str[NGX_MAX_PATH + 1]; ngx_str_t root_path; size_t root, len; u_char page_cache_file_str[NGX_MAX_PATH + 1]; ngx_str_t page_cache_file; passenger_context_t *context; if (r->subrequest_in_memory) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "ngx_http_passenger_module does not support " "subrequest in memory"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } slcf = ngx_http_get_module_loc_conf(r, ngx_http_passenger_module); /* Let the next content handler take care of this request if Phusion * Passenger is disabled for this URL. */ if (!slcf->enabled) { return NGX_DECLINED; } /* Let the next content handler take care of this request if this URL * maps to an existing file. */ path_last = ngx_http_map_uri_to_path(r, &path, &root, 0); if (path_last != NULL && file_exists(path.data, 0)) { return NGX_DECLINED; } /* Create a string containing the root path. This path already * contains a trailing slash. */ end = ngx_copy(root_path_str, path.data, root); *end = '\0'; root_path.data = root_path_str; root_path.len = root; context = ngx_pcalloc(r->pool, sizeof(passenger_context_t)); if (context == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_http_set_ctx(r, context, ngx_http_passenger_module); /* Find the base URI for this web application, if any. */ if (find_base_uri(r, slcf, &base_uri)) { /* Store the found base URI in context->public_dir. We infer that the 'public' * directory of the web application is document root + base URI. */ len = root_path.len + base_uri.len + 1; context->public_dir.data = ngx_palloc(r->pool, sizeof(u_char) * len); end = ngx_copy(context->public_dir.data, root_path.data, root_path.len); end = ngx_copy(end, base_uri.data, base_uri.len); *end = '\0'; context->public_dir.len = len - 1; context->base_uri = base_uri; } else { /* No base URI directives are applicable for this request. So assume that * the web application's public directory is the document root. * context->base_uri is now a NULL string. */ len = sizeof(u_char *) * (root_path.len + 1); context->public_dir.data = ngx_palloc(r->pool, len); end = ngx_copy(context->public_dir.data, root_path.data, root_path.len); *end = '\0'; context->public_dir.len = root_path.len; } /* If there's a corresponding page cache file for this URL, then serve that * file instead. */ page_cache_file.data = page_cache_file_str; page_cache_file.len = sizeof(page_cache_file_str); if (map_uri_to_page_cache_file(r, &context->public_dir, path.data, path_last - path.data, &page_cache_file)) { return passenger_static_content_handler(r, &page_cache_file); } context->app_type = detect_application_type(&context->public_dir); if (context->app_type == AP_NONE) { return NGX_DECLINED; } /* Setup upstream stuff and prepare sending the request to the backend. */ u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t)); if (u == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } #if NGINX_VERSION_NUM >= 7000 u->schema = passenger_schema_string; #endif u->peer.log = r->connection->log; u->peer.log_error = NGX_ERROR_ERR; #if (NGX_THREADS) u->peer.lock = &r->connection->lock; #endif u->output.tag = (ngx_buf_tag_t) &ngx_http_passenger_module; u->conf = &slcf->upstream; u->create_request = create_request; u->reinit_request = reinit_request; u->process_header = process_status_line; u->abort_request = abort_request; u->finalize_request = finalize_request; u->buffering = 1; u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t)); if (u->pipe == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } u->pipe->input_filter = ngx_event_pipe_copy_input_filter; r->upstream = u; rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init); if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; } return NGX_DONE; }
static ngx_int_t ngx_http_image_handler(ngx_http_request_t *r) { u_char *last; size_t root; ngx_int_t rc; ngx_str_t path; char request_uri[255]; int request_uri_len; ngx_image_conf_t *conf; conf = ngx_http_get_module_loc_conf(r, ngx_http_image_module); if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) { return NGX_HTTP_NOT_ALLOWED; } if (r->headers_in.if_modified_since) { return NGX_HTTP_NOT_MODIFIED; } if (r->uri.data[r->uri.len - 1] == '/') { return NGX_DECLINED; } rc = ngx_http_discard_request_body(r); if (rc != NGX_OK) { return rc; } last = ngx_http_map_uri_to_path(r, &path, &root, 0); if (last == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if(file_exists((char*) path.data) == -1) { request_uri_len = strlen((char *)r->uri_start) - strlen((char *)r->uri_end); strncpy(request_uri, (char *)r->uri_start, request_uri_len); request_uri[request_uri_len] = '\0'; dirname(request_uri,conf->request_dir); conf->url = request_uri;//请求的URL地址 conf->dest_file = (char *)path.data; check_image_type(conf);//检查图片类型(根据后缀进行简单判断) if( conf->dest_type > 0 ) { if (parse_image_info(conf) == 0)//解析并处理请求的图片URL { make_thumb(conf);//生成图片缩略图 water_mark(conf);//图片打上水印 thumb_to_string(conf);//GD对象转换成二进制字符串 if(conf->image_output == 0) { write_img(conf);//保存图片缩略图到文件 } if(conf->image_output == 1) { return output(r,conf,ngx_http_image_types[conf->dest_type]); } } } } return NGX_DECLINED; }
static ngx_int_t ngx_http_flv_handler(ngx_http_request_t *r) { u_char *last; off_t start, len; size_t root; ngx_int_t rc; ngx_uint_t level, i; ngx_str_t path, value; ngx_log_t *log; ngx_buf_t *b; ngx_chain_t out[2]; ngx_open_file_info_t of; ngx_http_core_loc_conf_t *clcf; if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) { return NGX_HTTP_NOT_ALLOWED; } if (r->uri.data[r->uri.len - 1] == '/') { return NGX_DECLINED; } rc = ngx_http_discard_request_body(r); if (rc != NGX_OK) { return rc; } last = ngx_http_map_uri_to_path(r, &path, &root, 0); if (last == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } log = r->connection->log; path.len = last - path.data; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http flv filename: \"%V\"", &path); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.read_ahead = clcf->read_ahead; of.directio = clcf->directio; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) { switch (of.err) { case 0: return NGX_HTTP_INTERNAL_SERVER_ERROR; case NGX_ENOENT: case NGX_ENOTDIR: case NGX_ENAMETOOLONG: level = NGX_LOG_ERR; rc = NGX_HTTP_NOT_FOUND; break; case NGX_EACCES: level = NGX_LOG_ERR; rc = NGX_HTTP_FORBIDDEN; break; default: level = NGX_LOG_CRIT; rc = NGX_HTTP_INTERNAL_SERVER_ERROR; break; } if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) { ngx_log_error(level, log, of.err, "%s \"%s\" failed", of.failed, path.data); } return rc; } if (!of.is_file) { if (ngx_close_file(of.fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, ngx_close_file_n " \"%s\" failed", path.data); } return NGX_DECLINED; } r->root_tested = !r->error_page; start = 0; len = of.size; i = 1; if (r->args.len) { if (ngx_http_arg(r, (u_char *) "start", 5, &value) == NGX_OK) { start = ngx_atoof(value.data, value.len); if (start == NGX_ERROR || start >= len) { start = 0; } if (start) { len = sizeof(ngx_flv_header) - 1 + len - start; i = 0; } } } log->action = "sending flv to client"; r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = len; r->headers_out.last_modified_time = of.mtime; if (ngx_http_set_content_type(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (i == 0) { b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b->pos = ngx_flv_header; b->last = ngx_flv_header + sizeof(ngx_flv_header) - 1; b->memory = 1; out[0].buf = b; out[0].next = &out[1]; } b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)); if (b->file == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } r->allow_ranges = 1; rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } b->file_pos = start; b->file_last = of.size; b->in_file = b->file_last ? 1: 0; b->last_buf = 1; b->last_in_chain = 1; b->file->fd = of.fd; b->file->name = path; b->file->log = log; b->file->directio = of.is_directio; out[1].buf = b; out[1].next = NULL; return ngx_http_output_filter(r, &out[i]); }
static ngx_int_t ngx_http_gzip_static_handler(ngx_http_request_t *r) { u_char *p; size_t root; ngx_str_t path; ngx_int_t rc; ngx_uint_t level; ngx_log_t *log; ngx_buf_t *b; ngx_chain_t out; ngx_table_elt_t *h; ngx_open_file_info_t of; ngx_http_core_loc_conf_t *clcf; ngx_http_gzip_static_conf_t *gzcf; if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) { return NGX_DECLINED; } if (r->uri.data[r->uri.len - 1] == '/') { return NGX_DECLINED; } gzcf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_static_module); if (!gzcf->enable) { return NGX_DECLINED; } rc = ngx_http_gzip_ok(r); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (!clcf->gzip_vary && rc != NGX_OK) { return NGX_DECLINED; } log = r->connection->log; p = ngx_http_map_uri_to_path(r, &path, &root, sizeof(".gz") - 1); if (p == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } *p++ = '.'; *p++ = 'g'; *p++ = 'z'; *p = '\0'; path.len = p - path.data; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http filename: \"%s\"", path.data); ngx_memzero(&of, sizeof(ngx_open_file_info_t)); #if (NGX_WIN32 && NGX_HAVE_FILE_AIO) of.aio = clcf->aio; #endif of.read_ahead = clcf->read_ahead; of.directio = clcf->directio; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) { switch (of.err) { case 0: return NGX_HTTP_INTERNAL_SERVER_ERROR; case NGX_ENOENT: case NGX_ENOTDIR: case NGX_ENAMETOOLONG: return NGX_DECLINED; case NGX_EACCES: level = NGX_LOG_ERR; break; default: level = NGX_LOG_CRIT; break; } ngx_log_error(level, log, of.err, "%s \"%s\" failed", of.failed, path.data); return NGX_DECLINED; } r->gzip_vary = 1; if (rc != NGX_OK) { return NGX_DECLINED; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", of.fd); if (of.is_dir) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http dir"); return NGX_DECLINED; } #if !(NGX_WIN32) /* the not regular files are probably Unix specific */ if (!of.is_file) { ngx_log_error(NGX_LOG_CRIT, log, 0, "\"%s\" is not a regular file", path.data); return NGX_HTTP_NOT_FOUND; } #endif r->root_tested = !r->error_page; rc = ngx_http_discard_request_body(r); if (rc != NGX_OK) { return rc; } log->action = "sending response to client"; r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = of.size; r->headers_out.last_modified_time = of.mtime; if (ngx_http_set_content_type(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } h = ngx_list_push(&r->headers_out.headers); if (h == NULL) { return NGX_ERROR; } h->hash = 1; ngx_str_set(&h->key, "Content-Encoding"); ngx_str_set(&h->value, "gzip"); r->headers_out.content_encoding = h; r->ignore_content_encoding = 1; /* we need to allocate all before the header would be sent */ b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)); if (b->file == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } b->file_pos = 0; b->file_last = of.size; b->in_file = b->file_last ? 1 : 0; b->last_buf = 1; b->last_in_chain = 1; b->file->fd = of.fd; b->file->name = path; b->file->log = log; b->file->directio = of.is_directio; out.buf = b; out.next = NULL; return ngx_http_output_filter(r, &out); }
static void ngx_http_dav_put_handler(ngx_http_request_t *r) { size_t root; time_t date; ngx_str_t *temp, path; ngx_uint_t status; ngx_file_info_t fi; ngx_ext_rename_file_t ext; ngx_http_dav_loc_conf_t *dlcf; if (r->request_body == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "PUT request body is unavailable"); ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } if (r->request_body->temp_file == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "PUT request body must be in a file"); ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } path.len--; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http put filename: \"%s\"", path.data); temp = &r->request_body->temp_file->file.name; if (ngx_file_info(path.data, &fi) == NGX_FILE_ERROR) { status = NGX_HTTP_CREATED; } else { status = NGX_HTTP_NO_CONTENT; if (ngx_is_dir(&fi)) { ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_EISDIR, "\"%s\" could not be created", path.data); if (ngx_delete_file(temp->data) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, ngx_delete_file_n " \"%s\" failed", temp->data); } ngx_http_finalize_request(r, NGX_HTTP_CONFLICT); return; } } dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module); ext.access = dlcf->access; ext.path_access = dlcf->access; ext.time = -1; ext.create_path = dlcf->create_full_put_path; ext.delete_file = 1; ext.log = r->connection->log; if (r->headers_in.date) { date = ngx_parse_http_time(r->headers_in.date->value.data, r->headers_in.date->value.len); if (date != NGX_ERROR) { ext.time = date; ext.fd = r->request_body->temp_file->file.fd; } } if (ngx_ext_rename_file(temp, &path, &ext) != NGX_OK) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } if (status == NGX_HTTP_CREATED) { if (ngx_http_dav_location(r, path.data) != NGX_OK) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } r->headers_out.content_length_n = 0; } r->headers_out.status = status; r->header_only = 1; ngx_http_finalize_request(r, ngx_http_send_header(r)); return; }
static ngx_int_t ngx_http_autoindex_handler(ngx_http_request_t *r) { u_char *last, *filename; size_t len, allocated, root; ngx_err_t err; ngx_buf_t *b; ngx_int_t rc; ngx_str_t path, callback; ngx_dir_t dir; ngx_uint_t level, format; ngx_pool_t *pool; ngx_chain_t out; ngx_array_t entries; ngx_http_autoindex_entry_t *entry; ngx_http_autoindex_loc_conf_t *alcf; if (r->uri.data[r->uri.len - 1] != '/') { return NGX_DECLINED; } if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) { return NGX_DECLINED; } alcf = ngx_http_get_module_loc_conf(r, ngx_http_autoindex_module); if (!alcf->enable) { return NGX_DECLINED; } rc = ngx_http_discard_request_body(r); if (rc != NGX_OK) { return rc; } last = ngx_http_map_uri_to_path(r, &path, &root, NGX_HTTP_AUTOINDEX_PREALLOCATE); if (last == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } allocated = path.len; path.len = last - path.data; if (path.len > 1) { path.len--; } path.data[path.len] = '\0'; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http autoindex: \"%s\"", path.data); format = alcf->format; if (format == NGX_HTTP_AUTOINDEX_JSONP) { if (ngx_http_autoindex_jsonp_callback(r, &callback) != NGX_OK) { return NGX_HTTP_BAD_REQUEST; } if (callback.len == 0) { format = NGX_HTTP_AUTOINDEX_JSON; } } if (ngx_open_dir(&path, &dir) == NGX_ERROR) { err = ngx_errno; if (err == NGX_ENOENT || err == NGX_ENOTDIR || err == NGX_ENAMETOOLONG) { level = NGX_LOG_ERR; rc = NGX_HTTP_NOT_FOUND; } else if (err == NGX_EACCES) { level = NGX_LOG_ERR; rc = NGX_HTTP_FORBIDDEN; } else { level = NGX_LOG_CRIT; rc = NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_log_error(level, r->connection->log, err, ngx_open_dir_n " \"%s\" failed", path.data); return rc; } #if (NGX_SUPPRESS_WARN) /* MSVC thinks 'entries' may be used without having been initialized */ ngx_memzero(&entries, sizeof(ngx_array_t)); #endif /* TODO: pool should be temporary pool */ pool = r->pool; if (ngx_array_init(&entries, pool, 40, sizeof(ngx_http_autoindex_entry_t)) != NGX_OK) { return ngx_http_autoindex_error(r, &dir, &path); } r->headers_out.status = NGX_HTTP_OK; switch (format) { case NGX_HTTP_AUTOINDEX_JSON: ngx_str_set(&r->headers_out.content_type, "application/json"); break; case NGX_HTTP_AUTOINDEX_JSONP: ngx_str_set(&r->headers_out.content_type, "application/javascript"); break; case NGX_HTTP_AUTOINDEX_XML: ngx_str_set(&r->headers_out.content_type, "text/xml"); ngx_str_set(&r->headers_out.charset, "utf-8"); break; default: /* NGX_HTTP_AUTOINDEX_HTML */ ngx_str_set(&r->headers_out.content_type, "text/html"); break; } r->headers_out.content_type_len = r->headers_out.content_type.len; r->headers_out.content_type_lowcase = NULL; rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { if (ngx_close_dir(&dir) == NGX_ERROR) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, ngx_close_dir_n " \"%V\" failed", &path); } return rc; } filename = path.data; filename[path.len] = '/'; for ( ;; ) { ngx_set_errno(0); if (ngx_read_dir(&dir) == NGX_ERROR) { err = ngx_errno; if (err != NGX_ENOMOREFILES) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, ngx_read_dir_n " \"%V\" failed", &path); return ngx_http_autoindex_error(r, &dir, &path); } break; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http autoindex file: \"%s\"", ngx_de_name(&dir)); len = ngx_de_namelen(&dir); if (ngx_de_name(&dir)[0] == '.') { continue; } if (!dir.valid_info) { /* 1 byte for '/' and 1 byte for terminating '\0' */ if (path.len + 1 + len + 1 > allocated) { allocated = path.len + 1 + len + 1 + NGX_HTTP_AUTOINDEX_PREALLOCATE; filename = ngx_pnalloc(pool, allocated); if (filename == NULL) { return ngx_http_autoindex_error(r, &dir, &path); } last = ngx_cpystrn(filename, path.data, path.len + 1); *last++ = '/'; } ngx_cpystrn(last, ngx_de_name(&dir), len + 1); if (ngx_de_info(filename, &dir) == NGX_FILE_ERROR) { err = ngx_errno; if (err != NGX_ENOENT && err != NGX_ELOOP) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, ngx_de_info_n " \"%s\" failed", filename); if (err == NGX_EACCES) { continue; } return ngx_http_autoindex_error(r, &dir, &path); } if (ngx_de_link_info(filename, &dir) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, ngx_de_link_info_n " \"%s\" failed", filename); return ngx_http_autoindex_error(r, &dir, &path); } } } entry = ngx_array_push(&entries); if (entry == NULL) { return ngx_http_autoindex_error(r, &dir, &path); } entry->name.len = len; entry->name.data = ngx_pnalloc(pool, len + 1); if (entry->name.data == NULL) { return ngx_http_autoindex_error(r, &dir, &path); } ngx_cpystrn(entry->name.data, ngx_de_name(&dir), len + 1); entry->dir = ngx_de_is_dir(&dir); entry->file = ngx_de_is_file(&dir); entry->mtime = ngx_de_mtime(&dir); entry->size = ngx_de_size(&dir); } if (ngx_close_dir(&dir) == NGX_ERROR) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, ngx_close_dir_n " \"%V\" failed", &path); } if (entries.nelts > 1) { ngx_qsort(entries.elts, (size_t) entries.nelts, sizeof(ngx_http_autoindex_entry_t), ngx_http_autoindex_cmp_entries); } switch (format) { case NGX_HTTP_AUTOINDEX_JSON: b = ngx_http_autoindex_json(r, &entries, NULL); break; case NGX_HTTP_AUTOINDEX_JSONP: b = ngx_http_autoindex_json(r, &entries, &callback); break; case NGX_HTTP_AUTOINDEX_XML: b = ngx_http_autoindex_xml(r, &entries); break; default: /* NGX_HTTP_AUTOINDEX_HTML */ b = ngx_http_autoindex_html(r, &entries); break; } if (b == NULL) { return NGX_ERROR; } /* TODO: free temporary pool */ if (r == r->main) { b->last_buf = 1; } b->last_in_chain = 1; out.buf = b; out.next = NULL; return ngx_http_output_filter(r, &out); }
static ngx_int_t ngx_http_dav_delete_handler(ngx_http_request_t *r) { size_t root; ngx_err_t err; ngx_int_t rc, depth; ngx_uint_t i, d, dir; ngx_str_t path; ngx_file_info_t fi; ngx_http_dav_loc_conf_t *dlcf; if (r->headers_in.content_length_n > 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "DELETE with body is unsupported"); return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE; } dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module); if (dlcf->min_delete_depth) { d = 0; for (i = 0; i < r->uri.len; /* void */) { if (r->uri.data[i++] == '/') { if (++d >= dlcf->min_delete_depth && i < r->uri.len) { goto ok; } } } ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "insufficient URI depth:%i to DELETE", d); return NGX_HTTP_CONFLICT; } ok: if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http delete filename: \"%s\"", path.data); if (ngx_link_info(path.data, &fi) == NGX_FILE_ERROR) { err = ngx_errno; rc = (err == NGX_ENOTDIR) ? NGX_HTTP_CONFLICT : NGX_HTTP_NOT_FOUND; return ngx_http_dav_error(r->connection->log, err, rc, ngx_link_info_n, path.data); } if (ngx_is_dir(&fi)) { if (r->uri.data[r->uri.len - 1] != '/') { ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_EISDIR, "DELETE \"%s\" failed", path.data); return NGX_HTTP_CONFLICT; } depth = ngx_http_dav_depth(r, NGX_HTTP_DAV_INFINITY_DEPTH); if (depth != NGX_HTTP_DAV_INFINITY_DEPTH) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "\"Depth\" header must be infinity"); return NGX_HTTP_BAD_REQUEST; } path.len -= 2; /* omit "/\0" */ dir = 1; } else { /* * we do not need to test (r->uri.data[r->uri.len - 1] == '/') * because ngx_link_info("/file/") returned NGX_ENOTDIR above */ depth = ngx_http_dav_depth(r, 0); if (depth != 0 && depth != NGX_HTTP_DAV_INFINITY_DEPTH) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "\"Depth\" header must be 0 or infinity"); return NGX_HTTP_BAD_REQUEST; } dir = 0; } rc = ngx_http_dav_delete_path(r, &path, dir); if (rc == NGX_OK) { return NGX_HTTP_NO_CONTENT; } return rc; }
/* 配置index index.html index_large.html gmime-gmime-cipher-context.html; 2025/02/14 08:24:04[ ngx_http_process_request_headers, 1412] [debug] 2955#2955: *2 http header done 2025/02/14 08:24:04[ ngx_event_del_timer, 39] [debug] 2955#2955: *2 < ngx_http_process_request, 2013> event timer del: 3: 30909486 2025/02/14 08:24:04[ ngx_http_core_rewrite_phase, 1810] [debug] 2955#2955: *2 rewrite phase: 0 (NGX_HTTP_SERVER_REWRITE_PHASE) 2025/02/14 08:24:04[ ngx_http_core_find_config_phase, 1868] [debug] 2955#2955: *2 find config phase: 1 (NGX_HTTP_FIND_CONFIG_PHASE), uri:/ 2025/02/14 08:24:04[ ngx_http_core_find_static_location, 2753] [debug] 2955#2955: *2 static_locations test location: "/", client uri:/ 2025/02/14 08:24:04[ ngx_http_core_find_location, 2693] [debug] 2955#2955: *2 ngx pcre test location: ~ "/1mytest" 2025/02/14 08:24:04[ ngx_http_core_find_config_phase, 1888] [debug] 2955#2955: *2 using configuration "/" 2025/02/14 08:24:04[ ngx_http_core_find_config_phase, 1895] [debug] 2955#2955: *2 http cl:-1 max:1048576 2025/02/14 08:24:04[ ngx_http_core_rewrite_phase, 1810] [debug] 2955#2955: *2 rewrite phase: 2 (NGX_HTTP_REWRITE_PHASE) 2025/02/14 08:24:04[ ngx_http_core_post_rewrite_phase, 1963] [debug] 2955#2955: *2 post rewrite phase: 3 (NGX_HTTP_POST_REWRITE_PHASE) 2025/02/14 08:24:04[ ngx_http_core_generic_phase, 1746] [debug] 2955#2955: *2 generic phase: 4 (NGX_HTTP_PREACCESS_PHASE) 2025/02/14 08:24:04[ ngx_http_core_generic_phase, 1746] [debug] 2955#2955: *2 generic phase: 5 (NGX_HTTP_PREACCESS_PHASE) 2025/02/14 08:24:04[ ngx_http_core_access_phase, 2061] [debug] 2955#2955: *2 access phase: 6 (NGX_HTTP_ACCESS_PHASE) 2025/02/14 08:24:04[ ngx_http_core_access_phase, 2061] [debug] 2955#2955: *2 access phase: 7 (NGX_HTTP_ACCESS_PHASE) 2025/02/14 08:24:04[ ngx_http_core_post_access_phase, 2163] [debug] 2955#2955: *2 post access phase: 8 (NGX_HTTP_POST_ACCESS_PHASE) 2025/02/14 08:24:04[ ngx_http_core_content_phase, 2491] [debug] 2955#2955: *2 content phase: 9 (NGX_HTTP_CONTENT_PHASE) 2025/02/14 08:24:04[ ngx_http_index_handler, 144] [debug] 2955#2955: *2 yang test ... index-count:3 2025/02/14 08:24:04[ ngx_http_index_handler, 216] [debug] 2955#2955: *2 open index "/usr/local/nginx/html/index.html" 2025/02/14 08:24:04[ ngx_http_internal_redirect, 3853] [debug] 2955#2955: *2 internal redirect: "/index.html?" 2025/02/14 08:24:04[ ngx_http_core_rewrite_phase, 1810] [debug] 2955#2955: *2 rewrite phase: 0 (NGX_HTTP_SERVER_REWRITE_PHASE) 2025/02/14 08:24:04[ ngx_http_core_find_config_phase, 1868] [debug] 2955#2955: *2 find config phase: 1 (NGX_HTTP_FIND_CONFIG_PHASE), uri:/index.html 2025/02/14 08:24:04[ ngx_http_core_find_static_location, 2753] [debug] 2955#2955: *2 static_locations test location: "/", client uri:/index.html 2025/02/14 08:24:04[ ngx_http_core_find_static_location, 2753] [debug] 2955#2955: *2 static_locations test location: "proxy1", client uri:/index.html 2025/02/14 08:24:04[ ngx_http_core_find_static_location, 2753] [debug] 2955#2955: *2 static_locations test location: "mytest", client uri:/index.html 2025/02/14 08:24:04[ ngx_http_core_find_location, 2693] [debug] 2955#2955: *2 ngx pcre test location: ~ "/1mytest" 2025/02/14 08:24:04[ ngx_http_core_find_config_phase, 1888] [debug] 2955#2955: *2 using configuration "/" 2025/02/14 08:24:04[ ngx_http_core_find_config_phase, 1895] [debug] 2955#2955: *2 http cl:-1 max:1048576 2025/02/14 08:24:04[ ngx_http_core_rewrite_phase, 1810] [debug] 2955#2955: *2 rewrite phase: 2 (NGX_HTTP_REWRITE_PHASE) 2025/02/14 08:24:04[ ngx_http_core_post_rewrite_phase, 1963] [debug] 2955#2955: *2 post rewrite phase: 3 (NGX_HTTP_POST_REWRITE_PHASE) 2025/02/14 08:24:04[ ngx_http_core_generic_phase, 1746] [debug] 2955#2955: *2 generic phase: 4 (NGX_HTTP_PREACCESS_PHASE) 2025/02/14 08:24:04[ ngx_http_core_generic_phase, 1746] [debug] 2955#2955: *2 generic phase: 5 (NGX_HTTP_PREACCESS_PHASE) 2025/02/14 08:24:04[ ngx_http_core_access_phase, 2061] [debug] 2955#2955: *2 access phase: 6 (NGX_HTTP_ACCESS_PHASE) 2025/02/14 08:24:04[ ngx_http_core_access_phase, 2061] [debug] 2955#2955: *2 access phase: 7 (NGX_HTTP_ACCESS_PHASE) 2025/02/14 08:24:04[ ngx_http_core_post_access_phase, 2163] [debug] 2955#2955: *2 post access phase: 8 (NGX_HTTP_POST_ACCESS_PHASE) 2025/02/14 08:24:04[ ngx_http_core_content_phase, 2491] [debug] 2955#2955: *2 content phase: 9 (NGX_HTTP_CONTENT_PHASE) 2025/02/14 08:24:04[ ngx_http_core_content_phase, 2491] [debug] 2955#2955: *2 content phase: 10 (NGX_HTTP_CONTENT_PHASE) 2025/02/14 08:24:04[ ngx_http_core_content_phase, 2491] [debug] 2955#2955: *2 content phase: 11 (NGX_HTTP_CONTENT_PHASE) 2025/02/14 08:24:04[ ngx_http_static_handler, 85] [debug] 2955#2955: *2 http filename: "/usr/local/nginx/html/index.html" 2025/02/14 08:24:04[ ngx_http_static_handler, 145] [debug] 2955#2955: *2 http static fd: 11 2025/02/14 08:24:04[ ngx_http_discard_request_body, 734] [debug] 2955#2955: *2 http set discard body */ static ngx_int_t //主要功能是检查uri中的文件是否存在,不存在直接关闭连接,存在则做内部重定向,重定向后由于是文件路径,因此末尾没有/,走到该函数直接退出,然后在static-module中获取文件内容 ngx_http_index_handler(ngx_http_request_t *r) {//注意:ngx_http_static_handler如果uri不是以/结尾返回,ngx_http_index_handler不以/结尾返回 //循环遍历index index.html index_large.html gmime-gmime-cipher-context.html;配置的文件,存在则返回,找到一个不在遍历后面的文件 //ngx_http_static_handler ngx_http_index_handler每次都要获取缓存信息stat信息,因此每次获取很可能是上一次stat执行的时候获取的信息,除非缓存过期 u_char *p, *name; size_t len, root, reserve, allocated; ngx_int_t rc; ngx_str_t path, uri; ngx_uint_t i, dir_tested; ngx_http_index_t *index; ngx_open_file_info_t of; ngx_http_script_code_pt code; ngx_http_script_engine_t e; ngx_http_core_loc_conf_t *clcf; ngx_http_index_loc_conf_t *ilcf; ngx_http_script_len_code_pt lcode; /* 一般匹配到location / { }的时候,才会执行下面的index,然后进行内部跳转 */ /* 如果浏览器输入:http://10.135.10.167/ABC/,则也会满足要求,uri会变为/ABC/index.html,打印如下 2015/10/16 12:08:03[ ngx_event_del_timer, 39] [debug] 12610#12610: *2 < ngx_http_process_request, 2013> event timer del: 3: 1859492499 2015/10/16 12:08:03[ ngx_http_core_rewrite_phase, 1810] [debug] 12610#12610: *2 rewrite phase: 0 (NGX_HTTP_SERVER_REWRITE_PHASE) 2015/10/16 12:08:03[ ngx_http_core_find_config_phase, 1868] [debug] 12610#12610: *2 find config phase: 1 (NGX_HTTP_FIND_CONFIG_PHASE), uri:/ABC/ 2015/10/16 12:08:03[ ngx_http_core_find_static_location, 2753] [debug] 12610#12610: *2 static_locations test location: "/", client uri:/ABC/ 2015/10/16 12:08:03[ ngx_http_core_find_static_location, 2753] [debug] 12610#12610: *2 static_locations test location: "proxy1", client uri:/ABC/ 2015/10/16 12:08:03[ ngx_http_core_find_static_location, 2753] [debug] 12610#12610: *2 static_locations test location: "mytest", client uri:/ABC/ 2015/10/16 12:08:03[ ngx_http_core_find_location, 2693] [debug] 12610#12610: *2 ngx pcre test location: ~ "\.php$" 2015/10/16 12:08:03[ ngx_http_core_find_location, 2693] [debug] 12610#12610: *2 ngx pcre test location: ~ "/1mytest" 2015/10/16 12:08:03[ ngx_http_core_find_config_phase, 1888] [debug] 12610#12610: *2 using configuration "/" 2015/10/16 12:08:03[ ngx_http_core_find_config_phase, 1895] [debug] 12610#12610: *2 http cl:-1 max:1048576 2015/10/16 12:08:03[ ngx_http_core_rewrite_phase, 1810] [debug] 12610#12610: *2 rewrite phase: 2 (NGX_HTTP_REWRITE_PHASE) 2015/10/16 12:08:03[ ngx_http_core_post_rewrite_phase, 1963] [debug] 12610#12610: *2 post rewrite phase: 3 (NGX_HTTP_POST_REWRITE_PHASE) 2015/10/16 12:08:03[ ngx_http_core_generic_phase, 1746] [debug] 12610#12610: *2 generic phase: 4 (NGX_HTTP_PREACCESS_PHASE) 2015/10/16 12:08:03[ ngx_http_core_generic_phase, 1746] [debug] 12610#12610: *2 generic phase: 5 (NGX_HTTP_PREACCESS_PHASE) 2015/10/16 12:08:03[ ngx_http_core_access_phase, 2061] [debug] 12610#12610: *2 access phase: 6 (NGX_HTTP_ACCESS_PHASE) 2015/10/16 12:08:03[ ngx_http_core_access_phase, 2061] [debug] 12610#12610: *2 access phase: 7 (NGX_HTTP_ACCESS_PHASE) 2015/10/16 12:08:03[ ngx_http_core_post_access_phase, 2163] [debug] 12610#12610: *2 post access phase: 8 (NGX_HTTP_POST_ACCESS_PHASE) 2015/10/16 12:08:03[ ngx_http_core_content_phase, 2491] [debug] 12610#12610: *2 content phase: 9 (NGX_HTTP_CONTENT_PHASE) 2015/10/16 12:08:03[ ngx_http_index_handler, 191] [debug] 12610#12610: *2 yang test ... index-count:3 2015/10/16 12:08:03[ ngx_http_index_handler, 263] [debug] 12610#12610: *2 open index "/var/yyz/www/ABC/index.html" 2015/10/16 12:08:03[ ngx_http_index_handler, 283] [debug] 12610#12610: *2 stat() "/var/yyz/www/ABC/index.html" failed (2: No such file or directory) 2015/10/16 12:08:03[ ngx_http_index_test_dir, 364] [debug] 12610#12610: *2 http index check dir: "/var/yyz/www/ABC" */ //默认http://10.2.13.167的时候,浏览器都会转换为http://10.2.13.167/发送到nginx服务器 if (r->uri.data[r->uri.len - 1] != '/') { //末尾不是/,直接跳转到下一阶段 return NGX_DECLINED; } if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_POST))) { return NGX_DECLINED; } ilcf = ngx_http_get_module_loc_conf(r, ngx_http_index_module); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); allocated = 0; root = 0; dir_tested = 0; name = NULL; /* suppress MSVC warning */ path.data = NULL; index = ilcf->indices->elts; //indices上默认有一个NGX_HTTP_DEFAULT_INDEX for (i = 0; i < ilcf->indices->nelts; i++) {//循环遍历index配置的文件,如果有该文件,则进行内部重定向,从新走NGX_HTTP_SERVER_REWRITE_PHASE if (index[i].lengths == NULL) { if (index[i].name.data[0] == '/') { return ngx_http_internal_redirect(r, &index[i].name, &r->args); } reserve = ilcf->max_index_len; len = index[i].name.len; } else { ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); e.ip = index[i].lengths->elts; e.request = r; e.flushed = 1; /* 1 is for terminating '\0' as in static names */ len = 1; while (*(uintptr_t *) e.ip) { lcode = *(ngx_http_script_len_code_pt *) e.ip; len += lcode(&e); } /* 16 bytes are preallocation */ reserve = len + 16; } if (reserve > allocated) { name = ngx_http_map_uri_to_path(r, &path, &root, reserve); if (name == NULL) { return NGX_ERROR; } allocated = path.data + path.len - name; } if (index[i].values == NULL) { /* index[i].name.len includes the terminating '\0' */ ngx_memcpy(name, index[i].name.data, index[i].name.len); path.len = (name + index[i].name.len - 1) - path.data; } else { e.ip = index[i].values->elts; e.pos = name; while (*(uintptr_t *) e.ip) { code = *(ngx_http_script_code_pt *) e.ip; code((ngx_http_script_engine_t *) &e); } if (*name == '/') { uri.len = len - 1; uri.data = name; return ngx_http_internal_redirect(r, &uri, &r->args); } path.len = e.pos - path.data; *e.pos = '\0'; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "open index \"%V\"", &path); ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.read_ahead = clcf->read_ahead; of.directio = clcf->directio; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.test_only = 1; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, of.err, "%s \"%s\" failed", of.failed, path.data); if (of.err == 0) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } #if (NGX_HAVE_OPENAT) if (of.err == NGX_EMLINK || of.err == NGX_ELOOP) { return NGX_HTTP_FORBIDDEN; } #endif if (of.err == NGX_ENOTDIR || of.err == NGX_ENAMETOOLONG || of.err == NGX_EACCES) { return ngx_http_index_error(r, clcf, path.data, of.err); } if (!dir_tested) { rc = ngx_http_index_test_dir(r, clcf, path.data, name - 1); if (rc != NGX_OK) { return rc; } dir_tested = 1; } if (of.err == NGX_ENOENT) { continue; //stat获取的参数file_name指定的文件不存在 } ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err, "%s \"%s\" failed", of.failed, path.data); return NGX_HTTP_INTERNAL_SERVER_ERROR; } uri.len = r->uri.len + len - 1; if (!clcf->alias) { uri.data = path.data + root; } else { uri.data = ngx_pnalloc(r->pool, uri.len); if (uri.data == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } p = ngx_copy(uri.data, r->uri.data, r->uri.len); ngx_memcpy(p, name, len - 1); } return ngx_http_internal_redirect(r, &uri, &r->args); //内部重定向 } return NGX_DECLINED; }
static ngx_int_t ngx_http_dav_copy_move_handler(ngx_http_request_t *r) { u_char *p, *host, *last, ch; size_t len, root; ngx_err_t err; ngx_int_t rc, depth; ngx_uint_t overwrite, slash, dir, flags; ngx_str_t path, uri, duri, args; ngx_tree_ctx_t tree; ngx_copy_file_t cf; ngx_file_info_t fi; ngx_table_elt_t *dest, *over; ngx_ext_rename_file_t ext; ngx_http_dav_copy_ctx_t copy; ngx_http_dav_loc_conf_t *dlcf; if (r->headers_in.content_length_n > 0) { return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE; } dest = r->headers_in.destination; if (dest == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "client sent no \"Destination\" header"); return NGX_HTTP_BAD_REQUEST; } p = dest->value.data; /* there is always '\0' even after empty header value */ if (p[0] == '/') { last = p + dest->value.len; goto destination_done; } len = r->headers_in.server.len; if (len == 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "client sent no \"Host\" header"); return NGX_HTTP_BAD_REQUEST; } #if (NGX_HTTP_SSL) if (r->connection->ssl) { if (ngx_strncmp(dest->value.data, "https://", sizeof("https://") - 1) != 0) { goto invalid_destination; } host = dest->value.data + sizeof("https://") - 1; } else #endif { if (ngx_strncmp(dest->value.data, "http://", sizeof("http://") - 1) != 0) { goto invalid_destination; } host = dest->value.data + sizeof("http://") - 1; } if (ngx_strncmp(host, r->headers_in.server.data, len) != 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "\"Destination\" URI \"%V\" is handled by " "different repository than the source URI", &dest->value); return NGX_HTTP_BAD_REQUEST; } last = dest->value.data + dest->value.len; for (p = host + len; p < last; p++) { if (*p == '/') { goto destination_done; } } invalid_destination: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "client sent invalid \"Destination\" header: \"%V\"", &dest->value); return NGX_HTTP_BAD_REQUEST; destination_done: duri.len = last - p; duri.data = p; flags = NGX_HTTP_LOG_UNSAFE; if (ngx_http_parse_unsafe_uri(r, &duri, &args, &flags) != NGX_OK) { goto invalid_destination; } if ((r->uri.data[r->uri.len - 1] == '/' && *(last - 1) != '/') || (r->uri.data[r->uri.len - 1] != '/' && *(last - 1) == '/')) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "both URI \"%V\" and \"Destination\" URI \"%V\" " "should be either collections or non-collections", &r->uri, &dest->value); return NGX_HTTP_CONFLICT; } depth = ngx_http_dav_depth(r, NGX_HTTP_DAV_INFINITY_DEPTH); if (depth != NGX_HTTP_DAV_INFINITY_DEPTH) { if (r->method == NGX_HTTP_COPY) { if (depth != 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "\"Depth\" header must be 0 or infinity"); return NGX_HTTP_BAD_REQUEST; } } else { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "\"Depth\" header must be infinity"); return NGX_HTTP_BAD_REQUEST; } } over = r->headers_in.overwrite; if (over) { if (over->value.len == 1) { ch = over->value.data[0]; if (ch == 'T' || ch == 't') { overwrite = 1; goto overwrite_done; } if (ch == 'F' || ch == 'f') { overwrite = 0; goto overwrite_done; } } ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "client sent invalid \"Overwrite\" header: \"%V\"", &over->value); return NGX_HTTP_BAD_REQUEST; } overwrite = 1; overwrite_done: if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http copy from: \"%s\"", path.data); uri = r->uri; r->uri = duri; if (ngx_http_map_uri_to_path(r, ©.path, &root, 0) == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } r->uri = uri; copy.path.len--; /* omit "\0" */ if (copy.path.data[copy.path.len - 1] == '/') { slash = 1; copy.path.len--; copy.path.data[copy.path.len] = '\0'; } else { slash = 0; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http copy to: \"%s\"", copy.path.data); if (ngx_link_info(copy.path.data, &fi) == NGX_FILE_ERROR) { err = ngx_errno; if (err != NGX_ENOENT) { return ngx_http_dav_error(r->connection->log, err, NGX_HTTP_NOT_FOUND, ngx_link_info_n, copy.path.data); } /* destination does not exist */ overwrite = 0; dir = 0; } else { /* destination exists */ if (ngx_is_dir(&fi) && !slash) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "\"%V\" could not be %Ved to collection \"%V\"", &r->uri, &r->method_name, &dest->value); return NGX_HTTP_CONFLICT; } if (!overwrite) { ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_EEXIST, "\"%s\" could not be created", copy.path.data); return NGX_HTTP_PRECONDITION_FAILED; } dir = ngx_is_dir(&fi); } if (ngx_link_info(path.data, &fi) == NGX_FILE_ERROR) { return ngx_http_dav_error(r->connection->log, ngx_errno, NGX_HTTP_NOT_FOUND, ngx_link_info_n, path.data); } if (ngx_is_dir(&fi)) { if (r->uri.data[r->uri.len - 1] != '/') { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "\"%V\" is collection", &r->uri); return NGX_HTTP_BAD_REQUEST; } if (overwrite) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http delete: \"%s\"", copy.path.data); rc = ngx_http_dav_delete_path(r, ©.path, dir); if (rc != NGX_OK) { return rc; } } } if (ngx_is_dir(&fi)) { path.len -= 2; /* omit "/\0" */ if (r->method == NGX_HTTP_MOVE) { if (ngx_rename_file(path.data, copy.path.data) != NGX_FILE_ERROR) { return NGX_HTTP_CREATED; } } if (ngx_create_dir(copy.path.data, ngx_file_access(&fi)) == NGX_FILE_ERROR) { return ngx_http_dav_error(r->connection->log, ngx_errno, NGX_HTTP_NOT_FOUND, ngx_create_dir_n, copy.path.data); } copy.len = path.len; tree.init_handler = NULL; tree.file_handler = ngx_http_dav_copy_tree_file; tree.pre_tree_handler = ngx_http_dav_copy_dir; tree.post_tree_handler = ngx_http_dav_copy_dir_time; tree.spec_handler = ngx_http_dav_noop; tree.data = © tree.alloc = 0; tree.log = r->connection->log; if (ngx_walk_tree(&tree, &path) == NGX_OK) { if (r->method == NGX_HTTP_MOVE) { rc = ngx_http_dav_delete_path(r, &path, 1); if (rc != NGX_OK) { return rc; } } return NGX_HTTP_CREATED; } } else { if (r->method == NGX_HTTP_MOVE) { dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module); ext.access = 0; ext.path_access = dlcf->access; ext.time = -1; ext.create_path = 1; ext.delete_file = 0; ext.log = r->connection->log; if (ngx_ext_rename_file(&path, ©.path, &ext) == NGX_OK) { return NGX_HTTP_NO_CONTENT; } return NGX_HTTP_INTERNAL_SERVER_ERROR; } cf.size = ngx_file_size(&fi); cf.buf_size = 0; cf.access = ngx_file_access(&fi); cf.time = ngx_file_mtime(&fi); cf.log = r->connection->log; if (ngx_copy_file(path.data, copy.path.data, &cf) == NGX_OK) { return NGX_HTTP_NO_CONTENT; } } return NGX_HTTP_INTERNAL_SERVER_ERROR; }
static ngx_int_t ngx_http_random_index_handler(ngx_http_request_t *r) { u_char *last, *filename; size_t len, allocated, root; ngx_err_t err; ngx_int_t rc; ngx_str_t path, uri, *name; ngx_dir_t dir; ngx_uint_t n, level; ngx_array_t names; ngx_http_random_index_loc_conf_t *rlcf; if (r->uri.data[r->uri.len - 1] != '/') { return NGX_DECLINED; } if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_POST))) { return NGX_DECLINED; } rlcf = ngx_http_get_module_loc_conf(r, ngx_http_random_index_module); if (!rlcf->enable) { return NGX_DECLINED; } #if (NGX_HAVE_D_TYPE) len = NGX_DIR_MASK_LEN; #else len = NGX_HTTP_RANDOM_INDEX_PREALLOCATE; #endif last = ngx_http_map_uri_to_path(r, &path, &root, len); if (last == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } allocated = path.len; path.len = last - path.data - 1; path.data[path.len] = '\0'; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http random index: \"%s\"", path.data); if (ngx_open_dir(&path, &dir) == NGX_ERROR) { err = ngx_errno; if (err == NGX_ENOENT || err == NGX_ENOTDIR || err == NGX_ENAMETOOLONG) { level = NGX_LOG_ERR; rc = NGX_HTTP_NOT_FOUND; } else if (err == NGX_EACCES) { level = NGX_LOG_ERR; rc = NGX_HTTP_FORBIDDEN; } else { level = NGX_LOG_CRIT; rc = NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_log_error(level, r->connection->log, err, ngx_open_dir_n " \"%s\" failed", path.data); return rc; } if (ngx_array_init(&names, r->pool, 32, sizeof(ngx_str_t)) != NGX_OK) { return ngx_http_random_index_error(r, &dir, &path); } filename = path.data; filename[path.len] = '/'; for ( ;; ) { ngx_set_errno(0); if (ngx_read_dir(&dir) == NGX_ERROR) { err = ngx_errno; if (err != NGX_ENOMOREFILES) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, ngx_read_dir_n " \"%V\" failed", &path); return ngx_http_random_index_error(r, &dir, &path); } break; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http random index file: \"%s\"", ngx_de_name(&dir)); if (ngx_de_name(&dir)[0] == '.') { continue; } len = ngx_de_namelen(&dir); if (dir.type == 0 || ngx_de_is_link(&dir)) { /* 1 byte for '/' and 1 byte for terminating '\0' */ if (path.len + 1 + len + 1 > allocated) { allocated = path.len + 1 + len + 1 + NGX_HTTP_RANDOM_INDEX_PREALLOCATE; filename = ngx_pnalloc(r->pool, allocated); if (filename == NULL) { return ngx_http_random_index_error(r, &dir, &path); } last = ngx_cpystrn(filename, path.data, path.len + 1); *last++ = '/'; } ngx_cpystrn(last, ngx_de_name(&dir), len + 1); if (ngx_de_info(filename, &dir) == NGX_FILE_ERROR) { err = ngx_errno; if (err != NGX_ENOENT) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, ngx_de_info_n " \"%s\" failed", filename); return ngx_http_random_index_error(r, &dir, &path); } if (ngx_de_link_info(filename, &dir) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, ngx_de_link_info_n " \"%s\" failed", filename); return ngx_http_random_index_error(r, &dir, &path); } } } if (!ngx_de_is_file(&dir)) { continue; } name = ngx_array_push(&names); if (name == NULL) { return ngx_http_random_index_error(r, &dir, &path); } name->len = len; name->data = ngx_pnalloc(r->pool, len); if (name->data == NULL) { return ngx_http_random_index_error(r, &dir, &path); } ngx_memcpy(name->data, ngx_de_name(&dir), len); } if (ngx_close_dir(&dir) == NGX_ERROR) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, ngx_close_dir_n " \"%s\" failed", &path); } n = names.nelts; if (n == 0) { return NGX_DECLINED; } name = names.elts; n = (ngx_uint_t) (((uint64_t) ngx_random() * n) / 0x80000000); uri.len = r->uri.len + name[n].len; uri.data = ngx_pnalloc(r->pool, uri.len); if (uri.data == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } last = ngx_copy(uri.data, r->uri.data, r->uri.len); ngx_memcpy(last, name[n].data, name[n].len); return ngx_http_internal_redirect(r, &uri, &r->args); }
static ngx_int_t ngx_http_concat_handler(ngx_http_request_t *r) { off_t length; size_t root, last_len; time_t last_modified; u_char *p, *v, *e, *last, *last_type; ngx_int_t rc; ngx_str_t *uri, *filename, path; ngx_buf_t *b; ngx_uint_t i, j, level; ngx_flag_t timestamp; ngx_array_t uris; ngx_chain_t out, **last_out, *cl; ngx_open_file_info_t of; ngx_http_core_loc_conf_t *ccf; ngx_http_concat_loc_conf_t *clcf; if (r->uri.data[r->uri.len - 1] != '/') { return NGX_DECLINED; } if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) { return NGX_DECLINED; } clcf = ngx_http_get_module_loc_conf(r, ngx_http_concat_module); if (!clcf->enable) { return NGX_DECLINED; } /* the length of args must be greater than or equal to 2 */ if (r->args.len < 2 || r->args.data[0] != '?') { return NGX_DECLINED; } rc = ngx_http_discard_request_body(r); if (rc != NGX_OK) { return rc; } last = ngx_http_map_uri_to_path(r, &path, &root, 0); if (last == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } path.len = last - path.data; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http concat root: \"%V\"", &path); ccf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); #if (NGX_SUPPRESS_WARN) ngx_memzero(&uris, sizeof(ngx_array_t)); #endif if (ngx_array_init(&uris, r->pool, 8, sizeof(ngx_str_t)) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } e = r->args.data + r->args.len; for (p = r->args.data + 1, v = p, timestamp = 0; p != e; p++) { if (*p == ',') { if (p == v || timestamp == 1) { v = p + 1; timestamp = 0; continue; } rc = ngx_http_concat_add_path(r, &uris, clcf->max_files, &path, p, v); if (rc != NGX_OK) { return rc; } v = p + 1; } else if (*p == '?') { if (timestamp == 1) { v = p; continue; } rc = ngx_http_concat_add_path(r, &uris, clcf->max_files, &path, p, v); if (rc != NGX_OK) { return rc; } v = p; timestamp = 1; } } if (p - v > 0 && timestamp == 0) { rc = ngx_http_concat_add_path(r, &uris, clcf->max_files, &path, p, v); if (rc != NGX_OK) { return rc; } } last_modified = 0; last_len = 0; last_out = NULL; b = NULL; last_type = NULL; length = 0; uri = uris.elts; for (i = 0; i < uris.nelts; i++) { filename = uri + i; for (j = filename->len - 1; j > 1; j--) { if (filename->data[j] == '.' && filename->data[j - 1] != '/') { r->exten.len = filename->len - j - 1; r->exten.data = &filename->data[j + 1]; break; } else if (filename->data[j] == '/') { break; } } r->headers_out.content_type.len = 0; if (ngx_http_set_content_type(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } r->headers_out.content_type_lowcase = NULL; if (ngx_http_test_content_type(r, &clcf->types) == NULL) { return NGX_HTTP_BAD_REQUEST; } if (clcf->unique) { /* test if all the content types are the same */ if ((i > 0) && (last_len != r->headers_out.content_type_len || (last_type != NULL && r->headers_out.content_type_lowcase != NULL && ngx_memcmp(last_type, r->headers_out.content_type_lowcase, last_len) != 0))) { return NGX_HTTP_BAD_REQUEST; } last_len = r->headers_out.content_type_len; last_type = r->headers_out.content_type_lowcase; } ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.read_ahead = ccf->read_ahead; of.directio = ccf->directio; of.valid = ccf->open_file_cache_valid; of.min_uses = ccf->open_file_cache_min_uses; of.errors = ccf->open_file_cache_errors; of.events = ccf->open_file_cache_events; if (ngx_open_cached_file(ccf->open_file_cache, filename, &of, r->pool) != NGX_OK) { switch (of.err) { case 0: return NGX_HTTP_INTERNAL_SERVER_ERROR; case NGX_ENOENT: case NGX_ENOTDIR: case NGX_ENAMETOOLONG: level = NGX_LOG_ERR; rc = NGX_HTTP_NOT_FOUND; break; case NGX_EACCES: level = NGX_LOG_ERR; rc = NGX_HTTP_FORBIDDEN; break; default: level = NGX_LOG_CRIT; rc = NGX_HTTP_INTERNAL_SERVER_ERROR; break; } if (rc != NGX_HTTP_NOT_FOUND || ccf->log_not_found) { ngx_log_error(level, r->connection->log, of.err, "%s \"%V\" failed", of.failed, filename); } if (clcf->ignore_file_error && (rc == NGX_HTTP_NOT_FOUND || rc == NGX_HTTP_FORBIDDEN)) { continue; } return rc; } if (!of.is_file) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, "\"%V\" is not a regular file", filename); if (clcf->ignore_file_error) { continue; } return NGX_HTTP_NOT_FOUND; } if (of.size == 0) { continue; } length += of.size; if (last_out == NULL) { last_modified = of.mtime; } else { if (of.mtime > last_modified) { last_modified = of.mtime; } } b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)); if (b->file == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b->file_pos = 0; b->file_last = of.size; b->in_file = b->file_last ? 1 : 0; b->file->fd = of.fd; b->file->name = *filename; b->file->log = r->connection->log; b->file->directio = of.is_directio; if (last_out == NULL) { out.buf = b; last_out = &out.next; out.next = NULL; } else { cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } cl->buf = b; *last_out = cl; last_out = &cl->next; cl->next = NULL; } if (i + 1 == uris.nelts || clcf->delimiter.len == 0) { continue; } b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b->pos = clcf->delimiter.data; b->last = b->pos + clcf->delimiter.len; b->memory = 1; length += clcf->delimiter.len; cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } cl->buf = b; *last_out = cl; last_out = &cl->next; cl->next = NULL; } r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = length; r->headers_out.last_modified_time = last_modified; if (b == NULL) { r->header_only = 1; } rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } if (b != NULL) { b->last_in_chain = 1; b->last_buf = 1; } return ngx_http_output_filter(r, &out); }