예제 #1
0
// reference: ngx_http_proxy_process_header
static ngx_int_t __decode_header(ngx_http_request_t *r)
{
    ngx_http_fetch_ctx_t * ctx = ngx_http_fetch_get_module_ctx(r);

    for (;;)
    {
        ngx_int_t rc = ngx_http_parse_header_line(r, &r->upstream->buffer, 1);

        if (rc == NGX_OK)
        {
            // a header line has been parsed successfully
            if (NGX_ERROR == __decode_header_line(r, ctx->headers_in_hash))
            {
                return NGX_ERROR;
            }
            continue;
        }

        if (rc == NGX_HTTP_PARSE_HEADER_DONE)
        {
            // a whole header has been parsed successfully
            return __finish_decode(r);
        }

        if (rc == NGX_AGAIN)
        {
            return NGX_AGAIN;
        }

        // there was error while a header line parsing
        return NGX_HTTP_UPSTREAM_INVALID_HEADER;
    }
    return NGX_ERROR;
}
static ngx_int_t
ngx_http_poller_process_header(ngx_http_request_t *r)
{
  static ngx_str_t      content_length = ngx_string("Content-Length");
  ngx_http_poller_t    *poller;
  ngx_http_upstream_t  *u;
  ngx_int_t             rc;
  ngx_str_t             name;
  ngx_str_t             value;

  poller = ngx_http_get_module_ctx(r, ngx_http_poller_module);
  if (poller == NULL) {
    return NGX_ERROR;
  }

  u = r->upstream;

  for ( ;; ) {
    rc = ngx_http_parse_header_line(r, &r->upstream->buffer, 1);

    if (rc == NGX_OK) {
      name.len = r->header_name_end - r->header_name_start;
      name.data = r->header_name_start;

      value.len = r->header_end - r->header_start;
      value.data = r->header_start;

      if (name.len == content_length.len &&
          ngx_strncasecmp(name.data, content_length.data, name.len) == 0) {
        u->headers_in.content_length_n = ngx_atoof(value.data, value.len);
      }

      if (poller->handler.header != NULL) {
	poller->handler.header(r, &name, &value);
      }

      continue;
    }

    if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
      return NGX_OK;
    }

    if (rc == NGX_AGAIN) {
      return NGX_AGAIN;
    }

    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                  "upstream sent invalid header");

    return NGX_HTTP_UPSTREAM_INVALID_HEADER;
  }
}
예제 #3
0
static ngx_int_t
zupstream_upstream_process_header(ngx_http_request_t *r)
{
    ngx_int_t                       rc;
    ngx_table_elt_t                *h;
    ngx_http_upstream_header_t     *hh;
    ngx_http_upstream_main_conf_t  *umcf;

    umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);

    for ( ;; )
    {

        rc = ngx_http_parse_header_line(r, &r->upstream->buffer, 1);

        if (rc == NGX_OK)
        {

            h = ngx_list_push(&r->upstream->headers_in.headers);
            if (h == NULL)
            {
                return NGX_ERROR;
            }

            h->hash = r->header_hash;

            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_memcpy(h->key.data, r->header_name_start, h->key.len);
            h->key.data[h->key.len] = '\0';
            ngx_memcpy(h->value.data, r->header_start, h->value.len);
            h->value.data[h->value.len] = '\0';

            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;
            }

            continue;
        }

        if (rc == NGX_HTTP_PARSE_HEADER_DONE)
        {
            if (r->upstream->headers_in.server == NULL)
            {
                h = ngx_list_push(&r->upstream->headers_in.headers);
                if (h == NULL)
                {
                    return NGX_ERROR;
                }

                h->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash(
                                                         ngx_hash('s', 'e'), 'r'), 'v'), 'e'), 'r');

                ngx_str_set(&h->key, "Server");
                ngx_str_null(&h->value);
                h->lowcase_key = (u_char *) "server";
            }

            if (r->upstream->headers_in.date == NULL)
            {
                h = ngx_list_push(&r->upstream->headers_in.headers);
                if (h == NULL)
                {
                    return NGX_ERROR;
                }

                h->hash = ngx_hash(ngx_hash(ngx_hash('d', 'a'), 't'), 'e');

                ngx_str_set(&h->key, "Date");
                ngx_str_null(&h->value);
                h->lowcase_key = (u_char *) "date";
            }

            return NGX_OK;
        }

        if (rc == NGX_AGAIN)
        {
            return NGX_AGAIN;
        }

        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "upstream sent invalid header");

        return NGX_HTTP_UPSTREAM_INVALID_HEADER;
    }
}
예제 #4
0
static ngx_int_t
process_header(ngx_http_request_t *r)
{
    ngx_str_t                      *status_line;
    ngx_int_t                       rc, status;
    ngx_table_elt_t                *h;
    ngx_http_upstream_t            *u;
    ngx_http_upstream_header_t     *hh;
    ngx_http_upstream_main_conf_t  *umcf;
    ngx_http_core_loc_conf_t       *clcf;

    umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

    for ( ;; ) {

        rc = ngx_http_parse_header_line(r, &r->upstream->buffer, 1);

        if (rc == NGX_OK) {

            /* a header line has been parsed successfully */

            h = ngx_list_push(&r->upstream->headers_in.headers);
            if (h == NULL) {
                return NGX_ERROR;
            }

            h->hash = r->header_hash;

            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_memcpy(h->key.data, r->header_name_start, h->key.len);
            h->key.data[h->key.len] = '\0';
            ngx_memcpy(h->value.data, r->header_start, h->value.len);
            h->value.data[h->value.len] = '\0';

            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 scgi header: \"%V: %V\"", &h->key, &h->value);

            continue;
        }

        if (rc == NGX_HTTP_PARSE_HEADER_DONE) {

            /* a whole header has been parsed successfully */

            ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                           "http scgi header done");

            /*
             * if no "Server" and "Date" in header line,
             * then add the default headers
             */

            if (r->upstream->headers_in.server == NULL) {
                h = ngx_list_push(&r->upstream->headers_in.headers);
                if (h == NULL) {
                    return NGX_HTTP_INTERNAL_SERVER_ERROR;
                }

                h->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash(
                                    ngx_hash('s', 'e'), 'r'), 'v'), 'e'), 'r');

                h->key.len = sizeof("Server") - 1;
                h->key.data = (u_char *) "Server";
                if (!passenger_main_conf.show_version_in_header) {
                    if (clcf->server_tokens) {
                        h->value.data = (u_char *) (NGINX_VER " + " PROGRAM_NAME);
                    } else {
                        h->value.data = (u_char *) ("nginx + " PROGRAM_NAME);
                    }
                } else {
                    if (clcf->server_tokens) {
                        h->value.data = (u_char *) (NGINX_VER " + " PROGRAM_NAME " " PASSENGER_VERSION);
                    } else {
                        h->value.data = (u_char *) ("nginx + " PROGRAM_NAME " " PASSENGER_VERSION);
                    }
                }
                h->value.len = ngx_strlen(h->value.data);
                h->lowcase_key = (u_char *) "server";
            }

            if (r->upstream->headers_in.date == NULL) {
                h = ngx_list_push(&r->upstream->headers_in.headers);
                if (h == NULL) {
                    return NGX_HTTP_INTERNAL_SERVER_ERROR;
                }

                h->hash = ngx_hash(ngx_hash(ngx_hash('d', 'a'), 't'), 'e');

                h->key.len = sizeof("Date") - 1;
                h->key.data = (u_char *) "Date";
                h->value.len = 0;
                h->value.data = NULL;
                h->lowcase_key = (u_char *) "date";
            }

            /* Process "Status" header. */

            u = r->upstream;

            if (u->headers_in.status_n) {
                goto 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;
                ngx_str_set(&u->headers_in.status_line,
                            "302 Moved Temporarily");

            } else {
                u->headers_in.status_n = 200;
                ngx_str_set(&u->headers_in.status_line, "200 OK");
            }

            if (u->state && u->state->status == 0) {
                u->state->status = u->headers_in.status_n;
            }

        done:

            /* Supported since Nginx 1.3.15. */
            #ifdef NGX_HTTP_SWITCHING_PROTOCOLS
                if (u->headers_in.status_n == NGX_HTTP_SWITCHING_PROTOCOLS
                    && r->headers_in.upgrade)
                {
                    u->upgrade = 1;
                }
            #endif

            return NGX_OK;
        }

        if (rc == NGX_AGAIN) {
            return NGX_AGAIN;
        }

        /* there was error while a header line parsing */

        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "upstream sent invalid header");

        return NGX_HTTP_UPSTREAM_INVALID_HEADER;
    }
}
예제 #5
0
ngx_int_t
ngx_http_srcache_process_header(ngx_http_request_t *r, ngx_buf_t *b)
{
    ngx_int_t                       rc;
    ngx_table_elt_t                 header;
    ngx_http_srcache_ctx_t         *ctx;
    off_t                           len, rest;
    unsigned                        truncate;
    u_char                         *p;
    ngx_http_srcache_header_t      *hh;
    ngx_http_srcache_main_conf_t   *smcf;

    smcf = ngx_http_get_module_main_conf(r, ngx_http_srcache_filter_module);

    ctx = ngx_http_get_module_ctx(r, ngx_http_srcache_filter_module);

    for ( ;; ) {

        len = b->last - b->pos;
        rest = ctx->header_buf->end - ctx->header_buf->last;

        dd("len: %d, rest: %d", (int) len, (int) rest);

        if (len > rest) {
            len = rest;
            truncate = 1;

        } else {
            truncate = 0;
        }

        ctx->header_buf->last = ngx_copy(ctx->header_buf->last, b->pos,
                                         (size_t) len);

        p = ctx->header_buf->pos;

        rc = ngx_http_parse_header_line(r, ctx->header_buf, 1);

        b->pos += ctx->header_buf->pos - p;

        if (rc == NGX_OK) {

            /* a header line has been parsed successfully */

            ngx_memzero(&header, sizeof(ngx_table_elt_t));

            header.hash = r->header_hash;

            header.key.len = r->header_name_end - r->header_name_start;
            header.value.len = r->header_end - r->header_start;

            header.key.data = ngx_pnalloc(r->pool,
                                          header.key.len + 1
                                          + header.value.len + 1
                                          + header.key.len);

            if (header.key.data == NULL) {
                return NGX_ERROR;
            }

            header.value.data = header.key.data + header.key.len + 1;
            header.lowcase_key = header.key.data + header.key.len + 1
                                 + header.value.len + 1;

            ngx_cpystrn(header.key.data, r->header_name_start,
                        header.key.len + 1);

            ngx_cpystrn(header.value.data, r->header_start,
                        header.value.len + 1);

            if (header.key.len == r->lowcase_index) {
                ngx_memcpy(header.lowcase_key, r->lowcase_header,
                           header.key.len);

            } else {
                ngx_strlow(header.lowcase_key, header.key.data, header.key.len);
            }

            hh = ngx_hash_find(&smcf->headers_in_hash, header.hash,
                               header.lowcase_key, header.key.len);

            if (hh) {
                if (hh->handler(r->parent, &header, hh->offset) != NGX_OK) {
                    return NGX_ERROR;
                }

            } else {

                if (ngx_http_srcache_process_header_line(r->parent, &header, 0)
                    != NGX_OK)
                {
                    return NGX_ERROR;
                }
            }

            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                           "srcache_fetch header: \"%V: %V\"",
                           &header.key, &header.value);

            ctx->header_buf->pos = ctx->header_buf->start;
            ctx->header_buf->last = ctx->header_buf->start;

            continue;
        }

        if (rc == NGX_HTTP_PARSE_HEADER_DONE) {

            /* a whole header has been parsed successfully */

            ctx->header_buf->pos = ctx->header_buf->start;
            ctx->header_buf->last = ctx->header_buf->start;
            ngx_pfree(r->pool, ctx->header_buf->start);

            ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                           "srcache_fetch header done");

            return NGX_OK;
        }

        if (rc == NGX_AGAIN) {
            if (truncate) {
                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                              "srcache_fetch: header buffer overflown "
                              "(maybe you should consider increasing "
                              "srcache_header_buffer_size?)");

                ctx->header_buf->pos = ctx->header_buf->start;
                ctx->header_buf->last = ctx->header_buf->start;
                ngx_pfree(r->pool, ctx->header_buf->start);

                return NGX_ERROR;
            }

            return NGX_AGAIN;
        }

        /* there was error while a header line parsing */

        ctx->header_buf->pos = ctx->header_buf->start;
        ctx->header_buf->last = ctx->header_buf->start;
        ngx_pfree(r->pool, ctx->header_buf->start);

        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "srcache_fetch: cache sent invalid header");

        return NGX_ERROR;
    }
}
예제 #6
0
static ngx_int_t
process_header(ngx_http_request_t *r)
{
    ngx_int_t                       rc;
    ngx_uint_t                      i;
    ngx_table_elt_t                *h;
    ngx_http_upstream_header_t     *hh;
    ngx_http_upstream_main_conf_t  *umcf;

    umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);

    for ( ;;  ) {

        #if NGINX_VERSION_NUM >= 7000
            rc = ngx_http_parse_header_line(r, &r->upstream->buffer, 1);
        #else
            rc = ngx_http_parse_header_line(r, &r->upstream->buffer);
        #endif

        if (rc == NGX_OK) {

            /* a header line has been parsed successfully */

            h = ngx_list_push(&r->upstream->headers_in.headers);
            if (h == NULL) {
                return NGX_HTTP_INTERNAL_SERVER_ERROR;
            }

            h->hash = r->header_hash;

            h->key.len = r->header_name_end - r->header_name_start;
            h->value.len = r->header_end - r->header_start;

            h->key.data = ngx_palloc(r->pool,
                               h->key.len + 1 + h->value.len + 1 + h->key.len);
            if (h->key.data == NULL) {
                return NGX_HTTP_INTERNAL_SERVER_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);

            if (h->key.len == r->lowcase_index) {
                ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len);

            } else {
                for (i = 0; i < h->key.len; i++) {
                    h->lowcase_key[i] = ngx_tolower(h->key.data[i]);
                }
            }

            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_HTTP_INTERNAL_SERVER_ERROR;
            }

            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                           "http scgi header: \"%V: %V\"",
                           &h->key, &h->value);

            continue;
        }

        if (rc == NGX_HTTP_PARSE_HEADER_DONE) {

            /* a whole header has been parsed successfully */

            ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                           "http scgi header done");

            /*
             * if no "Server" and "Date" in header line,
             * then add the default headers
             */

            if (r->upstream->headers_in.server == NULL) {
                h = ngx_list_push(&r->upstream->headers_in.headers);
                if (h == NULL) {
                    return NGX_HTTP_INTERNAL_SERVER_ERROR;
                }

                h->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash(
                                    ngx_hash('s', 'e'), 'r'), 'v'), 'e'), 'r');

                h->key.len = sizeof("Server") - 1;
                h->key.data = (u_char *) "Server";
                h->value.data = (u_char *) (NGINX_VER " + Phusion Passenger " PASSENGER_VERSION " (mod_rails/mod_rack)");
                h->value.len = ngx_strlen(h->value.data);
                h->lowcase_key = (u_char *) "server";
            }

            if (r->upstream->headers_in.date == NULL) {
                h = ngx_list_push(&r->upstream->headers_in.headers);
                if (h == NULL) {
                    return NGX_HTTP_INTERNAL_SERVER_ERROR;
                }

                h->hash = ngx_hash(ngx_hash(ngx_hash('d', 'a'), 't'), 'e');

                h->key.len = sizeof("Date") - 1;
                h->key.data = (u_char *) "Date";
                h->value.len = 0;
                h->value.data = NULL;
                h->lowcase_key = (u_char *) "date";
            }

            return NGX_OK;
        }

        if (rc == NGX_AGAIN) {
            return NGX_AGAIN;
        }

        /* there was error while a header line parsing */

        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "upstream sent invalid header");

        return NGX_HTTP_UPSTREAM_INVALID_HEADER;
    }
}
//mytest_upstream_process_header方法可以解析HTTP响应头部,而这里只是简单的
//把上游服务器发送的HTTP头部添加到了请求r->upstream->headers_in.headers链表
//中。
static ngx_int_t
mytest_upstream_process_header(ngx_http_request_t *r)
{
	ngx_int_t					rc;
	ngx_table_elt_t				*h;
	ngx_http_upstream_header_t	*hh;
	ngx_http_upstream_main_conf_t	*umcf;

	//这里将upstream模块配置项ngx_http_upstream_main_conf_t取出来,对将要转发给
	//下游客户端的HTTP响应头部进行统一处理
	umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);

	//循环的解析所有的HTTP头部
	for(;;){
		//HTTP框架提供了基础性的ngx_http_parse_header_line方法,它用于解析HTTP头部
		rc = ngx_http_parse_header_line(r, &r->upstream->buffer, 1);
		//返回NGX_OK时,表示解析出一行HTTP头部
		if(rc == NGX_OK){

			//向headers_in.headers这个ngx_list_t链表中添加HTTP头部
			h = ngx_list_push(&r->upstream->headers_in.headers);
			if(h == NULL){
				return NGX_ERROR;
			}
			//下面开始构造刚刚添加到headers链表中的HTTP头部
			h->hash = r->header_hash;
			h->key.len = r->header_name_end - r->header_name_start;
			h->value.len = r->header_end - r->header_start;
			//必须在内存池中非配存放HTTP头部的内存空间
			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_memcpy(h->key.data, r->header_name_start, h->key.len);
			h->value.data[h->value.len] = '\0';
			ngx_memcpy(h->value.data, r->header_start, h->value.len);
			h->value.data[h->value.len] = '\0';

			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);
			}

			//upstream模块会对一些HTTP头部作特殊处理
			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;
			}
			continue;
		}

		//返回NGX_HTTP_PARSE_HEADER_DONE时,表示响应中的所有的HTTP头部都解析完毕,接下来
		//在接收到的都将是HTTP包体
		if(rc == NGX_HTTP_PARSE_HEADER_DONE) {
			//如果之前解析HTTP头部时没有发现server和date头部,那么下面会根据HTTP协议
			//规范添加这两个头部
			if(r->upstream->headers_in.server == NULL){
				h = ngx_list_push(&r->upstream->headers_in.headers);
				if(h == NULL){
					return NGX_ERROR;
				}
				h->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash(ngx_hash('s', 'e'),
									'r'), 'v'), 'e'), 'r');
				ngx_str_set(&h->key, "Server");
				ngx_str_null(&h->value);
				h->lowcase_key = (u_char *)"server";
			}

			if(r->upstream->headers_in.date == NULL){
				h = ngx_list_push(&r->upstream->headers_in.headers);
				if(h == NULL){
					return NGX_ERROR;
				}

				h->hash = ngx_hash(ngx_hash(ngx_hash('d', 'a'), 't'), 'e');

				ngx_str_set(&h->key, "Date");
				ngx_str_null(&h->value);
				h->lowcase_key = (u_char *)"date";
			}

			return NGX_OK;
		}

		//如果返回NGX_AGAIN,则表示状态机还没有解析到完整的HTTP头部,此时要求upstream模块
		//继续接收新的字符流,然后交由process_header回调方法解析
		if(rc == NGX_AGAIN){
			return NGX_AGAIN;
		}

		ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
				"upstream sent invalid header");

		return NGX_HTTP_UPSTREAM_INVALID_HEADER; //当mytest_upstream_process_header返回NGX_OK后
												 //upstream模块开始把上游的包体直接转发到下游客户端
	}
}
static ngx_int_t
ngx_http_scgi_process_header(ngx_http_request_t *r)
{
    ngx_str_t                      *status_line;
    ngx_int_t                       rc, status;
    ngx_table_elt_t                *h;
    ngx_http_upstream_t            *u;
    ngx_http_upstream_header_t     *hh;
    ngx_http_upstream_main_conf_t  *umcf;

    umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);

    for ( ;; ) {

        rc = ngx_http_parse_header_line(r, &r->upstream->buffer, 1);

        if (rc == NGX_OK) {

            /* a header line has been parsed successfully */

            h = ngx_list_push(&r->upstream->headers_in.headers);
            if (h == NULL) {
                return NGX_ERROR;
            }

            h->hash = r->header_hash;

            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);

            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 scgi header: \"%V: %V\"", &h->key, &h->value);

            continue;
        }

        if (rc == NGX_HTTP_PARSE_HEADER_DONE) {

            /* a whole header has been parsed successfully */

            ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                           "http scgi header done");

            if (r->http_version > NGX_HTTP_VERSION_9) {
                return NGX_OK;
            }

            u = r->upstream;

            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;
                }

                r->http_version = NGX_HTTP_VERSION_10;
                u->headers_in.status_n = status;
                u->headers_in.status_line = *status_line;

            } else if (u->headers_in.location) {
                r->http_version = NGX_HTTP_VERSION_10;
                u->headers_in.status_n = 302;
                ngx_str_set(&u->headers_in.status_line,
                            "302 Moved Temporarily");

            } else {
                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                              "upstream sent neither valid HTTP/1.0 header "
                              "nor \"Status\" header line");
                u->headers_in.status_n = 200;
                ngx_str_set(&u->headers_in.status_line, "200 OK");
            }

            if (u->state) {
                u->state->status = u->headers_in.status_n;
            }

            return NGX_OK;
        }

        if (rc == NGX_AGAIN) {
            return NGX_AGAIN;
        }

        /* there was error while a header line parsing */

        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "upstream sent invalid header");

        return NGX_HTTP_UPSTREAM_INVALID_HEADER;
    }
}
예제 #9
0
static ngx_int_t
mytest_upstream_process_header(ngx_http_request_t *r)
{
    ngx_int_t                       rc;
    ngx_table_elt_t                *h;
    ngx_http_upstream_header_t     *hh;
    ngx_http_upstream_main_conf_t  *umcf;

    //这里将upstream模块配置项ngx_http_upstream_main_conf_t取了
//出来,目的只有1个,对将要转发给下游客户端的http响应头部作统一
//处理。该结构体中存储了需要做统一处理的http头部名称和回调方法
    umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);

    //循环的解析所有的http头部
    for ( ;; )
    {
        // http框架提供了基础性的ngx_http_parse_header_line
//方法,它用于解析http头部
        rc = ngx_http_parse_header_line(r, &r->upstream->buffer, 1);
        //返回NGX_OK表示解析出一行http头部
        if (rc == NGX_OK)
        {
            //向headers_in.headers这个ngx_list_t链表中添加http头部
            h = ngx_list_push(&r->upstream->headers_in.headers);
            if (h == NULL)
            {
                return NGX_ERROR;
            }
            //以下开始构造刚刚添加到headers链表中的http头部
            h->hash = r->header_hash;

            h->key.len = r->header_name_end - r->header_name_start;
            h->value.len = r->header_end - r->header_start;
            //必须由内存池中分配存放http头部的内存
            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_memcpy(h->key.data, r->header_name_start, h->key.len);
            h->key.data[h->key.len] = '\0';
            ngx_memcpy(h->value.data, r->header_start, h->value.len);
            h->value.data[h->value.len] = '\0';

            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);
            }

            //upstream模块会对一些http头部做特殊处理
            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;
            }

            continue;
        }

        //返回NGX_HTTP_PARSE_HEADER_DONE表示响应中所有的http头部都解析
