static ngx_int_t ngx_tcp_process_http_header(ngx_tcp_lua_http_parse_ctx_t *r, ngx_buf_t *b, lua_State *L) { ngx_int_t rc; size_t header_name_len; size_t header_len; for ( ;; ) { rc = ngx_tcp_parse_http_header_line(r, b, 1); if (rc == NGX_OK) { /* a header line has been parsed successfully */ header_name_len = r->header_name_end - r->header_name_start; header_len = r->header_end - r->header_start; lua_pushlstring(L, (const char*)r->header_name_start, header_name_len); lua_pushlstring(L, (const char*)r->header_start, header_len); lua_rawset(L, -3); if (0 == ngx_strncasecmp(r->header_name_start, (u_char *) "content-length", header_name_len) || 0 == ngx_strncasecmp(r->header_name_start, (u_char *) "content_length", header_name_len) ) { r->content_length_n = ngx_atoof(r->header_start, header_len); } if ( (0 == ngx_strncasecmp(r->header_name_start, (u_char *) "transfer-encoding", header_name_len) || 0 == ngx_strncasecmp(r->header_name_start, (u_char *) "transfer-encoding", header_name_len) ) && ngx_strlcasestrn(r->header_start, r->header_end, (u_char *) "chunked", 7 - 1) != NULL ) { r->chunked = 1; } continue; } if (rc == NGX_TCP_HTTP_PARSE_HEADER_DONE) { /* a whole header has been parsed successfully */ //ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, // "http proxy header done"); return NGX_OK; } if (rc == NGX_AGAIN) { return NGX_AGAIN; } //rc = NGX_HTTP_PARSE_INVALID_HEADER /* there was error while a header line parsing */ //ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, // "upstream sent invalid header"); r->error_code = NGX_TCP_LUA_SOCKET_ERR_HEADERS; return NGX_ERROR; } }
static off_t ngx_http_parallel_get_instance_length(ngx_str_t *content_range, ngx_log_t* log) { u_char* last_slash; off_t content_length; last_slash = ngx_http_parallel_memrchr( content_range->data, '/', content_range->len); if (last_slash == NULL) { ngx_log_error(NGX_LOG_ERR, log, 0, "ngx_http_parallel_get_instance_length: " "no slash in content-range value \"%V\"", content_range); return -1; } content_length = ngx_atoof( last_slash + 1, content_range->data + content_range->len - last_slash - 1); if (content_length < 0) { ngx_log_error(NGX_LOG_ERR, log, 0, "ngx_http_parallel_get_instance_length: failed to parse " "instance length from content-range \"%V\"", content_range); return -1; } return content_length; }
static ngx_int_t ngx_http_redis_process_header(ngx_http_request_t *r) { u_char *p;//, *start; //ngx_str_t line; //ngx_uint_t flags; //ngx_table_elt_t *h; ngx_http_upstream_t *u; //ngx_http_redis_ctx_t *ctx; //ngx_http_redis_loc_conf_t *mlcf; u = r->upstream; for (p = u->buffer.pos; p < u->buffer.last; p++) { if (*p == LF) { goto found; } } return NGX_AGAIN; found: *p = '\0'; switch (u->buffer.pos[0]) { case '+': case '-': case ':': u->headers_in.content_length_n = p - u->buffer.pos - 1; u->headers_in.status_n = 200; u->state->status = 200; return NGX_OK; case '$': { u->headers_in.content_length_n = ngx_atoof(u->buffer.pos + 1, p - u->buffer.pos - 2); if (u->headers_in.content_length_n == -1) { u->headers_in.status_n = 404; u->state->status = 404; }else { u->headers_in.status_n = 200; u->state->status = 200; u->buffer.pos = p + 1; } } } return NGX_OK; /* no_valid: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "redis sent invalid response: \"%V\"", &line); return NGX_HTTP_UPSTREAM_INVALID_HEADER; */ }
static ngx_int_t ngx_http_poller_process_header(ngx_http_request_t *r) { static ngx_str_t content_length = ngx_string("Content-Length"); ngx_http_poller_t *poller; ngx_http_upstream_t *u; ngx_int_t rc; ngx_str_t name; ngx_str_t value; poller = ngx_http_get_module_ctx(r, ngx_http_poller_module); if (poller == NULL) { return NGX_ERROR; } u = r->upstream; for ( ;; ) { rc = ngx_http_parse_header_line(r, &r->upstream->buffer, 1); if (rc == NGX_OK) { name.len = r->header_name_end - r->header_name_start; name.data = r->header_name_start; value.len = r->header_end - r->header_start; value.data = r->header_start; if (name.len == content_length.len && ngx_strncasecmp(name.data, content_length.data, name.len) == 0) { u->headers_in.content_length_n = ngx_atoof(value.data, value.len); } if (poller->handler.header != NULL) { poller->handler.header(r, &name, &value); } continue; } if (rc == NGX_HTTP_PARSE_HEADER_DONE) { return NGX_OK; } if (rc == NGX_AGAIN) { return NGX_AGAIN; } ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "upstream sent invalid header"); return NGX_HTTP_UPSTREAM_INVALID_HEADER; } }
//指定空间时,可以使用多种单位 //默认(不指定)为B(b) off_t ngx_parse_offset(ngx_str_t *line) { u_char unit; off_t offset, scale, max; size_t len; len = line->len; unit = line->data[len - 1]; switch (unit) { case 'K': case 'k': len--; max = NGX_MAX_OFF_T_VALUE / 1024; scale = 1024; break; case 'M': case 'm': len--; max = NGX_MAX_OFF_T_VALUE / (1024 * 1024); scale = 1024 * 1024; break; case 'G': case 'g': len--; max = NGX_MAX_OFF_T_VALUE / (1024 * 1024 * 1024); scale = 1024 * 1024 * 1024; break; default: max = NGX_MAX_OFF_T_VALUE; scale = 1; } offset = ngx_atoof(line->data, len); if (offset == NGX_ERROR || offset > max) { return NGX_ERROR; } offset *= scale; return offset; }
static ngx_int_t ngx_http_srcache_process_content_length(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset) { ngx_table_elt_t *ho; ho = ngx_list_push(&r->headers_out.headers); if (ho == NULL) { return NGX_ERROR; } *ho = *h; r->headers_out.content_length = ho; r->headers_out.content_length_n = ngx_atoof(h->value.data, h->value.len); return NGX_OK; }
off_t ngx_parse_offset(ngx_str_t *line) { u_char unit; off_t offset; size_t len; ngx_int_t scale; len = line->len; unit = line->data[len - 1]; switch (unit) { case 'K': case 'k': len--; scale = 1024; break; case 'M': case 'm': len--; scale = 1024 * 1024; break; case 'G': case 'g': len--; scale = 1024 * 1024 * 1024; break; default: scale = 1; } offset = ngx_atoof(line->data, len); if (offset == NGX_ERROR) { return NGX_ERROR; } offset *= scale; return offset; }
static ngx_int_t ngx_http_memcached_hash_process_header(ngx_http_request_t *r) { u_char *p, *start; ngx_str_t line; ngx_uint_t flags; ngx_table_elt_t *h; ngx_http_upstream_t *u; ngx_http_memcached_hash_ctx_t *ctx; ngx_http_memcached_hash_loc_conf_t *mlcf; u = r->upstream; for (p = u->buffer.pos; p < u->buffer.last; p++) { if (*p == LF) { goto found; } } return NGX_AGAIN; found: *p = '\0'; line.len = p - u->buffer.pos - 1; line.data = u->buffer.pos; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "memcached hash: \"%V\"", &line); p = u->buffer.pos; ctx = ngx_http_get_module_ctx(r, ngx_http_memcached_hash_module); mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_hash_module); if (ngx_strncmp(p, "VALUE ", sizeof("VALUE ") - 1) == 0) { p += sizeof("VALUE ") - 1; if (ngx_strncmp(p, ctx->key.data, ctx->key.len) != 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "memcached sent invalid key in response \"%V\" " "for key \"%V\"", &line, &ctx->key); return NGX_HTTP_UPSTREAM_INVALID_HEADER; } p += ctx->key.len; if (*p++ != ' ') { goto no_valid; } /* flags */ start = p; while (*p) { if (*p++ == ' ') { if (mlcf->gzip_flag) { goto flags; } else { goto length; } } } goto no_valid; flags: flags = ngx_atoi(start, p - start - 1); if (flags == (ngx_uint_t) NGX_ERROR) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "memcached sent invalid flags in response \"%V\" " "for key \"%V\"", &line, &ctx->key); return NGX_HTTP_UPSTREAM_INVALID_HEADER; } if (flags & mlcf->gzip_flag) { h = ngx_list_push(&r->headers_out.headers); if (h == NULL) { return NGX_ERROR; } h->hash = 1; h->key.len = sizeof("Content-Encoding") - 1; h->key.data = (u_char *) "Content-Encoding"; h->value.len = sizeof("gzip") - 1; h->value.data = (u_char *) "gzip"; r->headers_out.content_encoding = h; } length: start = p; while (*p && *p++ != CR) { /* void */ } r->headers_out.content_length_n = ngx_atoof(start, p - start - 1); if (r->headers_out.content_length_n == -1) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "memcached sent invalid length in response \"%V\" " "for key \"%V\"", &line, &ctx->key); return NGX_HTTP_UPSTREAM_INVALID_HEADER; } u->headers_in.status_n = 200; u->state->status = 200; u->buffer.pos = p + 1; return NGX_OK; } if (ngx_strcmp(p, "END\x0d") == 0) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "key: \"%V\" was not found by memcached", &ctx->key); u->headers_in.status_n = 404; u->state->status = 404; return NGX_OK; } no_valid: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "memcached sent invalid response: \"%V\"", &line); return NGX_HTTP_UPSTREAM_INVALID_HEADER; }
ngx_int_t ngx_stream_upm_process_resp_header(ngx_stream_session_t *s) { ngx_int_t rc; ngx_array_t *resp_headers; ngx_table_elt_t *h; ngx_stream_upm_ctx_t *ctx; ngx_stream_upstream_t *u; //ngx_stream_upm_main_conf_t *ummcf; //ngx_http_upstream_header_t *hh; //ngx_stream_upstream_srv_conf_t *umcf; ngx_stream_upm_resp_header_ctx_t hctx; //ummcf = ngx_stream_get_module_srv_conf(s, ngx_stream_upm_module); ctx = ngx_stream_get_module_ctx(s, ngx_stream_upm_module); u = s->upstream; resp_headers = ctx->resp_headers; if (resp_headers == NULL) { resp_headers = ngx_array_create(ctx->pool, 4, sizeof(ngx_table_elt_t)); if (resp_headers == NULL) { return NGX_ERROR; } ctx->resp_headers = resp_headers; } ngx_memzero(&hctx, sizeof(ngx_stream_upm_resp_header_ctx_t)); for ( ;; ) { rc = ngx_stream_upm_parse_header_line(&hctx, &u->upstream_buf, 1); if (rc == NGX_OK) { /* a header line has been parsed successfully */ h = ngx_array_push(resp_headers); if (h == NULL) { return NGX_ERROR; } h->hash = hctx.header_hash; h->key.len = hctx.header_name_end - hctx.header_name_start; h->value.len = hctx.header_end - hctx.header_start; h->key.data = hctx.header_name_start; h->value.data = hctx.header_start; /*No need to care lowcase_key if (h->key.len == r->lowcase_index) { ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len); } else { ngx_strlow(h->lowcase_key, h->key.data, h->key.len); }*/ ngx_log_debug2(NGX_LOG_DEBUG_STREAM, r->connection->log, 0, "stream header: \"%V: %V\"", &h->key, &h->value); if (h->key.len == 14 && ngx_strncmp(h->key.data, "Content-Length", h->key.len) == 0) { ctx->content_length_n = ngx_atoof(h->value.data, h->value.len); } if (h->key.len == 17 && ngx_strncmp(h->key.data, "Transfer-Encoding", h->key.len) == 0) { if (ngx_strlcasestrn(h->value.data, h->value.data + h->value.len, (u_char *) "chunked", 7 - 1) != NULL) { ctx->chunked = 1; } } continue; } if (rc == NGX_HTTP_PARSE_HEADER_DONE) { /* a whole header has been parsed successfully */ ngx_log_debug0(NGX_LOG_DEBUG_STREAM, r->connection->log, 0, "stream upm header done"); /* Get content length */ u = s->upstream; if (ctx->chunked) { ctx->content_length_n = -1; } /* * set u->keepalive if response has no body; this allows to keep * connections alive in case of r->header_only or X-Accel-Redirect */ return NGX_DONE; } if (rc == NGX_AGAIN) { return NGX_AGAIN; } /* there was error while a header line parsing */ ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "upm upstream sent invalid header"); return NGX_HTTP_UPSTREAM_INVALID_HEADER; } }
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_lua_http_parse_headers(ngx_lua_http_ctx_t *ctx) { u_char *p, ch; ngx_int_t rc; ngx_str_t str; ngx_keyval_t *header; ngx_lua_thread_t *thr; ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, "lua http parse headers"); for ( ;; ) { rc = ngx_lua_http_parse_header_line(ctx); if (rc != NGX_OK) { return rc; } ngx_log_debug2(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, "header name:%*s value:%*s", ctx->header_name_end - ctx->header_name_start, ctx->header_name_start, ctx->header_end - ctx->header_start, ctx->header_start); /* TODO */ if (ctx->content_length == 0 && ngx_strncmp(ctx->header_name_start, "Content-Length", sizeof("Content-Length") - 1) == 0) { ctx->content_length = ngx_atoof(ctx->header_start, ctx->header_end - ctx->header_start); if (ctx->content_length == NGX_ERROR) { return NGX_ERROR; } } thr = ctx->thr; if (ctx->thr == NULL) { continue; } for (p = ctx->header_name_start; p < ctx->header_name_end - 1; p++) { ch = *p; if (ch >= 'A' && ch <= 'Z') { ch |= 0x20; } else if (ch == '-') { ch = '_'; } *p = ch; } *ctx->header_name_end = '\0'; header = ngx_array_push(&ctx->headers); if (header == NULL) { return NGX_ERROR; } str.len = ctx->header_name_end - ctx->header_name_start + 1; str.data = ctx->header_name_start; header->key.len = str.len; header->key.data = ngx_pstrdup(ctx->pool, &str); str.len = ctx->header_end - ctx->header_start; str.data = ctx->header_start; header->value.len = str.len; header->value.data = ngx_pstrdup(ctx->pool, &str); } }
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]); }
static ngx_inline ngx_int_t ngx_http_modsecurity_save_headers_in(ngx_http_request_t *r) { ngx_http_modsecurity_ctx_t *ctx; ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity); /* clean up headers_in */ ngx_memzero(&r->headers_in, sizeof(ngx_http_headers_in_t)); if (ngx_list_init(&r->headers_in.headers, r->pool, 20, sizeof(ngx_table_elt_t)) != NGX_OK) { return NGX_ERROR; } if (ngx_array_init(&r->headers_in.cookies, r->pool, 2, sizeof(ngx_table_elt_t *)) != NGX_OK) { return NGX_ERROR; } r->headers_in.content_length_n = -1; r->headers_in.keep_alive_n = -1; r->headers_in.headers.part.nelts = 0; r->headers_in.headers.part.next = NULL; r->headers_in.headers.last = &r->headers_in.headers.part; /* shadow copy */ if (apr_table_do(ngx_http_modsecurity_save_headers_in_visitor, r, ctx->req->headers_in, NULL) == 0) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ModSecurity: save headers in error"); return NGX_ERROR; } if (r->headers_in.content_length) { r->headers_in.content_length_n = ngx_atoof(r->headers_in.content_length->value.data, r->headers_in.content_length->value.len); if (r->headers_in.content_length_n == NGX_ERROR) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "ModSecurity: invalid \"Content-Length\" header"); return NGX_ERROR; } } if (r->headers_in.connection_type == NGX_HTTP_CONNECTION_KEEP_ALIVE) { if (r->headers_in.keep_alive) { r->headers_in.keep_alive_n = ngx_atotm(r->headers_in.keep_alive->value.data, r->headers_in.keep_alive->value.len); } } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ModSecurity: save headers in done"); return NGX_OK; }
static ngx_int_t ngx_http_memcached_process_header(ngx_http_request_t *r) { u_char *p, *start; ngx_str_t line; ngx_uint_t flags; ngx_table_elt_t *h; ngx_http_upstream_t *u; ngx_http_memcached_ctx_t *ctx; ngx_http_memcached_loc_conf_t *mlcf; for (u = r->upstream, p = u->buffer.pos; p < u->buffer.last; ++p) { if (*p == LF) goto found; } return NGX_AGAIN; found: line.data = u->buffer.pos; u->buffer.pos = p + 1; /* eat */ if (*--p != CR) goto no_valid; *p = '\0'; line.len = p - line.data; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "memcached: \"%V\"", &line); ctx = ngx_http_get_module_ctx(r, ngx_http_memcached_module); mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_module); p = line.data; switch (ctx->type) { case NGX_HTTP_MEMCACHED_SET: case NGX_HTTP_MEMCACHED_DEL: case NGX_HTTP_MEMCACHED_CAS: if (!ngx_strcmp(p, "STORED")) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "key: \"%V\" was stored by memcached", &ctx->key); NGX_HTTP_PREPARE_RESPONSE_HEADER(u, "200 STORED"); return NGX_OK; } if (!ngx_strcmp(p, "NOT_STORED")) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "key: \"%V\" was not found by memcached", &ctx->key); NGX_HTTP_PREPARE_RESPONSE_HEADER(u, "404 NOT_STORED"); return NGX_OK; } if (!ngx_strcmp(p, "NOT_FOUND")) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "key: \"%V\" was not found by memcached", &ctx->key); NGX_HTTP_PREPARE_RESPONSE_HEADER(u, "404 NOT_FOUND"); return NGX_OK; } if (!ngx_strcmp(p, "DELETED")) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "key: \"%V\" was deleted by memcached", &ctx->key); NGX_HTTP_PREPARE_RESPONSE_HEADER(u, "200 DELETED"); return NGX_OK; } if (!ngx_strcmp(p, "EXISTS")) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "key: \"%V\" was not found by memcached", &ctx->key); NGX_HTTP_PREPARE_RESPONSE_HEADER(u, "406 EXISTS"); return NGX_OK; } break; case NGX_HTTP_MEMCACHED_GET: /* VALUE <key> <flags> <bytes> */ if (!ngx_strncmp(p, "VALUE ", sizeof("VALUE ") - 1)) { p += sizeof("VALUE ") - 1; if (ngx_strncmp(p, ctx->key.data, ctx->key.len)) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "memcached sent invalid key in response \"%V\" " "for key \"%V\"", &line, &ctx->key); return NGX_HTTP_UPSTREAM_INVALID_HEADER; } if (*(p += ctx->key.len) != ' ') goto no_valid; /* flags */ for (start = ++p; *p;) { if (*p++ == ' ') { /*if (mlcf->gzip_flag)*/ goto flags; /*else goto length;*/ } } goto no_valid; flags: if (!(h = ngx_list_push(&r->headers_out.headers))) return NGX_ERROR; h->hash = 1; ngx_str_set(&h->key, "Memcached-Flags"); h->value.data = start; h->value.len = p - 1 - start; /* gzip flags for data */ flags = ngx_atoi(start, p - 1 - start); if (flags == (ngx_uint_t)NGX_ERROR) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "memcached sent invalid flags in response \"%V\" " "for key \"%V\"", &line, &ctx->key); return NGX_HTTP_UPSTREAM_INVALID_HEADER; } if (flags & mlcf->gzip_flag) { if (!(h = ngx_list_push(&r->headers_out.headers))) 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; } /*length:*/ for (start = p; *p && *p != ' '; ++p); u->headers_in.content_length_n = ngx_atoof(start, p - start); if (u->headers_in.content_length_n == -1) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "memcached sent invalid length in response \"%V\" " "for key \"%V\"", &line, &ctx->key); return NGX_HTTP_UPSTREAM_INVALID_HEADER; } /*unique:*/ if (*p) { if (!(h = ngx_list_push(&r->headers_out.headers))) return NGX_ERROR; h->hash = 1; ngx_str_set(&h->key, "Memcached-Unique"); h->value.data = ++p; h->value.len = line.data + line.len - p; } /*value:*/ if (mlcf->value_flag) { u->process_header = ngx_http_memcached_process_value; return ngx_http_memcached_process_value(r); } u->headers_in.status_n = u->state->status = 200; ngx_str_set(&u->headers_in.status_line, "200 OK"); return NGX_OK; } if (!ngx_strcmp(p, "END")) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "key: \"%V\" was not found by memcached", &ctx->key); NGX_HTTP_PREPARE_RESPONSE_HEADER(u, "404 NOT_FOUND"); return NGX_OK; } } no_valid: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "memcached sent invalid response: \"%V\"", &line); return NGX_HTTP_UPSTREAM_INVALID_HEADER; }
static ngx_int_t ngx_lua_http_btt_parse_args(ngx_http_request_t *r, ngx_btt_ctx_t *ctx) { size_t nlen, vlen; u_char *p, *last, *name, *val, *dst, *src; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua http btt parse args"); if (r->args.len == 0) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "invalid uri \"%V\"", &r->args); return NGX_ERROR; } p = r->args.data; last = p + r->args.len; for ( /* void */ ; p < last; p++) { name = p; p = ngx_strlchr(p, last, '&'); if (p == NULL) { p = last; } val = ngx_strlchr(name, p, '='); if (val == NULL) { val = p; } nlen = val - name; vlen = (++val < p) ? p - val : 0; dst = ngx_pnalloc(r->pool, vlen); if (dst == NULL) { return NGX_ERROR; } src = val; val = dst; ngx_unescape_uri(&dst, &src, vlen, 0); vlen = dst - val; ngx_log_debug4(NGX_LOG_ALERT, r->connection->log, 0, "%*s=%*s", nlen, name, vlen, val); /* * BT Client: * * BitComet: localip, natmapped, port_type * NetTransport: supportcrypto * uTorrent: corrupt * XunLei: ip */ switch (nlen) { case 2: if (ngx_strncmp(name, "ip", nlen) == 0) { ctx->internal_ip = ngx_inet_addr(val, vlen); if (ctx->internal_ip == INADDR_NONE) { goto invalid; } break; } break; case 3: if (ngx_strncmp(name, "key", nlen) == 0) { ngx_memcpy(ctx->key, val, vlen); break; } break; case 4: if (ngx_strncmp(name, "port", nlen) == 0) { ctx->internal_port = (in_port_t) ngx_atoi(val, vlen); if (ctx->internal_port == NGX_ERROR) { goto invalid; } break; } if (ngx_strncmp(name, "left", nlen) == 0) { ctx->left = ngx_atoof(val, vlen); if (ctx->left == NGX_ERROR) { goto invalid; } break; } break; case 5: if (ngx_strncmp(name, "event", nlen) == 0) { if (ngx_strncmp(val, "none", sizeof("none") - 1) == 0) { ctx->event = NGX_BTT_EVENT_NONE; } else if (ngx_strncmp(val, "completed", sizeof("completed") - 1) == 0) { ctx->event = NGX_BTT_EVENT_COMPLETED; } else if (ngx_strncmp(val, "started", sizeof("started") - 1) == 0) { ctx->event = NGX_BTT_EVENT_STARTED; } else if (ngx_strncmp(val, "stopped", sizeof("stopped") - 1) == 0) { ctx->event = NGX_BTT_EVENT_STOPPED; } else { goto invalid; } break; } break; case 7: if (ngx_strncmp(name, "peer_id", nlen) == 0) { ngx_memcpy(ctx->peer_id, val, vlen); break; } if (ngx_strncmp(name, "localip", nlen) == 0) { ctx->internal_ip = ngx_inet_addr(val, vlen); if (ctx->internal_ip == INADDR_NONE) { goto invalid; } break; } if (ngx_strncmp(name, "numwant", nlen) == 0) { ctx->numwant = ngx_atoi(val, vlen); if (ctx->numwant == NGX_ERROR) { goto invalid; } break; } if (ngx_strncmp(name, "compact", nlen) == 0) { ctx->compact = ngx_atoi(val, vlen); if (ctx->compact == NGX_ERROR) { goto invalid; } break; } if (ngx_strncmp(name, "corrupt", nlen) == 0) { ctx->corrupt = ngx_atoi(val, vlen); if (ctx->corrupt == NGX_ERROR) { goto invalid; } break; } break; case 8: if (ngx_strncmp(name, "uploaded", nlen) == 0) { ctx->uploaded = ngx_atoof(val, vlen); if (ctx->uploaded == NGX_ERROR) { goto invalid; } break; } break; case 9: if (ngx_strncmp(name, "info_hash ", nlen) == 0) { ngx_memcpy(ctx->info_hash, val, vlen); break; } if (ngx_strncmp(name, "natmapped ", nlen) == 0) { ctx->natmapped = ngx_atoi(val, vlen); if (ctx->natmapped == NGX_ERROR) { goto invalid; } break; } if (ngx_strncmp(name, "port_type", nlen) == 0) { ngx_memcpy(ctx->port_type, val, vlen); break; } break; case 10: if (ngx_strncmp(name, "downloaded", nlen) == 0) { ctx->downloaded = ngx_atoof(val, vlen); if (ctx->downloaded == NGX_ERROR) { goto invalid; } break; } if (ngx_strncmp(name, "no_peer_id ", nlen) == 0) { ctx->no_peer_id = ngx_atoi(val, vlen); if (ctx->no_peer_id == NGX_ERROR) { goto invalid; } break; } break; case 13: if (ngx_strncmp(name, "supportcrypto", nlen) == 0) { ctx->supportcrypto = ngx_atoi(val, vlen); if (ctx->supportcrypto == NGX_ERROR) { goto invalid; } break; } break; default: break; } } return NGX_OK; invalid: ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "invalid value \"%*s\" of the key \"%*s\"", nlen, name, vlen, val); return NGX_ERROR; }
static ngx_int_t ngx_http_redis_process_header(ngx_http_request_t *r) { u_char *p, *len; ngx_str_t line; ngx_http_upstream_t *u; ngx_http_redis_ctx_t *ctx; u = r->upstream; for (p = u->buffer.pos; p < u->buffer.last; p++) { if (*p == LF) { goto found; } } return NGX_AGAIN; found: *p = '\0'; line.len = p - u->buffer.pos - 1; line.data = u->buffer.pos; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "redis: \"%V\"", &line); p = u->buffer.pos; ctx = ngx_http_get_module_ctx(r, ngx_http_redis_module); if (ngx_strcmp(p, "-ERR") == 0) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "error was received from redis"); u->headers_in.status_n = 404; u->state->status = 404; return NGX_OK; } if (ngx_strcmp(p, "+OK\x0d") == 0) { p += sizeof("+OK") - 1 + sizeof(CRLF) - 1; } if (ngx_strcmp(p, "$-1\x0d") == 0) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "key: \"%V\" was not found by redis", &ctx->key); u->headers_in.status_n = 404; u->state->status = 404; return NGX_OK; } if (ngx_strncmp(p, "$", sizeof("$") - 1) == 0) { p += sizeof("$") - 1; len = p; while (*p && *p++ != CR) { /* void */ } r->headers_out.content_length_n = ngx_atoof(len, p - len - 1); if (r->headers_out.content_length_n == -1) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "redis sent invalid length in response \"%V\" " "for key \"%V\"", &line, &ctx->key); return NGX_HTTP_UPSTREAM_INVALID_HEADER; } u->headers_in.status_n = 200; u->state->status = 200; u->buffer.pos = p + 1; return NGX_OK; } no_valid: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "redis sent invalid response: \"%V\"", &line); return NGX_HTTP_UPSTREAM_INVALID_HEADER; }
static ngx_int_t ngx_http_memcached_process_header(ngx_http_request_t *r) { u_char *p, *len; ngx_str_t line; ngx_http_upstream_t *u; ngx_http_memcached_ctx_t *ctx; u = r->upstream; for (p = u->buffer.pos; p < u->buffer.last; p++) { if (*p == LF) { goto found; } } return NGX_AGAIN; found: *p = '\0'; line.len = p - u->buffer.pos - 1; line.data = u->buffer.pos; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "memcached: \"%V\"", &line); p = u->buffer.pos; ctx = ngx_http_get_module_ctx(r, ngx_http_memcached_module); if (ngx_strncmp(p, "VALUE ", sizeof("VALUE ") - 1) == 0) { p += sizeof("VALUE ") - 1; if (ngx_strncmp(p, ctx->key.data, ctx->key.len) != 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "memcached sent invalid key in response \"%V\" " "for key \"%V\"", &line, &ctx->key); return NGX_HTTP_UPSTREAM_INVALID_HEADER; } p += ctx->key.len; if (*p++ != ' ') { goto no_valid; } /* skip flags */ while (*p) { if (*p++ == ' ') { goto length; } } goto no_valid; length: len = p; while (*p && *p++ != CR) { /* void */ } r->headers_out.content_length_n = ngx_atoof(len, p - len - 1); if (r->headers_out.content_length_n == -1) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "memcached sent invalid length in response \"%V\" " "for key \"%V\"", &line, &ctx->key); return NGX_HTTP_UPSTREAM_INVALID_HEADER; } u->headers_in.status_n = 200; u->state->status = 200; u->buffer.pos = p + 1; return NGX_OK; } if (ngx_strcmp(p, "END\x0d") == 0) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "key: \"%V\" was not found by memcached", &ctx->key); u->headers_in.status_n = 404; u->state->status = 404; return NGX_OK; } no_valid: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "memcached sent invalid response: \"%V\"", &line); return NGX_HTTP_UPSTREAM_INVALID_HEADER; }