static ngx_int_t ngx_http_write_request_body(ngx_http_request_t *r, ngx_chain_t *body) { syslog(LOG_INFO, "[%s:%s:%d]", __FILE__, __func__, __LINE__); ssize_t n; ngx_temp_file_t *tf; ngx_http_request_body_t *rb; ngx_http_core_loc_conf_t *clcf; rb = r->request_body; if (rb->temp_file == NULL) { tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)); if (tf == NULL) { return NGX_ERROR; } clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); 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 (body == NULL) { /* empty body with r->request_body_in_file_only */ if (ngx_create_temp_file(&tf->file, tf->path, tf->pool, tf->persistent, tf->clean, tf->access) != NGX_OK) { return NGX_ERROR; } return NGX_OK; } } n = ngx_write_chain_to_temp_file(rb->temp_file, body); /* TODO: n == 0 or not complete and level event */ if (n == NGX_ERROR) { return NGX_ERROR; } rb->temp_file->offset += n; return NGX_OK; }
ssize_t ngx_write_chain_to_temp_file(ngx_temp_file_t *tf, ngx_chain_t *chain) { ngx_int_t rc; if (tf->file.fd == NGX_INVALID_FILE) { rc = ngx_create_temp_file(&tf->file, tf->path, tf->pool, tf->persistent, tf->clean, tf->access); if (rc != NGX_OK) { return rc; } if (tf->log_level) { ngx_log_error(tf->log_level, tf->file.log, 0, "%s %V", tf->warn, &tf->file.name); } } #if (NGX_THREADS && NGX_HAVE_PWRITEV) if (tf->thread_write) { return ngx_thread_write_chain_to_file(&tf->file, chain, tf->offset, tf->pool); } #endif return ngx_write_chain_to_file(&tf->file, chain, tf->offset, tf->pool); }
ngx_int_t ngx_http_small_light_imlib2_init(ngx_http_request_t *r, ngx_http_small_light_ctx_t *ctx) { ngx_http_small_light_imlib2_ctx_t *ictx; ictx = (ngx_http_small_light_imlib2_ctx_t *)ctx->ictx; ictx->image = ctx->content; ictx->image_len = ctx->content_length; ictx->type = ngx_http_small_light_type_detect(ictx->image, ictx->image_len); ictx->r = r; if (ictx->type == NGX_HTTP_SMALL_LIGHT_IMAGE_NONE) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "failed to get image type %s:%d", __FUNCTION__, __LINE__); return NGX_ERROR; } ictx->tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)); if (ictx->tf == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "failed to allocate memory from r->pool %s:%d", __FUNCTION__, __LINE__); return NGX_ERROR; } ictx->tf->file.fd = NGX_INVALID_FILE; ictx->tf->file.log = r->connection->log; ictx->tf->path = ctx->imlib2_temp_dir; ictx->tf->pool = r->pool; if (ngx_create_temp_file(&ictx->tf->file, ictx->tf->path, ictx->tf->pool, 1, 0, 0600) != NGX_OK) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "failed to create temporary file %s:%d", __FUNCTION__, __LINE__); return NGX_ERROR; } if (ngx_write_file(&ictx->tf->file, ictx->image, ictx->image_len, 0) == NGX_ERROR) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "failed to save temporary file %s:%d", __FUNCTION__, __LINE__); ngx_http_small_light_imlib2_term(ctx); return NGX_ERROR; } return NGX_OK; }
int ngx_write_chain_to_temp_file(ngx_temp_file_t *tf, ngx_chain_t *chain) { int rc; if (tf->file.fd == NGX_INVALID_FILE) { rc = ngx_create_temp_file(&tf->file, tf->path, tf->pool, tf->persistent); if (rc == NGX_ERROR || rc == NGX_AGAIN) { return rc; } if (!tf->persistent && tf->warn) { ngx_log_error(NGX_LOG_WARN, tf->file.log, 0, tf->warn); } } return ngx_write_chain_to_file(&tf->file, chain, tf->offset, tf->pool); }
ssize_t ngx_write_chain_to_temp_file(ngx_temp_file_t *tf, ngx_chain_t *chain) { ngx_int_t rc; if (tf->file.fd == NGX_INVALID_FILE) { rc = ngx_create_temp_file(&tf->file, tf->path, tf->pool, tf->persistent, tf->clean, tf->access); if (rc == NGX_ERROR || rc == NGX_AGAIN) { return rc; } if (tf->log_level) { ngx_log_error(tf->log_level, tf->file.log, 0, "%s %V", tf->warn, &tf->file.name); } } return ngx_write_chain_to_file(&tf->file, chain, tf->offset, tf->pool); }
static ngx_int_t ngx_http_write_request_body(ngx_http_request_t *r) { ssize_t n; ngx_chain_t *cl, *ln; ngx_temp_file_t *tf; ngx_http_request_body_t *rb; ngx_http_core_loc_conf_t *clcf; rb = r->request_body; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http write client request body, bufs %p", rb->bufs); if (rb->temp_file == NULL) { tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)); if (tf == NULL) { return NGX_ERROR; } clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); 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 (rb->bufs == NULL) { /* empty body with r->request_body_in_file_only */ if (ngx_create_temp_file(&tf->file, tf->path, tf->pool, tf->persistent, tf->clean, tf->access) != NGX_OK) { return NGX_ERROR; } return NGX_OK; } } if (rb->bufs == NULL) { return NGX_OK; } n = ngx_write_chain_to_temp_file(rb->temp_file, rb->bufs); /* TODO: n == 0 or not complete and level event */ if (n == NGX_ERROR) { return NGX_ERROR; } rb->temp_file->offset += n; /* mark all buffers as written */ for (cl = rb->bufs; cl; /* void */) { cl->buf->pos = cl->buf->last; ln = cl; cl = cl->next; ngx_free_chain(r->pool, ln); } rb->bufs = NULL; return NGX_OK; }
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_filter_cache_header_filter(ngx_http_request_t *r) { ngx_http_filter_cache_ctx_t *ctx = NULL; ngx_http_filter_cache_conf_t *conf = NULL; time_t now, valid; ngx_temp_file_t *tf; ngx_chain_t out; ssize_t offset; ngx_list_part_t *part; ngx_table_elt_t *h; ngx_uint_t i; u_char *p; size_t len; ngx_pool_cleanup_t *cln = NULL; ngx_http_filter_cache_meta_t meta; if(r != r->main) { /*just skip as we got headers in main*/ return ngx_http_next_header_filter(r); } conf = ngx_http_get_module_loc_conf(r, ngx_http_filter_cache_module); switch (ngx_http_test_predicates(r, conf->upstream.no_cache)) { case NGX_ERROR: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, __FILE__" ngx_http_test_predicates returned an error for no_cache"); return NGX_ERROR; case NGX_DECLINED: goto nocache; default: /* NGX_OK */ break; } ctx = r->filter_cache; if(!ctx || (FILTER_DONOTCACHE == ctx->cacheable)) { goto nocache; } /* ngx_http_filter_cache_create(r); */ if (ctx->cache && ctx->cache->file.fd != NGX_INVALID_FILE) { ngx_pool_run_cleanup_file(r->pool, ctx->cache->file.fd); ctx->cache->file.fd = NGX_INVALID_FILE; } ctx->cache->valid_sec = 0; now = ngx_time(); valid = 0; valid = ngx_http_filter_cache_valid(conf->upstream.cache_valid, r->headers_out.status); if (valid) { ctx->cache->valid_sec = now + valid; } else { goto nocache; } tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)); if (tf == NULL) { return NGX_ERROR; } tf->file.fd = NGX_INVALID_FILE; tf->file.log = r->connection->log; tf->path = conf->upstream.temp_path; tf->pool = r->pool; tf->persistent = 1; if (ngx_create_temp_file(&tf->file, tf->path, tf->pool, tf->persistent, tf->clean, tf->access) != NGX_OK) { return NGX_ERROR; } ctx->tf = tf; cln = ngx_pool_cleanup_add(r->pool, 0); if (cln == NULL) { return NGX_ERROR; } cln->handler = filter_cache_cleanup; cln->data = ctx; ctx->buffer.pos = ctx->buffer.start = ngx_palloc(r->pool, conf->upstream.buffer_size); ctx->buffer.end = ctx->buffer.start + conf->upstream.buffer_size; ctx->buffer.temporary = 1; ctx->buffer.memory = 1; ctx->buffer.last_buf = 1; ctx->buffer.pos += ctx->cache->header_start; ctx->cache->last_modified = r->headers_out.last_modified_time; ctx->cache->date = now; /* Headers */ /* fill in the metadata*/ meta.status = r->headers_out.status; #if (NGX_HTTP_GZIP) meta.gzip_vary = r->gzip_vary; /* Note: there is still some wierdness to how gzip_vary works...*/ #endif meta.last_modified_time = r->headers_out.last_modified_time; ngx_memcpy((void *)(ctx->buffer.pos), (void *)(&meta), sizeof(ngx_http_filter_cache_meta_t) ); ctx->buffer.pos += sizeof(ngx_http_filter_cache_meta_t); /* Headers taht aren't in teh table for some reason */ /*Do we need to try to set it if it's not set???*/ /* Content Type */ if ( r->headers_out.content_type.data ) { p = memchr((void *)r->headers_out.content_type.data, ';', r->headers_out.content_type.len ); if ( p ) { len = p - r->headers_out.content_type.data; ngx_cpystrn( ctx->buffer.pos, r->headers_out.content_type.data, len + 1); ctx->buffer.pos += len + 1; } else { ngx_cpystrn( ctx->buffer.pos, r->headers_out.content_type.data, r->headers_out.content_type.len + 1 ); ctx->buffer.pos += r->headers_out.content_type.len + 1; } } else { *ctx->buffer.pos = (u_char)'\0'; ctx->buffer.pos++; } /* Charset */ if ( r->headers_out.charset.data ) { ngx_cpystrn( ctx->buffer.pos, r->headers_out.charset.data, r->headers_out.charset.len + 1 ); ctx->buffer.pos += r->headers_out.charset.len + 1; } else { *ctx->buffer.pos = (u_char)'\0'; ctx->buffer.pos++; } /* Content Encoding */ if ( r->headers_out.content_encoding && r->headers_out.content_encoding->value.len) { ngx_cpystrn( ctx->buffer.pos, r->headers_out.content_encoding->value.data, r->headers_out.content_encoding->value.len + 1 ); ctx->buffer.pos += r->headers_out.content_encoding->value.len + 1; } else { *ctx->buffer.pos = (u_char)'\0'; ctx->buffer.pos++; } /* Last-Modified */ if(r->headers_out.last_modified_time && r->headers_out.last_modified && r->headers_out.last_modified->value.len) { ngx_cpystrn( ctx->buffer.pos, r->headers_out.last_modified->value.data, r->headers_out.last_modified->value.len + 1 ); ctx->buffer.pos += r->headers_out.last_modified->value.len + 1; } else { *ctx->buffer.pos = (u_char)'\0'; ctx->buffer.pos++; } /* XXX: is last-modified special???*/ /* Everything From the Table */ part = &r->headers_out.headers.part; h = part->elts; for (i=0; /* void */; i++) { if ( i >= part->nelts || !part->nelts ) { if ( part->next == NULL ) { ctx->cacheable = FILTER_CACHEABLE; break; } part = part->next; h = part->elts; i = 0; } /*need to be really sure this header is "valid"*/ /* if(h[i].key.len && h[i].value.len && h[i].hash && h[i].lowcase_key) {*/ /* if(!h[i].lowcase_key) { */ /* if((h[i].lowcase_key = ngx_pnalloc(r->pool, h->key.len +1)) == NULL) { */ /* continue; */ /* } */ /* ngx_strlow(h[i].lowcase_key, h[i].key.data, h[i].key.len); */ /* } */ /* if(!h[i].hash) { */ /* h[i].hash = ngx_hash_key_lc(h[i].key.data, h[i].key.len); */ /* } */ /* if (ngx_hash_find(&conf->upstream.hide_headers_hash, h[i].hash, */ /* h[i].lowcase_key, h[i].key.len)) */ /* { */ /* continue; */ /* } */ if(h[i].key.len && h[i].value.len) { if(find_string_in_array(&(h[i].key), conf->upstream.hide_headers)){ continue; } if ( (ngx_uint_t)(h[i].key.len + h[i].value.len + 4) > (ngx_uint_t)(ctx->buffer.last - ctx->buffer.pos) ) { ctx->cacheable = FILTER_DONOTCACHE; break; } ngx_cpystrn( ctx->buffer.pos, h[i].key.data, h[i].key.len + 1 ); ctx->buffer.pos += h[i].key.len + 1; ngx_cpystrn( ctx->buffer.pos, h[i].value.data, h[i].value.len + 1 ); ctx->buffer.pos += h[i].value.len + 1; } } if(FILTER_CACHEABLE != ctx->cacheable) { goto nocache; } ctx->buffer.last = ctx->buffer.pos; ctx->cache->body_start = (u_short) (ctx->buffer.pos - ctx->buffer.start); ngx_http_filter_cache_set_header(r, ctx->buffer.start); ctx->cache->date = now; /*write to temp file*/ ctx->buffer.pos = ctx->buffer.start; out.buf = &ctx->buffer; out.next = NULL; offset = ngx_write_chain_to_temp_file(tf, &out); tf->offset += offset; r->main_filter_need_in_memory = 1; return ngx_http_next_header_filter(r); nocache: if(ctx) { ctx->cacheable = FILTER_DONOTCACHE; /* if(ctx->cache) { */ /* ngx_http_filter_cache_free(ctx->cache, ctx->tf); */ /* } */ } return ngx_http_next_header_filter(r); }
static ngx_buf_t * ngx_http_pngquant_quantize(ngx_http_request_t *r, ngx_http_pngquant_ctx_t *ctx) { u_char *out; ngx_buf_t *b; ngx_pool_cleanup_t *cln; ngx_http_pngquant_conf_t *conf; gdImagePtr img; int size; ngx_int_t rc; ngx_temp_file_t *tf; ssize_t n; ngx_ext_rename_file_t ext; ngx_str_t dest; ngx_str_t value; img = gdImageCreateFromPngPtr(ctx->length, ctx->image); if (img == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "gdImageCreateFromPngPtr() failed"); return NULL; } conf = ngx_http_get_module_loc_conf(r, ngx_http_pngquant_module); /* * gdImageTrueColorToPaletteSetMethod(img, GD_QUANT_LIQ, conf->speed); * gdImageTrueColorToPalette(img, conf->dither, conf->colors); */ ngx_pngquant_gd_image(img, conf->dither, conf->colors, conf->speed); out = gdImagePngPtr(img, &size); gdImageDestroy(img); ngx_pfree(r->pool, ctx->image); if (out == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "gdImagePngPtr() failed"); return NULL; } if (conf->store) { if(ngx_http_complex_value(r, conf->store, &value) != NGX_OK) { goto failed; } dest.len = value.len + 1; dest.data = ngx_pnalloc(r->pool, dest.len); if (dest.data == NULL) { goto failed; } ngx_memzero(dest.data, dest.len); ngx_memcpy(dest.data, value.data, value.len); ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "pngquant_store (%s)", dest.data); tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)); if (tf == NULL) { goto failed; } tf->file.fd = NGX_INVALID_FILE; tf->file.log = r->connection->log; tf->path = conf->temp_path; tf->pool = r->pool; tf->persistent = 1; rc = ngx_create_temp_file(&tf->file, tf->path, tf->pool, tf->persistent, tf->clean, tf->access); if (rc != NGX_OK) { goto failed; } n = ngx_write_fd(tf->file.fd, out, size); if (n == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, ngx_write_fd_n " \"%s\" failed", tf->file.name.data); goto failed; } if ((int) n != size) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, ngx_write_fd_n " has written only %z of %uz bytes", n, size); goto failed; } ext.access = conf->store_access; ext.path_access = conf->store_access; ext.time = -1; ext.create_path = 1; ext.delete_file = 1; ext.log = r->connection->log; rc = ngx_ext_rename_file(&tf->file.name, &dest, &ext); if (rc != NGX_OK) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_ext_rename_file() failed"); goto failed; } } cln = ngx_pool_cleanup_add(r->pool, 0); if (cln == NULL) { goto failed; } b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); if (b == NULL) { goto failed; } cln->handler = ngx_http_pngquant_cleanup; cln->data = out; b->pos = out; b->last = out + size; b->memory = 1; b->last_buf = 1; ngx_http_pngquant_length(r, b); #if defined(nginx_version) && (nginx_version >= 1007003) ngx_http_weak_etag(r); #endif return b; failed: gdFree(out); return NULL; }
static void ngx_http_graphicsmagick_command_handler(ngx_http_request_t *r) { ngx_str_t *source; ngx_str_t *dest; ngx_str_t *ai; ngx_str_t *cmd; ngx_str_t *uri; ngx_array_t *tokens; ngx_int_t rc; ngx_uint_t i; ngx_log_t *log; ngx_buf_t *b; ngx_chain_t out; ngx_fd_t fd; ngx_open_file_info_t of; ngx_http_core_loc_conf_t *clcf; size_t argc; char **argv; u_char *cp; u_char *last; size_t root; ngx_temp_file_t *tf; unsigned int status; log = r->connection->log; tokens = ngx_array_create(r->pool, 10, sizeof(ngx_str_t)); if (tokens == NULL) { ngx_http_graphicsmagick_server_error(r); return; } ai = ngx_array_push(tokens); if (ai == NULL) { ngx_http_graphicsmagick_server_error(r); return; } ai->data = (u_char *) "convert"; ai->len = 7; // get command from HTTP headers or queryString cmd = ngx_http_graphicsmagick_get_command(r); if (cmd == NULL) { ngx_http_graphicsmagick_server_error(r); return; } ngx_log_error(NGX_LOG_ERR, log, 0, "graphicsmagick convert command: \"%s\"", cmd->data); //ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, // "graphicsmagick convert command: \"%s\"", cmd->data); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (r->method & NGX_HTTP_POST) { source = dest = &r->request_body->temp_file->file.name; } else { uri = ngx_pcalloc(r->pool, sizeof(ngx_str_t)); source = ngx_pcalloc(r->pool, sizeof(ngx_str_t)); cp = cmd->data; while (cp < cmd->data + cmd->len) { if (*cp == ' ') { uri->data = cmd->data; uri->len = cp - cmd->data; cmd->data = cp + 1; cmd->len = cmd->len - uri->len - 1; break; } cp++; } if (uri->len == 0) { ngx_http_graphicsmagick_server_error(r); return; } last = ngx_http_graphicsmagickd_map_uri_to_path(r, uri, source, &root, 0); if (last == NULL) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } source->len = last - source->data; tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)); if (tf == NULL) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } tf->file.fd = NGX_INVALID_FILE; tf->file.log = r->connection->log; tf->path = clcf->client_body_temp_path; tf->pool = r->pool; tf->log_level = r->request_body_file_log_level; tf->persistent = r->request_body_in_persistent_file; tf->clean = 1; if (r->request_body_file_group_access) { tf->access = 0660; } if (ngx_create_temp_file(&tf->file, tf->path, tf->pool, tf->persistent, tf->clean, tf->access) != NGX_OK) { ngx_http_graphicsmagick_server_error(r); return; } dest = &tf->file.name; } // push source file name into tokens ai = ngx_array_push(tokens); if (ai == NULL) { ngx_http_graphicsmagick_server_error(r); return; } *ai = *source; // tokenize command, and push them into tokens array rc = ngx_http_graphicsmagick_tokenize_command(r, cmd, tokens); if (rc == NGX_ERROR) { ngx_http_graphicsmagick_server_error(r); return; } ai = ngx_array_push_n(tokens, 2); if (ai == NULL) { ngx_http_graphicsmagick_server_error(r); return; } ai->data = (u_char *) "-compress"; ai->len = 9; ai++; ai->data = (u_char *) "JPEG"; ai->len = 4; // push dest filename into tokens again, to save generated thumbnail into dest file ai = ngx_array_push(tokens); if (ai == NULL) { ngx_http_graphicsmagick_server_error(r); return; } *ai = *dest; // OK, prepare convert args argc = tokens->nelts; argv = ngx_palloc(r->pool, argc * sizeof(char*)); if (argv == NULL) { ngx_http_graphicsmagick_server_error(r); return; } ai = tokens->elts; for (i = 0; i < argc; i++) { argv[i] = (char *) ai[i].data; ngx_log_error(NGX_LOG_ERR, log, 0, "current[%d]: %s", i, argv[i]); } ngx_array_destroy(tokens); // DO graphicsmagick converting status = ngx_http_graphicsmagick_convert(argv, argc); if (status == 0) { ngx_http_graphicsmagick_server_error(r); return; } // Done, write response of.test_dir = 0; //of.retest = clcf->open_file_cache_retest; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; rc = ngx_open_cached_file(clcf->open_file_cache, dest, &of, r->pool); if (rc == NGX_ERROR) { ngx_log_error(NGX_LOG_ERR, log, of.err, "failed to open file \"%s\"", dest->data); ngx_http_graphicsmagick_server_error(r); return; } fd = of.fd; log->action = "sending response to client"; r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_type.len = sizeof("image/jpeg") - 1; r->headers_out.content_type.data = (u_char *) "image/jpeg"; r->headers_out.content_length_n = of.size; r->headers_out.last_modified_time = of.mtime; if (r != r->main && of.size == 0) { rc = ngx_http_send_header(r); ngx_http_finalize_request(r, rc); return; } b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); if (b == NULL) { ngx_http_graphicsmagick_server_error(r); return; } b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)); if (b->file == NULL) { ngx_http_graphicsmagick_server_error(r); return; } rc = ngx_http_send_header(r); b->file_pos = 0; b->file_last = of.size; b->in_file = b->file_last ? 1: 0; b->last_buf = (r == r->main) ? 1: 0; b->last_in_chain = 1; b->file->fd = fd; b->file->name = *dest; b->file->log = log; out.buf = b; out.next = NULL; rc = ngx_http_output_filter(r, &out); ngx_http_finalize_request(r, rc); return; }
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; ngx_chain_t *cl, **next; ngx_temp_file_t *tf; ngx_http_request_body_t *rb; ngx_http_core_loc_conf_t *clcf; //主请求引用+1 r->main->count++; //请求体已经被读取或丢弃 if (r->request_body || r->discard_body) { post_handler(r); return NGX_OK; } //检查是否有Expect: 100-continue头,该请求头表示客户端期望发送请求体,服务器回复“HTTP/1.1 100 Continue”允许客户端发送请求体 if (ngx_http_test_expect(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } //分配ngx_http_request_body_t结构 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) { post_handler(r); return NGX_OK; } clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); //请求体长度为0 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) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } } 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; //header_in中有未处理数据,表明预读了请求体 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; 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) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } } 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); }