# HG changeset patch # User Igor Sysoev # Date 1267613018 0 # Node ID bbea0b19b6087a9c262d44aed04e69f2c2cdda7c # Parent 958f8de0c45fd525e1d02322b21031febc9057f8 fix cached FastCGI response with large stderr output before header diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -62,7 +62,8 @@ typedef struct { size_t length; size_t padding; - ngx_uint_t fastcgi_stdout; /* unsigned :1 */ + unsigned fastcgi_stdout:1; + unsigned large_stderr:1; ngx_array_t *split_parts; @@ -1081,6 +1082,7 @@ ngx_http_fastcgi_reinit_request(ngx_http f->state = ngx_http_fastcgi_st_version; f->fastcgi_stdout = 0; + f->large_stderr = 0; return NGX_OK; } @@ -1099,6 +1101,7 @@ ngx_http_fastcgi_process_header(ngx_http ngx_table_elt_t *h; ngx_http_upstream_t *u; ngx_http_fastcgi_ctx_t *f; + ngx_http_fastcgi_header_t *fh; ngx_http_upstream_header_t *hh; ngx_http_fastcgi_loc_conf_t *flcf; ngx_http_fastcgi_split_part_t *part; @@ -1223,8 +1226,17 @@ ngx_http_fastcgi_process_header(ngx_http * of the PHP warnings to not allocate memory */ - u->buffer.pos = u->buffer.start; - u->buffer.last = u->buffer.start; +#if (NGX_HTTP_CACHE) + if (r->cache) { + u->buffer.pos = u->buffer.start + + r->cache->header_start; + } else { + u->buffer.pos = u->buffer.start; + } +#endif + + u->buffer.last = u->buffer.pos; + f->large_stderr = 1; } return NGX_AGAIN; @@ -1240,6 +1252,45 @@ ngx_http_fastcgi_process_header(ngx_http /* f->type == NGX_HTTP_FASTCGI_STDOUT */ +#if (NGX_HTTP_CACHE) + + if (f->large_stderr) { + u_char *start; + ssize_t len; + + start = u->buffer.start + r->cache->header_start; + + len = u->buffer.pos - start - 2 * sizeof(ngx_http_fastcgi_header_t); + + /* + * A tail of large stderr output before HTTP header is placed + * in a cache file without a FastCGI record header. + * To workaround it we put a dummy FastCGI record header at the + * start of the stderr output or update r->cache_header_start, + * if there is no enough place for the record header. + */ + + if (len >= 0) { + fh = (ngx_http_fastcgi_header_t *) start; + fh->version = 1; + fh->type = NGX_HTTP_FASTCGI_STDERR; + fh->request_id_hi = 0; + fh->request_id_lo = 1; + fh->content_length_hi = (u_char) ((len >> 8) & 0xff); + fh->content_length_lo = (u_char) (len & 0xff); + fh->padding_length = 0; + fh->reserved = 0; + + } else { + r->cache->header_start += u->buffer.pos - start + - sizeof(ngx_http_fastcgi_header_t); + } + + f->large_stderr = 0; + } + +#endif + f->fastcgi_stdout = 1; start = u->buffer.pos; diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c --- a/src/http/ngx_http_file_cache.c +++ b/src/http/ngx_http_file_cache.c @@ -346,7 +346,7 @@ ngx_http_file_cache_read(ngx_http_reques h = (ngx_http_file_cache_header_t *) c->buf->pos; - if (h->crc32 != c->crc32 || (size_t) h->header_start != c->header_start) { + if (h->crc32 != c->crc32) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0, "cache file \"%s\" has md5 collision", c->file.name.data); return NGX_DECLINED; @@ -358,6 +358,7 @@ ngx_http_file_cache_read(ngx_http_reques c->last_modified = h->last_modified; c->date = h->date; c->valid_msec = h->valid_msec; + c->header_start = h->header_start; c->body_start = h->body_start; r->cached = 1;