ngx_int_t ngx_http_srcache_store_response_header(ngx_http_request_t *r, ngx_http_srcache_ctx_t *ctx) { ngx_chain_t *cl; size_t len; ngx_buf_t *b; ngx_uint_t status; ngx_uint_t i; ngx_str_t *status_line; ngx_list_part_t *part; ngx_table_elt_t *header; u_char buf[sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1]; ngx_http_srcache_loc_conf_t *conf; conf = ngx_http_get_module_loc_conf(r, ngx_http_srcache_filter_module); dd("request: %p, uri: %.*s", r, (int) r->uri.len, r->uri.data); len = sizeof("HTTP/1.x ") - 1 + sizeof(CRLF) - 1 /* the end of the header */ + sizeof(CRLF) - 1; if (r->headers_out.status_line.len) { dd("status line defined"); len += r->headers_out.status_line.len; status_line = &r->headers_out.status_line; status = 0; } else { dd("status line not defined"); status = r->headers_out.status; if (status >= NGX_HTTP_OK && status < NGX_HTTP_LAST_LEVEL_200) { /* 2XX */ status -= NGX_HTTP_OK; dd("status: %d", (int) status); status_line = &ngx_http_status_lines[status]; len += ngx_http_status_lines[status].len; } else if (status >= NGX_HTTP_MOVED_PERMANENTLY && status < NGX_HTTP_LAST_LEVEL_300) { /* 3XX */ if (status == NGX_HTTP_NOT_MODIFIED) { r->header_only = 1; } status = status - NGX_HTTP_MOVED_PERMANENTLY + NGX_HTTP_LEVEL_200; status_line = &ngx_http_status_lines[status]; len += ngx_http_status_lines[status].len; } else if (status >= NGX_HTTP_BAD_REQUEST && status < NGX_HTTP_LAST_LEVEL_400) { /* 4XX */ status = status - NGX_HTTP_BAD_REQUEST + NGX_HTTP_LEVEL_200 + NGX_HTTP_LEVEL_300; status_line = &ngx_http_status_lines[status]; len += ngx_http_status_lines[status].len; } else if (status >= NGX_HTTP_INTERNAL_SERVER_ERROR && status < NGX_HTTP_LAST_LEVEL_500) { /* 5XX */ status = status - NGX_HTTP_INTERNAL_SERVER_ERROR + NGX_HTTP_LEVEL_200 + NGX_HTTP_LEVEL_300 + NGX_HTTP_LEVEL_400; status_line = &ngx_http_status_lines[status]; len += ngx_http_status_lines[status].len; } else { len += NGX_INT_T_LEN; status_line = NULL; } } if (!conf->hide_content_type && r->headers_out.content_type.len) { len += sizeof("Content-Type: ") - 1 + r->headers_out.content_type.len + 2; if (r->headers_out.content_type_len == r->headers_out.content_type.len && r->headers_out.charset.len) { len += sizeof("; charset=") - 1 + r->headers_out.charset.len; } } if (!conf->hide_last_modified) { if (r->headers_out.last_modified_time != -1) { if (r->headers_out.status != NGX_HTTP_OK && r->headers_out.status != NGX_HTTP_PARTIAL_CONTENT && r->headers_out.status != NGX_HTTP_NOT_MODIFIED && r->headers_out.status != NGX_HTTP_NO_CONTENT) { r->headers_out.last_modified_time = -1; r->headers_out.last_modified = NULL; } } dd("last modified time: %d", (int) r->headers_out.last_modified_time); if (r->headers_out.last_modified == NULL && r->headers_out.last_modified_time != -1) { (void) ngx_http_time(buf, r->headers_out.last_modified_time); len += sizeof("Last-Modified: ") - 1 + sizeof(buf) + 2; } } if (r->allow_ranges) { len += sizeof("X-SRCache-Allow-Ranges: 1") - 1 + 2; } part = &r->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 (ngx_hash_find(&conf->hide_headers_hash, header[i].hash, header[i].lowcase_key, header[i].key.len)) { continue; } len += header[i].key.len + sizeof(": ") - 1 + header[i].value.len + sizeof(CRLF) - 1; } b = ngx_create_temp_buf(r->pool, len); if (b == NULL) { return NGX_ERROR; } /* "HTTP/1.x " */ b->last = ngx_cpymem(b->last, "HTTP/1.1 ", sizeof("HTTP/1.x ") - 1); /* status line */ if (status_line) { b->last = ngx_copy(b->last, status_line->data, status_line->len); } else { b->last = ngx_sprintf(b->last, "%ui", status); } *b->last++ = CR; *b->last++ = LF; if (!conf->hide_content_type && r->headers_out.content_type.len) { b->last = ngx_cpymem(b->last, "Content-Type: ", sizeof("Content-Type: ") - 1); b->last = ngx_copy(b->last, r->headers_out.content_type.data, r->headers_out.content_type.len); if (r->headers_out.content_type_len == r->headers_out.content_type.len && r->headers_out.charset.len) { b->last = ngx_cpymem(b->last, "; charset=", sizeof("; charset=") - 1); b->last = ngx_copy(b->last, r->headers_out.charset.data, r->headers_out.charset.len); } *b->last++ = CR; *b->last++ = LF; } if (!conf->hide_last_modified && r->headers_out.last_modified == NULL && r->headers_out.last_modified_time != -1) { b->last = ngx_cpymem(b->last, "Last-Modified: ", sizeof("Last-Modified: ") - 1); b->last = ngx_cpymem(b->last, buf, sizeof(buf)); *b->last++ = CR; *b->last++ = LF; } if (r->allow_ranges) { b->last = ngx_cpymem(b->last, "X-SRCache-Allow-Ranges: 1\r\n", sizeof("X-SRCache-Allow-Ranges: 1\r\n") - 1); } part = &r->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; } dd("header hash: %lu, hash lc: %lu", (unsigned long) header[i].hash, (unsigned long) ngx_hash_key_lc(header[i].key.data, header[i].key.len)); if (ngx_hash_find(&conf->hide_headers_hash, header[i].hash, header[i].lowcase_key, header[i].key.len)) { dd("skipped header key: %.*s", (int) header[i].key.len, header[i].key.data); continue; } dd("header not skipped"); b->last = ngx_copy(b->last, header[i].key.data, header[i].key.len); *b->last++ = ':'; *b->last++ = ' '; b->last = ngx_copy(b->last, header[i].value.data, header[i].value.len); *b->last++ = CR; *b->last++ = LF; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "srcache store header %*s", (size_t) (b->last - b->pos), b->pos); /* the end of HTTP header */ *b->last++ = CR; *b->last++ = LF; if (b->last != b->end) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "srcache_fetch: buffer error when serializing the " "response header: %O left", (off_t) (b->last - b->end)); return NGX_ERROR; } cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_ERROR; } cl->buf = b; cl->next = NULL; ctx->body_to_cache = cl; ctx->response_length += len; return NGX_OK; }
static ngx_int_t ngx_http_upstream_send_request_body(ngx_http_request_t *r, ngx_http_upstream_t *u) { ngx_int_t rc; ngx_chain_t *cl; ajp_msg_t *msg, local_msg; ngx_connection_t *c; ngx_http_ajp_ctx_t *a; ngx_http_ajp_loc_conf_t *alcf; c = u->peer.connection; a = ngx_http_get_module_ctx(r, ngx_http_ajp_module); alcf = ngx_http_get_module_loc_conf(r, ngx_http_ajp_module); if (a->state > ngx_http_ajp_st_request_body_data_sending) { ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, "ngx_http_upstream_send_request_body: bad state(%d)", a->state); } cl = ajp_data_msg_send_body(r, alcf->max_ajp_data_packet_size_conf, &a->body); if (u->output.in == NULL && u->output.busy == NULL) { if (cl == NULL) { /* If there is no more data in the body (i.e. the servlet * container is trying to read past the end of the body), * the server will send back an "empty" packet, which is * a body packet with a payload length of 0. * (0x12,0x34,0x00,0x00) */ msg = ajp_msg_reuse(&local_msg); if (ajp_alloc_data_msg(r->pool, msg) != NGX_OK) { return NGX_ERROR; } ajp_data_msg_end(msg, 0); cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_ERROR; } cl->buf = msg->buf; cl->next = NULL; } } if (a->body) { a->state = ngx_http_ajp_st_request_body_data_sending; } else { a->state = ngx_http_ajp_st_request_send_all_done; } c->log->action = "sending request body again to upstream"; rc = ngx_output_chain(&u->output, cl); if (rc == NGX_ERROR) { return NGX_ERROR; } if (c->write->timer_set) { ngx_del_timer(c->write); } if (rc == NGX_AGAIN) { ngx_add_timer(c->write, u->conf->send_timeout); if (ngx_handle_write_event(c->write, u->conf->send_lowat) != NGX_OK) { return NGX_ERROR; } u->write_event_handler = ngx_http_upstream_send_request_body_handler; return NGX_AGAIN; } /* rc == NGX_OK */ if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) { if (ngx_tcp_push(c->fd) == NGX_ERROR) { ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno, ngx_tcp_push_n " failed"); return NGX_ERROR; } c->tcp_nopush = NGX_TCP_NOPUSH_UNSET; } ngx_add_timer(c->read, u->conf->read_timeout); if (ngx_handle_write_event(c->write, 0) != NGX_OK) { return NGX_ERROR; } u->write_event_handler = ngx_http_upstream_dummy_handler; return NGX_OK; }
static ngx_int_t ngx_http_ajp_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf) { ngx_int_t rc; ngx_buf_t *b, **prev; ngx_chain_t *cl; ngx_http_request_t *r; ngx_http_ajp_ctx_t *a; ngx_http_ajp_loc_conf_t *alcf; if (buf->pos == buf->last) { return NGX_OK; } r = p->input_ctx; a = ngx_http_get_module_ctx(r, ngx_http_ajp_module); alcf = ngx_http_get_module_loc_conf(r, ngx_http_ajp_module); ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "ngx_http_ajp_input_filter: state(%d)", a->state); b = NULL; prev = &buf->shadow; while(buf->pos < buf->last) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, p->log, 0, "input filter packet, begin length: %z, buffer_size: %z", a->length, ngx_buf_size(buf)); /* This a new data packet */ if (a->length == 0) { if (a->extra_zero_byte) { if (*(buf->pos) == 0x00){ buf->pos++; } a->extra_zero_byte = 0; } rc = ngx_http_ajp_process_packet_header(r, a, buf); if (buf->pos == buf->last) { break; } if (rc == NGX_AGAIN) { break; } if (rc == NGX_DONE) { break; } if (rc == NGX_ERROR) { return NGX_ERROR; } } /* Get a zero length packet */ if (a->length == 0) { if (a->extra_zero_byte && (buf->pos < buf->last) && (*(buf->pos) == 0x00)) { buf->pos++; a->extra_zero_byte = 0; } continue; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, p->log, 0, "input filter packet, length:%z, buffer_size:%z", a->length, ngx_buf_size(buf)); if (p->free) { b = p->free->buf; p->free = p->free->next; } else { b = ngx_alloc_buf(p->pool); if (b == NULL) { return NGX_ERROR; } } ngx_memzero(b, sizeof(ngx_buf_t)); b->pos = buf->pos; b->start = buf->start; b->end = buf->end; b->tag = p->tag; b->temporary = 1; b->recycled = 1; *prev = b; prev = &b->shadow; cl = ngx_alloc_chain_link(p->pool); if (cl == NULL) { return NGX_ERROR; } cl->buf = b; cl->next = NULL; if (p->in) { *p->last_in = cl; } else { p->in = cl; } p->last_in = &cl->next; /* STUB */ b->num = buf->num; if (buf->pos + a->length < buf->last) { buf->pos += a->length; b->last = buf->pos; a->length = 0; } else { a->length -= buf->last - buf->pos; buf->pos = buf->last; b->last = buf->last; } if (b->pos == b->last) { b->sync = 1; } if ((a->length == 0) && a->extra_zero_byte && (buf->pos < buf->last) && (*(buf->pos) == 0x00)) { /* The last byte of this message always seems to be * 0x00 and is not part of the chunk. */ buf->pos++; a->extra_zero_byte = 0; } ngx_log_debug3(NGX_LOG_DEBUG_EVENT, p->log, 0, "input buf #%d %p size: %z", b->num, b->pos, b->last - b->pos); } ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0, "free buf %p %z", buf->pos, ngx_buf_size(buf)); if (alcf->keep_conn) { /* set p->length, minimal amount of data we want to see */ if (!a->length) { p->length = 1; } else { p->length = a->length; } if (p->upstream_done) { p->length = 0; } } if (b) { b->shadow = buf; b->last_shadow = 1; ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0, "input buf %p %z", b->pos, ngx_buf_size(buf)); return NGX_OK; } /* there is no data record in the buf, add it to free chain */ if (ngx_event_pipe_add_free_buf(p, buf) != NGX_OK) { return NGX_ERROR; } return NGX_OK; }
ngx_int_t ngx_http_memc_create_storage_cmd_request(ngx_http_request_t *r) { size_t len; off_t bytes; size_t bytes_len; uintptr_t escape; ngx_buf_t *b; ngx_chain_t *cl, *in; ngx_chain_t **ll; ngx_http_memc_ctx_t *ctx; ngx_http_variable_value_t *key_vv; ngx_http_variable_value_t *flags_vv; ngx_http_variable_value_t *exptime_vv; ngx_http_variable_value_t *memc_value_vv; u_char bytes_buf[NGX_UINT32_LEN]; /* TODO add support for the "cas" command */ ctx = ngx_http_get_module_ctx(r, ngx_http_memc_module); /* prepare the "key" argument */ key_vv = ctx->memc_key_vv; if (key_vv == NULL || key_vv->not_found || key_vv->len == 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "the \"$memc_key\" variable is not set"); return NGX_ERROR; } escape = 2 * ngx_escape_uri(NULL, key_vv->data, key_vv->len, NGX_ESCAPE_MEMCACHED); /* prepare the "bytes" argument */ if (ctx->memc_value_vv && !ctx->memc_value_vv->not_found) { dd("found variable $memc_value"); memc_value_vv = ctx->memc_value_vv; bytes = memc_value_vv->len; } else if (r->request_body == NULL || r->request_body->bufs == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "neither the \"$memc_value\" variable " "nor the request body is available"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } else { memc_value_vv = NULL; bytes = 0; for (cl = r->request_body->bufs; cl; cl = cl->next) { bytes += ngx_buf_size(cl->buf); } } bytes_len = ngx_snprintf(bytes_buf, sizeof(bytes_buf), "%O", bytes) - bytes_buf; /* prepare the "flags" argument */ flags_vv = ctx->memc_flags_vv; if (flags_vv == NULL) { return NGX_ERROR; } if (flags_vv->not_found) { flags_vv->not_found = 0; flags_vv->valid = 1; flags_vv->no_cacheable = 0; flags_vv->len = sizeof("0") - 1; flags_vv->data = (u_char *) "0"; } else if (flags_vv->len == 0) { flags_vv->len = sizeof("0") - 1; flags_vv->data = (u_char *) "0"; } /* prepare the "exptime" argument */ exptime_vv = ctx->memc_exptime_vv; if (exptime_vv == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (exptime_vv->not_found || exptime_vv->len == 0) { dd("setting exptime to its default value 0..."); exptime_vv->not_found = 0; exptime_vv->valid = 1; exptime_vv->no_cacheable = 0; exptime_vv->len = sizeof("0") - 1; exptime_vv->data = (u_char *) "0"; } /* calculate the total length of the command */ len = ctx->cmd_str.len + sizeof(" ") - 1 + key_vv->len + escape + sizeof(" ") - 1 + flags_vv->len + sizeof(" ") - 1 + exptime_vv->len + sizeof(" ") - 1 + bytes_len + sizeof(CRLF) - 1; 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; ll = &cl->next; r->upstream->request_bufs = cl; /* copy the memcached command over */ b->last = ngx_copy(b->last, ctx->cmd_str.data, ctx->cmd_str.len); *b->last++ = ' '; /* copy the memcached key over */ ctx->key.data = b->last; if (escape == 0) { b->last = ngx_copy(b->last, key_vv->data, key_vv->len); } else { b->last = (u_char *) ngx_escape_uri(b->last, key_vv->data, key_vv->len, NGX_ESCAPE_MEMCACHED); } ctx->key.len = b->last - ctx->key.data; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http memcached request: \"%V\"", &ctx->key); *b->last++ = ' '; /* copy the memcached flags over */ b->last = ngx_copy(b->last, flags_vv->data, flags_vv->len); *b->last++ = ' '; /* copy the memcached exptime over */ b->last = ngx_copy(b->last, exptime_vv->data, exptime_vv->len); *b->last++ = ' '; /* copy the memcached bytes over */ b->last = ngx_copy(b->last, bytes_buf, bytes_len); *b->last++ = CR; *b->last++ = LF; if (memc_value_vv) { if (memc_value_vv->len) { dd("copy $memc_value to the request"); b = ngx_calloc_buf(r->pool); if (b == NULL) { return NGX_ERROR; } b->memory = 1; b->start = b->pos = memc_value_vv->data; b->last = b->end = b->start + memc_value_vv->len; cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_ERROR; } cl->buf = b; cl->next = NULL; *ll = cl; ll = &cl->next; } } else { /* to preserve the r->request_body->bufs untouched */ in = r->request_body->bufs; while (in) { cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_ERROR; } cl->buf = ngx_calloc_buf(r->pool); if (cl->buf == NULL) { return NGX_ERROR; } cl->buf->memory = 1; *cl->buf = *in->buf; *ll = cl; ll = &cl->next; in = in->next; } } /* append the trailing CRLF */ b = ngx_calloc_buf(r->pool); if (b == NULL) { return NGX_ERROR; } b->start = b->pos = (u_char *) CRLF; b->last = b->end = b->start + sizeof(CRLF) - 1; b->memory = 1; cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_ERROR; } cl->buf = b; cl->next = NULL; *ll = cl; return NGX_OK; }
ngx_int_t ngx_http_memc_create_delete_cmd_request(ngx_http_request_t *r) { size_t len; ngx_buf_t *b; ngx_http_memc_ctx_t *ctx; ngx_chain_t *cl; uintptr_t escape; ngx_http_variable_value_t *key_vv; ngx_http_variable_value_t *exptime_vv; ctx = ngx_http_get_module_ctx(r, ngx_http_memc_module); /* prepare the "key" argument */ key_vv = ctx->memc_key_vv; if (key_vv == NULL || key_vv->not_found || key_vv->len == 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "the \"$memc_key\" variable is not set"); return NGX_ERROR; } escape = 2 * ngx_escape_uri(NULL, key_vv->data, key_vv->len, NGX_ESCAPE_MEMCACHED); /* prepare the (optional) "exptime" argument */ exptime_vv = ctx->memc_exptime_vv; if (exptime_vv == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } len = ctx->cmd_str.len + sizeof(' ') + key_vv->len + escape; if ( ! exptime_vv->not_found && exptime_vv->len) { dd("found exptime: %s", exptime_vv->data); len += sizeof(' ') + exptime_vv->len; } len += sizeof(CRLF) - 1; 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; b->last = ngx_copy(b->last, ctx->cmd_str.data, ctx->cmd_str.len); *b->last++ = ' '; if (escape == 0) { b->last = ngx_copy(b->last, key_vv->data, key_vv->len); } else { b->last = (u_char *) ngx_escape_uri(b->last, key_vv->data, key_vv->len, NGX_ESCAPE_MEMCACHED); } if ( ! exptime_vv->not_found && exptime_vv->len) { *b->last++ = ' '; b->last = ngx_copy(b->last, exptime_vv->data, exptime_vv->len); } *b->last++ = CR; *b->last++ = LF; return NGX_OK; }
static int ngx_http_lua_ngx_req_set_body_file(lua_State *L) { u_char *p; ngx_http_request_t *r; int n; ngx_http_request_body_t *rb; ngx_temp_file_t *tf; ngx_buf_t *b; ngx_str_t name; ngx_int_t rc; int clean; ngx_open_file_info_t of; ngx_str_t key, value; ngx_pool_cleanup_t *cln; ngx_pool_cleanup_file_t *clnf; ngx_err_t err; ngx_chain_t *cl; ngx_buf_tag_t tag; n = lua_gettop(L); if (n != 1 && n != 2) { return luaL_error(L, "expecting 1 or 2 arguments but seen %d", n); } p = (u_char *) luaL_checklstring(L, 1, &name.len); r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request found"); } ngx_http_lua_check_fake_request(L, r); if (r->discard_body) { return luaL_error(L, "request body already discarded asynchronously"); } if (r->request_body == NULL) { return luaL_error(L, "request body not read yet"); } name.data = ngx_palloc(r->pool, name.len + 1); if (name.data == NULL) { return luaL_error(L, "no memory"); } ngx_memcpy(name.data, p, name.len); name.data[name.len] = '\0'; if (n == 2) { luaL_checktype(L, 2, LUA_TBOOLEAN); clean = lua_toboolean(L, 2); } else { clean = 0; } dd("clean: %d", (int) clean); rb = r->request_body; /* clean up existing r->request_body->bufs (if any) */ tag = (ngx_buf_tag_t) &ngx_http_lua_module; if (rb->bufs) { dd("XXX reusing buf"); for (cl = rb->bufs; cl; cl = cl->next) { if (cl->buf->tag == tag && cl->buf->temporary) { dd("free old request body buffer: size:%d", (int) ngx_buf_size(cl->buf)); ngx_pfree(r->pool, cl->buf->start); cl->buf->tag = (ngx_buf_tag_t) NULL; cl->buf->temporary = 0; } } rb->bufs->next = NULL; b = rb->bufs->buf; ngx_memzero(b, sizeof(ngx_buf_t)); b->tag = tag; rb->buf = NULL; } else { dd("XXX creating new buf"); rb->bufs = ngx_alloc_chain_link(r->pool); if (rb->bufs == NULL) { return luaL_error(L, "no memory"); } rb->bufs->next = NULL; b = ngx_calloc_buf(r->pool); if (b == NULL) { return luaL_error(L, "no memory"); } b->tag = tag; rb->bufs->buf = b; rb->buf = NULL; } b->last_in_chain = 1; /* just make r->request_body->temp_file a bare stub */ tf = rb->temp_file; if (tf) { if (tf->file.fd != NGX_INVALID_FILE) { dd("cleaning temp file %.*s", (int) tf->file.name.len, tf->file.name.data); ngx_http_lua_pool_cleanup_file(r->pool, tf->file.fd); ngx_memzero(tf, sizeof(ngx_temp_file_t)); tf->file.fd = NGX_INVALID_FILE; dd("temp file cleaned: %.*s", (int) tf->file.name.len, tf->file.name.data); } } else { tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)); if (tf == NULL) { return luaL_error(L, "no memory"); } tf->file.fd = NGX_INVALID_FILE; rb->temp_file = tf; } /* read the file info and construct an in-file buf */ ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.directio = NGX_OPEN_FILE_DIRECTIO_OFF; if (ngx_http_lua_open_and_stat_file(name.data, &of, r->connection->log) != NGX_OK) { return luaL_error(L, "%s \"%s\" failed", of.failed, name.data); } dd("XXX new body file fd: %d", of.fd); tf->file.fd = of.fd; tf->file.name = name; tf->file.log = r->connection->log; tf->file.directio = 0; if (of.size == 0) { if (clean) { if (ngx_delete_file(name.data) == NGX_FILE_ERROR) { err = ngx_errno; if (err != NGX_ENOENT) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, ngx_delete_file_n " \"%s\" failed", name.data); } } } if (ngx_close_file(of.fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, ngx_close_file_n " \"%s\" failed", name.data); } r->request_body->bufs = NULL; r->request_body->buf = NULL; goto set_header; } /* register file cleanup hook */ cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_pool_cleanup_file_t)); if (cln == NULL) { return luaL_error(L, "no memory"); } cln->handler = clean ? ngx_pool_delete_file : ngx_pool_cleanup_file; clnf = cln->data; clnf->fd = of.fd; clnf->name = name.data; clnf->log = r->pool->log; b->file = &tf->file; if (b->file == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } dd("XXX file size: %d", (int) of.size); b->file_pos = 0; b->file_last = of.size; b->in_file = 1; dd("buf file: %p, f:%u", b->file, b->in_file); set_header: /* override input header Content-Length (value must be null terminated) */ value.data = ngx_palloc(r->pool, NGX_OFF_T_LEN + 1); if (value.data == NULL) { return luaL_error(L, "no memory"); } value.len = ngx_sprintf(value.data, "%O", of.size) - value.data; value.data[value.len] = '\0'; r->headers_in.content_length_n = of.size; if (r->headers_in.content_length) { r->headers_in.content_length->value.data = value.data; r->headers_in.content_length->value.len = value.len; } else { ngx_str_set(&key, "Content-Length"); rc = ngx_http_lua_set_input_header(r, key, value, 1 /* override */); if (rc != NGX_OK) { return luaL_error(L, "failed to reset the Content-Length " "input header"); } } return 0; }
static ngx_int_t ngx_http_xss_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { ngx_uint_t last; ngx_chain_t *cl, *orig_in; ngx_chain_t **ll = NULL; ngx_http_xss_ctx_t *ctx; ngx_http_xss_conf_t *conf; size_t len; ngx_buf_t *b; if (in == NULL || r->header_only) { return ngx_http_next_body_filter(r, in); } ctx = ngx_http_get_module_ctx(r, ngx_http_xss_filter_module); if (ctx == NULL) { return ngx_http_next_body_filter(r, in); } conf = ngx_http_get_module_loc_conf(r, ngx_http_xss_filter_module); orig_in = in; if (!ctx->before_body_sent) { ctx->before_body_sent = 1; dd("callback: %.*s", ctx->callback.len, ctx->callback.data); len = ctx->callback.len + sizeof("(") - 1; b = ngx_create_temp_buf(r->pool, len); if (b == NULL) { return NGX_ERROR; } b->last = ngx_copy(b->last, ctx->callback.data, ctx->callback.len); *b->last++ = '('; cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_ERROR; } cl->buf = b; cl->next = in; in = cl; } last = 0; for (cl = orig_in; cl; cl = cl->next) { if (cl->buf->last_buf) { cl->buf->last_buf = 0; cl->buf->sync = 1; ll = &cl->next; last = 1; } } if (last) { len = sizeof(");") - 1; b = ngx_create_temp_buf(r->pool, len); if (b == NULL) { return NGX_ERROR; } *b->last++ = ')'; *b->last++ = ';'; b->last_buf = 1; cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_ERROR; } cl->buf = b; cl->next = NULL; *ll = cl; ngx_http_set_ctx(r, NULL, ngx_http_xss_filter_module); } return ngx_http_next_body_filter(r, in); }
static ngx_int_t ngx_http_pb_msgpack_body_filter(ngx_http_request_t* r , ngx_chain_t* in) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "enter pb msgpack body filter!"); ngx_http_pb_msgpack_transfer_loc_conf_t* loc_conf = NULL; ngx_http_pbmsgpack_transfer_ctx_t* ctx = NULL; int req_cmd = -1; int ret ; loc_conf = (ngx_http_pb_msgpack_transfer_loc_conf_t*) ngx_http_get_module_loc_conf(r, ngx_http_pb_msgpack_transfer_module); // flag is unset/0 , skip deal it if(0 == loc_conf->pbmsgpack_filter_flag || NGX_CONF_UNSET == loc_conf->pbmsgpack_filter_flag ) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "output transfer flag is 0!"); return ngx_http_next_body_filter(r, in); } // response is failed, skip it if(r->headers_out.status != NGX_HTTP_OK) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "Bypassed"); return ngx_http_next_body_filter(r, in); } ctx = (ngx_http_pbmsgpack_transfer_ctx_t*) ngx_http_get_module_ctx(r, ngx_http_pb_msgpack_transfer_module); if(NULL == ctx) { ctx = (ngx_http_pbmsgpack_transfer_ctx_t* )ngx_pcalloc(r->pool, sizeof(ngx_http_pbmsgpack_transfer_ctx_t) ); if(NULL == ctx) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "ngx_pcalloc ngx_http_pbmsgpack_transfer_ctx_t failed"); return ngx_http_next_body_filter(r,in); } ctx->msgpack_buf_size = ctx->pb_buf_size = g_pbmsgpack_buf_size; ctx->msgpack_buf = (u_char*) ngx_pcalloc(r->pool, ctx->msgpack_buf_size); ctx->msgpack_pos = 0; if(NULL == ctx->msgpack_buf) { ngx_log_error(NGX_LOG_ALERT, r->connection->log,0, "ngx_pcalloc ngx_http_pbmsgpack_transfer_ctx_t failed"); return ngx_http_next_body_filter(r,in); } ngx_http_set_ctx(r, ctx, ngx_http_pb_msgpack_transfer_module); } else { if(NULL == ctx->msgpack_buf) { ctx->msgpack_buf_size = ctx->pb_buf_size = g_pbmsgpack_buf_size; ctx->msgpack_buf = (u_char*) ngx_pcalloc(r->pool, ctx->msgpack_buf_size); ctx->msgpack_pos = 0; } if(NULL == ctx->msgpack_buf) { ngx_log_error(NGX_LOG_ALERT, r->connection->log,0, "ngx_pcalloc ngx_http_pbmsgpack_transfer_ctx_t failed"); return ngx_http_next_body_filter(r,in); } } if( 1 == ctx->has_filter_deal) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "pbmsgpack filter transfer has already deal! skip it!"); return ngx_http_next_body_filter(r,in); } if(NULL == ctx->sent_data_type_header) { // check whether the res data type is msgpack ngx_table_elt_t* res_data_type = ngx_http_pbmsgpack_get_res_header(r, & g_out_data_type_header); ctx->sent_data_type_header = res_data_type; if(NULL == res_data_type) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "pbmsgpack sent_http_x_data_type is NULL, skip deal it!"); ctx->has_filter_deal = 1; return ngx_http_next_body_filter(r, in); } else if( res_data_type->value.len != g_msgpack_nginx_str.len || 0 != memcmp(res_data_type->value.data, g_msgpack_nginx_str.data, g_msgpack_str.len)) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "pbmsgpack sent_http_x_data_type is: %V, skip it", & res_data_type->value); ctx->has_filter_deal = 1; return ngx_http_next_body_filter(r, in); } } req_cmd = ngx_http_pbmsgpack_get_cmd(r); if( -1 == req_cmd) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0 ,"ngx_http_pbmsgpack_get_cmd failed, skip it"); return ngx_http_next_body_filter(r, in); } ngx_chain_t *it; for(it = in; it; it = it->next) { if(it->buf->last == it->buf->pos) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "pb msgpack filter skip empty buf"); } else { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "pb msgpack output filter %db\n", (int)(it->buf->last - it->buf->pos)); if(ctx->msgpack_pos + it->buf->last - it->buf->pos >= ctx->msgpack_buf_size) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "pbmsgpack output body size is too large!"); return ngx_http_next_body_filter(r, in); } memcpy(ctx->msgpack_buf + ctx->msgpack_pos , it->buf->pos, it->buf->last - it->buf->pos); ctx->msgpack_pos += it->buf->last - it->buf->pos; } // mark as sent to client so nginx is happy it->buf->pos = it->buf->last; if(it->buf->last_buf) { unsigned long int start_time, end_time; start_time = ngx_http_pbmsgpack_get_time_us(); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "pb msgpack output filter total size: %d ", ctx->msgpack_pos); //it->buf->last_buf = 0; ret = pkg_msgpack2pb(g_ctx, ctx->msgpack_buf, (int*) & ctx->msgpack_pos, ctx->msgpack_buf_size, req_cmd, PKG_DOWNSTREAM); if(0 != ret) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "pkg_msgpack2pb failed! [ret:%d]", ret); // ctx->sent_data_type_header = g_protobuf_str; // we do not skip to the next body filter // because if failed, we will still send the msgpack info to client ctx->has_filter_deal = 1; return ngx_http_next_body_filter(r, in); } else { ctx->sent_data_type_header->value = g_protobuf_nginx_str; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "pb msgpack output filter new size: %d ", ctx->msgpack_pos); // mark the filter deal flag ctx->has_filter_deal = 1; /* * ngx_chain_t * empty_chain = ngx_alloc_chain_link(r->pool); * if(NULL == empty_chain) * { * return NGX_ERROR; * } * empty_chain->next = NULL; * * ngx_buf_t* empty_buf = (ngx_buf_t*) ngx_calloc_buf(r->pool); * empty_buf->memory = 1; * empty_buf->last_buf = 1; * empty_buf->pos = empty_buf->last = ctx->msgpack_buf; * empty_chain->buf = empty_buf; */ // ngx_chain_t* empty_chain = NULL; ngx_chain_t *rc = ngx_alloc_chain_link(r->pool); if(rc == NULL ) { return NGX_ERROR; } //rc->next = it; rc->next = NULL; rc->buf = (ngx_buf_t*)ngx_calloc_buf(r->pool); if(rc->buf == NULL) { return NGX_ERROR; } rc->buf->memory = 1; rc->buf->last_buf = 0; rc->buf->pos = ctx->msgpack_buf; rc->buf->last = ctx->msgpack_buf + ctx->msgpack_pos; end_time = ngx_http_pbmsgpack_get_time_us(); ctx->filter_cost = end_time - start_time; // Link into the buffer chain return ngx_http_next_body_filter(r, rc); } } return ngx_http_next_body_filter(r, NULL); }
static int ngx_http_lua_ngx_location_capture_multi(lua_State *L) { ngx_http_request_t *r; ngx_http_request_t *sr; /* subrequest object */ ngx_http_post_subrequest_t *psr; ngx_http_lua_ctx_t *sr_ctx; ngx_http_lua_ctx_t *ctx; ngx_array_t *extra_vars; ngx_str_t uri; ngx_str_t args; ngx_str_t extra_args; ngx_uint_t flags; u_char *p; u_char *q; size_t len; size_t nargs; int rc; int n; ngx_uint_t method; ngx_http_request_body_t *body; int type; ngx_buf_t *b; unsigned vars_action; ngx_uint_t nsubreqs; ngx_uint_t index; size_t sr_statuses_len; size_t sr_headers_len; size_t sr_bodies_len; unsigned custom_ctx; n = lua_gettop(L); if (n != 1) { return luaL_error(L, "only one argument is expected, but got %d", n); } luaL_checktype(L, 1, LUA_TTABLE); nsubreqs = lua_objlen(L, 1); if (nsubreqs == 0) { return luaL_error(L, "at least one subrequest should be specified"); } lua_getglobal(L, GLOBALS_SYMBOL_REQUEST); r = lua_touserdata(L, -1); lua_pop(L, 1); if (r == NULL) { return luaL_error(L, "no request object found"); } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { return luaL_error(L, "no ctx found"); } sr_statuses_len = nsubreqs * sizeof(ngx_int_t); sr_headers_len = nsubreqs * sizeof(ngx_http_headers_out_t *); sr_bodies_len = nsubreqs * sizeof(ngx_str_t); p = ngx_pcalloc(r->pool, sr_statuses_len + sr_headers_len + sr_bodies_len); if (p == NULL) { return luaL_error(L, "out of memory"); } ctx->sr_statuses = (void *) p; p += sr_statuses_len; ctx->sr_headers = (void *) p; p += sr_headers_len; ctx->sr_bodies = (void *) p; ctx->nsubreqs = nsubreqs; n = lua_gettop(L); dd("top before loop: %d", n); ctx->done = 0; ctx->waiting = 0; extra_vars = NULL; for (index = 0; index < nsubreqs; index++) { ctx->waiting++; lua_rawgeti(L, 1, index + 1); if (lua_isnil(L, -1)) { return luaL_error(L, "only array-like tables are allowed"); } dd("queries query: top %d", lua_gettop(L)); if (lua_type(L, -1) != LUA_TTABLE) { return luaL_error(L, "the query argument %d is not a table, " "but a %s", index, lua_typename(L, lua_type(L, -1))); } nargs = lua_objlen(L, -1); if (nargs != 1 && nargs != 2) { return luaL_error(L, "query argument %d expecting one or " "two arguments", index); } lua_rawgeti(L, 2, 1); /* queries query uri */ dd("queries query uri: %d", lua_gettop(L)); dd("first arg in first query: %s", lua_typename(L, lua_type(L, -1))); body = NULL; extra_args.data = NULL; extra_args.len = 0; if (extra_vars != NULL) { /* flush out existing elements in the array */ extra_vars->nelts = 0; } vars_action = 0; custom_ctx = 0; if (nargs == 2) { /* check out the options table */ lua_rawgeti(L, 2, 2); /* queries query uri opts */ dd("queries query uri opts: %d", lua_gettop(L)); if (lua_type(L, 4) != LUA_TTABLE) { return luaL_error(L, "expecting table as the 2nd argument for " "subrequest %d, but got %s", index, luaL_typename(L, 4)); } dd("queries query uri opts: %d", lua_gettop(L)); /* check the args option */ lua_getfield(L, 4, "args"); type = lua_type(L, -1); switch (type) { case LUA_TTABLE: ngx_http_lua_process_args_option(r, L, -1, &extra_args); break; case LUA_TNIL: /* do nothing */ break; case LUA_TNUMBER: case LUA_TSTRING: extra_args.data = (u_char *) lua_tolstring(L, -1, &len); extra_args.len = len; break; default: return luaL_error(L, "Bad args option value"); } lua_pop(L, 1); dd("queries query uri opts: %d", lua_gettop(L)); /* check the vars option */ lua_getfield(L, 4, "vars"); switch (lua_type(L, -1)) { case LUA_TTABLE: ngx_http_lua_process_vars_option(r, L, -1, &extra_vars); dd("post process vars top: %d", lua_gettop(L)); break; case LUA_TNIL: /* do nothing */ break; default: return luaL_error(L, "Bad vars option value"); } lua_pop(L, 1); dd("queries query uri opts: %d", lua_gettop(L)); /* check the share_all_vars option */ lua_getfield(L, 4, "share_all_vars"); switch (lua_type(L, -1)) { case LUA_TNIL: /* do nothing */ break; case LUA_TBOOLEAN: if (lua_toboolean(L, -1)) { vars_action |= NGX_HTTP_LUA_SHARE_ALL_VARS; } break; default: return luaL_error(L, "Bad share_all_vars option value"); } lua_pop(L, 1); dd("queries query uri opts: %d", lua_gettop(L)); /* check the copy_all_vars option */ lua_getfield(L, 4, "copy_all_vars"); switch (lua_type(L, -1)) { case LUA_TNIL: /* do nothing */ break; case LUA_TBOOLEAN: if (lua_toboolean(L, -1)) { vars_action |= NGX_HTTP_LUA_COPY_ALL_VARS; } break; default: return luaL_error(L, "Bad copy_all_vars option value"); } lua_pop(L, 1); dd("queries query uri opts: %d", lua_gettop(L)); /* check the "method" option */ lua_getfield(L, 4, "method"); type = lua_type(L, -1); if (type == LUA_TNIL) { method = NGX_HTTP_GET; } else { if (type != LUA_TNUMBER) { return luaL_error(L, "Bad http request method"); } method = (ngx_uint_t) lua_tonumber(L, -1); } lua_pop(L, 1); dd("queries query uri opts: %d", lua_gettop(L)); /* check the "ctx" option */ lua_getfield(L, 4, "ctx"); type = lua_type(L, -1); if (type != LUA_TNIL) { if (type != LUA_TTABLE) { return luaL_error(L, "Bad ctx option value type %s, " "expected a Lua table", lua_typename(L, type)); } custom_ctx = 1; } else { lua_pop(L, 1); } dd("queries query uri opts ctx?: %d", lua_gettop(L)); /* check the "body" option */ lua_getfield(L, 4, "body"); type = lua_type(L, -1); if (type != LUA_TNIL) { if (type != LUA_TSTRING && type != LUA_TNUMBER) { return luaL_error(L, "Bad http request body"); } body = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); if (body == NULL) { return luaL_error(L, "out of memory"); } q = (u_char *) lua_tolstring(L, -1, &len); dd("request body: [%.*s]", (int) len, q); if (len) { b = ngx_create_temp_buf(r->pool, len); if (b == NULL) { return luaL_error(L, "out of memory"); } b->last = ngx_copy(b->last, q, len); body->bufs = ngx_alloc_chain_link(r->pool); if (body->bufs == NULL) { return luaL_error(L, "out of memory"); } body->bufs->buf = b; body->bufs->next = NULL; body->buf = b; } } lua_pop(L, 1); /* pop the body */ /* stack: queries query uri opts ctx? */ lua_remove(L, 4); /* stack: queries query uri ctx? */ dd("queries query uri ctx?: %d", lua_gettop(L)); } else { method = NGX_HTTP_GET; } /* stack: queries query uri ctx? */ n = lua_gettop(L); dd("top size so far: %d", n); p = (u_char *) luaL_checklstring(L, 3, &len); uri.data = ngx_palloc(r->pool, len); if (uri.data == NULL) { return luaL_error(L, "memory allocation error"); } ngx_memcpy(uri.data, p, len); uri.len = len; args.data = NULL; args.len = 0; flags = 0; rc = ngx_http_parse_unsafe_uri(r, &uri, &args, &flags); if (rc != NGX_OK) { dd("rc = %d", (int) rc); return luaL_error(L, "unsafe uri in argument #1: %s", p); } if (args.len == 0) { args = extra_args; } else if (extra_args.len) { /* concatenate the two parts of args together */ len = args.len + (sizeof("&") - 1) + extra_args.len; p = ngx_palloc(r->pool, len); if (p == NULL) { return luaL_error(L, "out of memory"); } q = ngx_copy(p, args.data, args.len); *q++ = '&'; ngx_memcpy(q, extra_args.data, extra_args.len); args.data = p; args.len = len; } psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t)); if (psr == NULL) { return luaL_error(L, "memory allocation error"); } sr_ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_lua_ctx_t)); if (sr_ctx == NULL) { return luaL_error(L, "out of memory"); } /* set by ngx_pcalloc: * sr_ctx->run_post_subrequest = 0 * sr_ctx->free = NULL */ sr_ctx->cc_ref = LUA_NOREF; sr_ctx->ctx_ref = LUA_NOREF; sr_ctx->capture = 1; sr_ctx->index = index; psr->handler = ngx_http_lua_post_subrequest; psr->data = sr_ctx; rc = ngx_http_subrequest(r, &uri, &args, &sr, psr, 0); if (rc != NGX_OK) { return luaL_error(L, "failed to issue subrequest: %d", (int) rc); } ngx_http_set_ctx(sr, sr_ctx, ngx_http_lua_module); rc = ngx_http_lua_adjust_subrequest(sr, method, body, vars_action, extra_vars); if (rc != NGX_OK) { return luaL_error(L, "failed to adjust the subrequest: %d", (int) rc); } dd("queries query uri opts ctx? %d", lua_gettop(L)); /* stack: queries query uri ctx? */ if (custom_ctx) { ngx_http_lua_ngx_set_ctx_helper(L, sr, sr_ctx, -1); lua_pop(L, 3); } else { lua_pop(L, 2); } /* stack: queries */ } if (extra_vars) { ngx_array_destroy(extra_vars); } return lua_yield(L, 0); }
static ngx_chain_t * ngx_http_charset_recode_from_utf8(ngx_pool_t *pool, ngx_buf_t *buf, ngx_http_charset_ctx_t *ctx) { size_t len, size; u_char c, *p, *src, *dst, *saved, **table; uint32_t n; ngx_buf_t *b; ngx_uint_t i; ngx_chain_t *out, *cl, **ll; src = buf->pos; if (ctx->saved_len == 0) { for (/* void */ ; src < buf->last; src++) { if (*src < 0x80) { continue; } len = src - buf->pos; if (len > 512) { out = ngx_http_charset_get_buf(pool, ctx); if (out == NULL) { return NULL; } b = out->buf; b->temporary = buf->temporary; b->memory = buf->memory; b->mmap = buf->mmap; b->flush = buf->flush; b->pos = buf->pos; b->last = src; out->buf = b; out->next = NULL; size = buf->last - src; saved = src; n = ngx_utf8_decode(&saved, size); if (n == 0xfffffffe) { /* incomplete UTF-8 symbol */ ngx_memcpy(ctx->saved, src, size); ctx->saved_len = size; b->shadow = buf; return out; } } else { out = NULL; size = len + buf->last - src; src = buf->pos; } if (size < NGX_HTML_ENTITY_LEN) { size += NGX_HTML_ENTITY_LEN; } cl = ngx_http_charset_get_buffer(pool, ctx, size); if (cl == NULL) { return NULL; } if (out) { out->next = cl; } else { out = cl; } b = cl->buf; dst = b->pos; goto recode; } out = ngx_alloc_chain_link(pool); if (out == NULL) { return NULL; } out->buf = buf; out->next = NULL; return out; } /* process incomplete UTF sequence from previous buffer */ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pool->log, 0, "http charset utf saved: %z", ctx->saved_len); p = src; for (i = ctx->saved_len; i < NGX_UTF_LEN; i++) { ctx->saved[i] = *p++; if (p == buf->last) { break; } } saved = ctx->saved; n = ngx_utf8_decode(&saved, i); c = '\0'; if (n < 0x10000) { table = (u_char **) ctx->table; p = table[n >> 8]; if (p) { c = p[n & 0xff]; } }
static void ngx_http_transfer_body(ngx_http_request_t* r) { // already get the whole request body ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "enter ngx_http_transfer_body"); unsigned long int start_time, end_time; start_time = ngx_http_pbmsgpack_get_time_us(); // first, set ctx read request flag to 0 ngx_http_pbmsgpack_transfer_ctx_t* ctx = NULL; ctx = (ngx_http_pbmsgpack_transfer_ctx_t*) ngx_http_get_module_ctx(r, ngx_http_pb_msgpack_transfer_module); if(NULL == ctx) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "[req_body_transfer] unexpected emmpty ctx!"); ngx_http_finalize_request(r,NGX_DONE); return; } ctx->is_waiting_body = 0; // second, process data ngx_chain_t* bufs = r->request_body->bufs; if(NULL == bufs) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "request bufs is NULL!"); ngx_http_finalize_request(r,NGX_DONE); return; } //try deal //first , get boundary info from header; char bound[g_max_content_type_size]; int ret = get_multipart_form_header_info(r, ctx->content_type_header, bound); if(0 != ret) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "pb msgpack get_multipart_form_header_info failed!"); ngx_http_finalize_request(r,NGX_DONE); return ; } // check cmd int cmd = ngx_http_pbmsgpack_get_cmd(r); if(cmd <= 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "illegal cmd is: %d", cmd); ngx_http_finalize_request(r,NGX_DONE); return; } ngx_int_t total_size = 0; ngx_int_t buf_num = 0; ngx_buf_t* temp_buf = NULL; ngx_chain_t* temp_chain = bufs; ctx->pb_buf_size = ctx->msgpack_buf_size = g_pbmsgpack_buf_size; ctx->pb_buf_pos = ctx->msgpack_pos = 0; ctx->pb_buf = (u_char*)ngx_pcalloc(r->pool, g_pbmsgpack_buf_size); // re-use pb buffer, ctx->msgpack_buf = ctx->pb_buf; while(NULL != temp_chain) { temp_buf = temp_chain->buf; if(NULL != temp_buf) { total_size += (int)(temp_buf->last - temp_buf->pos); ++ buf_num; } temp_chain = temp_chain->next; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "[req_body_transfer]total requst body size:%d ,bufs:%d", total_size, buf_num); if(total_size >= g_pbmsgpack_buf_size) { //TODO ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "illegal request body size![now:%d][limit:%d]", total_size, g_pbmsgpack_buf_size); ngx_http_finalize_request(r,NGX_DONE); return; } temp_chain = bufs; while(NULL != temp_chain) { temp_buf = temp_chain->buf; if(NULL != temp_buf) { total_size = (int)(temp_buf->last - temp_buf->pos); memcpy(ctx->pb_buf + ctx->pb_buf_pos , temp_buf->pos, total_size); ctx->pb_buf_pos += total_size; } temp_chain = temp_chain->next; } //get the whole request body ctx->pb_buf[ ctx->pb_buf_pos ] = '\0'; int data_start_pos; int data_end_pos; ret = get_multipart_form_info( (char*)ctx->pb_buf, ctx->pb_buf_pos,bound, g_tag_name, data_start_pos, data_end_pos); if(0 != ret) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "pb msgpack get_multipart_form_info failed!"); ngx_http_finalize_request(r,NGX_DONE); return ; } // 节省空间,拷贝两次 // 上面的pos是闭区间 int temp_copy_size = ctx->pb_buf_pos - data_end_pos + 1; int temp_src_copy_pos = data_end_pos; int temp_dst_copy_pos = g_pbmsgpack_buf_size - temp_copy_size ; int raw_data_size = data_end_pos - data_start_pos ; int old_data_size = raw_data_size; memmove(ctx->pb_buf + temp_dst_copy_pos, ctx->pb_buf + temp_src_copy_pos, temp_copy_size ); ngx_log_debug6(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "pb msgpack post body start:%d,end:%d,copy:%d,new_copy_pos:%d,old_data:%d,total:%d", data_start_pos, data_end_pos, temp_copy_size, temp_dst_copy_pos, old_data_size, ctx->pb_buf_pos); ret = pkg_pb2msgpack(g_ctx, ctx->pb_buf + data_start_pos, & raw_data_size, g_pbmsgpack_buf_size - temp_copy_size - data_start_pos, cmd, PKG_UPSTREAM); if(0 != ret) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "post body trans failed! pkg_pb2msgpack return failed!"); ngx_http_finalize_request(r,NGX_DONE); return; } temp_src_copy_pos += raw_data_size - old_data_size; memmove(ctx->pb_buf + temp_src_copy_pos, ctx->pb_buf + temp_dst_copy_pos, temp_copy_size); ctx->pb_buf_pos += raw_data_size - old_data_size; ngx_log_debug6(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "pb msgpack post body start:%d,end:%d,copy:%d,new_copy_pos:%d,new_data:%d,total:%d", data_start_pos, data_end_pos, temp_copy_size, temp_dst_copy_pos, raw_data_size, ctx->pb_buf_pos); // first , reset the request body info ngx_chain_t* test_chain = ngx_alloc_chain_link(r->pool); ngx_buf_t* test_buf = (ngx_buf_t*)ngx_calloc_buf(r->pool); test_buf->pos = test_buf->start = ctx->pb_buf; test_buf->last = test_buf->end = (u_char*) (ctx->pb_buf + ctx->pb_buf_pos); test_buf->temporary = 1; test_chain->buf = test_buf; test_chain->next = NULL; r->request_body->bufs = test_chain; r->headers_in.content_length_n = ctx->pb_buf_pos; // second , reset the requset header info , include content-length and x_bd_data_type char* str_content_length = (char*)ngx_pcalloc(r->pool, DEFAULT_STR_BUF_SIZE); int str_size = snprintf(str_content_length, DEFAULT_STR_BUF_SIZE, "%u", r->headers_in.content_length_n); r->headers_in.content_length->value.data = (u_char*) str_content_length; r->headers_in.content_length->value.len = str_size; ctx->data_type_header->value = g_msgpack_str; end_time = ngx_http_pbmsgpack_get_time_us(); ctx->transfer_cost = end_time - start_time; ngx_http_finalize_request(r,NGX_DONE); }
static ngx_int_t ngx_http_charset_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { ngx_int_t rc; ngx_buf_t *b; ngx_chain_t *cl, *out, **ll; ngx_http_charset_ctx_t *ctx; ctx = ngx_http_get_module_ctx(r, ngx_http_charset_filter_module); if (ctx == NULL || ctx->table == NULL) { return ngx_http_next_body_filter(r, in); } if ((ctx->to_utf8 || ctx->from_utf8) || ctx->busy) { out = NULL; ll = &out; for (cl = in; cl; cl = cl->next) { b = cl->buf; if (ngx_buf_size(b) == 0) { *ll = ngx_alloc_chain_link(r->pool); if (*ll == NULL) { return NGX_ERROR; } (*ll)->buf = b; (*ll)->next = NULL; ll = &(*ll)->next; continue; } if (ctx->to_utf8) { *ll = ngx_http_charset_recode_to_utf8(r->pool, b, ctx); } else { *ll = ngx_http_charset_recode_from_utf8(r->pool, b, ctx); } if (*ll == NULL) { return NGX_ERROR; } while (*ll) { ll = &(*ll)->next; } } rc = ngx_http_next_body_filter(r, out); if (out) { if (ctx->busy == NULL) { ctx->busy = out; } else { for (cl = ctx->busy; cl->next; cl = cl->next) { /* void */ } cl->next = out; } } while (ctx->busy) { cl = ctx->busy; b = cl->buf; if (ngx_buf_size(b) != 0) { break; } ctx->busy = cl->next; if (b->tag != (ngx_buf_tag_t) &ngx_http_charset_filter_module) { continue; } if (b->shadow) { b->shadow->pos = b->shadow->last; } if (b->pos) { cl->next = ctx->free_buffers; ctx->free_buffers = cl; continue; } cl->next = ctx->free_bufs; ctx->free_bufs = cl; } return rc; } for (cl = in; cl; cl = cl->next) { (void) ngx_http_charset_recode(cl->buf, ctx->table); } return ngx_http_next_body_filter(r, in); }
ngx_int_t ngx_http_echo_exec_echo(ngx_http_request_t *r, ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args, ngx_flag_t in_filter, ngx_array_t *opts) { ngx_uint_t i; ngx_buf_t *space_buf; ngx_buf_t *newline_buf; ngx_buf_t *buf; ngx_str_t *computed_arg; ngx_str_t *computed_arg_elts; ngx_str_t *opt; ngx_chain_t *cl = NULL; /* the head of the chain link */ ngx_chain_t **ll = &cl; /* always point to the address of the last link */ dd_enter(); if (computed_args == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } computed_arg_elts = computed_args->elts; for (i = 0; i < computed_args->nelts; i++) { computed_arg = &computed_arg_elts[i]; if (computed_arg->len == 0) { buf = NULL; } else { buf = ngx_calloc_buf(r->pool); if (buf == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } buf->start = buf->pos = computed_arg->data; buf->last = buf->end = computed_arg->data + computed_arg->len; buf->memory = 1; } if (cl == NULL) { cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } cl->buf = buf; cl->next = NULL; ll = &cl->next; } else { /* append a space first */ *ll = ngx_alloc_chain_link(r->pool); if (*ll == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } space_buf = ngx_calloc_buf(r->pool); if (space_buf == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } /* nginx clears buf flags at the end of each request handling, * so we have to make a clone here. */ *space_buf = ngx_http_echo_space_buf; (*ll)->buf = space_buf; (*ll)->next = NULL; ll = &(*ll)->next; /* then append the buf only if it's non-empty */ if (buf) { *ll = ngx_alloc_chain_link(r->pool); if (*ll == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } (*ll)->buf = buf; (*ll)->next = NULL; ll = &(*ll)->next; } } } /* end for */ if (cl && cl->buf == NULL) { cl = cl->next; } if (opts && opts->nelts > 0) { opt = opts->elts; /* FIXME handle other unrecognized options here */ if (opt[0].len == 1 && opt[0].data[0] == 'n') { goto done; } } /* append the newline character */ newline_buf = ngx_calloc_buf(r->pool); if (newline_buf == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } *newline_buf = ngx_http_echo_newline_buf; if (cl == NULL) { cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } cl->buf = newline_buf; cl->next = NULL; /* ll = &cl->next; */ } else { *ll = ngx_alloc_chain_link(r->pool); if (*ll == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } (*ll)->buf = newline_buf; (*ll)->next = NULL; /* ll = &(*ll)->next; */ } done: if (cl == NULL || cl->buf == NULL) { return NGX_OK; } if (in_filter) { return ngx_http_echo_next_body_filter(r, cl); } return ngx_http_echo_send_chain_link(r, ctx, cl); }
ngx_int_t ngx_http_echo_exec_echo_duplicate(ngx_http_request_t *r, ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args) { ngx_str_t *computed_arg; ngx_str_t *computed_arg_elts; ssize_t i, count; ngx_str_t *str; u_char *p; ngx_int_t rc; ngx_buf_t *buf; ngx_chain_t *cl; dd_enter(); computed_arg_elts = computed_args->elts; computed_arg = &computed_arg_elts[0]; count = ngx_http_echo_atosz(computed_arg->data, computed_arg->len); if (count == NGX_ERROR) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "invalid size specified: \"%V\"", computed_arg); return NGX_HTTP_INTERNAL_SERVER_ERROR; } str = &computed_arg_elts[1]; if (count == 0 || str->len == 0) { rc = ngx_http_echo_send_header_if_needed(r, ctx); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; } return NGX_OK; } buf = ngx_create_temp_buf(r->pool, count * str->len); if (buf == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } p = buf->pos; for (i = 0; i < count; i++) { p = ngx_copy(p, str->data, str->len); } buf->last = p; cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } cl->next = NULL; cl->buf = buf; return ngx_http_echo_send_chain_link(r, ctx, cl); }
static int ngx_http_lua_ngx_req_set_body_data(lua_State *L) { ngx_http_request_t *r; int n; ngx_http_request_body_t *rb; ngx_temp_file_t *tf; ngx_buf_t *b; ngx_str_t body, key, value; #if 1 ngx_int_t rc; #endif ngx_chain_t *cl; ngx_buf_tag_t tag; n = lua_gettop(L); if (n != 1) { return luaL_error(L, "expecting 1 arguments but seen %d", n); } body.data = (u_char *) luaL_checklstring(L, 1, &body.len); r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "request object not found"); } ngx_http_lua_check_fake_request(L, r); if (r->discard_body) { return luaL_error(L, "request body already discarded asynchronously"); } if (r->request_body == NULL) { return luaL_error(L, "request body not read yet"); } rb = r->request_body; tag = (ngx_buf_tag_t) &ngx_http_lua_module; tf = rb->temp_file; if (tf) { if (tf->file.fd != NGX_INVALID_FILE) { dd("cleaning temp file %.*s", (int) tf->file.name.len, tf->file.name.data); ngx_http_lua_pool_cleanup_file(r->pool, tf->file.fd); tf->file.fd = NGX_INVALID_FILE; dd("temp file cleaned: %.*s", (int) tf->file.name.len, tf->file.name.data); } rb->temp_file = NULL; } if (body.len == 0) { if (rb->bufs) { for (cl = rb->bufs; cl; cl = cl->next) { if (cl->buf->tag == tag && cl->buf->temporary) { dd("free old request body buffer: size:%d", (int) ngx_buf_size(cl->buf)); ngx_pfree(r->pool, cl->buf->start); cl->buf->tag = (ngx_buf_tag_t) NULL; cl->buf->temporary = 0; } } } rb->bufs = NULL; rb->buf = NULL; dd("request body is set to empty string"); goto set_header; } if (rb->bufs) { for (cl = rb->bufs; cl; cl = cl->next) { if (cl->buf->tag == tag && cl->buf->temporary) { dd("free old request body buffer: size:%d", (int) ngx_buf_size(cl->buf)); ngx_pfree(r->pool, cl->buf->start); cl->buf->tag = (ngx_buf_tag_t) NULL; cl->buf->temporary = 0; } } rb->bufs->next = NULL; b = rb->bufs->buf; ngx_memzero(b, sizeof(ngx_buf_t)); b->temporary = 1; b->tag = tag; b->start = ngx_palloc(r->pool, body.len); if (b->start == NULL) { return luaL_error(L, "no memory"); } b->end = b->start + body.len; b->pos = b->start; b->last = ngx_copy(b->pos, body.data, body.len); } else { rb->bufs = ngx_alloc_chain_link(r->pool); if (rb->bufs == NULL) { return luaL_error(L, "no memory"); } rb->bufs->next = NULL; b = ngx_create_temp_buf(r->pool, body.len); if (b == NULL) { return luaL_error(L, "no memory"); } b->tag = tag; b->last = ngx_copy(b->pos, body.data, body.len); rb->bufs->buf = b; rb->buf = b; } set_header: /* override input header Content-Length (value must be null terminated) */ value.data = ngx_palloc(r->pool, NGX_SIZE_T_LEN + 1); if (value.data == NULL) { return luaL_error(L, "no memory"); } value.len = ngx_sprintf(value.data, "%uz", body.len) - value.data; value.data[value.len] = '\0'; dd("setting request Content-Length to %.*s (%d)", (int) value.len, value.data, (int) body.len); r->headers_in.content_length_n = body.len; if (r->headers_in.content_length) { r->headers_in.content_length->value.data = value.data; r->headers_in.content_length->value.len = value.len; } else { ngx_str_set(&key, "Content-Length"); rc = ngx_http_lua_set_input_header(r, key, value, 1 /* override */); if (rc != NGX_OK) { return luaL_error(L, "failed to reset the Content-Length " "input header"); } } return 0; }
static void ngx_rtmp_netcall_recv(ngx_event_t *rev) { ngx_rtmp_netcall_session_t *cs; ngx_connection_t *cc; ngx_chain_t *cl; ngx_int_t n; ngx_buf_t *b; cc = rev->data; cs = cc->data; if (cc->destroyed) { return; } if (rev->timedout) { cc->timedout = 1; ngx_rtmp_netcall_close(cc); return; } if (rev->timer_set) { ngx_del_timer(rev); } for ( ;; ) { if (cs->inlast == NULL || cs->inlast->buf->last == cs->inlast->buf->end) { if (cs->in && cs->sink) { if (!cs->detached) { if (cs->sink(cs->session, cs->in) != NGX_OK) { ngx_rtmp_netcall_close(cc); return; } } b = cs->in->buf; b->pos = b->last = b->start; } else { cl = ngx_alloc_chain_link(cc->pool); if (cl == NULL) { ngx_rtmp_netcall_close(cc); return; } cl->next = NULL; cl->buf = ngx_create_temp_buf(cc->pool, cs->bufsize); if (cl->buf == NULL) { ngx_rtmp_netcall_close(cc); return; } if (cs->in == NULL) { cs->in = cl; } else { cs->inlast->next = cl; } cs->inlast = cl; } } b = cs->inlast->buf; n = cc->recv(cc, b->last, b->end - b->last); if (n == NGX_ERROR || n == 0) { ngx_rtmp_netcall_close(cc); return; } if (n == NGX_AGAIN) { if (cs->filter && cs->in && cs->filter(cs->in) != NGX_AGAIN) { ngx_rtmp_netcall_close(cc); return; } ngx_add_timer(rev, cs->timeout); if (ngx_handle_read_event(rev, 0) != NGX_OK) { ngx_rtmp_netcall_close(cc); } return; } b->last += n; } }
static int ngx_http_lua_ngx_req_init_body(lua_State *L) { ngx_http_request_t *r; int n; ngx_http_request_body_t *rb; size_t size; lua_Integer num; #if 1 ngx_temp_file_t *tf; #endif ngx_http_core_loc_conf_t *clcf; n = lua_gettop(L); if (n != 1 && n != 0) { return luaL_error(L, "expecting 0 or 1 argument but seen %d", n); } r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request found"); } ngx_http_lua_check_fake_request(L, r); if (r->discard_body) { return luaL_error(L, "request body already discarded asynchronously"); } if (r->request_body == NULL) { return luaL_error(L, "request body not read yet"); } if (n == 1) { num = luaL_checkinteger(L, 1); if (num <= 0) { return luaL_error(L, "bad size argument: %d", (int) num); } size = (size_t) num; } else { clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); size = clcf->client_body_buffer_size; size += size >> 2; /* avoid allocating an unnecessary large buffer */ if (size > (size_t) r->headers_in.content_length_n) { size = (size_t) r->headers_in.content_length_n; } } rb = r->request_body; #if 1 tf = rb->temp_file; if (tf) { if (tf->file.fd != NGX_INVALID_FILE) { dd("cleaning temp file %.*s", (int) tf->file.name.len, tf->file.name.data); ngx_http_lua_pool_cleanup_file(r->pool, tf->file.fd); ngx_memzero(tf, sizeof(ngx_temp_file_t)); tf->file.fd = NGX_INVALID_FILE; dd("temp file cleaned: %.*s", (int) tf->file.name.len, tf->file.name.data); } rb->temp_file = NULL; } #endif r->request_body_in_clean_file = 1; r->headers_in.content_length_n = 0; rb->buf = ngx_create_temp_buf(r->pool, size); if (rb->buf == NULL) { return luaL_error(L, "no memory"); } rb->bufs = ngx_alloc_chain_link(r->pool); if (rb->bufs == NULL) { return luaL_error(L, "no memory"); } rb->bufs->buf = rb->buf; rb->bufs->next = NULL; return 0; }
static ngx_int_t ngx_http_chunked_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { u_char *chunk; off_t size; ngx_int_t rc; ngx_buf_t *b; ngx_chain_t *out, *cl, *tl, **ll; ngx_http_chunked_filter_ctx_t *ctx; if (in == NULL || !r->chunked || r->header_only) { return ngx_http_next_body_filter(r, in); } ctx = ngx_http_get_module_ctx(r, ngx_http_chunked_filter_module); out = NULL; ll = &out; size = 0; cl = in; for ( ;; ) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http chunk: %d", ngx_buf_size(cl->buf)); size += ngx_buf_size(cl->buf); if (cl->buf->flush || cl->buf->sync || ngx_buf_in_memory(cl->buf) || cl->buf->in_file) { tl = ngx_alloc_chain_link(r->pool); if (tl == NULL) { return NGX_ERROR; } tl->buf = cl->buf; *ll = tl; ll = &tl->next; } if (cl->next == NULL) { break; } cl = cl->next; } if (size) { tl = ngx_chain_get_free_buf(r->pool, &ctx->free); if (tl == NULL) { return NGX_ERROR; } b = tl->buf; chunk = b->start; if (chunk == NULL) { /* the "0000000000000000" is 64-bit hexadecimal string */ chunk = ngx_palloc(r->pool, sizeof("0000000000000000" CRLF) - 1); if (chunk == NULL) { return NGX_ERROR; } b->start = chunk; b->end = chunk + sizeof("0000000000000000" CRLF) - 1; } b->tag = (ngx_buf_tag_t) &ngx_http_chunked_filter_module; b->memory = 0; b->temporary = 1; b->pos = chunk; b->last = ngx_sprintf(chunk, "%xO" CRLF, size); tl->next = out; out = tl; } if (cl->buf->last_buf) { tl = ngx_chain_get_free_buf(r->pool, &ctx->free); if (tl == NULL) { return NGX_ERROR; } b = tl->buf; b->tag = (ngx_buf_tag_t) &ngx_http_chunked_filter_module; b->temporary = 0; b->memory = 1; b->last_buf = 1; b->pos = (u_char *) CRLF "0" CRLF CRLF; b->last = b->pos + 7; cl->buf->last_buf = 0; *ll = tl; if (size == 0) { b->pos += 2; } } else if (size > 0) { tl = ngx_chain_get_free_buf(r->pool, &ctx->free); if (tl == NULL) { return NGX_ERROR; } b = tl->buf; b->tag = (ngx_buf_tag_t) &ngx_http_chunked_filter_module; b->temporary = 0; b->memory = 1; b->pos = (u_char *) CRLF; b->last = b->pos + 2; *ll = tl; } else { *ll = NULL; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "send chunked data: %d", size); rc = ngx_http_next_body_filter(r, out); ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &out, (ngx_buf_tag_t) &ngx_http_chunked_filter_module); return rc; }
ngx_int_t ngx_http_read_client_request_body(ngx_http_request_t *r, ngx_http_client_body_handler_pt post_handler) { size_t preread; ssize_t size; ngx_buf_t *b, buf; ngx_int_t rc; ngx_chain_t *cl, **next; ngx_temp_file_t *tf; ngx_http_request_body_t *rb; ngx_http_core_loc_conf_t *clcf; r->main->count++; if (r->request_body || r->discard_body) { ngx_http_probe_read_body_abort(r, (r->request_body ? "body exists" : "body discarded")); post_handler(r); return NGX_OK; } if (ngx_http_test_expect(r) != NGX_OK) { ngx_http_probe_read_body_abort(r, "test expect failed"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); if (rb == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } r->request_body = rb; if (r->headers_in.content_length_n < 0) { ngx_http_probe_read_body_abort(r, "no content length"); post_handler(r); return NGX_OK; } clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (r->headers_in.content_length_n == 0) { if (r->request_body_in_file_only) { tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)); if (tf == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } tf->file.fd = NGX_INVALID_FILE; tf->file.log = r->connection->log; tf->path = clcf->client_body_temp_path; tf->pool = r->pool; tf->warn = "a client request body is buffered to a temporary file"; tf->log_level = r->request_body_file_log_level; tf->persistent = r->request_body_in_persistent_file; tf->clean = r->request_body_in_clean_file; if (r->request_body_file_group_access) { tf->access = 0660; } rb->temp_file = tf; if (ngx_create_temp_file(&tf->file, tf->path, tf->pool, tf->persistent, tf->clean, tf->access) != NGX_OK) { ngx_http_probe_read_body_abort(r, "create temp file failed"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } } ngx_http_probe_read_body_done(r); post_handler(r); return NGX_OK; } rb->post_handler = post_handler; /* * set by ngx_pcalloc(): * * rb->bufs = NULL; * rb->buf = NULL; * rb->rest = 0; */ preread = r->header_in->last - r->header_in->pos; if (preread) { /* there is the pre-read part of the request body */ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http client request body preread %uz", preread); b = ngx_calloc_buf(r->pool); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b->temporary = 1; b->start = r->header_in->pos; b->pos = r->header_in->pos; b->last = r->header_in->last; b->end = r->header_in->end; buf.start = r->header_in->pos; buf.pos = r->header_in->pos; buf.last = (off_t) preread >= r->headers_in.content_length_n ? r->header_in->pos + (size_t) r->headers_in.content_length_n : r->header_in->last; buf.end = r->header_in->end; rc = ngx_http_top_input_body_filter(r, &buf); if (rc != NGX_OK) { return rc; } rb->bufs = ngx_alloc_chain_link(r->pool); if (rb->bufs == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } rb->bufs->buf = b; rb->bufs->next = NULL; rb->buf = b; if ((off_t) preread >= r->headers_in.content_length_n) { /* the whole request body was pre-read */ r->header_in->pos += (size_t) r->headers_in.content_length_n; r->request_length += r->headers_in.content_length_n; b->last = r->header_in->pos; if (r->request_body_in_file_only) { if (ngx_http_write_request_body(r, rb->bufs) != NGX_OK) { ngx_http_probe_read_body_abort(r, "write temp file failed"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } } ngx_http_probe_read_body_done(r); post_handler(r); return NGX_OK; } /* * to not consider the body as pipelined request in * ngx_http_set_keepalive() */ r->header_in->pos = r->header_in->last; r->request_length += preread; rb->rest = r->headers_in.content_length_n - preread; if (rb->rest <= (off_t) (b->end - b->last)) { /* the whole request body may be placed in r->header_in */ rb->to_write = rb->bufs; r->read_event_handler = ngx_http_read_client_request_body_handler; return ngx_http_do_read_client_request_body(r); } next = &rb->bufs->next; } else { b = NULL; rb->rest = r->headers_in.content_length_n; next = &rb->bufs; } size = clcf->client_body_buffer_size; size += size >> 2; if (rb->rest < size) { size = (ssize_t) rb->rest; if (r->request_body_in_single_buf) { size += preread; } } else { size = clcf->client_body_buffer_size; /* disable copying buffer for r->request_body_in_single_buf */ b = NULL; } rb->buf = ngx_create_temp_buf(r->pool, size); if (rb->buf == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } cl->buf = rb->buf; cl->next = NULL; if (b && r->request_body_in_single_buf) { size = b->last - b->pos; ngx_memcpy(rb->buf->pos, b->pos, size); rb->buf->last += size; next = &rb->bufs; } *next = cl; if (r->request_body_in_file_only || r->request_body_in_single_buf) { rb->to_write = rb->bufs; } else { rb->to_write = rb->bufs->next ? rb->bufs->next : rb->bufs; } r->read_event_handler = ngx_http_read_client_request_body_handler; return ngx_http_do_read_client_request_body(r); }
static ngx_int_t ngx_http_range_multipart_body(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in) { ngx_buf_t *b, *buf; ngx_uint_t i; ngx_chain_t *out, *hcl, *rcl, *dcl, **ll; ngx_http_range_t *range; ll = &out; buf = in->buf; range = ctx->ranges.elts; for (i = 0; i < ctx->ranges.nelts; i++) { /* * The boundary header of the range: * CRLF * "--0123456789" CRLF * "Content-Type: image/jpeg" CRLF * "Content-Range: bytes " */ b = ngx_calloc_buf(r->pool); if (b == NULL) { return NGX_ERROR; } b->memory = 1; b->pos = ctx->boundary_header.data; b->last = ctx->boundary_header.data + ctx->boundary_header.len; hcl = ngx_alloc_chain_link(r->pool); if (hcl == NULL) { return NGX_ERROR; } hcl->buf = b; /* "SSSS-EEEE/TTTT" CRLF CRLF */ b = ngx_calloc_buf(r->pool); if (b == NULL) { return NGX_ERROR; } b->temporary = 1; b->pos = range[i].content_range.data; b->last = range[i].content_range.data + range[i].content_range.len; rcl = ngx_alloc_chain_link(r->pool); if (rcl == NULL) { return NGX_ERROR; } rcl->buf = b; /* the range data */ b = ngx_calloc_buf(r->pool); if (b == NULL) { return NGX_ERROR; } b->in_file = buf->in_file; b->temporary = buf->temporary; b->memory = buf->memory; b->mmap = buf->mmap; b->file = buf->file; if (buf->in_file) { b->file_pos = buf->file_pos + range[i].start; b->file_last = buf->file_pos + range[i].end; } if (ngx_buf_in_memory(buf)) { b->pos = buf->pos + (size_t) range[i].start; b->last = buf->pos + (size_t) range[i].end; } dcl = ngx_alloc_chain_link(r->pool); if (dcl == NULL) { return NGX_ERROR; } dcl->buf = b; *ll = hcl; hcl->next = rcl; rcl->next = dcl; ll = &dcl->next; } /* the last boundary CRLF "--0123456789--" CRLF */ b = ngx_calloc_buf(r->pool); if (b == NULL) { return NGX_ERROR; } b->temporary = 1; b->last_buf = 1; b->pos = ngx_pnalloc(r->pool, sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN + sizeof("--" CRLF) - 1); if (b->pos == NULL) { return NGX_ERROR; } b->last = ngx_cpymem(b->pos, ctx->boundary_header.data, sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN); *b->last++ = '-'; *b->last++ = '-'; *b->last++ = CR; *b->last++ = LF; hcl = ngx_alloc_chain_link(r->pool); if (hcl == NULL) { return NGX_ERROR; } hcl->buf = b; hcl->next = NULL; *ll = hcl; return ngx_http_next_body_filter(r, out); }
static ngx_int_t create_request(ngx_http_request_t *r) { passenger_loc_conf_t *slcf; passenger_context_t *context; buffer_construction_state state; ngx_uint_t request_size; ngx_buf_t *b; ngx_chain_t *cl, *body; slcf = ngx_http_get_module_loc_conf(r, ngx_http_passenger_module); context = ngx_http_get_module_ctx(r, ngx_http_passenger_module); if (context == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } /* Construct and pass request headers */ if (prepare_request_buffer_construction(r, context, &state) != NGX_OK) { return NGX_ERROR; } request_size = construct_request_buffer(r, slcf, context, &state, NULL); b = ngx_create_temp_buf(r->pool, request_size); if (b == NULL) { return NGX_ERROR; } cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_ERROR; } cl->buf = b; construct_request_buffer(r, slcf, context, &state, b); /* Pass request body */ body = r->upstream->request_bufs; r->upstream->request_bufs = cl; while (body) { b = ngx_alloc_buf(r->pool); if (b == NULL) { return NGX_ERROR; } ngx_memcpy(b, body->buf, sizeof(ngx_buf_t)); cl->next = ngx_alloc_chain_link(r->pool); if (cl->next == NULL) { return NGX_ERROR; } cl = cl->next; cl->buf = b; body = body->next; } b->flush = 1; cl->next = NULL; return NGX_OK; }
static ngx_int_t ngx_http_echo_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { ngx_http_echo_ctx_t *ctx; ngx_int_t rc; ngx_http_echo_loc_conf_t *conf; unsigned last; ngx_chain_t *cl; ngx_chain_t *prev; ngx_buf_t *buf; if (in == NULL || r->header_only) { return ngx_http_echo_next_body_filter(r, in); } ctx = ngx_http_get_module_ctx(r, ngx_http_echo_module); if (ctx == NULL || ctx->skip_filter) { return ngx_http_echo_next_body_filter(r, in); } conf = ngx_http_get_module_loc_conf(r, ngx_http_echo_module); if (!ctx->before_body_sent) { ctx->before_body_sent = 1; if (conf->before_body_cmds != NULL) { rc = ngx_http_echo_exec_filter_cmds(r, ctx, conf->before_body_cmds, &ctx->next_before_body_cmd); if (rc != NGX_OK) { return NGX_ERROR; } } } if (conf->after_body_cmds == NULL) { ctx->skip_filter = 1; return ngx_http_echo_next_body_filter(r, in); } last = 0; prev = NULL; for (cl = in; cl; prev = cl, cl = cl->next) { dd("prev %p, cl %p, special %d", prev, cl, ngx_buf_special(cl->buf)); if (cl->buf->last_buf) { if (ngx_buf_special(cl->buf)) { if (prev) { prev->next = NULL; } else { in = NULL; } } else { cl->buf->last_buf = 0; } last = 1; } } dd("in %p, last %d", in, (int) last); if (in) { rc = ngx_http_echo_next_body_filter(r, in); #if 0 if (rc == NGX_AGAIN) { return NGX_ERROR; } #endif dd("next filter returns %d, last %d", (int) rc, (int) last); if (rc == NGX_ERROR || rc > NGX_OK || !last) { return rc; } } dd("exec filter cmds for after body cmds"); rc = ngx_http_echo_exec_filter_cmds(r, ctx, conf->after_body_cmds, &ctx->next_after_body_cmd); if (rc == NGX_ERROR || rc > NGX_OK) { dd("FAILED: exec filter cmds for after body cmds"); return NGX_ERROR; } ctx->skip_filter = 1; dd("after body cmds executed...terminating..."); /* XXX we can NOT use * ngx_http_send_special(r, NGX_HTTP_LAST) here * because we should bypass the upstream filters. */ if (r != r->main) { return NGX_OK; } buf = ngx_calloc_buf(r->pool); if (buf == NULL) { return NGX_ERROR; } buf->last_buf = 1; cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_ERROR; } cl->next = NULL; cl->buf = buf; return ngx_http_echo_next_body_filter(r, cl); }
ngx_int_t ngx_http_memc_create_get_cmd_request(ngx_http_request_t *r) { size_t len; uintptr_t escape; ngx_buf_t *b; ngx_chain_t *cl; ngx_http_memc_ctx_t *ctx; ngx_http_variable_value_t *vv; ctx = ngx_http_get_module_ctx(r, ngx_http_memc_module); vv = ctx->memc_key_vv; if (vv == NULL || vv->not_found || vv->len == 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "the \"$memc_key\" variable is not set"); return NGX_ERROR; } escape = 2 * ngx_escape_uri(NULL, vv->data, vv->len, NGX_ESCAPE_MEMCACHED); len = sizeof("get ") - 1 + vv->len + escape + sizeof(CRLF) - 1; 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; *b->last++ = 'g'; *b->last++ = 'e'; *b->last++ = 't'; *b->last++ = ' '; ctx->key.data = b->last; if (escape == 0) { b->last = ngx_copy(b->last, vv->data, vv->len); } else { b->last = (u_char *) ngx_escape_uri(b->last, vv->data, vv->len, NGX_ESCAPE_MEMCACHED); } ctx->key.len = b->last - ctx->key.data; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http memcached request: \"%V\"", &ctx->key); *b->last++ = CR; *b->last++ = LF; ctx->parser_state = NGX_ERROR; return NGX_OK; }
static ngx_int_t ngx_http_gunzip_filter_inflate(ngx_http_request_t *r, ngx_http_gunzip_ctx_t *ctx) { int rc; ngx_buf_t *b; ngx_chain_t *cl; ngx_log_debug6(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "inflate in: ni:%p no:%p ai:%ud ao:%ud fl:%d redo:%d", ctx->zstream.next_in, ctx->zstream.next_out, ctx->zstream.avail_in, ctx->zstream.avail_out, ctx->flush, ctx->redo); rc = inflate(&ctx->zstream, ctx->flush); if (rc != Z_OK && rc != Z_STREAM_END && rc != Z_BUF_ERROR) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "inflate() failed: %d, %d", ctx->flush, rc); return NGX_ERROR; } ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "inflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d", ctx->zstream.next_in, ctx->zstream.next_out, ctx->zstream.avail_in, ctx->zstream.avail_out, rc); ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "gunzip in_buf:%p pos:%p", ctx->in_buf, ctx->in_buf->pos); if (ctx->zstream.next_in) { ctx->in_buf->pos = ctx->zstream.next_in; if (ctx->zstream.avail_in == 0) { ctx->zstream.next_in = NULL; } } ctx->out_buf->last = ctx->zstream.next_out; if (ctx->zstream.avail_out == 0) { /* zlib wants to output some more data */ cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_ERROR; } cl->buf = ctx->out_buf; cl->next = NULL; *ctx->last_out = cl; ctx->last_out = &cl->next; ctx->redo = 1; return NGX_AGAIN; } ctx->redo = 0; if (ctx->flush == Z_SYNC_FLUSH) { ctx->flush = Z_NO_FLUSH; cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_ERROR; } b = ctx->out_buf; if (ngx_buf_size(b) == 0) { b = ngx_calloc_buf(ctx->request->pool); if (b == NULL) { return NGX_ERROR; } } else { ctx->zstream.avail_out = 0; } b->flush = 1; cl->buf = b; cl->next = NULL; *ctx->last_out = cl; ctx->last_out = &cl->next; return NGX_OK; } if (ctx->flush == Z_FINISH && ctx->zstream.avail_in == 0) { if (rc != Z_STREAM_END) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "inflate() returned %d on response end", rc); return NGX_ERROR; } if (ngx_http_gunzip_filter_inflate_end(r, ctx) != NGX_OK) { return NGX_ERROR; } return NGX_OK; } if (rc == Z_STREAM_END && ctx->zstream.avail_in > 0) { rc = inflateReset(&ctx->zstream); if (rc != Z_OK) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "inflateReset() failed: %d", rc); return NGX_ERROR; } ctx->redo = 1; return NGX_AGAIN; } if (ctx->in == NULL) { b = ctx->out_buf; if (ngx_buf_size(b) == 0) { return NGX_OK; } cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_ERROR; } ctx->zstream.avail_out = 0; cl->buf = b; cl->next = NULL; *ctx->last_out = cl; ctx->last_out = &cl->next; return NGX_OK; } return NGX_AGAIN; }
ngx_int_t ngx_http_memc_create_incr_decr_cmd_request(ngx_http_request_t *r) { size_t len; ngx_buf_t *b; ngx_http_memc_ctx_t *ctx; ngx_chain_t *cl; uintptr_t escape; ngx_http_variable_value_t *key_vv; ngx_http_variable_value_t *value_vv; ctx = ngx_http_get_module_ctx(r, ngx_http_memc_module); /* prepare the "key" argument */ key_vv = ctx->memc_key_vv; if (key_vv == NULL || key_vv->not_found || key_vv->len == 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "the \"$memc_key\" variable is not set"); return NGX_ERROR; } escape = 2 * ngx_escape_uri(NULL, key_vv->data, key_vv->len, NGX_ESCAPE_MEMCACHED); /* prepare the "value" argument */ value_vv = ctx->memc_value_vv; /* XXX validate if $memc_value_vv is a valid uint64 string */ len = ctx->cmd_str.len + sizeof(' ') + key_vv->len + escape + sizeof(' ') + value_vv->len + sizeof(CRLF) - 1; 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; b->last = ngx_copy(b->last, ctx->cmd_str.data, ctx->cmd_str.len); *b->last++ = ' '; if (escape == 0) { b->last = ngx_copy(b->last, key_vv->data, key_vv->len); } else { b->last = (u_char *) ngx_escape_uri(b->last, key_vv->data, key_vv->len, NGX_ESCAPE_MEMCACHED); } *b->last++ = ' '; b->last = ngx_copy(b->last, value_vv->data, value_vv->len); *b->last++ = CR; *b->last++ = LF; return NGX_OK; }
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 (ngx_http_set_etag(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_http_weak_etag(r); 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); }
ngx_chain_t * ajp_data_msg_send_body(ngx_http_request_t *r, size_t max_size, ngx_chain_t **body) { size_t size; ngx_buf_t *b_in, *b_out; ajp_msg_t *msg; ngx_chain_t *out, *cl, *in; ngx_http_ajp_ctx_t *a; a = ngx_http_get_module_ctx(r, ngx_http_ajp_module); if (*body == NULL || a == NULL) { return NULL; } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ajp_data_msg_send_body"); msg = ajp_msg_reuse(&a->msg); if (ajp_alloc_data_msg(r->pool, msg) != NGX_OK) { return NULL; } out = cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NULL; } cl->buf = msg->buf; max_size -= AJP_HEADER_SZ; size = 0; in = *body; b_out = NULL; while (in) { b_in = in->buf; b_out = ngx_alloc_buf(r->pool); if (b_out == NULL) { return NULL; } ngx_memcpy(b_out, b_in, sizeof(ngx_buf_t)); if (b_in->in_file) { if ((size_t)(b_in->file_last - b_in->file_pos) <= (max_size - size)) { b_out->file_pos = b_in->file_pos; b_out->file_last = b_in->file_pos = b_in->file_last; size += (size_t) b_out->file_last - (size_t) b_out->file_pos; } else if ((size_t)(b_in->file_last - b_in->file_pos) > (max_size - size)) { b_out->file_pos = b_in->file_pos; b_in->file_pos += max_size - size; b_out->file_last = b_in->file_pos; size += (size_t) b_out->file_last - (size_t) b_out->file_pos; } } else { if ((size_t)(b_in->last - b_in->pos) <= (max_size - size)) { b_out->pos = b_in->pos; b_out->last = b_in->pos = b_in->last; size += b_out->last - b_out->pos; } else if ((size_t)(b_in->last - b_in->pos) > (max_size - size)) { b_out->pos = b_in->pos; b_in->pos += max_size - size; b_out->last = b_in->pos; size += b_out->last - b_out->pos; } } cl->next = ngx_alloc_chain_link(r->pool); if (cl->next == NULL) { return NULL; } cl = cl->next; cl->buf = b_out; if (size >= max_size) { break; } else { in = in->next; } } *body = in; cl->next = NULL; ajp_data_msg_end(msg, size); return out; }
ngx_int_t ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) { off_t size, sent, nsent, limit; ngx_uint_t last, flush, sync; ngx_msec_t delay; ngx_chain_t *cl, *ln, **ll, *chain; ngx_connection_t *c; ngx_http_core_loc_conf_t *clcf; c = r->connection; if (c->error) { return NGX_ERROR; } size = 0; flush = 0; sync = 0; last = 0; ll = &r->out; /* find the size, the flush point and the last link of the saved chain */ for (cl = r->out; cl; cl = cl->next) { ll = &cl->next; ngx_log_debug7(NGX_LOG_DEBUG_EVENT, c->log, 0, "write old buf t:%d f:%d %p, pos %p, size: %z " "file: %O, size: %O", cl->buf->temporary, cl->buf->in_file, cl->buf->start, cl->buf->pos, cl->buf->last - cl->buf->pos, cl->buf->file_pos, cl->buf->file_last - cl->buf->file_pos); #if 1 if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) { ngx_log_error(NGX_LOG_ALERT, c->log, 0, "zero size buf in writer " "t:%d r:%d f:%d %p %p-%p %p %O-%O", cl->buf->temporary, cl->buf->recycled, cl->buf->in_file, cl->buf->start, cl->buf->pos, cl->buf->last, cl->buf->file, cl->buf->file_pos, cl->buf->file_last); ngx_debug_point(); return NGX_ERROR; } #endif size += ngx_buf_size(cl->buf); if (cl->buf->flush || cl->buf->recycled) { flush = 1; } if (cl->buf->sync) { sync = 1; } if (cl->buf->last_buf) { last = 1; } } /* add the new chain to the existent one */ for (ln = in; ln; ln = ln->next) { cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return NGX_ERROR; } cl->buf = ln->buf; *ll = cl; ll = &cl->next; ngx_log_debug7(NGX_LOG_DEBUG_EVENT, c->log, 0, "write new buf t:%d f:%d %p, pos %p, size: %z " "file: %O, size: %O", cl->buf->temporary, cl->buf->in_file, cl->buf->start, cl->buf->pos, cl->buf->last - cl->buf->pos, cl->buf->file_pos, cl->buf->file_last - cl->buf->file_pos); #if 1 if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) { ngx_log_error(NGX_LOG_ALERT, c->log, 0, "zero size buf in writer " "t:%d r:%d f:%d %p %p-%p %p %O-%O", cl->buf->temporary, cl->buf->recycled, cl->buf->in_file, cl->buf->start, cl->buf->pos, cl->buf->last, cl->buf->file, cl->buf->file_pos, cl->buf->file_last); ngx_debug_point(); return NGX_ERROR; } #endif size += ngx_buf_size(cl->buf); if (cl->buf->flush || cl->buf->recycled) { flush = 1; } if (cl->buf->sync) { sync = 1; } if (cl->buf->last_buf) { last = 1; } } *ll = NULL; ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, "http write filter: l:%d f:%d s:%O", last, flush, size); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); /* * avoid the output if there are no last buf, no flush point, * there are the incoming bufs and the size of all bufs * is smaller than "postpone_output" directive */ if (!last && !flush && in && size < (off_t) clcf->postpone_output) { return NGX_OK; } if (c->write->delayed) { c->buffered |= NGX_HTTP_WRITE_BUFFERED; return NGX_AGAIN; } if (size == 0 && !(c->buffered & NGX_LOWLEVEL_BUFFERED) && !(last && c->need_last_buf)) { if (last || flush || sync) { for (cl = r->out; cl; /* void */) { ln = cl; cl = cl->next; ngx_free_chain(r->pool, ln); } r->out = NULL; c->buffered &= ~NGX_HTTP_WRITE_BUFFERED; return NGX_OK; } ngx_log_error(NGX_LOG_ALERT, c->log, 0, "the http output chain is empty"); ngx_debug_point(); return NGX_ERROR; } if (r->limit_rate) { if (r->limit_rate_after == 0) { r->limit_rate_after = clcf->limit_rate_after; } limit = (off_t) r->limit_rate * (ngx_time() - r->start_sec + 1) - (c->sent - r->limit_rate_after); if (limit <= 0) { c->write->delayed = 1; delay = (ngx_msec_t) (- limit * 1000 / r->limit_rate + 1); ngx_add_timer(c->write, delay); c->buffered |= NGX_HTTP_WRITE_BUFFERED; return NGX_AGAIN; } if (clcf->sendfile_max_chunk && (off_t) clcf->sendfile_max_chunk < limit) { limit = clcf->sendfile_max_chunk; } } else { limit = clcf->sendfile_max_chunk; } sent = c->sent; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http write filter limit %O", limit); chain = c->send_chain(c, r->out, limit); if (ngx_http_log_flow && ngx_http_log_flow(r) == NGX_ERROR) { return NGX_ERROR; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http write filter %p", chain); if (chain == NGX_CHAIN_ERROR) { c->error = 1; return NGX_ERROR; } if (r->limit_rate) { nsent = c->sent; if (r->limit_rate_after) { sent -= r->limit_rate_after; if (sent < 0) { sent = 0; } nsent -= r->limit_rate_after; if (nsent < 0) { nsent = 0; } } delay = (ngx_msec_t) ((nsent - sent) * 1000 / r->limit_rate); if (delay > 0) { limit = 0; c->write->delayed = 1; ngx_add_timer(c->write, delay); } } if (limit && c->write->ready && c->sent - sent >= limit - (off_t) (2 * ngx_pagesize)) { c->write->delayed = 1; ngx_add_timer(c->write, 1); } for (cl = r->out; cl && cl != chain; /* void */) { ln = cl; cl = cl->next; ngx_free_chain(r->pool, ln); } r->out = chain; if (chain) { c->buffered |= NGX_HTTP_WRITE_BUFFERED; return NGX_AGAIN; } c->buffered &= ~NGX_HTTP_WRITE_BUFFERED; if ((c->buffered & NGX_LOWLEVEL_BUFFERED) && r->postponed == NULL) { return NGX_AGAIN; } return NGX_OK; }
static ngx_chain_t * ngx_http_tfs_create_write_meta_message(ngx_http_tfs_t *t) { u_char *p; size_t size, frag_size; ngx_buf_t *b; ngx_int_t need_write_frag_count, i; ngx_chain_t *cl; ngx_http_tfs_restful_ctx_t *r_ctx; ngx_http_tfs_segment_data_t *segment_data; ngx_http_tfs_meta_frag_info_t *wfi; ngx_http_tfs_ms_base_msg_header_t *req; r_ctx = &t->r_ctx; need_write_frag_count = t->file.segment_index - t->file.last_write_segment_index; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, t->log, 0 , "last_write_segment_index: %uD, segment_index: %uD", t->file.last_write_segment_index, t->file.segment_index); frag_size = sizeof(ngx_http_tfs_meta_frag_info_t) + sizeof(ngx_http_tfs_meta_frag_meta_info_t) * need_write_frag_count; size = sizeof(ngx_http_tfs_ms_base_msg_header_t) + r_ctx->file_path_s.len + 1 + /* version */ sizeof(uint64_t) + frag_size; b = ngx_create_temp_buf(t->pool, size); if (b == NULL) { return NULL; } req = (ngx_http_tfs_ms_base_msg_header_t *) b->pos; req->header.type = NGX_HTTP_TFS_WRITE_FILEPATH_MESSAGE; req->header.flag = NGX_HTTP_TFS_PACKET_FLAG; req->header.version = NGX_HTTP_TFS_PACKET_VERSION; req->header.id = ngx_http_tfs_generate_packet_id(); req->app_id = r_ctx->app_id; req->user_id = r_ctx->user_id; req->file_len = r_ctx->file_path_s.len + 1; p = ngx_cpymem(req->file_path_s, r_ctx->file_path_s.data, r_ctx->file_path_s.len + 1); *((uint64_t *)p) = t->loc_conf->meta_server_table.version; wfi = (ngx_http_tfs_meta_frag_info_t*)(p + sizeof(uint64_t)); wfi->cluster_id = t->file.cluster_id; wfi->frag_count = need_write_frag_count; segment_data = &t->file.segment_data[t->file.last_write_segment_index]; for (i = 0; i < need_write_frag_count; i++) { #if (NGX_DEBUG) ngx_http_tfs_dump_segment_data(segment_data, t->log); #endif wfi->frag_meta[i].block_id = segment_data->segment_info.block_id; wfi->frag_meta[i].file_id = segment_data->segment_info.file_id; wfi->frag_meta[i].offset = segment_data->segment_info.offset; wfi->frag_meta[i].size = segment_data->segment_info.size; segment_data++; } t->file.last_write_segment_index += need_write_frag_count; b->last += size; req->header.len = size - sizeof(ngx_http_tfs_header_t); req->header.crc = ngx_http_tfs_crc(NGX_HTTP_TFS_PACKET_FLAG, (const char *) (&req->header + 1), size - sizeof(ngx_http_tfs_header_t)); cl = ngx_alloc_chain_link(t->pool); if (cl == NULL) { return NULL; } cl->buf = b; cl->next = NULL; return cl; }
static ngx_int_t ngx_event_pipe_read_upstream(ngx_event_pipe_t *p) { ssize_t n, size; ngx_int_t rc; ngx_buf_t *b; ngx_chain_t *chain, *cl, *ln; if (p->upstream_eof || p->upstream_error || p->upstream_done) { return NGX_OK; } ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe read upstream: %d", p->upstream->read->ready); for ( ;; ) { if (p->upstream_eof || p->upstream_error || p->upstream_done) { break; } if (p->preread_bufs == NULL && !p->upstream->read->ready) { break; } if (p->preread_bufs) { /* use the pre-read bufs if they exist */ chain = p->preread_bufs; p->preread_bufs = NULL; n = p->preread_size; ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe preread: %z", n); if (n) { p->read = 1; } } else { #if (NGX_HAVE_KQUEUE) /* * kqueue notifies about the end of file or a pending error. * This test allows not to allocate a buf on these conditions * and not to call c->recv_chain(). */ if (p->upstream->read->available == 0 && p->upstream->read->pending_eof) { p->upstream->read->ready = 0; p->upstream->read->eof = 0; p->upstream_eof = 1; p->read = 1; if (p->upstream->read->kq_errno) { p->upstream->read->error = 1; p->upstream_error = 1; p->upstream_eof = 0; ngx_log_error(NGX_LOG_ERR, p->log, p->upstream->read->kq_errno, "kevent() reported that upstream " "closed connection"); } break; } #endif if (p->free_raw_bufs) { /* use the free bufs if they exist */ chain = p->free_raw_bufs; if (p->single_buf) { p->free_raw_bufs = p->free_raw_bufs->next; chain->next = NULL; } else { p->free_raw_bufs = NULL; } } else if (p->allocated < p->bufs.num) { /* allocate a new buf if it's still allowed */ b = ngx_create_temp_buf(p->pool, p->bufs.size); if (b == NULL) { return NGX_ABORT; } p->allocated++; chain = ngx_alloc_chain_link(p->pool); if (chain == NULL) { return NGX_ABORT; } chain->buf = b; chain->next = NULL; } else if (!p->cacheable && p->downstream->data == p->output_ctx && p->downstream->write->ready && !p->downstream->write->delayed) { /* * if the bufs are not needed to be saved in a cache and * a downstream is ready then write the bufs to a downstream */ p->upstream_blocked = 1; ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe downstream ready"); break; } else if (p->cacheable || p->temp_file->offset < p->max_temp_file_size) { /* * if it is allowed, then save some bufs from r->in * to a temporary file, and add them to a r->out chain */ rc = ngx_event_pipe_write_chain_to_temp_file(p); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe temp offset: %O", p->temp_file->offset); if (rc == NGX_BUSY) { break; } if (rc == NGX_AGAIN) { if (ngx_event_flags & NGX_USE_LEVEL_EVENT && p->upstream->read->active && p->upstream->read->ready) { if (ngx_del_event(p->upstream->read, NGX_READ_EVENT, 0) == NGX_ERROR) { return NGX_ABORT; } } } if (rc != NGX_OK) { return rc; } chain = p->free_raw_bufs; if (p->single_buf) { p->free_raw_bufs = p->free_raw_bufs->next; chain->next = NULL; } else { p->free_raw_bufs = NULL; } } else { /* there are no bufs to read in */ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0, "no pipe bufs to read in"); break; } n = p->upstream->recv_chain(p->upstream, chain); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe recv chain: %z", n); if (p->free_raw_bufs) { chain->next = p->free_raw_bufs; } p->free_raw_bufs = chain; if (n == NGX_ERROR) { p->upstream_error = 1; return NGX_ERROR; } if (n == NGX_AGAIN) { if (p->single_buf) { ngx_event_pipe_remove_shadow_links(chain->buf); } break; } p->read = 1; if (n == 0) { p->upstream_eof = 1; break; } } p->read_length += n; cl = chain; p->free_raw_bufs = NULL; while (cl && n > 0) { ngx_event_pipe_remove_shadow_links(cl->buf); size = cl->buf->end - cl->buf->last; if (n >= size) { cl->buf->last = cl->buf->end; /* STUB */ cl->buf->num = p->num++; if (p->input_filter(p, cl->buf) == NGX_ERROR) { return NGX_ABORT; } n -= size; ln = cl; cl = cl->next; ngx_free_chain(p->pool, ln); } else { cl->buf->last += n; n = 0; } } if (cl) { for (ln = cl; ln->next; ln = ln->next) { /* void */ } ln->next = p->free_raw_bufs; p->free_raw_bufs = cl; } } #if (NGX_DEBUG) for (cl = p->busy; cl; cl = cl->next) { ngx_log_debug8(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe buf busy s:%d t:%d f:%d " "%p, pos %p, size: %z " "file: %O, size: %z", (cl->buf->shadow ? 1 : 0), cl->buf->temporary, cl->buf->in_file, cl->buf->start, cl->buf->pos, cl->buf->last - cl->buf->pos, cl->buf->file_pos, cl->buf->file_last - cl->buf->file_pos); } for (cl = p->out; cl; cl = cl->next) { ngx_log_debug8(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe buf out s:%d t:%d f:%d " "%p, pos %p, size: %z " "file: %O, size: %z", (cl->buf->shadow ? 1 : 0), cl->buf->temporary, cl->buf->in_file, cl->buf->start, cl->buf->pos, cl->buf->last - cl->buf->pos, cl->buf->file_pos, cl->buf->file_last - cl->buf->file_pos); } for (cl = p->in; cl; cl = cl->next) { ngx_log_debug8(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe buf in s:%d t:%d f:%d " "%p, pos %p, size: %z " "file: %O, size: %z", (cl->buf->shadow ? 1 : 0), cl->buf->temporary, cl->buf->in_file, cl->buf->start, cl->buf->pos, cl->buf->last - cl->buf->pos, cl->buf->file_pos, cl->buf->file_last - cl->buf->file_pos); } for (cl = p->free_raw_bufs; cl; cl = cl->next) { ngx_log_debug8(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe buf free s:%d t:%d f:%d " "%p, pos %p, size: %z " "file: %O, size: %z", (cl->buf->shadow ? 1 : 0), cl->buf->temporary, cl->buf->in_file, cl->buf->start, cl->buf->pos, cl->buf->last - cl->buf->pos, cl->buf->file_pos, cl->buf->file_last - cl->buf->file_pos); } #endif if ((p->upstream_eof || p->upstream_error) && p->free_raw_bufs) { /* STUB */ p->free_raw_bufs->buf->num = p->num++; if (p->input_filter(p, p->free_raw_bufs->buf) == NGX_ERROR) { return NGX_ABORT; } p->free_raw_bufs = p->free_raw_bufs->next; if (p->free_bufs && p->buf_to_file == NULL) { for (cl = p->free_raw_bufs; cl; cl = cl->next) { if (cl->buf->shadow == NULL) { ngx_pfree(p->pool, cl->buf->start); } } } } if (p->cacheable && p->in) { if (ngx_event_pipe_write_chain_to_temp_file(p) == NGX_ABORT) { return NGX_ABORT; } } return NGX_OK; }