static ngx_int_t ngx_http_data_dome_auth_handler(ngx_http_request_t *r) { ngx_buf_t *b; ngx_int_t rc; ngx_str_t val; ngx_str_t x_datadome_response; ngx_uint_t i; ngx_chain_t out; ngx_list_part_t *part; ngx_table_elt_t *header; ngx_table_elt_t *location; ngx_http_data_dome_auth_ctx_t *ctx; ngx_http_data_dome_auth_conf_t *acf; // you can dissable this module in location or if level acf = ngx_http_get_module_loc_conf(r, ngx_http_data_dome_auth_module); if (acf->uri_lengths == NULL) { return NGX_DECLINED; } if (r->internal && acf->pass_internal_redirect) { return NGX_DECLINED; } // but module use main request context to keep the status // to prevent duplicated query to API server ctx = ngx_http_get_module_ctx(r->main, ngx_http_data_dome_auth_module); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->main->connection->log, 0, "Data Dome auth request handler, ctx: %p", ctx); if (ctx != NULL) { ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->main->connection->log, 0, "Data Dome auth request handler ctx: declined %d, processing: %d, done: %d", ctx->declined, ctx->processing, ctx->done); if (ctx->declined) { return NGX_DECLINED; } if (ctx->processing) { return NGX_OK; } if (!ctx->done) { return NGX_AGAIN; } if (ngx_http_data_dome_auth_set_variables(r, acf, ctx) != NGX_OK) { return NGX_ERROR; } if (acf->learning) { return NGX_OK; } if (ctx->subrequest_rc < NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } x_datadome_response.len = 0; part = &ctx->subrequest->headers_out.headers.part; header = part->elts; for (i = 0; /* void */ ; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; header = part->elts; i = 0; } if (header[i].hash == 0) { continue; } if (header[i].key.len != sizeof("X-DataDomeResponse") - 1) { continue; } if (ngx_strncmp(header[i].key.data, "X-DataDomeResponse", header[i].key.len) != 0) { continue; } x_datadome_response = header[i].value; break; } if (x_datadome_response.len == 0) { ngx_log_error(NGX_LOG_ERR, r->main->connection->log, 0, "API server response hasn't got X-DataDomeResponse"); return NGX_DECLINED; } if ((ngx_uint_t)ngx_atoi(x_datadome_response.data, x_datadome_response.len) != ctx->subrequest->headers_out.status) { ngx_log_error(NGX_LOG_ERR, r->main->connection->log, 0, "API server response's X-DataDomeResponse (%V) != status (%d)", &x_datadome_response, ctx->subrequest->headers_out.status); return NGX_DECLINED; } if (ngx_http_data_dome_auth_execute_x_datadome_headers(r->main->pool, "X-DataDome-headers", &ctx->subrequest->headers_out.headers, &r->main->headers_out.headers) == NGX_ERROR) { return NGX_ERROR; } if (ngx_http_data_dome_auth_execute_x_datadome_headers(r->main->pool, "X-DataDome-request-headers", &ctx->subrequest->headers_out.headers, &r->main->headers_in.headers) == NGX_ERROR) { return NGX_ERROR; } switch (ctx->subrequest->headers_out.status) { case NGX_HTTP_MOVED_PERMANENTLY: case NGX_HTTP_MOVED_TEMPORARILY: case NGX_HTTP_UNAUTHORIZED: case NGX_HTTP_FORBIDDEN: part = &ctx->subrequest->headers_out.headers.part; header = part->elts; for (i = 0; /* void */ ; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; header = part->elts; i = 0; } if (header[i].hash == 0) { continue; } if (header[i].key.len != sizeof("Location") - 1) { continue; } if (ngx_strncmp(header[i].key.data, "Location", header[i].key.len) != 0) { continue; } location = ngx_list_push(&r->main->headers_out.headers); if (location == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } location->hash = 1; location->key = header[i].key; location->lowcase_key = header[i].lowcase_key; location->value = header[i].value; break; } // nginx reset upstream buffer length, so, use body lenght from header ;) val.len = ctx->subrequest->headers_out.content_length_n; val.data = ctx->subrequest->upstream->buffer.pos; // if response hasn't Content-Length and body the length was -1, fix it if (ctx->subrequest->headers_out.content_length_n < 0) { val.len = 0; } if (val.len == 0) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "Data Dome auth send response without body: s: %d", ctx->subrequest->headers_out.status); return ctx->subrequest->headers_out.status; } ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "Data Dome auth send response: s: %d, c: %V, b: %V", ctx->subrequest->headers_out.status, &ctx->subrequest->headers_out.content_type, &val); r->headers_out.status = ctx->subrequest->headers_out.status; r->headers_out.content_length_n = val.len; if (ctx->subrequest->headers_out.content_type.len) { r->headers_out.content_type_len = ctx->subrequest->headers_out.content_type.len; r->headers_out.content_type = ctx->subrequest->headers_out.content_type; } else { if (ngx_http_set_content_type(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } } if (r->method == NGX_HTTP_HEAD || val.len == 0) { rc = ngx_http_send_header(r); if (rc != NGX_OK) { return rc; } return NGX_DONE; } b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b->pos = val.data; b->last = val.data + val.len; b->memory = val.len ? 1 : 0; b->last_buf = (r == r->main) ? 1 : 0; b->last_in_chain = 1; out.buf = b; out.next = NULL; rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK) { return rc; } if (r->header_only) { ngx_http_finalize_request(r, NGX_DONE); return NGX_DONE; } rc = ngx_http_output_filter(r, &out); if (rc != NGX_OK) { return rc; } ngx_http_finalize_request(r, NGX_DONE); return NGX_DONE; case NGX_HTTP_OK: return NGX_OK; default: ngx_log_error(NGX_LOG_ERR, r->main->connection->log, 0, "Data Dome auth request unexpected status: %d, pass", ctx->subrequest->headers_out.status); return NGX_OK; } } ctx = ngx_pcalloc(r->main->pool, sizeof(ngx_http_data_dome_auth_ctx_t)); if (ctx == NULL) { return NGX_ERROR; } if (ngx_http_script_run(r, &ctx->uri, acf->uri_lengths->elts, 0, acf->uri_values->elts) == NULL) { return NGX_ERROR; } if (ngx_strncmp(ctx->uri.data, "off", ctx->uri.len) == 0) { return NGX_DECLINED; } ngx_http_set_ctx(r->main, ctx, ngx_http_data_dome_auth_module); #if (NGX_PCRE) if (acf->uri_regex_exclusion) { if (ngx_regex_exec(acf->uri_regex_exclusion, &r->main->uri, NULL, 0) != NGX_REGEX_NO_MATCHED) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->main->connection->log, 0, "Data Dome auth URI regex exclusion: \"%V\" match with URI: %V", &acf->uri_regex_exclusion_raw, &r->main->uri); ctx->declined = 1; return NGX_DECLINED; } } if (acf->uri_regex) { if (ngx_regex_exec(acf->uri_regex, &r->main->uri, NULL, 0) != NGX_REGEX_NO_MATCHED) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->main->connection->log, 0, "Data Dome auth URI regex: \"%V\" match with URI: %V", &acf->uri_regex_raw, &r->main->uri); goto validate; } ctx->declined = 1; return NGX_DECLINED; } validate: #endif ctx->processing = 1; // keep original read and write event handler because read client body may override it ctx->read_event_handler = r->main->read_event_handler; ctx->write_event_handler = r->main->write_event_handler; return ngx_http_data_dome_subrequest(r); }
static ngx_int_t ngx_http_static_handler(ngx_http_request_t *r) { u_char *last; ngx_fd_t fd; ngx_int_t rc; ngx_uint_t level; ngx_str_t name, location; ngx_err_t err; ngx_log_t *log; ngx_buf_t *b; ngx_chain_t out; ngx_file_info_t fi; ngx_http_cleanup_t *file_cleanup, *redirect_cleanup; ngx_http_log_ctx_t *ctx; ngx_http_core_loc_conf_t *clcf; ngx_http_static_loc_conf_t *slcf; #if (NGX_HTTP_CACHE) uint32_t file_crc, redirect_crc; ngx_http_cache_t *file, *redirect; #endif if (r->uri.data[r->uri.len - 1] == '/') { return NGX_DECLINED; } if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) { return NGX_HTTP_NOT_ALLOWED; } rc = ngx_http_discard_body(r); if (rc != NGX_OK && rc != NGX_AGAIN) { return rc; } #if (NGX_HTTP_CACHE) /* * there is a valid cached open file, i.e by the index handler, * and it should be already registered in r->cleanup */ if (r->cache && !r->cache->expired) { return ngx_http_send_cached(r); } #endif log = r->connection->log; clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); /* * make a file name, reserve 2 bytes for a trailing '/' * in a possible redirect and for the last '\0' */ if (clcf->alias) { name.data = ngx_palloc(r->pool, clcf->root.len + r->uri.len + 2 - clcf->name.len); if (name.data == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } last = ngx_cpymem(name.data, clcf->root.data, clcf->root.len); last = ngx_cpystrn(last, r->uri.data + clcf->name.len, r->uri.len + 1 - clcf->name.len); name.len = last - name.data; location.data = ngx_palloc(r->pool, r->uri.len + 2); if (location.data == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } last = ngx_cpystrn(location.data, r->uri.data, r->uri.len + 1); #if 0 /* * aliases usually have trailling "/", * set it in the start of the possible redirect */ if (*location.data != '/') { location.data--; } #endif location.len = last - location.data + 1; } else { name.data = ngx_palloc(r->pool, clcf->root.len + r->uri.len + 2); if (name.data == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } location.data = ngx_cpymem(name.data, clcf->root.data, clcf->root.len); last = ngx_cpystrn(location.data, r->uri.data, r->uri.len + 1); name.len = last - name.data; location.len = last - location.data + 1; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http filename: \"%s\"", name.data); /* allocate cleanups */ if (!(file_cleanup = ngx_push_array(&r->cleanup))) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } file_cleanup->valid = 0; slcf = ngx_http_get_module_loc_conf(r, ngx_http_static_module); if (slcf->redirect_cache) { if (!(redirect_cleanup = ngx_push_array(&r->cleanup))) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } redirect_cleanup->valid = 0; } else { redirect_cleanup = NULL; } #if (NGX_HTTP_CACHE) /* look up an open files cache */ if (clcf->open_files) { file = ngx_http_cache_get(clcf->open_files, file_cleanup, &name, &file_crc); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http open file cache get: " PTR_FMT, file); if (file && !file->expired) { r->cache = file; return ngx_http_send_cached(r); } } else { file = NULL; } /* look up an redirect cache */ if (slcf->redirect_cache) { redirect = ngx_http_cache_get(slcf->redirect_cache, redirect_cleanup, &name, &redirect_crc); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http redirect cache get: " PTR_FMT, redirect); if (redirect && !redirect->expired) { /* * We do not copy a cached value so the cache entry is locked * until the end of the request. In a single threaded model * the redirected request should complete before other event * will be processed. In a multithreaded model this locking * should keep more popular redirects in cache. */ if (!(r->headers_out.location = ngx_http_add_header(&r->headers_out, ngx_http_headers_out))) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } r->headers_out.location->value = redirect->data.value; return NGX_HTTP_MOVED_PERMANENTLY; } } else { redirect = NULL; } #endif /* open file */ #if (WIN9X) /* TODO: redirect cache */ if (ngx_win32_version < NGX_WIN_NT) { /* * there is no way to open a file or a directory in Win9X with * one syscall because Win9X has no FILE_FLAG_BACKUP_SEMANTICS flag * so we need to check its type before the opening */ if (ngx_file_info(name.data, &fi) == NGX_FILE_ERROR) { err = ngx_errno; ngx_log_error(NGX_LOG_ERR, log, err, ngx_file_info_n " \"%s\" failed", name.data); if (err == NGX_ENOENT || err == NGX_ENOTDIR) { return NGX_HTTP_NOT_FOUND; } else if (err == NGX_EACCES) { return NGX_HTTP_FORBIDDEN; } else { return NGX_HTTP_INTERNAL_SERVER_ERROR; } } if (ngx_is_dir(&fi)) { ngx_log_debug(log, "HTTP DIR: '%s'" _ name.data); if (!(r->headers_out.location = ngx_http_add_header(&r->headers_out, ngx_http_headers_out))) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } *last++ = '/'; *last = '\0'; r->headers_out.location->value.len = last - location; r->headers_out.location->value.data = location; return NGX_HTTP_MOVED_PERMANENTLY; } } #endif fd = ngx_open_file(name.data, NGX_FILE_RDONLY, NGX_FILE_OPEN); if (fd == NGX_INVALID_FILE) { err = ngx_errno; if (err == NGX_ENOENT || err == NGX_ENOTDIR) { 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, log, err, ngx_open_file_n " \"%s\" failed", name.data); return rc; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", fd); if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_CRIT, log, ngx_errno, ngx_fd_info_n " \"%s\" failed", name.data); if (ngx_close_file(fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, ngx_close_file_n " \"%s\" failed", name.data); } return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (ngx_is_dir(&fi)) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http dir"); if (ngx_close_file(fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, ngx_close_file_n " \"%s\" failed", name.data); } *last++ = '/'; *last = '\0'; r->headers_out.location = ngx_list_push(&r->headers_out.headers); if (r->headers_out.location == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } r->headers_out.location->value = location; #if (NGX_HTTP_CACHE) if (slcf->redirect_cache) { if (redirect) { if (location.len == redirect->data.value.len && ngx_memcmp(redirect->data.value.data, location.data, location.len) == 0) { redirect->accessed = ngx_cached_time; redirect->updated = ngx_cached_time; /* * we can unlock the cache entry because * we have the local copy anyway */ ngx_http_cache_unlock(slcf->redirect_cache, redirect, log); redirect_cleanup->valid = 0; return NGX_HTTP_MOVED_PERMANENTLY; } } location.len++; redirect = ngx_http_cache_alloc(slcf->redirect_cache, redirect, redirect_cleanup, &name, redirect_crc, &location, log); location.len--; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http redirect cache alloc: " PTR_FMT, redirect); if (redirect) { redirect->fd = NGX_INVALID_FILE; redirect->accessed = ngx_cached_time; redirect->last_modified = 0; redirect->updated = ngx_cached_time; redirect->memory = 1; ngx_http_cache_unlock(slcf->redirect_cache, redirect, log); redirect_cleanup->valid = 0; } } #endif return NGX_HTTP_MOVED_PERMANENTLY; } #if !(WIN32) /* the not regular files are probably Unix specific */ if (!ngx_is_file(&fi)) { ngx_log_error(NGX_LOG_CRIT, log, ngx_errno, "%s is not a regular file", name.data); if (ngx_close_file(fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, ngx_close_file_n " \"%s\" failed", name.data); } return NGX_HTTP_NOT_FOUND; } #endif #if (NGX_HTTP_CACHE) if (clcf->open_files) { #if (NGX_USE_HTTP_FILE_CACHE_UNIQ) if (file && file->uniq == ngx_file_uniq(&fi)) { if (ngx_close_file(fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, ngx_close_file_n " \"%s\" failed", name.data); } file->accessed = ngx_cached_time; file->updated = ngx_cached_time; file->expired = 0; r->cache = file; return ngx_http_send_cached(r); } else { if (file) { ngx_http_cache_unlock(clcf->open_files, file, log); file = NULL; } file = ngx_http_cache_alloc(clcf->open_files, file, file_cleanup, &name, file_crc, NULL, log); if (file) { file->uniq = ngx_file_uniq(&fi); } } #else file = ngx_http_cache_alloc(clcf->open_files, file, file_cleanup, &name, file_crc, NULL, log); #endif ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http open file cache alloc: " PTR_FMT, file); if (file) { file->fd = fd; file->data.size = ngx_file_size(&fi); file->accessed = ngx_cached_time; file->last_modified = ngx_file_mtime(&fi); file->updated = ngx_cached_time; r->cache = file; } return ngx_http_send_cached(r); } #endif ctx = log->data; ctx->action = "sending response to client"; file_cleanup->data.file.fd = fd; file_cleanup->data.file.name = name.data; file_cleanup->valid = 1; file_cleanup->cache = 0; r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = ngx_file_size(&fi); r->headers_out.last_modified_time = ngx_file_mtime(&fi); if (r->headers_out.content_length_n == 0) { r->header_only = 1; } if (ngx_http_set_content_type(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } #if (NGX_SUPPRESS_WARN) b = NULL; #endif if (!r->header_only) { /* we need to allocate all before the header would be sent */ if (!(b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)))) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (!(b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)))) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } r->filter_allow_ranges = 1; } rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } b->in_file = 1; if (!r->main) { b->last_buf = 1; } b->file_pos = 0; b->file_last = ngx_file_size(&fi); b->file->fd = fd; b->file->log = log; out.buf = b; out.next = NULL; return ngx_http_output_filter(r, &out); }
static ngx_int_t ngx_http_redis_handler(ngx_http_request_t *r) { ngx_int_t rc; ngx_http_upstream_t *u; ngx_http_redis_ctx_t *ctx; ngx_http_redis_loc_conf_t *rlcf; if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) { return NGX_HTTP_NOT_ALLOWED; } rc = ngx_http_discard_request_body(r); if (rc != NGX_OK) { return rc; } if (ngx_http_set_content_type(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } rlcf = ngx_http_get_module_loc_conf(r, ngx_http_redis_module); if (rlcf->complex_target) { ngx_str_t target; ngx_url_t url; /* variables used in the redis_pass directive */ if (ngx_http_complex_value(r, rlcf->complex_target, &target) != NGX_OK) { return NGX_ERROR; } if (target.len == 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "handler: empty \"redis_pass\" target"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } url.host = target; url.port = 0; url.default_port = 6379; url.no_resolve = 1; rlcf->upstream.upstream = ngx_http_redis_upstream_add(r, &url); if (rlcf->upstream.upstream == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "redis: upstream \"%V\" not found", &target); return NGX_HTTP_INTERNAL_SERVER_ERROR; } } #if defined nginx_version && nginx_version >= 8011 if (ngx_http_upstream_create(r) != NGX_OK) { #else u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t)); if (u == NULL) { #endif return NGX_HTTP_INTERNAL_SERVER_ERROR; } #if defined nginx_version && nginx_version >= 8011 u = r->upstream; #endif #if defined nginx_version && nginx_version >= 8037 ngx_str_set(&u->schema, "redis://"); #else u->schema.len = sizeof("redis://") - 1; u->schema.data = (u_char *) "redis://"; #endif #if defined nginx_version && nginx_version >= 8011 u->output.tag = (ngx_buf_tag_t) &ngx_http_redis_module; #else u->peer.log = r->connection->log; u->peer.log_error = NGX_ERROR_ERR; #endif #if !defined(nginx_version) || nginx_version < 8011 u->output.tag = (ngx_buf_tag_t) &ngx_http_redis_module; #endif u->conf = &rlcf->upstream; u->create_request = ngx_http_redis_create_request; u->reinit_request = ngx_http_redis_reinit_request; u->process_header = ngx_http_redis_process_header; u->abort_request = ngx_http_redis_abort_request; u->finalize_request = ngx_http_redis_finalize_request; #if defined nginx_version && nginx_version < 8011 r->upstream = u; #endif ctx = ngx_palloc(r->pool, sizeof(ngx_http_redis_ctx_t)); if (ctx == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } ctx->rest = NGX_HTTP_REDIS_END; ctx->request = r; ngx_http_set_ctx(r, ctx, ngx_http_redis_module); u->input_filter_init = ngx_http_redis_filter_init; u->input_filter = ngx_http_redis_filter; u->input_filter_ctx = ctx; #if defined nginx_version && nginx_version >= 8011 r->main->count++; #endif ngx_http_upstream_init(r); return NGX_DONE; } static ngx_int_t ngx_http_redis_create_request(ngx_http_request_t *r) { size_t len = 0; uintptr_t escape; ngx_buf_t *b; ngx_chain_t *cl; ngx_http_redis_ctx_t *ctx; ngx_http_variable_value_t *vv[3]; ngx_http_redis_loc_conf_t *rlcf; u_char lenbuf[NGX_INT_T_LEN]; rlcf = ngx_http_get_module_loc_conf(r, ngx_http_redis_module); vv[0] = ngx_http_get_indexed_variable(r, ngx_http_redis_auth_index); if (vv[0] == NULL || vv[0]->not_found || vv[0]->len == 0) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "no auth command provided" ); } else { len += sizeof("*2\r\n$4\r\nauth\r\n$") - 1; len += ngx_sprintf(lenbuf, "%d", vv[0]->len) - lenbuf; len += sizeof(CRLF) - 1 + vv[0]->len; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "auth info: %s", vv[0]->data); } len += sizeof(CRLF) - 1; vv[1] = ngx_http_get_indexed_variable(r, ngx_http_redis_db_index); /* * If user do not select redis database in nginx.conf by redis_db * variable, just add size of "select 0" to request. This is add * some overhead in talk with redis, but this way simplify parsing * the redis answer in ngx_http_redis_process_header(). */ if (vv[1] == NULL || vv[1]->not_found || vv[1]->len == 0) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "select 0 redis database" ); len += sizeof("*2\r\n$6\r\nselect\r\n$1\r\n0") - 1; } else { len += sizeof("*2\r\n$6\r\nselect\r\n$") - 1; len += ngx_sprintf(lenbuf, "%d", vv[1]->len) - lenbuf; len += sizeof(CRLF) - 1 + vv[1]->len; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "select %s redis database", vv[1]->data); } len += sizeof(CRLF) - 1; vv[2] = ngx_http_get_indexed_variable(r, rlcf->index); /* If nginx.conf have no redis_key return error. */ if (vv[2] == NULL || vv[2]->not_found || vv[2]->len == 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "the \"$redis_key\" variable is not set"); return NGX_ERROR; } /* Count have space required escape symbols. */ escape = 2 * ngx_escape_uri(NULL, vv[2]->data, vv[2]->len, NGX_ESCAPE_REDIS); len += sizeof("*2\r\n$3\r\nget\r\n$") - 1; len += ngx_sprintf(lenbuf, "%d", vv[2]->len) - lenbuf; len += sizeof(CRLF) - 1 + vv[2]->len + escape + sizeof(CRLF) - 1; /* Create temporary buffer for request with size len. */ b = ngx_create_temp_buf(r->pool, len); if (b == NULL) { return NGX_ERROR; } cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_ERROR; } cl->buf = b; cl->next = NULL; r->upstream->request_bufs = cl; /* add "auth " for request */ if (vv[0] != NULL && !(vv[0]->not_found) && vv[0]->len != 0) { /* Add "auth " for request. */ b->last = ngx_sprintf(b->last, "*2\r\n$4\r\nauth\r\n$%d\r\n", vv[0]->len); b->last = ngx_copy(b->last, vv[0]->data, vv[0]->len); *b->last++ = CR; *b->last++ = LF; } /* Get context redis_db from configuration file. */ ctx = ngx_http_get_module_ctx(r, ngx_http_redis_module); ctx->key.data = b->last; /* * Add "0" as redis number db to request if redis_db undefined, * othervise add real number from context. */ if (vv[1] == NULL || vv[1]->not_found || vv[1]->len == 0) { b->last = ngx_sprintf(b->last, "*2\r\n$6\r\nselect\r\n$1\r\n0"); ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "select 0 redis database" ); } else { b->last = ngx_sprintf(b->last, "*2\r\n$6\r\nselect\r\n$%d\r\n", vv[1]->len); b->last = ngx_copy(b->last, vv[1]->data, vv[1]->len); ctx->key.len = b->last - ctx->key.data; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "select %V redis database", &ctx->key); } /* Add "\r\n". */ *b->last++ = CR; *b->last++ = LF; b->last = ngx_sprintf(b->last, "*2\r\n$3\r\nget\r\n$%d\r\n", vv[2]->len); /* Get context redis_key from nginx.conf. */ ctx = ngx_http_get_module_ctx(r, ngx_http_redis_module); ctx->key.data = b->last; /* * If no escape symbols then copy data as is, othervise use * escape-copy function. */ if (escape == 0) { b->last = ngx_copy(b->last, vv[2]->data, vv[2]->len); } else { b->last = (u_char *) ngx_escape_uri(b->last, vv[2]->data, vv[2]->len, NGX_ESCAPE_REDIS); } ctx->key.len = b->last - ctx->key.data; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http redis request: \"%V\"", &ctx->key); /* Add one more "\r\n". */ *b->last++ = CR; *b->last++ = LF; /* * Summary, the request looks like this: * "auth $redis_auth\r\nselect $redis_db\r\nget $redis_key\r\n", where * $redis_auth, $redis_db and $redis_key are variable's values. */ return NGX_OK; }
static ngx_int_t ngx_http_memcached_handler(ngx_http_request_t *r) { ngx_int_t rc; ngx_http_upstream_t *u; ngx_http_memcached_ctx_t *ctx; ngx_http_memcached_loc_conf_t *mlcf; if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) { return NGX_HTTP_NOT_ALLOWED; } rc = ngx_http_discard_request_body(r); if (rc != NGX_OK) { return rc; } if (ngx_http_set_content_type(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (ngx_http_upstream_create(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } u = r->upstream; ngx_str_set(&u->schema, "memcached://"); u->output.tag = (ngx_buf_tag_t) &ngx_http_memcached_module; mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_module); u->conf = &mlcf->upstream; u->create_request = ngx_http_memcached_create_request; u->reinit_request = ngx_http_memcached_reinit_request; u->process_header = ngx_http_memcached_process_header; u->abort_request = ngx_http_memcached_abort_request; u->finalize_request = ngx_http_memcached_finalize_request; ctx = ngx_palloc(r->pool, sizeof(ngx_http_memcached_ctx_t)); if (ctx == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } ctx->rest = NGX_HTTP_MEMCACHED_END; ctx->request = r; ngx_http_set_ctx(r, ctx, ngx_http_memcached_module); u->input_filter_init = ngx_http_memcached_filter_init; u->input_filter = ngx_http_memcached_filter; u->input_filter_ctx = ctx; r->main->count++; ngx_http_upstream_init(r); return NGX_DONE; }
static ngx_int_t ngx_http_gridfs_handler(ngx_http_request_t* request) { ngx_http_gridfs_loc_conf_t* gridfs_conf; ngx_http_core_loc_conf_t* core_conf; ngx_buf_t* buffer; ngx_chain_t out; ngx_str_t location_name; ngx_str_t full_uri; char* filename; gridfile_t gridfile; gridfs_conf = ngx_http_get_module_loc_conf(request, ngx_http_gridfs_module); core_conf = ngx_http_get_module_loc_conf(request, ngx_http_core_module); location_name = core_conf->name; full_uri = request->uri; /* defensive */ if (full_uri.len < location_name.len) { ngx_log_error(NGX_LOG_ERR, request->connection->log, 0, "Invalid location name or uri"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } filename = (char*)malloc(sizeof(char) * (full_uri.len - location_name.len + 1)); if (filename == NULL) { ngx_log_error(NGX_LOG_ERR, request->connection->log, 0, "Failed to allocate filename buffer"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } memcpy(filename, full_uri.data + location_name.len, full_uri.len - location_name.len); filename[full_uri.len - location_name.len] = '\0'; /* TODO url decode filename */ gridfile = get_gridfile((const char*)gridfs_conf->mongod_host.data, (const char*)gridfs_conf->gridfs_db.data, (const char*)gridfs_conf->gridfs_root_collection.data, filename); free(filename); if (gridfile.error_code == 1) { /* TODO log what exception mongo is throwing */ ngx_log_error(NGX_LOG_ERR, request->connection->log, 0, "Mongo exception"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (gridfile.error_code == 2) { return NGX_HTTP_NOT_FOUND; } request->headers_out.status = NGX_HTTP_OK; request->headers_out.content_length_n = gridfile.length; ngx_http_set_content_type(request); ngx_http_send_header(request); buffer = ngx_pcalloc(request->pool, sizeof(ngx_buf_t)); if (buffer == NULL) { ngx_log_error(NGX_LOG_ERR, request->connection->log, 0, "Failed to allocate response buffer"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } buffer->pos = (u_char*)gridfile.data; buffer->last = (u_char*)gridfile.data + gridfile.length; buffer->memory = 1; buffer->last_buf = 1; out.buf = buffer; out.next = NULL; return ngx_http_output_filter(request, &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; //ngx_str_t temp = ngx_string("/test1.js"); //r->uri= temp; myChain=&out; r->uri.data=value; r->uri.len=valueLen; /*in=&out; in =in;*/ 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_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; } 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; out.buf = b; out.next = NULL; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "GZIP HANDLER 1"); return 1; }
static ngx_int_t ngx_http_memcached_handler(ngx_http_request_t *r) { ngx_int_t rc; ngx_http_upstream_t *u; ngx_http_memcached_ctx_t *ctx; ngx_http_memcached_loc_conf_t *mlcf; if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) { return NGX_HTTP_NOT_ALLOWED; } rc = ngx_http_discard_request_body(r); if (rc != NGX_OK) { return rc; } if (ngx_http_set_content_type(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_module); u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t)); if (u == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } u->schema = mlcf->upstream.schema; 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_memcached_module; u->conf = &mlcf->upstream; u->create_request = ngx_http_memcached_create_request; u->reinit_request = ngx_http_memcached_reinit_request; u->process_header = ngx_http_memcached_process_header; u->abort_request = ngx_http_memcached_abort_request; u->finalize_request = ngx_http_memcached_finalize_request; r->upstream = u; ctx = ngx_palloc(r->pool, sizeof(ngx_http_memcached_ctx_t)); if (ctx == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } ctx->rest = NGX_HTTP_MEMCACHED_END; ctx->request = r; ngx_http_set_ctx(r, ctx, ngx_http_memcached_module); u->input_filter_init = ngx_http_memcached_filter_init; u->input_filter = ngx_http_memcached_filter; u->input_filter_ctx = ctx; ngx_http_upstream_init(r); return NGX_DONE; }