//完毕,接下来再接收到的都将是http包体
        if (rc == NGX_HTTP_PARSE_HEADER_DONE)
        {
            //如果之前解析http头部时没有发现server和date头部,以下会
            //根据http协议添加这两个头部
            if (r->upstream->headers_in.server == NULL)
            {
                h = ngx_list_push(&r->upstream->headers_in.headers);
                if (h == NULL)
                {
                    return NGX_ERROR;
                }

                h->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash(
                                                         ngx_hash('s', 'e'), 'r'), 'v'), 'e'), 'r');

                ngx_str_set(&h->key, "Server");
                ngx_str_null(&h->value);
                h->lowcase_key = (u_char *) "server";
            }

            if (r->upstream->headers_in.date == NULL)
            {
                h = ngx_list_push(&r->upstream->headers_in.headers);
                if (h == NULL)
                {
                    return NGX_ERROR;
                }

                h->hash = ngx_hash(ngx_hash(ngx_hash('d', 'a'), 't'), 'e');

                ngx_str_set(&h->key, "Date");
                ngx_str_null(&h->value);
                h->lowcase_key = (u_char *) "date";
            }

            return NGX_OK;
        }

        //如果返回NGX_AGAIN则表示状态机还没有解析到完整的http头部,
//要求upstream模块继续接收新的字符流再交由process_header
//回调方法解析
        if (rc == NGX_AGAIN)
        {
            return NGX_AGAIN;
        }

        //其他返回值都是非法的
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "upstream sent invalid header");

        return NGX_HTTP_UPSTREAM_INVALID_HEADER;
    }
}