mirror of
https://github.com/nginx/nginx.git
synced 2025-06-07 17:52:38 +08:00
nginx-0.0.1-2003-10-27-11:53:49 import
This commit is contained in:
parent
6414b96ebc
commit
10fc9ef775
@ -7,6 +7,27 @@ static int ngx_temp_number;
|
||||
static int ngx_random;
|
||||
|
||||
|
||||
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->file.offset, tf->pool);
|
||||
}
|
||||
|
||||
|
||||
int ngx_create_temp_file(ngx_file_t *file, ngx_path_t *path,
|
||||
ngx_pool_t *pool, int persistent)
|
||||
{
|
||||
|
@ -26,6 +26,17 @@ typedef struct {
|
||||
} ngx_path_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_file_t file;
|
||||
ngx_path_t path;
|
||||
ngx_pool_t *pool;
|
||||
char *warn;
|
||||
|
||||
unsigned persistent:1;
|
||||
} ngx_temp_file_t;
|
||||
|
||||
|
||||
int ngx_write_chain_to_temp_file(ngx_temp_file_t *tf, ngx_chain_t *chain);
|
||||
int ngx_create_temp_file(ngx_file_t *file, ngx_path_t *path,
|
||||
ngx_pool_t *pool, int persistent);
|
||||
void ngx_create_hashed_filename(ngx_file_t *file, ngx_path_t *path);
|
||||
@ -46,7 +57,7 @@ char *ngx_conf_set_path_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
|
||||
conf->level[0] = l1; \
|
||||
conf->level[1] = l2; \
|
||||
conf->level[2] = l3; \
|
||||
conf->len = l1 + l2 + l3 + l1 ? 1:0 + l2 ? 1:0 + l3 ? 1:0; \
|
||||
conf->len = l1 + l2 + l3 + (l1 ? 1:0) + (l2 ? 1:0) + (l3 ? 1:0); \
|
||||
} else { \
|
||||
conf = prev; \
|
||||
} \
|
||||
|
@ -26,6 +26,48 @@ ngx_hunk_t *ngx_create_temp_hunk(ngx_pool_t *pool, int size,
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
ngx_chain_t *ngx_create_chain_of_hunks(ngx_pool_t *pool, ngx_bufs_t *bufs)
|
||||
{
|
||||
int i;
|
||||
char *p;
|
||||
ngx_hunk_t *h;
|
||||
ngx_chain_t *chain, *cl, **ll;
|
||||
|
||||
ngx_test_null(p, ngx_palloc(pool, bufs->num * bufs->size), NULL);
|
||||
|
||||
ll = &chain;
|
||||
|
||||
for (i = 0; i < bufs->num; i++) {
|
||||
ngx_test_null(h, ngx_alloc_hunk(pool), NULL);
|
||||
|
||||
h->pos = p;
|
||||
h->last = p;
|
||||
h->file_pos = 0;
|
||||
h->file_last = 0;
|
||||
|
||||
h->type = NGX_HUNK_IN_MEMORY|NGX_HUNK_TEMP;
|
||||
|
||||
h->start = p;
|
||||
p += bufs->size;
|
||||
h->end = p;
|
||||
|
||||
h->file = NULL;
|
||||
h->shadow = NULL;
|
||||
h->tag = 0;
|
||||
|
||||
ngx_test_null(cl, ngx_alloc_chain_link(pool), NULL);
|
||||
cl->hunk = h;
|
||||
*ll = cl;
|
||||
ll = &cl->next;
|
||||
}
|
||||
|
||||
*ll = NULL;
|
||||
|
||||
return chain;
|
||||
}
|
||||
|
||||
|
||||
ngx_hunk_t *ngx_create_hunk_before(ngx_pool_t *pool, ngx_hunk_t *hunk, int size)
|
||||
{
|
||||
ngx_hunk_t *h;
|
||||
@ -61,6 +103,7 @@ ngx_hunk_t *ngx_create_hunk_before(ngx_pool_t *pool, ngx_hunk_t *hunk, int size)
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
ngx_hunk_t *ngx_create_hunk_after(ngx_pool_t *pool, ngx_hunk_t *hunk, int size)
|
||||
{
|
||||
ngx_hunk_t *h;
|
||||
|
@ -73,6 +73,29 @@ typedef struct {
|
||||
} ngx_bufs_t;
|
||||
|
||||
|
||||
typedef int (*ngx_output_chain_filter_pt)(void *ctx, ngx_chain_t *out);
|
||||
|
||||
typedef struct {
|
||||
ngx_hunk_t *hunk;
|
||||
ngx_chain_t *in;
|
||||
ngx_chain_t *free;
|
||||
ngx_chain_t *busy;
|
||||
|
||||
unsigned sendfile;
|
||||
unsigned need_in_memory;
|
||||
unsigned need_in_temp;
|
||||
unsigned copy_chain;
|
||||
|
||||
ngx_pool_t *pool;
|
||||
int hunks;
|
||||
ngx_bufs_t bufs;
|
||||
ngx_hunk_tag_t tag;
|
||||
|
||||
ngx_output_chain_filter_pt output_filter;
|
||||
void *output_ctx;
|
||||
} ngx_output_chain_ctx_t;
|
||||
|
||||
|
||||
#define NGX_CHAIN_ERROR (ngx_chain_t *) NGX_ERROR
|
||||
|
||||
|
||||
@ -120,6 +143,7 @@ ngx_hunk_t *ngx_create_temp_hunk(ngx_pool_t *pool, int size,
|
||||
last = &cl->next
|
||||
|
||||
|
||||
int ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in);
|
||||
int ngx_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain, ngx_chain_t *in);
|
||||
void ngx_chain_update_chains(ngx_chain_t **free, ngx_chain_t **busy,
|
||||
ngx_chain_t **out, ngx_hunk_tag_t tag);
|
||||
|
@ -63,11 +63,14 @@ typedef enum {
|
||||
*/
|
||||
|
||||
|
||||
typedef size_t (*ngx_log_handler_pt) (void *ctx, char *buf, size_t len);
|
||||
|
||||
|
||||
typedef struct {
|
||||
int log_level;
|
||||
ngx_open_file_t *file;
|
||||
void *data;
|
||||
size_t (*handler)(void *ctx, char *buf, size_t len);
|
||||
int log_level;
|
||||
ngx_open_file_t *file;
|
||||
void *data;
|
||||
ngx_log_handler_pt handler;
|
||||
|
||||
#if 0
|
||||
/* STUB */
|
||||
|
252
src/core/ngx_output_chain.c
Normal file
252
src/core/ngx_output_chain.c
Normal file
@ -0,0 +1,252 @@
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
#define NGX_NONE 1
|
||||
|
||||
|
||||
ngx_inline static int ngx_output_chain_need_to_copy(ngx_output_chain_ctx_t *ctx,
|
||||
ngx_hunk_t *hunk);
|
||||
static int ngx_output_chain_copy_hunk(ngx_hunk_t *dst, ngx_hunk_t *src,
|
||||
int sendfile);
|
||||
|
||||
|
||||
int ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in)
|
||||
{
|
||||
int rc, last;
|
||||
ssize_t size, hsize;
|
||||
ngx_chain_t *cl, *out, **last_out;
|
||||
|
||||
/*
|
||||
* the short path for the case when the chain ctx->in is empty
|
||||
* and the incoming chain is empty too or it has the single hunk
|
||||
* that does not require the copy
|
||||
*/
|
||||
|
||||
if (ctx->in == NULL) {
|
||||
|
||||
if (in == NULL) {
|
||||
return ctx->output_filter(ctx->output_ctx, in);
|
||||
}
|
||||
|
||||
if (!ctx->copy_chain
|
||||
&& in->next == NULL
|
||||
&& (!ngx_output_chain_need_to_copy(ctx, in->hunk)))
|
||||
{
|
||||
return ctx->output_filter(ctx->output_ctx, in);
|
||||
}
|
||||
}
|
||||
|
||||
/* add the incoming hunk to the chain ctx->in */
|
||||
|
||||
if (in) {
|
||||
if (ngx_chain_add_copy(ctx->pool, &ctx->in, in) == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
last = NGX_NONE;
|
||||
last_out = &out;
|
||||
|
||||
for ( ;; ) {
|
||||
|
||||
while (ctx->in) {
|
||||
|
||||
if (!ngx_output_chain_need_to_copy(ctx, ctx->in->hunk)) {
|
||||
|
||||
/* move the chain link to the chain out */
|
||||
|
||||
cl = ctx->in;
|
||||
ctx->in = cl->next;
|
||||
|
||||
*last_out = cl;
|
||||
last_out = &cl->next;
|
||||
cl->next = NULL;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ctx->hunk == NULL) {
|
||||
|
||||
/* get the free hunk */
|
||||
|
||||
if (ctx->free) {
|
||||
ctx->hunk = ctx->free->hunk;
|
||||
ctx->free = ctx->free->next;
|
||||
|
||||
} else if (ctx->hunks < ctx->bufs.num) {
|
||||
|
||||
size = ctx->bufs.size;
|
||||
|
||||
if (ctx->in->hunk->type & NGX_HUNK_LAST) {
|
||||
|
||||
hsize = ngx_hunk_size(ctx->in->hunk);
|
||||
|
||||
if (hsize < ctx->bufs.size) {
|
||||
|
||||
/*
|
||||
* allocate small temp hunk for the small last hunk
|
||||
* or its small last part
|
||||
*/
|
||||
|
||||
size = hsize;
|
||||
|
||||
} else if (ctx->bufs.num == 1
|
||||
&& (hsize < ctx->bufs.size
|
||||
+ (ctx->bufs.size >> 2)))
|
||||
{
|
||||
/*
|
||||
* allocate a temp hunk that equals
|
||||
* to the last hunk if the last hunk size is lesser
|
||||
* than 1.25 of bufs.size and a temp hunk is single
|
||||
*/
|
||||
|
||||
size = hsize;
|
||||
}
|
||||
}
|
||||
|
||||
ngx_test_null(ctx->hunk,
|
||||
ngx_create_temp_hunk(ctx->pool, size, 0, 0),
|
||||
NGX_ERROR);
|
||||
ctx->hunk->tag = ctx->tag;
|
||||
ctx->hunk->type |= NGX_HUNK_RECYCLED;
|
||||
ctx->hunks++;
|
||||
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rc = ngx_output_chain_copy_hunk(ctx->hunk, ctx->in->hunk,
|
||||
ctx->sendfile);
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (rc == NGX_AGAIN) {
|
||||
if (out) {
|
||||
break;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* delete the completed hunk from the chain ctx->in */
|
||||
|
||||
if (ngx_hunk_size(ctx->in->hunk) == 0) {
|
||||
ctx->in = ctx->in->next;
|
||||
}
|
||||
|
||||
ngx_alloc_link_and_set_hunk(cl, ctx->hunk, ctx->pool, NGX_ERROR);
|
||||
*last_out = cl;
|
||||
last_out = &cl->next;
|
||||
ctx->hunk = NULL;
|
||||
|
||||
if (ctx->free == NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (out == NULL && last != NGX_NONE) {
|
||||
return last;
|
||||
}
|
||||
|
||||
last = ctx->output_filter(ctx->output_ctx, out);
|
||||
|
||||
ngx_chain_update_chains(&ctx->free, &ctx->busy, &out, ctx->tag);
|
||||
last_out = &out;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ngx_inline static int ngx_output_chain_need_to_copy(ngx_output_chain_ctx_t *ctx,
|
||||
ngx_hunk_t *hunk)
|
||||
{
|
||||
if (ngx_hunk_special(hunk)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!ctx->sendfile) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ctx->need_in_memory && (!(hunk->type & NGX_HUNK_IN_MEMORY))) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
if (ctx->need_in_temp && (hunk->type & (NGX_HUNK_MEMORY|NGX_HUNK_MMAP))) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ngx_output_chain_copy_hunk(ngx_hunk_t *dst, ngx_hunk_t *src,
|
||||
int sendfile)
|
||||
{
|
||||
ssize_t n, size;
|
||||
|
||||
size = ngx_hunk_size(src);
|
||||
|
||||
if (size > (dst->end - dst->pos)) {
|
||||
size = dst->end - dst->pos;
|
||||
}
|
||||
|
||||
if (src->type & NGX_HUNK_IN_MEMORY) {
|
||||
ngx_memcpy(dst->pos, src->pos, size);
|
||||
src->pos += size;
|
||||
dst->last += size;
|
||||
|
||||
if (src->type & NGX_HUNK_FILE) {
|
||||
src->file_pos += size;
|
||||
}
|
||||
|
||||
if ((src->type & NGX_HUNK_LAST) && src->pos == src->last) {
|
||||
dst->type |= NGX_HUNK_LAST;
|
||||
}
|
||||
|
||||
} else {
|
||||
n = ngx_read_file(src->file, dst->pos, size, src->file_pos);
|
||||
|
||||
if (n == 0) {
|
||||
ngx_log_debug(src->file->log, "READ: %qd:%qd %X:%X %X:%X" _
|
||||
src->file_pos _ src->file_last _
|
||||
dst->pos _ dst->last _ dst->start _ dst->end);
|
||||
}
|
||||
|
||||
if (n == NGX_ERROR) {
|
||||
return n;
|
||||
}
|
||||
|
||||
#if (NGX_FILE_AIO_READ)
|
||||
if (n == NGX_AGAIN) {
|
||||
return n;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (n != size) {
|
||||
ngx_log_error(NGX_LOG_ALERT, src->file->log, 0,
|
||||
ngx_read_file_n " reads only %d of %d from file",
|
||||
n, size);
|
||||
if (n == 0) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
src->file_pos += n;
|
||||
dst->last += n;
|
||||
|
||||
if (!sendfile) {
|
||||
dst->type &= ~NGX_HUNK_FILE;
|
||||
}
|
||||
|
||||
if ((src->type & NGX_HUNK_LAST) && src->file_pos == src->file_last) {
|
||||
dst->type |= NGX_HUNK_LAST;
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
@ -168,7 +168,6 @@ static int ngx_http_gzip_header_filter(ngx_http_request_t *r)
|
||||
if (!conf->enable
|
||||
|| r->headers_out.status != NGX_HTTP_OK
|
||||
|| r->header_only
|
||||
|| r->main
|
||||
/* TODO: conf->http_version */
|
||||
|| (r->headers_out.content_encoding
|
||||
&& r->headers_out.content_encoding->value.len)
|
||||
|
@ -4,6 +4,41 @@
|
||||
#include <ngx_http.h>
|
||||
|
||||
|
||||
/*
|
||||
* the single part format:
|
||||
*
|
||||
* "HTTP/1.0 206 Partial Content" CRLF
|
||||
* ... header ...
|
||||
* "Content-Type: image/jpeg" CRLF
|
||||
* "Content-Length: SIZE" CRLF
|
||||
* "Content-Range: bytes START-END/SIZE" CRLF
|
||||
* CRLF
|
||||
* ... data ...
|
||||
*
|
||||
*
|
||||
* the mutlipart format:
|
||||
*
|
||||
* "HTTP/1.0 206 Partial Content" CRLF
|
||||
* ... header ...
|
||||
* "Content-Type: multipart/byteranges; boundary=0123456789" CRLF
|
||||
* CRLF
|
||||
* CRLF
|
||||
* "--0123456789" CRLF
|
||||
* "Content-Type: image/jpeg" CRLF
|
||||
* "Content-Range: bytes START0-END0/SIZE" CRLF
|
||||
* CRLF
|
||||
* ... data ...
|
||||
* CRLF
|
||||
* "--0123456789" CRLF
|
||||
* "Content-Type: image/jpeg" CRLF
|
||||
* "Content-Range: bytes START1-END1/SIZE" CRLF
|
||||
* CRLF
|
||||
* ... data ...
|
||||
* CRLF
|
||||
* "--0123456789--" CRLF
|
||||
*/
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_str_t boundary_header;
|
||||
} ngx_http_range_filter_ctx_t;
|
||||
@ -46,11 +81,12 @@ static int ngx_http_range_header_filter(ngx_http_request_t *r)
|
||||
ngx_http_range_t *range;
|
||||
ngx_http_range_filter_ctx_t *ctx;
|
||||
|
||||
if (r->main
|
||||
|| r->http_version < NGX_HTTP_VERSION_10
|
||||
if (r->http_version < NGX_HTTP_VERSION_10
|
||||
|| r->headers_out.status != NGX_HTTP_OK
|
||||
|| r->headers_out.content_length_n == -1
|
||||
|
||||
/* STUB: we currently support ranges for file hunks only */
|
||||
|| !r->sendfile
|
||||
|| r->filter & NGX_HTTP_FILTER_NEED_IN_MEMORY)
|
||||
{
|
||||
return ngx_http_next_header_filter(r);
|
||||
@ -75,11 +111,8 @@ static int ngx_http_range_header_filter(ngx_http_request_t *r)
|
||||
ngx_init_array(r->headers_out.ranges, r->pool, 5, sizeof(ngx_http_range_t),
|
||||
NGX_ERROR);
|
||||
|
||||
#if (NGX_SUPPRESS_WARN)
|
||||
range = NULL;
|
||||
#endif
|
||||
|
||||
rc = 0;
|
||||
range = NULL;
|
||||
p = r->headers_in.range->value.data + 6;
|
||||
|
||||
for ( ;; ) {
|
||||
@ -156,6 +189,9 @@ static int ngx_http_range_header_filter(ngx_http_request_t *r)
|
||||
}
|
||||
|
||||
if (rc) {
|
||||
|
||||
/* rc == NGX_HTTP_RANGE_NOT_SATISFIABLE */
|
||||
|
||||
r->headers_out.status = rc;
|
||||
r->headers_out.ranges.nelts = 0;
|
||||
|
||||
@ -189,6 +225,8 @@ static int ngx_http_range_header_filter(ngx_http_request_t *r)
|
||||
ngx_palloc(r->pool, 6 + 20 + 1 + 20 + 1 + 20 + 1),
|
||||
NGX_ERROR);
|
||||
|
||||
/* "Content-Range: bytes SSSS-EEEE/TTTT" header */
|
||||
|
||||
r->headers_out.content_range->value.len =
|
||||
ngx_snprintf(r->headers_out.content_range->value.data,
|
||||
6 + 20 + 1 + 20 + 1 + 20 + 1,
|
||||
@ -222,6 +260,14 @@ static int ngx_http_range_header_filter(ngx_http_request_t *r)
|
||||
|
||||
boundary = ngx_next_temp_number(0);
|
||||
|
||||
/*
|
||||
* The boundary header of the range:
|
||||
* CRLF
|
||||
* "--0123456789" CRLF
|
||||
* "Content-Type: image/jpeg" CRLF
|
||||
* "Content-Range: bytes "
|
||||
*/
|
||||
|
||||
if (r->headers_out.charset.len) {
|
||||
ctx->boundary_header.len =
|
||||
ngx_snprintf(ctx->boundary_header.data, len,
|
||||
@ -248,30 +294,34 @@ static int ngx_http_range_header_filter(ngx_http_request_t *r)
|
||||
ngx_palloc(r->pool, 31 + 10 + 1),
|
||||
NGX_ERROR);
|
||||
|
||||
/* "Content-Type: multipart/byteranges; boundary=0123456789" */
|
||||
|
||||
r->headers_out.content_type->value.len =
|
||||
ngx_snprintf(r->headers_out.content_type->value.data,
|
||||
31 + 10 + 1,
|
||||
"multipart/byteranges; boundary=%010u",
|
||||
boundary);
|
||||
|
||||
/* the last "CRLF--BOUNDARY--CRLF" */
|
||||
/* the size of the last boundary CRLF "--0123456789--" CRLF */
|
||||
len = 4 + 10 + 4;
|
||||
|
||||
range = r->headers_out.ranges.elts;
|
||||
for (i = 0; i < r->headers_out.ranges.nelts; i++) {
|
||||
ngx_test_null(range[i].content_range.data,
|
||||
ngx_palloc(r->pool, 20 + 1 + 20 + 1 + 20 + 5),
|
||||
NGX_ERROR);
|
||||
ngx_test_null(range[i].content_range.data,
|
||||
ngx_palloc(r->pool, 20 + 1 + 20 + 1 + 20 + 5),
|
||||
NGX_ERROR);
|
||||
|
||||
range[i].content_range.len =
|
||||
/* the size of the range: "SSSS-EEEE/TTTT" CRLF CRLF */
|
||||
|
||||
range[i].content_range.len =
|
||||
ngx_snprintf(range[i].content_range.data,
|
||||
20 + 1 + 20 + 1 + 20 + 5,
|
||||
OFF_FMT "-" OFF_FMT "/" OFF_FMT CRLF CRLF,
|
||||
range[i].start, range[i].end - 1,
|
||||
r->headers_out.content_length_n);
|
||||
|
||||
len += ctx->boundary_header.len + range[i].content_range.len
|
||||
+ (size_t) (range[i].end - range[i].start);
|
||||
len += ctx->boundary_header.len + range[i].content_range.len
|
||||
+ (size_t) (range[i].end - range[i].start);
|
||||
}
|
||||
|
||||
r->headers_out.content_length_n = len;
|
||||
@ -304,8 +354,9 @@ static int ngx_http_range_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
|
||||
&& in->hunk->type & NGX_HUNK_FILE
|
||||
&& in->hunk->type & NGX_HUNK_LAST)
|
||||
{
|
||||
range = r->headers_out.ranges.elts;
|
||||
|
||||
if (r->headers_out.ranges.nelts == 1) {
|
||||
range = r->headers_out.ranges.elts;
|
||||
in->hunk->file_pos = range->start;
|
||||
in->hunk->file_last = range->end;
|
||||
|
||||
@ -315,9 +366,16 @@ static int ngx_http_range_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_range_filter_module);
|
||||
ll = &out;
|
||||
|
||||
range = r->headers_out.ranges.elts;
|
||||
for (i = 0; i < r->headers_out.ranges.nelts; i++) {
|
||||
|
||||
/*
|
||||
* The boundary header of the range:
|
||||
* CRLF
|
||||
* "--0123456789" CRLF
|
||||
* "Content-Type: image/jpeg" CRLF
|
||||
* "Content-Range: bytes "
|
||||
*/
|
||||
|
||||
ngx_test_null(h, ngx_calloc_hunk(r->pool), NGX_ERROR);
|
||||
h->type = NGX_HUNK_IN_MEMORY|NGX_HUNK_MEMORY;
|
||||
h->pos = ctx->boundary_header.data;
|
||||
@ -326,6 +384,8 @@ static int ngx_http_range_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
|
||||
ngx_test_null(hcl, ngx_alloc_chain_link(r->pool), NGX_ERROR);
|
||||
hcl->hunk = h;
|
||||
|
||||
/* "SSSS-EEEE/TTTT" CRLF CRLF */
|
||||
|
||||
ngx_test_null(h, ngx_calloc_hunk(r->pool), NGX_ERROR);
|
||||
h->type = NGX_HUNK_IN_MEMORY|NGX_HUNK_TEMP;
|
||||
h->pos = range[i].content_range.data;
|
||||
@ -334,6 +394,8 @@ static int ngx_http_range_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
|
||||
ngx_test_null(rcl, ngx_alloc_chain_link(r->pool), NGX_ERROR);
|
||||
rcl->hunk = h;
|
||||
|
||||
/* the range data */
|
||||
|
||||
ngx_test_null(h, ngx_calloc_hunk(r->pool), NGX_ERROR);
|
||||
h->type = NGX_HUNK_FILE;
|
||||
h->file_pos = range[i].start;
|
||||
@ -348,6 +410,8 @@ static int ngx_http_range_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
|
||||
ll = &dcl->next;
|
||||
}
|
||||
|
||||
/* the last boundary CRLF "--0123456789--" CRLF */
|
||||
|
||||
ngx_test_null(h, ngx_calloc_hunk(r->pool), NGX_ERROR);
|
||||
h->type = NGX_HUNK_IN_MEMORY|NGX_HUNK_TEMP|NGX_HUNK_LAST;
|
||||
ngx_test_null(h->pos, ngx_palloc(r->pool, 4 + 10 + 4), NGX_ERROR);
|
||||
|
@ -88,7 +88,7 @@ ngx_log_debug(r->connection->log, "HTTP filename: '%s'" _ r->file.name.data);
|
||||
/*
|
||||
* There is no way to open a file or a directory in Win9X with
|
||||
* one syscall: Win9X has no FILE_FLAG_BACKUP_SEMANTICS flag.
|
||||
* so we need to check its type before the opening
|
||||
* So we need to check its type before the opening
|
||||
*/
|
||||
|
||||
r->file.info.dwFileAttributes = GetFileAttributes(r->file.name.data);
|
||||
@ -151,6 +151,21 @@ ngx_log_debug(r->connection->log, "FILE: %d" _ r->file.fd);
|
||||
|
||||
r->file.info_valid = 1;
|
||||
}
|
||||
|
||||
#if !(WIN32) /* the not regular files are probably Unix specific */
|
||||
|
||||
if (!ngx_is_file(r->file.info)) {
|
||||
ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
|
||||
"%s is not a regular file", r->file.name.data);
|
||||
|
||||
if (ngx_close_file(r->file.fd) == NGX_FILE_ERROR)
|
||||
ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
|
||||
ngx_close_file_n " %s failed", r->file.name.data);
|
||||
|
||||
return NGX_HTTP_NOT_FOUND;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (ngx_is_dir(r->file.info)) {
|
||||
@ -163,6 +178,7 @@ ngx_log_debug(r->connection->log, "HTTP DIR: '%s'" _ r->file.name.data);
|
||||
}
|
||||
|
||||
r->file.fd = NGX_INVALID_FILE;
|
||||
r->file.info_valid = 0;
|
||||
#endif
|
||||
|
||||
ngx_test_null(h, ngx_push_table(r->headers_out.headers),
|
||||
@ -203,7 +219,7 @@ static int ngx_http_static_handler(ngx_http_request_t *r)
|
||||
}
|
||||
|
||||
ctx = r->connection->log->data;
|
||||
ctx->action = "sending response";
|
||||
ctx->action = "sending response to client";
|
||||
|
||||
if (r->file.fd == NGX_INVALID_FILE) {
|
||||
r->file.fd = ngx_open_file(r->file.name.data,
|
||||
@ -242,21 +258,6 @@ static int ngx_http_static_handler(ngx_http_request_t *r)
|
||||
r->file.info_valid = 1;
|
||||
}
|
||||
|
||||
#if !(WIN32) /* the not regular files are probably Unix specific */
|
||||
|
||||
if (!ngx_is_file(r->file.info)) {
|
||||
ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
|
||||
"%s is not regular file", r->file.name.data);
|
||||
|
||||
if (ngx_close_file(r->file.fd) == NGX_FILE_ERROR)
|
||||
ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
|
||||
ngx_close_file_n " %s failed", r->file.name.data);
|
||||
|
||||
return NGX_HTTP_NOT_FOUND;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
r->headers_out.status = NGX_HTTP_OK;
|
||||
r->headers_out.content_length_n = ngx_file_size(r->file.info);
|
||||
r->headers_out.last_modified_time = ngx_file_mtime(r->file.info);
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
|
||||
static int ngx_http_proxy_handler(ngx_http_request_t *r);
|
||||
static void ngx_http_proxy_init_request(void *data);
|
||||
static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p);
|
||||
static void ngx_http_proxy_send_request_handler(ngx_event_t *wev);
|
||||
static void ngx_http_proxy_send_request(ngx_http_proxy_ctx_t *p);
|
||||
@ -20,7 +21,7 @@ static void ngx_http_proxy_send_response(ngx_http_proxy_ctx_t *p);
|
||||
static void ngx_http_proxy_process_body(ngx_event_t *ev);
|
||||
|
||||
static int ngx_http_proxy_parse_status_line(ngx_http_proxy_ctx_t *p);
|
||||
static void ngx_http_proxy_next_upstream(ngx_http_proxy_ctx_t *p);
|
||||
static void ngx_http_proxy_next_upstream(ngx_http_proxy_ctx_t *p, int ft_type);
|
||||
static void ngx_http_proxy_finalize_request(ngx_http_proxy_ctx_t *p, int rc);
|
||||
static void ngx_http_proxy_close_connection(ngx_connection_t *c);
|
||||
|
||||
@ -46,6 +47,13 @@ static ngx_command_t ngx_http_proxy_commands[] = {
|
||||
0,
|
||||
NULL},
|
||||
|
||||
{ngx_string("proxy_request_buffer_size"),
|
||||
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
|
||||
ngx_conf_set_size_slot,
|
||||
NGX_HTTP_LOC_CONF_OFFSET,
|
||||
offsetof(ngx_http_proxy_loc_conf_t, request_buffer_size),
|
||||
NULL},
|
||||
|
||||
{ngx_string("proxy_connect_timeout"),
|
||||
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
|
||||
ngx_conf_set_msec_slot,
|
||||
@ -135,13 +143,10 @@ static ngx_str_t http_methods[] = {
|
||||
};
|
||||
|
||||
|
||||
#if 0
|
||||
static char *header_errors[] = {
|
||||
"upstream sent too long status line",
|
||||
static char *upstream_header_errors[] = {
|
||||
"upstream sent invalid header",
|
||||
"upstream sent too long header line"
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
static ngx_http_header_t headers_in[] = {
|
||||
@ -170,6 +175,7 @@ static char connection_close_header[] = "Connection: close" CRLF;
|
||||
|
||||
static int ngx_http_proxy_handler(ngx_http_request_t *r)
|
||||
{
|
||||
int rc;
|
||||
ngx_http_proxy_ctx_t *p;
|
||||
|
||||
ngx_http_create_ctx(r, p, ngx_http_proxy_module,
|
||||
@ -186,20 +192,89 @@ static int ngx_http_proxy_handler(ngx_http_request_t *r)
|
||||
/* TODO: we currently support reverse proxy only */
|
||||
p->accel = 1;
|
||||
|
||||
ngx_test_null(p->request_hunks, ngx_http_proxy_create_request(p),
|
||||
NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||
if (r->headers_in.content_length_n > 0) {
|
||||
ngx_test_null(r->temp_file,
|
||||
ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)),
|
||||
NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||
|
||||
/* TODO: read request body */
|
||||
r->temp_file->file.fd = NGX_INVALID_FILE;
|
||||
r->temp_file->file.log = r->connection->log;
|
||||
r->temp_file->path = *p->lcf->temp_path;
|
||||
r->temp_file->pool = r->pool;
|
||||
r->temp_file->warn = "a client request body is buffered "
|
||||
"to a temporary file";
|
||||
/* STUB */ r->temp_file->persistent = 1;
|
||||
|
||||
r->request_body_handler = ngx_http_proxy_init_request;
|
||||
r->data = p;
|
||||
|
||||
rc = ngx_http_read_client_request_body(r, p->lcf->request_buffer_size);
|
||||
|
||||
if (rc != NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
ngx_http_proxy_init_request(p);
|
||||
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
|
||||
static void ngx_http_proxy_init_request(void *data)
|
||||
{
|
||||
ngx_http_proxy_ctx_t *p = data;
|
||||
|
||||
ngx_chain_t *cl;
|
||||
ngx_http_request_t *r;
|
||||
ngx_output_chain_ctx_t *ctx;
|
||||
|
||||
|
||||
r = p->request;
|
||||
|
||||
cl = ngx_http_proxy_create_request(p);
|
||||
if (cl == NULL) {
|
||||
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (r->request_hunks) {
|
||||
cl->next = r->request_hunks;
|
||||
}
|
||||
|
||||
r->request_hunks = cl;
|
||||
|
||||
p->upstream.log = r->connection->log;
|
||||
p->saved_ctx = r->connection->log->data;
|
||||
r->connection->log->data = p;;
|
||||
p->saved_handler = r->connection->log->handler;
|
||||
r->connection->log->data = p;
|
||||
r->connection->log->handler = ngx_http_proxy_log_error;
|
||||
p->action = "connecting to upstream";
|
||||
|
||||
ngx_http_proxy_send_request(p);
|
||||
ctx = ngx_pcalloc(r->pool, sizeof(ngx_output_chain_ctx_t));
|
||||
if (ctx == NULL) {
|
||||
ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
return NGX_DONE;
|
||||
p->output_chain_ctx = ctx;
|
||||
|
||||
if (r->request_body_hunk) {
|
||||
ctx->free = ngx_alloc_chain_link(r->pool);
|
||||
if (ctx->free == NULL) {
|
||||
ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
ctx->free->hunk = r->request_body_hunk;
|
||||
ctx->free->next = NULL;
|
||||
}
|
||||
|
||||
ctx->sendfile = r->sendfile;
|
||||
ctx->copy_chain = 1;
|
||||
ctx->pool = r->pool;
|
||||
ctx->bufs.num = 1;
|
||||
ctx->tag = (ngx_hunk_tag_t) &ngx_http_proxy_module;
|
||||
ctx->output_filter = (ngx_output_chain_filter_pt) ngx_write_chain;
|
||||
|
||||
ngx_http_proxy_send_request(p);
|
||||
}
|
||||
|
||||
|
||||
@ -324,9 +399,11 @@ static void ngx_http_proxy_send_request_handler(ngx_event_t *wev)
|
||||
c = wev->data;
|
||||
p = c->data;
|
||||
|
||||
p->action = "sending request to upstream";
|
||||
|
||||
if (wev->timedout) {
|
||||
p->timedout = 1;
|
||||
ngx_http_proxy_next_upstream(p);
|
||||
ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_TIMEOUT);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -338,30 +415,43 @@ static void ngx_http_proxy_send_request_handler(ngx_event_t *wev)
|
||||
|
||||
static void ngx_http_proxy_send_request(ngx_http_proxy_ctx_t *p)
|
||||
{
|
||||
int rc;
|
||||
ngx_chain_t *chain, *cl, *tl, **ll;
|
||||
ngx_connection_t *c;
|
||||
int rc;
|
||||
ngx_chain_t *cl;
|
||||
ngx_connection_t *c;
|
||||
|
||||
c = p->upstream.connection;
|
||||
|
||||
for ( ;; ) {
|
||||
|
||||
if (c) {
|
||||
chain = ngx_write_chain(c, p->work_request_hunks);
|
||||
p->output_chain_ctx->output_ctx = c;
|
||||
rc = ngx_output_chain(p->output_chain_ctx,
|
||||
p->request->request_hunks);
|
||||
|
||||
if (chain != NGX_CHAIN_ERROR) {
|
||||
p->work_request_hunks = chain;
|
||||
if (rc != NGX_ERROR) {
|
||||
p->request_sent = 1;
|
||||
|
||||
if (c->write->timer_set) {
|
||||
ngx_del_timer(c->write);
|
||||
}
|
||||
|
||||
if (chain) {
|
||||
if (rc == NGX_AGAIN) {
|
||||
ngx_add_timer(c->write, p->lcf->send_timeout);
|
||||
|
||||
} else {
|
||||
/* TODO: del event */
|
||||
|
||||
if (c->tcp_nopush) {
|
||||
if (ngx_tcp_push(c->fd) == NGX_ERROR) {
|
||||
ngx_log_error(NGX_LOG_CRIT, c->log,
|
||||
ngx_socket_errno,
|
||||
ngx_tcp_push_n " failed");
|
||||
ngx_http_proxy_finalize_request(p,
|
||||
NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||
return;
|
||||
}
|
||||
c->tcp_nopush = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
@ -404,34 +494,9 @@ static void ngx_http_proxy_send_request(ngx_http_proxy_ctx_t *p)
|
||||
|
||||
/* reinit the request chain */
|
||||
|
||||
p->work_request_hunks = ngx_alloc_chain_link(p->request->pool);
|
||||
if (p->work_request_hunks == NULL) {
|
||||
ngx_http_proxy_finalize_request(p,
|
||||
NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
tl = p->work_request_hunks;
|
||||
ll = &p->work_request_hunks;
|
||||
|
||||
for (cl = p->request_hunks; cl; cl = cl->next) {
|
||||
tl->hunk = cl->hunk;
|
||||
*ll = tl;
|
||||
ll = &tl->next;
|
||||
for (cl = p->request->request_hunks; cl; cl = cl->next) {
|
||||
cl->hunk->pos = cl->hunk->start;
|
||||
|
||||
tl = ngx_alloc_chain_link(p->request->pool);
|
||||
if (tl == NULL) {
|
||||
ngx_http_proxy_finalize_request(p,
|
||||
NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
*ll = NULL;
|
||||
|
||||
} else {
|
||||
p->work_request_hunks = p->request_hunks;
|
||||
}
|
||||
|
||||
p->request_sent = 0;
|
||||
@ -461,11 +526,13 @@ static void ngx_http_proxy_process_upstream_status_line(ngx_event_t *rev)
|
||||
c = rev->data;
|
||||
p = c->data;
|
||||
|
||||
p->action = "reading upstream status line";
|
||||
|
||||
ngx_log_debug(rev->log, "http proxy process status line");
|
||||
|
||||
if (rev->timedout) {
|
||||
p->timedout = 1;
|
||||
ngx_http_proxy_next_upstream(p);
|
||||
ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_TIMEOUT);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -483,7 +550,7 @@ static void ngx_http_proxy_process_upstream_status_line(ngx_event_t *rev)
|
||||
n = ngx_http_proxy_read_upstream_header(p);
|
||||
|
||||
if (n == NGX_ERROR) {
|
||||
ngx_http_proxy_next_upstream(p);
|
||||
ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -496,21 +563,39 @@ static void ngx_http_proxy_process_upstream_status_line(ngx_event_t *rev)
|
||||
if (rc == NGX_AGAIN) {
|
||||
if (p->header_in->pos == p->header_in->last) {
|
||||
ngx_log_error(NGX_LOG_ERR, rev->log, 0,
|
||||
"upstream sent too big header");
|
||||
ngx_http_proxy_finalize_request(p, NGX_HTTP_BAD_GATEWAY);
|
||||
return;
|
||||
"upstream sent too long status line");
|
||||
ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_HTTP_HEADER);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (rc == NGX_HTTP_PROXY_PARSE_NO_HEADER) {
|
||||
/* TODO: HTTP/0.9 */
|
||||
ngx_log_error(NGX_LOG_ERR, rev->log, 0,
|
||||
"upstream sent no valid HTTP/1.0 header");
|
||||
|
||||
if (p->accel) {
|
||||
ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_HTTP_HEADER);
|
||||
|
||||
} else {
|
||||
p->request->http_version = NGX_HTTP_VERSION_9;
|
||||
p->status = NGX_HTTP_OK;
|
||||
ngx_http_proxy_send_response(p);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* rc == NGX_OK */
|
||||
|
||||
if (p->status == NGX_HTTP_INTERNAL_SERVER_ERROR
|
||||
&& p->upstream.tries > 1
|
||||
&& (p->lcf->next_upstream & NGX_HTTP_PROXY_FT_HTTP_500))
|
||||
{
|
||||
ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_HTTP_500);
|
||||
return;
|
||||
}
|
||||
|
||||
p->status_line.len = p->status_end - p->status_start;
|
||||
p->status_line.data = ngx_palloc(p->request->pool, p->status_line.len + 1);
|
||||
if (p->status_line.data == NULL) {
|
||||
@ -522,7 +607,6 @@ static void ngx_http_proxy_process_upstream_status_line(ngx_event_t *rev)
|
||||
ngx_log_debug(rev->log, "http proxy status %d '%s'" _
|
||||
p->status _ p->status_line.data);
|
||||
|
||||
|
||||
if (p->headers_in.headers) {
|
||||
p->headers_in.headers->nelts = 0;
|
||||
} else {
|
||||
@ -549,11 +633,13 @@ static void ngx_http_proxy_process_upstream_headers(ngx_event_t *rev)
|
||||
p = c->data;
|
||||
r = p->request;
|
||||
|
||||
p->action = "reading upstream headers";
|
||||
|
||||
ngx_log_debug(rev->log, "http proxy process header line");
|
||||
|
||||
if (rev->timedout) {
|
||||
p->timedout = 1;
|
||||
ngx_http_proxy_next_upstream(p);
|
||||
ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_TIMEOUT);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -564,7 +650,7 @@ static void ngx_http_proxy_process_upstream_headers(ngx_event_t *rev)
|
||||
n = ngx_http_proxy_read_upstream_header(p);
|
||||
|
||||
if (n == NGX_ERROR) {
|
||||
ngx_http_proxy_next_upstream(p);
|
||||
ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -609,6 +695,7 @@ static void ngx_http_proxy_process_upstream_headers(ngx_event_t *rev)
|
||||
if (ngx_strcasecmp(headers_in[i].name.data, h->key.data) == 0) {
|
||||
*((ngx_table_elt_t **)
|
||||
((char *) &p->headers_in + headers_in[i].offset)) = h;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -631,7 +718,10 @@ static void ngx_http_proxy_process_upstream_headers(ngx_event_t *rev)
|
||||
|
||||
/* there was error while a header line parsing */
|
||||
|
||||
ngx_http_proxy_finalize_request(p, NGX_HTTP_BAD_GATEWAY);
|
||||
ngx_log_error(NGX_LOG_ERR, rev->log, 0,
|
||||
upstream_header_errors[rc - NGX_HTTP_PARSE_HEADER_ERROR]);
|
||||
|
||||
ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_HTTP_HEADER);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -640,7 +730,8 @@ static void ngx_http_proxy_process_upstream_headers(ngx_event_t *rev)
|
||||
if (p->header_in->last == p->header_in->end) {
|
||||
ngx_log_error(NGX_LOG_ERR, rev->log, 0,
|
||||
"upstream sent too big header");
|
||||
ngx_http_proxy_finalize_request(p, NGX_HTTP_BAD_GATEWAY);
|
||||
|
||||
ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_HTTP_HEADER);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -679,7 +770,7 @@ static ssize_t ngx_http_proxy_read_upstream_header(ngx_http_proxy_ctx_t *p)
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
ngx_log_error(NGX_LOG_INFO, rev->log, 0,
|
||||
ngx_log_error(NGX_LOG_ERR, rev->log, 0,
|
||||
"upstream closed prematurely connection");
|
||||
}
|
||||
|
||||
@ -834,11 +925,6 @@ static void ngx_http_proxy_send_response(ngx_http_proxy_ctx_t *p)
|
||||
|
||||
p->event_pipe = ep;
|
||||
|
||||
#if 0
|
||||
lcx = p->log->data;
|
||||
lcx->action = "reading an upstream";
|
||||
#endif
|
||||
|
||||
p->upstream.connection->read->event_handler = ngx_http_proxy_process_body;
|
||||
r->connection->write->event_handler = ngx_http_proxy_process_body;
|
||||
|
||||
@ -861,11 +947,13 @@ static void ngx_http_proxy_process_body(ngx_event_t *ev)
|
||||
ngx_log_debug(ev->log, "http proxy process downstream");
|
||||
r = c->data;
|
||||
p = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
|
||||
p->action = "sending to client";
|
||||
|
||||
} else {
|
||||
ngx_log_debug(ev->log, "http proxy process upstream");
|
||||
p = c->data;
|
||||
r = p->request;
|
||||
p->action = "reading upstream body";
|
||||
}
|
||||
|
||||
ep = p->event_pipe;
|
||||
@ -1123,7 +1211,7 @@ static int ngx_http_proxy_parse_status_line(ngx_http_proxy_ctx_t *p)
|
||||
}
|
||||
|
||||
|
||||
static void ngx_http_proxy_next_upstream(ngx_http_proxy_ctx_t *p)
|
||||
static void ngx_http_proxy_next_upstream(ngx_http_proxy_ctx_t *p, int ft_type)
|
||||
{
|
||||
ngx_event_connect_peer_failed(&p->upstream);
|
||||
|
||||
@ -1137,7 +1225,7 @@ static void ngx_http_proxy_next_upstream(ngx_http_proxy_ctx_t *p)
|
||||
p->upstream.connection = NULL;
|
||||
}
|
||||
|
||||
if (p->upstream.tries == 0) {
|
||||
if (p->upstream.tries == 0 || !(p->lcf->next_upstream & ft_type)) {
|
||||
ngx_http_proxy_finalize_request(p,
|
||||
p->timedout ? NGX_HTTP_GATEWAY_TIME_OUT:
|
||||
NGX_HTTP_BAD_GATEWAY);
|
||||
@ -1146,8 +1234,11 @@ static void ngx_http_proxy_next_upstream(ngx_http_proxy_ctx_t *p)
|
||||
|
||||
if (!p->fatal_error) {
|
||||
ngx_http_proxy_send_request(p);
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_log_debug(p->request->connection->log, "FATAL ERROR IN NEXT UPSTREAM");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1164,6 +1255,9 @@ static void ngx_http_proxy_finalize_request(ngx_http_proxy_ctx_t *p, int rc)
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
p->request->connection->log->data = p->saved_ctx;
|
||||
p->request->connection->log->handler = p->saved_handler;
|
||||
|
||||
ngx_http_finalize_request(p->request, rc);
|
||||
|
||||
p->fatal_error = 1;
|
||||
@ -1223,11 +1317,15 @@ static size_t ngx_http_proxy_log_error(void *data, char *buf, size_t len)
|
||||
ngx_http_proxy_ctx_t *p = data;
|
||||
|
||||
return ngx_snprintf(buf, len,
|
||||
" while %s, upstream: %s, client: %s, URL: %s",
|
||||
" while %s, client: %s, URL: %s, upstream: %s%s%s%s%s",
|
||||
p->action,
|
||||
p->upstream.peers->peers[p->upstream.cur_peer].addr_port_text.data,
|
||||
p->request->connection->addr_text.data,
|
||||
p->request->unparsed_uri.data);
|
||||
p->request->unparsed_uri.data,
|
||||
p->upstream.peers->peers[p->upstream.cur_peer].addr_port_text.data,
|
||||
p->lcf->upstream->uri.data,
|
||||
p->request->uri.data + p->lcf->upstream->location->len,
|
||||
p->request->args.len ? "?" : "",
|
||||
p->request->args.len ? p->request->args.data : "");
|
||||
}
|
||||
|
||||
|
||||
@ -1250,6 +1348,7 @@ static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
|
||||
|
||||
*/
|
||||
|
||||
conf->request_buffer_size = NGX_CONF_UNSET;
|
||||
conf->connect_timeout = NGX_CONF_UNSET;
|
||||
conf->send_timeout = NGX_CONF_UNSET;
|
||||
conf->header_buffer_size = NGX_CONF_UNSET;
|
||||
@ -1267,6 +1366,8 @@ static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
|
||||
/* "proxy_cyclic_temp_file" is disabled */
|
||||
conf->cyclic_temp_file = 0;
|
||||
|
||||
conf->next_upstream = NGX_CONF_UNSET;
|
||||
|
||||
return conf;
|
||||
}
|
||||
|
||||
@ -1277,6 +1378,8 @@ static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf,
|
||||
ngx_http_proxy_loc_conf_t *prev = parent;
|
||||
ngx_http_proxy_loc_conf_t *conf = child;
|
||||
|
||||
ngx_conf_merge_size_value(conf->request_buffer_size,
|
||||
prev->request_buffer_size, 8192);
|
||||
ngx_conf_merge_msec_value(conf->connect_timeout,
|
||||
prev->connect_timeout, 60000);
|
||||
ngx_conf_merge_msec_value(conf->send_timeout, prev->send_timeout, 30000);
|
||||
@ -1297,6 +1400,9 @@ static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf,
|
||||
ngx_conf_merge_size_value(conf->temp_file_write_size,
|
||||
prev->temp_file_write_size, 16384);
|
||||
|
||||
ngx_conf_merge_value(conf->next_upstream, prev->next_upstream,
|
||||
(NGX_HTTP_PROXY_FT_ERROR|NGX_HTTP_PROXY_FT_TIMEOUT));
|
||||
|
||||
ngx_conf_merge_path_value(conf->temp_path, prev->temp_path,
|
||||
"temp", 1, 2, 0, cf->pool);
|
||||
|
||||
|
@ -19,6 +19,7 @@ typedef struct {
|
||||
|
||||
|
||||
typedef struct {
|
||||
ssize_t request_buffer_size;
|
||||
ngx_msec_t connect_timeout;
|
||||
ngx_msec_t send_timeout;
|
||||
ssize_t header_buffer_size;
|
||||
@ -31,6 +32,8 @@ typedef struct {
|
||||
ssize_t temp_file_write_size;
|
||||
int cyclic_temp_file;
|
||||
|
||||
int next_upstream;
|
||||
|
||||
ngx_path_t *temp_path;
|
||||
|
||||
ngx_http_proxy_upstream_t *upstream;
|
||||
@ -67,8 +70,7 @@ struct ngx_http_proxy_ctx_s {
|
||||
int status;
|
||||
ngx_str_t status_line;
|
||||
|
||||
ngx_chain_t *work_request_hunks;
|
||||
ngx_chain_t *request_hunks;
|
||||
ngx_output_chain_ctx_t *output_chain_ctx;
|
||||
|
||||
int method;
|
||||
|
||||
@ -89,10 +91,16 @@ struct ngx_http_proxy_ctx_s {
|
||||
|
||||
char *action;
|
||||
ngx_http_log_ctx_t *saved_ctx;
|
||||
ngx_log_handler_pt saved_handler;
|
||||
};
|
||||
|
||||
|
||||
#define NGX_HTTP_PROXY_PARSE_NO_HEADER 20
|
||||
|
||||
#define NGX_HTTP_PROXY_FT_ERROR 1
|
||||
#define NGX_HTTP_PROXY_FT_TIMEOUT 2
|
||||
#define NGX_HTTP_PROXY_FT_HTTP_HEADER 4
|
||||
#define NGX_HTTP_PROXY_FT_HTTP_500 8
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_PROXY_HANDLER_H_INCLUDED_ */
|
||||
|
@ -51,12 +51,8 @@ void ngx_http_close_request(ngx_http_request_t *r, int error);
|
||||
void ngx_http_close_connection(ngx_connection_t *c);
|
||||
|
||||
|
||||
|
||||
int ngx_http_init_client_request_body(ngx_http_request_t *r, int size);
|
||||
int ngx_http_read_client_request_body(ngx_http_request_t *r);
|
||||
int ngx_http_init_client_request_body_chain(ngx_http_request_t *r);
|
||||
void ngx_http_reinit_client_request_body_hunks(ngx_http_request_t *r);
|
||||
|
||||
int ngx_http_read_client_request_body(ngx_http_request_t *r,
|
||||
int request_buffer_size);
|
||||
|
||||
int ngx_http_send_header(ngx_http_request_t *r);
|
||||
int ngx_http_special_response_handler(ngx_http_request_t *r, int error);
|
||||
|
@ -232,7 +232,7 @@ void ngx_http_handler(ngx_http_request_t *r)
|
||||
break;
|
||||
}
|
||||
|
||||
#if 1
|
||||
#if 0
|
||||
/* TEST STUB */ r->http_version = NGX_HTTP_VERSION_10;
|
||||
/* TEST STUB */ r->keepalive = 0;
|
||||
#endif
|
||||
@ -295,11 +295,6 @@ static void ngx_http_run_phases(ngx_http_request_t *r)
|
||||
return;
|
||||
}
|
||||
|
||||
/* TODO THINK: is it dupliate NGX_DONE ??? */
|
||||
if (r->closed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (rc == NGX_DECLINED) {
|
||||
continue;
|
||||
}
|
||||
@ -403,6 +398,10 @@ ngx_log_debug(r->connection->log, "rc: %d" _ rc);
|
||||
|
||||
int ngx_http_send_header(ngx_http_request_t *r)
|
||||
{
|
||||
if (r->main) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
return (*ngx_http_top_header_filter)(r);
|
||||
}
|
||||
|
||||
|
@ -9,33 +9,6 @@ typedef struct {
|
||||
} ngx_http_output_filter_conf_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
|
||||
/*
|
||||
* NOTE: we do not need now to store hunk in ctx,
|
||||
* it's needed for the future NGX_FILE_AIO_READ support only
|
||||
*/
|
||||
|
||||
ngx_hunk_t *hunk;
|
||||
|
||||
ngx_chain_t *in;
|
||||
|
||||
/* TODO: out and last_out should be local variables */
|
||||
ngx_chain_t *out;
|
||||
ngx_chain_t **last_out;
|
||||
/* */
|
||||
|
||||
ngx_chain_t *free;
|
||||
ngx_chain_t *busy;
|
||||
|
||||
int hunks;
|
||||
} ngx_http_output_filter_ctx_t;
|
||||
|
||||
|
||||
ngx_inline static int ngx_http_output_filter_need_to_copy(ngx_http_request_t *r,
|
||||
ngx_hunk_t *hunk);
|
||||
static int ngx_http_output_filter_copy_hunk(ngx_hunk_t *dst, ngx_hunk_t *src,
|
||||
int sendfile);
|
||||
static void *ngx_http_output_filter_create_conf(ngx_conf_t *cf);
|
||||
static char *ngx_http_output_filter_merge_conf(ngx_conf_t *cf,
|
||||
void *parent, void *child);
|
||||
@ -79,244 +52,34 @@ ngx_module_t ngx_http_output_filter_module = {
|
||||
|
||||
int ngx_http_output_filter(ngx_http_request_t *r, ngx_chain_t *in)
|
||||
{
|
||||
int rc, last;
|
||||
ssize_t size;
|
||||
ngx_chain_t *cl;
|
||||
ngx_http_output_filter_ctx_t *ctx;
|
||||
ngx_output_chain_ctx_t *ctx;
|
||||
ngx_http_output_filter_conf_t *conf;
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r->main ? r->main : r,
|
||||
ngx_http_output_filter_module);
|
||||
|
||||
if (ctx == NULL) {
|
||||
conf = ngx_http_get_module_loc_conf(r->main ? r->main : r,
|
||||
ngx_http_output_filter_module);
|
||||
|
||||
ngx_http_create_ctx(r, ctx, ngx_http_output_filter_module,
|
||||
sizeof(ngx_http_output_filter_ctx_t), NGX_ERROR);
|
||||
ctx->last_out = &ctx->out;
|
||||
sizeof(ngx_output_chain_ctx_t), NGX_ERROR);
|
||||
|
||||
ctx->sendfile = r->sendfile;
|
||||
ctx->need_in_memory = r->filter & NGX_HTTP_FILTER_NEED_IN_MEMORY;
|
||||
ctx->need_in_temp = r->filter & NGX_HTTP_FILTER_NEED_TEMP;
|
||||
|
||||
ctx->pool = r->pool;
|
||||
ctx->bufs = conf->bufs;
|
||||
ctx->tag = (ngx_hunk_tag_t) &ngx_http_output_filter_module;
|
||||
|
||||
ctx->output_filter = (ngx_output_chain_filter_pt)
|
||||
ngx_http_top_body_filter;
|
||||
ctx->output_ctx = r;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* the short path for the case when the chain ctx->in is empty
|
||||
* and the incoming chain is empty too or it has the single hunk
|
||||
* that does not require the copy
|
||||
*/
|
||||
|
||||
if (ctx->in == NULL) {
|
||||
|
||||
if (in == NULL) {
|
||||
return ngx_http_top_body_filter(r, in);
|
||||
}
|
||||
|
||||
if (in->next == NULL
|
||||
&& (!ngx_http_output_filter_need_to_copy(r, in->hunk)))
|
||||
{
|
||||
return ngx_http_top_body_filter(r, in);
|
||||
}
|
||||
}
|
||||
|
||||
/* add the incoming hunk to the chain ctx->in */
|
||||
|
||||
if (in) {
|
||||
if (ngx_chain_add_copy(r->pool, &ctx->in, in) == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
conf = ngx_http_get_module_loc_conf(r->main ? r->main : r,
|
||||
ngx_http_output_filter_module);
|
||||
|
||||
last = NGX_NONE;
|
||||
|
||||
for ( ;; ) {
|
||||
|
||||
while (ctx->in) {
|
||||
|
||||
if (!ngx_http_output_filter_need_to_copy(r, ctx->in->hunk)) {
|
||||
|
||||
/* move the chain link to the chain ctx->out */
|
||||
|
||||
cl = ctx->in;
|
||||
ctx->in = cl->next;
|
||||
|
||||
*ctx->last_out = cl;
|
||||
ctx->last_out = &cl->next;
|
||||
cl->next = NULL;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ctx->hunk == NULL) {
|
||||
|
||||
/* get the free hunk */
|
||||
|
||||
if (ctx->free) {
|
||||
ctx->hunk = ctx->free->hunk;
|
||||
ctx->free = ctx->free->next;
|
||||
|
||||
} else if (ctx->hunks < conf->bufs.num) {
|
||||
ngx_test_null(ctx->hunk,
|
||||
ngx_create_temp_hunk(r->pool, conf->bufs.size,
|
||||
0, 0),
|
||||
NGX_ERROR);
|
||||
ctx->hunk->tag = (ngx_hunk_tag_t)
|
||||
&ngx_http_output_filter_module;
|
||||
ctx->hunk->type |= NGX_HUNK_RECYCLED;
|
||||
ctx->hunks++;
|
||||
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rc = ngx_http_output_filter_copy_hunk(ctx->hunk, ctx->in->hunk,
|
||||
r->sendfile);
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if (NGX_FILE_AIO_READ)
|
||||
if (rc == NGX_AGAIN) {
|
||||
if (ctx->out) {
|
||||
break;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ctx->in->hunk->type & NGX_HUNK_IN_MEMORY) {
|
||||
size = ctx->in->hunk->last - ctx->in->hunk->pos;
|
||||
|
||||
} else {
|
||||
size = (size_t) (ctx->in->hunk->file_last
|
||||
- ctx->in->hunk->file_pos);
|
||||
}
|
||||
|
||||
/* delete the completed hunk from the chain ctx->in */
|
||||
|
||||
if (size == 0) {
|
||||
ctx->in = ctx->in->next;
|
||||
}
|
||||
|
||||
ngx_alloc_link_and_set_hunk(cl, ctx->hunk, r->pool, NGX_ERROR);
|
||||
*ctx->last_out = cl;
|
||||
ctx->last_out = &cl->next;
|
||||
ctx->hunk = NULL;
|
||||
|
||||
if (ctx->free == NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->out == NULL && last != NGX_NONE) {
|
||||
return last;
|
||||
}
|
||||
|
||||
last = ngx_http_top_body_filter(r, ctx->out);
|
||||
|
||||
ngx_chain_update_chains(&ctx->free, &ctx->busy, &ctx->out,
|
||||
(ngx_hunk_tag_t) &ngx_http_output_filter_module);
|
||||
ctx->last_out = &ctx->out;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ngx_inline static int ngx_http_output_filter_need_to_copy(ngx_http_request_t *r,
|
||||
ngx_hunk_t *hunk)
|
||||
{
|
||||
if (ngx_hunk_special(hunk)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!r->sendfile) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((r->filter & NGX_HTTP_FILTER_NEED_IN_MEMORY)
|
||||
&& (!(hunk->type & NGX_HUNK_IN_MEMORY)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
if ((r->filter & NGX_HTTP_FILTER_NEED_TEMP)
|
||||
&& (hunk->type & (NGX_HUNK_MEMORY|NGX_HUNK_MMAP)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ngx_http_output_filter_copy_hunk(ngx_hunk_t *dst, ngx_hunk_t *src,
|
||||
int sendfile)
|
||||
{
|
||||
ssize_t n, size;
|
||||
|
||||
if (src->type & NGX_HUNK_IN_MEMORY) {
|
||||
size = src->last - src->pos;
|
||||
} else {
|
||||
size = (size_t) (src->file_last - src->file_pos);
|
||||
}
|
||||
|
||||
if (size > (dst->end - dst->pos)) {
|
||||
size = dst->end - dst->pos;
|
||||
}
|
||||
|
||||
if (src->type & NGX_HUNK_IN_MEMORY) {
|
||||
ngx_memcpy(dst->pos, src->pos, size);
|
||||
src->pos += size;
|
||||
dst->last += size;
|
||||
|
||||
if (src->type & NGX_HUNK_FILE) {
|
||||
src->file_pos += size;
|
||||
}
|
||||
|
||||
if ((src->type & NGX_HUNK_LAST) && src->pos == src->last) {
|
||||
dst->type |= NGX_HUNK_LAST;
|
||||
}
|
||||
|
||||
} else {
|
||||
n = ngx_read_file(src->file, dst->pos, size, src->file_pos);
|
||||
|
||||
if (n == 0) {
|
||||
ngx_log_debug(src->file->log, "READ: %qd:%qd %X:%X %X:%X" _
|
||||
src->file_pos _ src->file_last _
|
||||
dst->pos _ dst->last _ dst->start _ dst->end);
|
||||
}
|
||||
|
||||
if (n == NGX_ERROR) {
|
||||
return n;
|
||||
}
|
||||
|
||||
#if (NGX_FILE_AIO_READ)
|
||||
if (n == NGX_AGAIN) {
|
||||
return n;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (n != size) {
|
||||
ngx_log_error(NGX_LOG_ALERT, src->file->log, 0,
|
||||
ngx_read_file_n " reads only %d of %d from file",
|
||||
n, size);
|
||||
if (n == 0) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
src->file_pos += n;
|
||||
dst->last += n;
|
||||
|
||||
if (!sendfile) {
|
||||
dst->type &= ~NGX_HUNK_FILE;
|
||||
}
|
||||
|
||||
if ((src->type & NGX_HUNK_LAST) && src->file_pos == src->file_last) {
|
||||
dst->type |= NGX_HUNK_LAST;
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
return ngx_output_chain(ctx, in);
|
||||
}
|
||||
|
||||
|
||||
@ -340,7 +103,7 @@ static char *ngx_http_output_filter_merge_conf(ngx_conf_t *cf,
|
||||
ngx_http_output_filter_conf_t *prev = parent;
|
||||
ngx_http_output_filter_conf_t *conf = child;
|
||||
|
||||
ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, 2, 32768);
|
||||
ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, 1, 32768);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -23,14 +23,14 @@ static void ngx_http_set_lingering_close(ngx_http_request_t *r);
|
||||
static void ngx_http_lingering_close_handler(ngx_event_t *ev);
|
||||
static void ngx_http_empty_handler(ngx_event_t *wev);
|
||||
|
||||
static void ngx_http_header_parse_error(ngx_http_request_t *r,
|
||||
int parse_err, int error);
|
||||
static void ngx_http_client_error(ngx_http_request_t *r,
|
||||
int client_error, int error);
|
||||
static size_t ngx_http_log_error(void *data, char *buf, size_t len);
|
||||
|
||||
|
||||
/* NGX_HTTP_PARSE_ ... errors */
|
||||
/* NGX_HTTP_PARSE_... errors */
|
||||
|
||||
static char *header_errors[] = {
|
||||
static char *client_header_errors[] = {
|
||||
"client %s sent invalid method",
|
||||
"client %s sent invalid request",
|
||||
"client %s sent too long URI",
|
||||
@ -66,6 +66,12 @@ static ngx_http_header_t headers_in[] = {
|
||||
};
|
||||
|
||||
|
||||
static void ngx_http_dummy(ngx_event_t *wev)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void ngx_http_init_connection(ngx_connection_t *c)
|
||||
{
|
||||
ngx_event_t *rev;
|
||||
@ -117,6 +123,16 @@ void ngx_http_init_connection(ngx_connection_t *c)
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
#if 0
|
||||
c->write->ready = 0;
|
||||
c->write->event_handler = ngx_http_dummy;
|
||||
|
||||
if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) {
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -135,6 +151,12 @@ static void ngx_http_init_request(ngx_event_t *rev)
|
||||
|
||||
c = rev->data;
|
||||
|
||||
if (rev->timedout) {
|
||||
ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
if (c->data) {
|
||||
r = c->data;
|
||||
ngx_memzero(r, sizeof(ngx_http_request_t));
|
||||
@ -281,8 +303,7 @@ static void ngx_http_process_request_line(ngx_event_t *rev)
|
||||
ngx_log_debug(rev->log, "http process request line");
|
||||
|
||||
if (rev->timedout) {
|
||||
ngx_http_close_request(r, NGX_HTTP_REQUEST_TIME_OUT);
|
||||
ngx_http_close_connection(c);
|
||||
ngx_http_client_error(r, 0, NGX_HTTP_REQUEST_TIME_OUT);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -304,8 +325,8 @@ static void ngx_http_process_request_line(ngx_event_t *rev)
|
||||
r->request_line.data = r->request_start;
|
||||
r->request_line.data[r->request_line.len] = '\0';
|
||||
|
||||
ngx_http_header_parse_error(r, NGX_HTTP_PARSE_INVALID_REQUEST,
|
||||
NGX_HTTP_BAD_REQUEST);
|
||||
ngx_http_client_error(r, NGX_HTTP_PARSE_INVALID_REQUEST,
|
||||
NGX_HTTP_BAD_REQUEST);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -317,8 +338,8 @@ static void ngx_http_process_request_line(ngx_event_t *rev)
|
||||
{
|
||||
/* no space for "\r\n" at the end of the header */
|
||||
|
||||
ngx_http_header_parse_error(r, NGX_HTTP_PARSE_TOO_LONG_URI,
|
||||
NGX_HTTP_REQUEST_URI_TOO_LARGE);
|
||||
ngx_http_client_error(r, NGX_HTTP_PARSE_TOO_LONG_URI,
|
||||
NGX_HTTP_REQUEST_URI_TOO_LARGE);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -447,7 +468,7 @@ static void ngx_http_process_request_line(ngx_event_t *rev)
|
||||
|
||||
/* there was error while a request line parsing */
|
||||
|
||||
ngx_http_header_parse_error(r, rc, NGX_HTTP_BAD_REQUEST);
|
||||
ngx_http_client_error(r, rc, NGX_HTTP_BAD_REQUEST);
|
||||
|
||||
return;
|
||||
}
|
||||
@ -470,8 +491,8 @@ static void ngx_http_process_request_line(ngx_event_t *rev)
|
||||
offset = r->request_start - r->header_in->start;
|
||||
|
||||
if (offset == 0) {
|
||||
ngx_http_header_parse_error(r, NGX_HTTP_PARSE_TOO_LONG_URI,
|
||||
NGX_HTTP_REQUEST_URI_TOO_LARGE);
|
||||
ngx_http_client_error(r, NGX_HTTP_PARSE_TOO_LONG_URI,
|
||||
NGX_HTTP_REQUEST_URI_TOO_LARGE);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -492,8 +513,8 @@ static void ngx_http_process_request_line(ngx_event_t *rev)
|
||||
}
|
||||
|
||||
} else {
|
||||
ngx_http_header_parse_error(r, NGX_HTTP_PARSE_TOO_LONG_URI,
|
||||
NGX_HTTP_REQUEST_URI_TOO_LARGE);
|
||||
ngx_http_client_error(r, NGX_HTTP_PARSE_TOO_LONG_URI,
|
||||
NGX_HTTP_REQUEST_URI_TOO_LARGE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -516,8 +537,7 @@ static void ngx_http_process_request_headers(ngx_event_t *rev)
|
||||
ngx_log_debug(rev->log, "http process request header line");
|
||||
|
||||
if (rev->timedout) {
|
||||
ngx_http_close_request(r, NGX_HTTP_REQUEST_TIME_OUT);
|
||||
ngx_http_close_connection(c);
|
||||
ngx_http_client_error(r, 0, NGX_HTTP_REQUEST_TIME_OUT);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -605,7 +625,7 @@ static void ngx_http_process_request_headers(ngx_event_t *rev)
|
||||
rc = ngx_http_process_request_header(r);
|
||||
|
||||
if (rc != NGX_OK) {
|
||||
ngx_http_header_parse_error(r, rc, NGX_HTTP_BAD_REQUEST);
|
||||
ngx_http_client_error(r, rc, NGX_HTTP_BAD_REQUEST);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -621,7 +641,7 @@ static void ngx_http_process_request_headers(ngx_event_t *rev)
|
||||
|
||||
/* there was error while a header line parsing */
|
||||
|
||||
ngx_http_header_parse_error(r, rc, NGX_HTTP_BAD_REQUEST);
|
||||
ngx_http_client_error(r, rc, NGX_HTTP_BAD_REQUEST);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -636,9 +656,8 @@ static void ngx_http_process_request_headers(ngx_event_t *rev)
|
||||
offset = r->header_name_start - r->header_in->start;
|
||||
|
||||
if (offset == 0) {
|
||||
ngx_http_header_parse_error(r,
|
||||
NGX_HTTP_PARSE_TOO_LONG_HEADER,
|
||||
NGX_HTTP_BAD_REQUEST);
|
||||
ngx_http_client_error(r, NGX_HTTP_PARSE_TOO_LONG_HEADER,
|
||||
NGX_HTTP_BAD_REQUEST);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -653,8 +672,8 @@ static void ngx_http_process_request_headers(ngx_event_t *rev)
|
||||
r->header_end -= offset;
|
||||
|
||||
} else {
|
||||
ngx_http_header_parse_error(r, NGX_HTTP_PARSE_TOO_LONG_HEADER,
|
||||
NGX_HTTP_BAD_REQUEST);
|
||||
ngx_http_client_error(r, NGX_HTTP_PARSE_TOO_LONG_HEADER,
|
||||
NGX_HTTP_BAD_REQUEST);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -798,12 +817,14 @@ static int ngx_http_process_request_header(ngx_http_request_t *r)
|
||||
|
||||
void ngx_http_finalize_request(ngx_http_request_t *r, int rc)
|
||||
{
|
||||
ngx_log_debug(r->connection->log, "finalize http request");
|
||||
/* r can be already destroyed when rc == NGX_DONE */
|
||||
|
||||
if (rc == NGX_DONE || r->main || r->closed) {
|
||||
if (rc == NGX_DONE || r->main) {
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_log_debug(r->connection->log, "finalize http request");
|
||||
|
||||
if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
|
||||
|
||||
if (r->connection->read->timer_set) {
|
||||
@ -886,6 +907,17 @@ void ngx_http_writer(ngx_event_t *wev)
|
||||
c = wev->data;
|
||||
r = c->data;
|
||||
|
||||
#if 0 /* TODO: THINK */
|
||||
if (wev->delayed) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (wev->timedout) {
|
||||
ngx_http_client_error(r, 0, NGX_HTTP_REQUEST_TIME_OUT);
|
||||
return;
|
||||
}
|
||||
|
||||
rc = ngx_http_output_filter(r, NULL);
|
||||
|
||||
ngx_log_debug(c->log, "writer output filter: %d" _ rc);
|
||||
@ -1356,8 +1388,6 @@ void ngx_http_close_request(ngx_http_request_t *r, int error)
|
||||
|
||||
ngx_destroy_pool(r->pool);
|
||||
|
||||
r->closed = 1;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1405,23 +1435,32 @@ void ngx_http_close_connection(ngx_connection_t *c)
|
||||
}
|
||||
|
||||
|
||||
static void ngx_http_header_parse_error(ngx_http_request_t *r,
|
||||
int parse_err, int error)
|
||||
static void ngx_http_client_error(ngx_http_request_t *r,
|
||||
int client_error, int error)
|
||||
{
|
||||
ngx_http_log_ctx_t *ctx;
|
||||
|
||||
ctx = r->connection->log->data;
|
||||
|
||||
if (error == NGX_HTTP_REQUEST_TIME_OUT) {
|
||||
ngx_log_error(NGX_LOG_INFO, r->connection->log, NGX_ETIMEDOUT,
|
||||
"client timed out");
|
||||
ngx_http_close_request(r, error);
|
||||
ngx_http_close_connection(r->connection);
|
||||
return;
|
||||
}
|
||||
|
||||
r->connection->log->handler = NULL;
|
||||
|
||||
if (ctx->url) {
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
header_errors[parse_err - NGX_HTTP_PARSE_INVALID_METHOD],
|
||||
ctx->client, ctx->url);
|
||||
client_header_errors[client_error - NGX_HTTP_CLIENT_ERROR],
|
||||
ctx->client, ctx->url);
|
||||
|
||||
} else {
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
header_errors[parse_err - NGX_HTTP_PARSE_INVALID_METHOD],
|
||||
ctx->client);
|
||||
client_header_errors[client_error - NGX_HTTP_CLIENT_ERROR],
|
||||
ctx->client);
|
||||
}
|
||||
|
||||
r->connection->log->handler = ngx_http_log_error;
|
||||
|
@ -18,10 +18,14 @@
|
||||
|
||||
|
||||
#define NGX_HTTP_PARSE_HEADER_DONE 1
|
||||
|
||||
#define NGX_HTTP_CLIENT_ERROR 10
|
||||
#define NGX_HTTP_PARSE_INVALID_METHOD 10
|
||||
#define NGX_HTTP_PARSE_INVALID_REQUEST 11
|
||||
#define NGX_HTTP_PARSE_TOO_LONG_URI 12
|
||||
#define NGX_HTTP_PARSE_INVALID_09_METHOD 13
|
||||
|
||||
#define NGX_HTTP_PARSE_HEADER_ERROR 14
|
||||
#define NGX_HTTP_PARSE_INVALID_HEADER 14
|
||||
#define NGX_HTTP_PARSE_TOO_LONG_HEADER 15
|
||||
#define NGX_HTTP_PARSE_NO_HOST_HEADER 16
|
||||
@ -176,6 +180,13 @@ struct ngx_http_request_s {
|
||||
int phase_handler;
|
||||
ngx_http_handler_pt content_handler;
|
||||
|
||||
ngx_temp_file_t *temp_file;
|
||||
ngx_chain_t *request_hunks;
|
||||
ngx_hunk_t *request_body_hunk;
|
||||
int request_body_len;
|
||||
void (*request_body_handler) (void *data);
|
||||
void *data;
|
||||
|
||||
char *discarded_buffer;
|
||||
|
||||
/* URI is not started with '/' - "GET http://" */
|
||||
@ -197,7 +208,9 @@ struct ngx_http_request_s {
|
||||
unsigned header_only:1;
|
||||
unsigned keepalive:1;
|
||||
unsigned lingering_close:1;
|
||||
#if 0
|
||||
unsigned closed:1;
|
||||
#endif
|
||||
|
||||
/* TODO: use filter or bits ???? */
|
||||
int filter;
|
||||
|
@ -1,196 +1,156 @@
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_event.h>
|
||||
#include <ngx_http.h>
|
||||
|
||||
|
||||
int ngx_http_init_client_request_body(ngx_http_request_t *r, int size)
|
||||
static void ngx_http_read_client_request_body_handler(ngx_event_t *rev);
|
||||
|
||||
|
||||
int ngx_http_read_client_request_body(ngx_http_request_t *r,
|
||||
int request_buffer_size)
|
||||
{
|
||||
int header_in_part, len;
|
||||
ngx_hunk_t *h;
|
||||
ngx_http_request_body_t *rb;
|
||||
ssize_t size;
|
||||
ngx_hunk_t *h;
|
||||
ngx_chain_t *cl;
|
||||
|
||||
ngx_test_null(rb, ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)),
|
||||
NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||
size = r->header_in->last - r->header_in->pos;
|
||||
|
||||
header_in_part = r->header_in->end - r->header_in->pos;
|
||||
if (size) {
|
||||
ngx_test_null(h, ngx_calloc_hunk(r->pool),
|
||||
NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||
|
||||
if (header_in_part) {
|
||||
rb->header_in_pos = r->header_in->pos;
|
||||
h->type = NGX_HUNK_IN_MEMORY|NGX_HUNK_TEMP;
|
||||
h->start = h->pos = r->header_in->pos;
|
||||
h->end = h->last = r->header_in->last;
|
||||
|
||||
ngx_alloc_link_and_set_hunk(r->request_hunks, h, r->pool,
|
||||
NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||
|
||||
if (size >= r->headers_in.content_length_n) {
|
||||
r->header_in->pos += r->headers_in.content_length_n;
|
||||
return NGX_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (header_in_part > r->headers_in.content_length_n) {
|
||||
header_in_part = r->headers_in.content_length_n;
|
||||
r->request_body_len = r->headers_in.content_length_n - size;
|
||||
|
||||
if (r->request_body_len < request_buffer_size + (request_buffer_size >> 2))
|
||||
{
|
||||
size = r->request_body_len;
|
||||
|
||||
} else {
|
||||
len = r->headers_in.content_length_n - header_in_part;
|
||||
if (len > size) {
|
||||
len = size;
|
||||
|
||||
} else if (len > NGX_PAGE_SIZE) {
|
||||
len = ((len + NGX_PAGE_SIZE - 1) / NGX_PAGE_SIZE) * NGX_PAGE_SIZE;
|
||||
}
|
||||
|
||||
if (len) {
|
||||
ngx_test_null(rb->hunk, ngx_create_temp_hunk(r->pool, len, 0, 0),
|
||||
NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
size = request_buffer_size;
|
||||
}
|
||||
|
||||
r->request_body = rb;
|
||||
ngx_test_null(r->request_body_hunk,
|
||||
ngx_create_temp_hunk(r->pool, size, 0, 0),
|
||||
NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||
|
||||
r->connection->read->event_handler =
|
||||
ngx_http_read_client_request_body_handler;
|
||||
|
||||
ngx_http_read_client_request_body_handler(r->connection->read);
|
||||
|
||||
ngx_alloc_link_and_set_hunk(cl, r->request_body_hunk, r->pool,
|
||||
NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||
|
||||
if (r->request_hunks) {
|
||||
r->request_hunks->next = cl;
|
||||
|
||||
} else {
|
||||
r->request_hunks = cl;
|
||||
}
|
||||
|
||||
if (r->request_body_len) {
|
||||
return NGX_AGAIN;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
int ngx_http_read_client_request_body(ngx_http_request_t *r)
|
||||
static void ngx_http_read_client_request_body_handler(ngx_event_t *rev)
|
||||
{
|
||||
int size, n, rc;
|
||||
ngx_chain_t *entry;
|
||||
ngx_http_request_body_t *rb;
|
||||
ssize_t n, size;
|
||||
ngx_hunk_t *h;
|
||||
ngx_connection_t *c;
|
||||
ngx_http_request_t *r;
|
||||
|
||||
rb = r->request_body;
|
||||
c = rev->data;
|
||||
r = c->data;
|
||||
|
||||
do {
|
||||
if (r->header_in->last < r->header_in->end) {
|
||||
rb->chain[0].hunk = r->header_in;
|
||||
if (r->request_body_hunk->end - r->request_body_hunk->last == 0) {
|
||||
n = ngx_write_chain_to_temp_file(r->temp_file,
|
||||
r->request_hunks->next ? r->request_hunks->next:
|
||||
r->request_hunks);
|
||||
/* TODO: n == 0 or not complete and level event */
|
||||
|
||||
if (rb->hunk) {
|
||||
rb->chain[0].next = &rb->chain[1];
|
||||
rb->chain[1].hunk = rb->hunk;
|
||||
rb->chain[1].next = NULL;
|
||||
r->request_body_hunk->pos = r->request_body_hunk->start;
|
||||
r->request_body_hunk->last = r->request_body_hunk->start;
|
||||
}
|
||||
|
||||
} else {
|
||||
rb->chain[0].next = NULL;
|
||||
}
|
||||
size = r->request_body_hunk->end - r->request_body_hunk->last;
|
||||
|
||||
if (size > r->request_body_len) {
|
||||
size = r->request_body_len;
|
||||
}
|
||||
|
||||
n = ngx_recv(c, r->request_body_hunk->last, size);
|
||||
|
||||
if (n == NGX_AGAIN) {
|
||||
if (ngx_handle_read_event(rev) == NGX_ERROR) {
|
||||
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
ngx_log_error(NGX_LOG_INFO, c->log, 0,
|
||||
"client closed prematurely connection");
|
||||
}
|
||||
|
||||
if (n == 0 || n == NGX_ERROR) {
|
||||
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
|
||||
return;
|
||||
}
|
||||
|
||||
r->request_body_hunk->last += n;
|
||||
r->request_body_len -= n;
|
||||
|
||||
if (r->request_body_len) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (r->temp_file->file.fd != NGX_INVALID_FILE) {
|
||||
|
||||
/* save the last part */
|
||||
n = ngx_write_chain_to_temp_file(r->temp_file,
|
||||
r->request_hunks->next ? r->request_hunks->next:
|
||||
r->request_hunks);
|
||||
/* TODO: n == 0 or not complete and level event */
|
||||
|
||||
|
||||
h = ngx_calloc_hunk(r->pool);
|
||||
if (h == NULL) {
|
||||
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
h->type = NGX_HUNK_FILE;
|
||||
h->file_pos = 0;
|
||||
h->file_last = r->temp_file->file.offset;
|
||||
h->file = &r->temp_file->file;
|
||||
|
||||
if (r->request_hunks->next) {
|
||||
r->request_hunks->next->hunk = h;
|
||||
|
||||
} else {
|
||||
rb->chain[0].hunk = rb->hunk;
|
||||
rb->chain[0].next = NULL;
|
||||
r->request_hunks->hunk = h;
|
||||
}
|
||||
}
|
||||
|
||||
n = ngx_recv_chain(r->connection, rb->chain);
|
||||
|
||||
if (n == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (n == NGX_AGAIN) {
|
||||
return NGX_AGAIN;
|
||||
}
|
||||
|
||||
for (entry = rb->chain; entry; entry = entry->next) {
|
||||
size = entry->hunk->end - entry->hunk->last;
|
||||
|
||||
if (n >= size) {
|
||||
n -= size;
|
||||
entry->hunk->last = entry->hunk->end;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
entry->hunk->last += n;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (rb->hunk && rb->hunk->last == rb->hunk->end) {
|
||||
if (rb->temp_file.fd == NGX_INVALID_FILE) {
|
||||
rc = ngx_create_temp_file(&rb->temp_file, rb->temp_path,
|
||||
r->pool, 0);
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (rc == NGX_AGAIN) {
|
||||
return NGX_AGAIN;
|
||||
}
|
||||
}
|
||||
|
||||
n = ngx_write_file(&rb->temp_file, rb->hunk->pos,
|
||||
rb->hunk->last - rb->hunk->pos, rb->offset);
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
rb->offset += n;
|
||||
rb->hunk->last = rb->hunk->pos;
|
||||
}
|
||||
|
||||
} while (r->connection->read->ready);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
int ngx_http_init_client_request_body_chain(ngx_http_request_t *r)
|
||||
{
|
||||
int i;
|
||||
ngx_hunk_t *h;
|
||||
ngx_http_request_body_t *rb;
|
||||
|
||||
rb = r->request_body;
|
||||
|
||||
rb->chain[0].hunk = rb->header_out;
|
||||
i = 0;
|
||||
|
||||
if (r->header_in->pos < r->header_in->last) {
|
||||
rb->chain[i].next = &rb->chain[i + 1];
|
||||
i++;
|
||||
rb->chain[i].hunk = r->header_in;
|
||||
}
|
||||
|
||||
if (rb->temp_file.fd != NGX_INVALID_FILE) {
|
||||
|
||||
if (rb->file_hunk == NULL) {
|
||||
ngx_test_null(h, ngx_alloc_hunk(r->pool), NGX_ERROR);
|
||||
|
||||
h->type = NGX_HUNK_FILE;
|
||||
h->pos = h->start = h->pre_start = 0;
|
||||
h->last = h->end = h->post_end = 0;
|
||||
h->file_pos = 0;
|
||||
h->file_last = rb->offset;
|
||||
h->file = &rb->temp_file;
|
||||
h->shadow = NULL;
|
||||
h->tag = 0;
|
||||
|
||||
rb->file_hunk = h;
|
||||
}
|
||||
|
||||
rb->chain[i].next = &rb->chain[i + 1];
|
||||
i++;
|
||||
rb->chain[i].hunk = rb->file_hunk;
|
||||
}
|
||||
|
||||
if (rb->hunk && rb->hunk->pos < rb->hunk->last) {
|
||||
rb->chain[i].next = &rb->chain[i + 1];
|
||||
i++;
|
||||
rb->chain[i].hunk = h;
|
||||
}
|
||||
|
||||
rb->chain[i].next = NULL;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
void ngx_http_reinit_client_request_body_hunks(ngx_http_request_t *r)
|
||||
{
|
||||
ngx_http_request_body_t *rb;
|
||||
|
||||
rb = r->request_body;
|
||||
|
||||
if (rb->header_in_pos) {
|
||||
r->header_in->pos = rb->header_in_pos;
|
||||
}
|
||||
|
||||
if (rb->file_hunk) {
|
||||
rb->file_hunk->file_pos = 0;
|
||||
}
|
||||
|
||||
if (rb->hunk) {
|
||||
rb->hunk->pos = rb->hunk->start;
|
||||
}
|
||||
r->request_body_handler(r->data);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user