static ngx_int_t
ngx_http_fastcgi_process_header(ngx_http_request_t *r)
{
    u_char                         *p, *msg, *start, *last,
                                   *part_start, *part_end;
    size_t                          size;
    ngx_str_t                      *status_line, *pattern;
    ngx_int_t                       rc, status;
    ngx_buf_t                       buf;
    ngx_uint_t                      i;
    ngx_table_elt_t                *h;
    ngx_http_upstream_t            *u;
    ngx_http_fastcgi_ctx_t         *f;
    ngx_http_upstream_header_t     *hh;
    ngx_http_fastcgi_loc_conf_t    *flcf;
    ngx_http_fastcgi_split_part_t  *part;
    ngx_http_upstream_main_conf_t  *umcf;
    f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
    umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
    u = r->upstream;
    for ( ;; ) {
        if (f->state < ngx_http_fastcgi_st_data) {
            f->pos = u->buffer.pos;
            f->last = u->buffer.last;
            rc = ngx_http_fastcgi_process_record(r, f);
            u->buffer.pos = f->pos;
            u->buffer.last = f->last;
            if (rc == NGX_AGAIN) {
                return NGX_AGAIN;
            }
            if (rc == NGX_ERROR) {
                return NGX_HTTP_UPSTREAM_INVALID_HEADER;
            }
            if (f->type != NGX_HTTP_FASTCGI_STDOUT
                && f->type != NGX_HTTP_FASTCGI_STDERR)
            {
                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                              "upstream sent unexpected FastCGI record: %d",
                              f->type);
                return NGX_HTTP_UPSTREAM_INVALID_HEADER;
            }
            if (f->type == NGX_HTTP_FASTCGI_STDOUT && f->length == 0) {
                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                              "upstream closed prematurely FastCGI stdout");
                return NGX_HTTP_UPSTREAM_INVALID_HEADER;
            }
        }
        if (f->state == ngx_http_fastcgi_st_padding) {
            if (u->buffer.pos + f->padding < u->buffer.last) {
                f->state = ngx_http_fastcgi_st_version;
                u->buffer.pos += f->padding;
                continue;
            }
            if (u->buffer.pos + f->padding == u->buffer.last) {
                f->state = ngx_http_fastcgi_st_version;
                u->buffer.pos = u->buffer.last;
                return NGX_AGAIN;
            }
            f->padding -= u->buffer.last - u->buffer.pos;
            u->buffer.pos = u->buffer.last;
            return NGX_AGAIN;
        }
        if (f->type == NGX_HTTP_FASTCGI_STDERR) {
            if (f->length) {
                msg = u->buffer.pos;
                if (u->buffer.pos + f->length <= u->buffer.last) {
                    u->buffer.pos += f->length;
                    f->length = 0;
                    f->state = ngx_http_fastcgi_st_padding;
                } else {
                    f->length -= u->buffer.last - u->buffer.pos;
                    u->buffer.pos = u->buffer.last;
                }
                for (p = u->buffer.pos - 1; msg < p; p--) {
                    if (*p != LF && *p != CR && *p != '.' && *p != ' ') {
                        break;
                    }
                }
                p++;
                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                              "FastCGI sent in stderr: \"%*s\"", p - msg, msg);
                flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
                if (flcf->catch_stderr) {
                    pattern = flcf->catch_stderr->elts;
                    for (i = 0; i < flcf->catch_stderr->nelts; i++) {
                        if (ngx_strnstr(msg, (char *) pattern[i].data,
                                        p - msg)
                            != NULL)
                        {
                            return NGX_HTTP_UPSTREAM_INVALID_HEADER;
                        }
                    }
                }
                if (u->buffer.pos == u->buffer.last) {
                    if (!f->fastcgi_stdout) {
                        u->buffer.pos = u->buffer.start;
                        u->buffer.last = u->buffer.start;
                    }
                    return NGX_AGAIN;
                }
            } else {
                f->state = ngx_http_fastcgi_st_version;
            }
            continue;
        }
        f->fastcgi_stdout = 1;
        start = u->buffer.pos;
        if (u->buffer.pos + f->length < u->buffer.last) {
            last = u->buffer.last;
            u->buffer.last = u->buffer.pos + f->length;
        } else {
            last = NULL;
        }
        for ( ;; ) {
            part_start = u->buffer.pos;
            part_end = u->buffer.last;
            rc = ngx_http_parse_header_line(r, &u->buffer, 1);
            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                           "http fastcgi parser: %d", rc);
            if (rc == NGX_AGAIN) {
                break;
            }
            if (rc == NGX_OK) {
                h = ngx_list_push(&u->headers_in.headers);
                if (h == NULL) {
                    return NGX_ERROR;
                }
                if (f->split_parts && f->split_parts->nelts) {
                    part = f->split_parts->elts;
                    size = u->buffer.pos - part_start;
                    for (i = 0; i < f->split_parts->nelts; i++) {
                        size += part[i].end - part[i].start;
                    }
                    p = ngx_pnalloc(r->pool, size);
                    if (p == NULL) {
                        return NGX_ERROR;
                    }
                    buf.pos = p;
                    for (i = 0; i < f->split_parts->nelts; i++) {
                        p = ngx_cpymem(p, part[i].start,
                                       part[i].end - part[i].start);
                    }
                    p = ngx_cpymem(p, part_start, u->buffer.pos - part_start);
                    buf.last = p;
                    f->split_parts->nelts = 0;
                    rc = ngx_http_parse_header_line(r, &buf, 1);
                    h->key.len = r->header_name_end - r->header_name_start;
                    h->key.data = r->header_name_start;
                    h->key.data[h->key.len] = '\0';
                    h->value.len = r->header_end - r->header_start;
                    h->value.data = r->header_start;
                    h->value.data[h->value.len] = '\0';
                    h->lowcase_key = ngx_pnalloc(r->pool, h->key.len);
                    if (h->lowcase_key == NULL) {
                        return NGX_ERROR;
                    }
                } else {
                    h->key.len = r->header_name_end - r->header_name_start;
                    h->value.len = r->header_end - r->header_start;
                    h->key.data = ngx_pnalloc(r->pool,
                                              h->key.len + 1 + h->value.len + 1
                                              + h->key.len);
                    if (h->key.data == NULL) {
                        return NGX_ERROR;
                    }
                    h->value.data = h->key.data + h->key.len + 1;
                    h->lowcase_key = h->key.data + h->key.len + 1
                                     + h->value.len + 1;
                    ngx_cpystrn(h->key.data, r->header_name_start,
                                h->key.len + 1);
                    ngx_cpystrn(h->value.data, r->header_start,
                                h->value.len + 1);
                }
                h->hash = r->header_hash;
                if (h->key.len == r->lowcase_index) {
                    ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len);
                } else {
                    ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
                }
                hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
                                   h->lowcase_key, h->key.len);
                if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
                    return NGX_ERROR;
                }
                ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                               "http fastcgi header: \"%V: %V\"",
                               &h->key, &h->value);
                if (u->buffer.pos < u->buffer.last) {
                    continue;
                }
                break;
            }
            if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
                ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                               "http fastcgi header done");
                if (u->headers_in.status) {
                    status_line = &u->headers_in.status->value;
                    status = ngx_atoi(status_line->data, 3);
                    if (status == NGX_ERROR) {
                        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                                      "upstream sent invalid status \"%V\"",
                                      status_line);
                        return NGX_HTTP_UPSTREAM_INVALID_HEADER;
                    }
                    u->headers_in.status_n = status;
                    u->headers_in.status_line = *status_line;
                } else if (u->headers_in.location) {
                    u->headers_in.status_n = 302;
                    u->headers_in.status_line.len =
                                           sizeof("302 Moved Temporarily") - 1;
                    u->headers_in.status_line.data =
                                           (u_char *) "302 Moved Temporarily";
                } else {
                    u->headers_in.status_n = 200;
                    u->headers_in.status_line.len = sizeof("200 OK") - 1;
                    u->headers_in.status_line.data = (u_char *) "200 OK";
                }
                if (u->state) {
                    u->state->status = u->headers_in.status_n;
                }
                break;
            }
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "upstream sent invalid header");
            return NGX_HTTP_UPSTREAM_INVALID_HEADER;
        }
        if (last) {
            u->buffer.last = last;
        }
        f->length -= u->buffer.pos - start;
        if (f->length == 0) {
            if (f->padding) {
                f->state = ngx_http_fastcgi_st_padding;
            } else {
                f->state = ngx_http_fastcgi_st_version;
            }
        }
        if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
            return NGX_OK;
        }
        if (rc == NGX_OK) {
            continue;
        }
        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "upstream split a header line in FastCGI records");
        if (f->split_parts == NULL) {
            f->split_parts = ngx_array_create(r->pool, 1,
                                        sizeof(ngx_http_fastcgi_split_part_t));
            if (f->split_parts == NULL) {
                return NGX_ERROR;
            }
        }
        part = ngx_array_push(f->split_parts);
        part->start = part_start;
        part->end = part_end;
        if (u->buffer.pos < u->buffer.last) {
            continue;
        }
        return NGX_AGAIN;
    }
}
['static ngx_int_t\nngx_http_fastcgi_process_header(ngx_http_request_t *r)\n{\n    u_char                         *p, *msg, *start, *last,\n                                   *part_start, *part_end;\n    size_t                          size;\n    ngx_str_t                      *status_line, *pattern;\n    ngx_int_t                       rc, status;\n    ngx_buf_t                       buf;\n    ngx_uint_t                      i;\n    ngx_table_elt_t                *h;\n    ngx_http_upstream_t            *u;\n    ngx_http_fastcgi_ctx_t         *f;\n    ngx_http_upstream_header_t     *hh;\n    ngx_http_fastcgi_loc_conf_t    *flcf;\n    ngx_http_fastcgi_split_part_t  *part;\n    ngx_http_upstream_main_conf_t  *umcf;\n    f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);\n    umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);\n    u = r->upstream;\n    for ( ;; ) {\n        if (f->state < ngx_http_fastcgi_st_data) {\n            f->pos = u->buffer.pos;\n            f->last = u->buffer.last;\n            rc = ngx_http_fastcgi_process_record(r, f);\n            u->buffer.pos = f->pos;\n            u->buffer.last = f->last;\n            if (rc == NGX_AGAIN) {\n                return NGX_AGAIN;\n            }\n            if (rc == NGX_ERROR) {\n                return NGX_HTTP_UPSTREAM_INVALID_HEADER;\n            }\n            if (f->type != NGX_HTTP_FASTCGI_STDOUT\n                && f->type != NGX_HTTP_FASTCGI_STDERR)\n            {\n                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,\n                              "upstream sent unexpected FastCGI record: %d",\n                              f->type);\n                return NGX_HTTP_UPSTREAM_INVALID_HEADER;\n            }\n            if (f->type == NGX_HTTP_FASTCGI_STDOUT && f->length == 0) {\n                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,\n                              "upstream closed prematurely FastCGI stdout");\n                return NGX_HTTP_UPSTREAM_INVALID_HEADER;\n            }\n        }\n        if (f->state == ngx_http_fastcgi_st_padding) {\n            if (u->buffer.pos + f->padding < u->buffer.last) {\n                f->state = ngx_http_fastcgi_st_version;\n                u->buffer.pos += f->padding;\n                continue;\n            }\n            if (u->buffer.pos + f->padding == u->buffer.last) {\n                f->state = ngx_http_fastcgi_st_version;\n                u->buffer.pos = u->buffer.last;\n                return NGX_AGAIN;\n            }\n            f->padding -= u->buffer.last - u->buffer.pos;\n            u->buffer.pos = u->buffer.last;\n            return NGX_AGAIN;\n        }\n        if (f->type == NGX_HTTP_FASTCGI_STDERR) {\n            if (f->length) {\n                msg = u->buffer.pos;\n                if (u->buffer.pos + f->length <= u->buffer.last) {\n                    u->buffer.pos += f->length;\n                    f->length = 0;\n                    f->state = ngx_http_fastcgi_st_padding;\n                } else {\n                    f->length -= u->buffer.last - u->buffer.pos;\n                    u->buffer.pos = u->buffer.last;\n                }\n                for (p = u->buffer.pos - 1; msg < p; p--) {\n                    if (*p != LF && *p != CR && *p != \'.\' && *p != \' \') {\n                        break;\n                    }\n                }\n                p++;\n                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,\n                              "FastCGI sent in stderr: \\"%*s\\"", p - msg, msg);\n                flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);\n                if (flcf->catch_stderr) {\n                    pattern = flcf->catch_stderr->elts;\n                    for (i = 0; i < flcf->catch_stderr->nelts; i++) {\n                        if (ngx_strnstr(msg, (char *) pattern[i].data,\n                                        p - msg)\n                            != NULL)\n                        {\n                            return NGX_HTTP_UPSTREAM_INVALID_HEADER;\n                        }\n                    }\n                }\n                if (u->buffer.pos == u->buffer.last) {\n                    if (!f->fastcgi_stdout) {\n                        u->buffer.pos = u->buffer.start;\n                        u->buffer.last = u->buffer.start;\n                    }\n                    return NGX_AGAIN;\n                }\n            } else {\n                f->state = ngx_http_fastcgi_st_version;\n            }\n            continue;\n        }\n        f->fastcgi_stdout = 1;\n        start = u->buffer.pos;\n        if (u->buffer.pos + f->length < u->buffer.last) {\n            last = u->buffer.last;\n            u->buffer.last = u->buffer.pos + f->length;\n        } else {\n            last = NULL;\n        }\n        for ( ;; ) {\n            part_start = u->buffer.pos;\n            part_end = u->buffer.last;\n            rc = ngx_http_parse_header_line(r, &u->buffer, 1);\n            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,\n                           "http fastcgi parser: %d", rc);\n            if (rc == NGX_AGAIN) {\n                break;\n            }\n            if (rc == NGX_OK) {\n                h = ngx_list_push(&u->headers_in.headers);\n                if (h == NULL) {\n                    return NGX_ERROR;\n                }\n                if (f->split_parts && f->split_parts->nelts) {\n                    part = f->split_parts->elts;\n                    size = u->buffer.pos - part_start;\n                    for (i = 0; i < f->split_parts->nelts; i++) {\n                        size += part[i].end - part[i].start;\n                    }\n                    p = ngx_pnalloc(r->pool, size);\n                    if (p == NULL) {\n                        return NGX_ERROR;\n                    }\n                    buf.pos = p;\n                    for (i = 0; i < f->split_parts->nelts; i++) {\n                        p = ngx_cpymem(p, part[i].start,\n                                       part[i].end - part[i].start);\n                    }\n                    p = ngx_cpymem(p, part_start, u->buffer.pos - part_start);\n                    buf.last = p;\n                    f->split_parts->nelts = 0;\n                    rc = ngx_http_parse_header_line(r, &buf, 1);\n                    h->key.len = r->header_name_end - r->header_name_start;\n                    h->key.data = r->header_name_start;\n                    h->key.data[h->key.len] = \'\\0\';\n                    h->value.len = r->header_end - r->header_start;\n                    h->value.data = r->header_start;\n                    h->value.data[h->value.len] = \'\\0\';\n                    h->lowcase_key = ngx_pnalloc(r->pool, h->key.len);\n                    if (h->lowcase_key == NULL) {\n                        return NGX_ERROR;\n                    }\n                } else {\n                    h->key.len = r->header_name_end - r->header_name_start;\n                    h->value.len = r->header_end - r->header_start;\n                    h->key.data = ngx_pnalloc(r->pool,\n                                              h->key.len + 1 + h->value.len + 1\n                                              + h->key.len);\n                    if (h->key.data == NULL) {\n                        return NGX_ERROR;\n                    }\n                    h->value.data = h->key.data + h->key.len + 1;\n                    h->lowcase_key = h->key.data + h->key.len + 1\n                                     + h->value.len + 1;\n                    ngx_cpystrn(h->key.data, r->header_name_start,\n                                h->key.len + 1);\n                    ngx_cpystrn(h->value.data, r->header_start,\n                                h->value.len + 1);\n                }\n                h->hash = r->header_hash;\n                if (h->key.len == r->lowcase_index) {\n                    ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len);\n                } else {\n                    ngx_strlow(h->lowcase_key, h->key.data, h->key.len);\n                }\n                hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,\n                                   h->lowcase_key, h->key.len);\n                if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {\n                    return NGX_ERROR;\n                }\n                ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,\n                               "http fastcgi header: \\"%V: %V\\"",\n                               &h->key, &h->value);\n                if (u->buffer.pos < u->buffer.last) {\n                    continue;\n                }\n                break;\n            }\n            if (rc == NGX_HTTP_PARSE_HEADER_DONE) {\n                ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,\n                               "http fastcgi header done");\n                if (u->headers_in.status) {\n                    status_line = &u->headers_in.status->value;\n                    status = ngx_atoi(status_line->data, 3);\n                    if (status == NGX_ERROR) {\n                        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,\n                                      "upstream sent invalid status \\"%V\\"",\n                                      status_line);\n                        return NGX_HTTP_UPSTREAM_INVALID_HEADER;\n                    }\n                    u->headers_in.status_n = status;\n                    u->headers_in.status_line = *status_line;\n                } else if (u->headers_in.location) {\n                    u->headers_in.status_n = 302;\n                    u->headers_in.status_line.len =\n                                           sizeof("302 Moved Temporarily") - 1;\n                    u->headers_in.status_line.data =\n                                           (u_char *) "302 Moved Temporarily";\n                } else {\n                    u->headers_in.status_n = 200;\n                    u->headers_in.status_line.len = sizeof("200 OK") - 1;\n                    u->headers_in.status_line.data = (u_char *) "200 OK";\n                }\n                if (u->state) {\n                    u->state->status = u->headers_in.status_n;\n                }\n                break;\n            }\n            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,\n                          "upstream sent invalid header");\n            return NGX_HTTP_UPSTREAM_INVALID_HEADER;\n        }\n        if (last) {\n            u->buffer.last = last;\n        }\n        f->length -= u->buffer.pos - start;\n        if (f->length == 0) {\n            if (f->padding) {\n                f->state = ngx_http_fastcgi_st_padding;\n            } else {\n                f->state = ngx_http_fastcgi_st_version;\n            }\n        }\n        if (rc == NGX_HTTP_PARSE_HEADER_DONE) {\n            return NGX_OK;\n        }\n        if (rc == NGX_OK) {\n            continue;\n        }\n        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,\n                       "upstream split a header line in FastCGI records");\n        if (f->split_parts == NULL) {\n            f->split_parts = ngx_array_create(r->pool, 1,\n                                        sizeof(ngx_http_fastcgi_split_part_t));\n            if (f->split_parts == NULL) {\n                return NGX_ERROR;\n            }\n        }\n        part = ngx_array_push(f->split_parts);\n        part->start = part_start;\n        part->end = part_end;\n        if (u->buffer.pos < u->buffer.last) {\n            continue;\n        }\n        return NGX_AGAIN;\n    }\n}']