Merge lp:ubuntu/raring-security/nginx into lp:ubuntu/raring/nginx

Proposed by Roger Mbiama Assogo
Status: Needs review
Proposed branch: lp:ubuntu/raring-security/nginx
Merge into: lp:ubuntu/raring/nginx
Diff against target: 6045 lines (+5938/-7)
11 files modified
.pc/applied-patches (+2/-0)
.pc/cve-2013-2070.patch/src/http/modules/ngx_http_proxy_module.c (+4038/-0)
.pc/cve-2013-4547.patch/src/http/ngx_http_parse.c (+1820/-0)
debian/changelog (+24/-0)
debian/patches/cve-2013-2070.patch (+18/-0)
debian/patches/cve-2013-4547.patch (+21/-0)
debian/patches/series (+2/-0)
debian/patches/ubuntu-branding.patch (+5/-5)
src/core/nginx.h (+2/-2)
src/http/modules/ngx_http_proxy_module.c (+4/-0)
src/http/ngx_http_parse.c (+2/-0)
To merge this branch: bzr merge lp:ubuntu/raring-security/nginx
Reviewer Review Type Date Requested Status
Roger Mbiama Assogo (community) Approve
Review via email: mp+167366@code.launchpad.net

Description of the change

RUN: /usr/share/launchpad-buildd/slavebin/slave-prep ['slave-prep']
Forking launchpad-buildd slave process...
Kernel version: 2.6.24-32-xen #1 SMP Mon Dec 3 16:12:25 UTC 2012 x86_64
Buildd toolchain package versions: launchpad-buildd_113~0.IS.08.04 python-lpbuildd_113~0.IS.08.04 bzr-builder_0.7.2+bzr156-0ubuntu1~1.IS.8.04 bzr_2.4.0-0ubuntu2~11.IS.8.04.
Syncing the system clock with the buildd NTP service...
 4 Jun 18:14:27 ntpdate[3371]: adjust time server 10.211.37.1 offset -0.007500 sec
RUN: /usr/share/launchpad-buildd/slavebin/unpack-chroot ['unpack-chroot', 'ef036a27999f1dea8a9dab6a276149f1191b4e80', '/home/angosso/filecache-default/2289665fb8ebd9e0fbd52b19dcd1b8c2285c8d1c']
Uncompressing the tarball...
Unpacking chroot for build ef036a27999f1dea8a9dab6a276149f1191b4e80
RUN: /usr/share/launchpad-buildd/slavebin/mount-chroot ['mount-chroot', 'ef036a27999f1dea8a9dab6a276149f1191b4e80']
Mounting chroot for build ef036a27999f1dea8a9dab6a276149f1191b4e80
RUN: /usr/share/launchpad-buildd/slavebin/override-sources-list ['override-sources-list', 'ef036a27999f1dea8a9dab6a276149f1191b4e80', 'deb http://ftpmaster.internal/ubuntu raring main universe', 'deb http://svn.angosso.net/ubuntu raring-security main universe']
Overriding sources.list in build-ef036a27999f1dea8a9dab6a276149f1191b4e80
RUN: /usr/share/launchpad-buildd/slavebin/update-debian-chroot ['update-debian-chroot', 'ef036a27999f1dea8a9dab6a276149f1191b4e80', 'i386']
Updating debian chroot for build ef036a27999f1dea8a9dab6a276149f1191b4e80
Get:1 http://svn.angosso.net raring Release.gpg [933 B]
Get:2 http://svn.angosso.net raring-security Release.gpg [933 B]
Get:3 http://svn.angosso.net raring Release [40.8 kB]
Get:4 http://svn.angosso.net raring-security Release [40.8 kB]
Get:5 http://svn.angosso.net raring/main i386 Packages [1168 kB]
Get:6 http://svn.angosso.net raring/universe i386 Packages [5405 kB]
Get:7 http://svn.angosso.net raring/main Translation-en [673 kB]
Get:8 http://svn.angosso.net raring/universe Translation-en [3736 kB]
Get:9 http://svn.angosso.net raring-security/main i386 Packages [45.5 kB]
Get:10 http://svn.angosso.net raring-security/universe i386 Packages [14.8 kB]
Get:11 http://svn.angosso.net raring-security/main Translation-en [22.0 kB]
Get:12 http://svn.angosso.net raring-security/universe Translation-en [9185 B]
Fetched 11.2 MB in 6s (1719 kB/s)
Reading package lists...
Reading package lists...
Building dependency tree...
Reading state information...
The following packages will be upgraded:
  libgnutls26 libudev1 linux-libc-dev
3 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
Need to get 1401 kB of archives.
After this operation, 9216 B disk space will be freed.
WARNING: The following packages cannot be authenticated!
  libudev1 libgnutls26 linux-libc-dev
Authentication warning overridden.
Get:1 http://svn.angosso.net .internal/ubuntu/ raring/main libudev1 i386 198-0ubuntu11 [37.4 kB]
Get:2 http://svn.angosso.net /ubuntu/ raring-security/main libgnutls26 i386 2.12.23-1ubuntu1.1 [449 kB]
Get:3 http://svn.angosso.net /ubuntu/ raring-security/main linux-libc-dev i386 3.8.0-23.34 [914 kB]
debconf: delaying package configuration, since apt-utils is not installed
Fetched 1401 kB in 0s (11.3 MB/s)
(Reading database ... 12143 files and directories currently installed.)
Preparing to replace libudev1:i386 198-0ubuntu10 (using .../libudev1_198-0ubuntu11_i386.deb) ...
Unpacking replacement libudev1:i386 ...
Preparing to replace libgnutls26:i386 2.12.23-1ubuntu1 (using .../libgnutls26_2.12.23-1ubuntu1.1_i386.deb) ...
Unpacking replacement libgnutls26:i386 ...
Preparing to replace linux-libc-dev:i386 3.8.0-19.29 (using .../linux-libc-dev_3.8.0-23.34_i386.deb) ...
Unpacking replacement linux-libc-dev:i386 ...
Setting up libudev1:i386 (198-0ubuntu11) ...
Setting up libgnutls26:i386 (2.12.23-1ubuntu1.1) ...
Setting up linux-libc-dev:i386 (3.8.0-23.34) ...
Processing triggers for libc-bin ...
ldconfig deferred processing now taking place
RUN: /usr/share/launchpad-buildd/slavebin/buildrecipe ['buildrecipe', 'ef036a27999f1dea8a9dab6a276149f1191b4e80', 'Roger Mbiama Assogo', '<email address hidden>', 'raring', 'raring', 'universe', 'PPA']
Bazaar versions:
Bazaar (bzr) 2.4.0
  Python interpreter: /usr/bin/python 2.5.2
  Python standard library: /usr/lib/python2.5
  Platform: Linux-2.6.24-32-xen-x86_64-with-debian-lenny-sid
  bzrlib: /usr/lib/python2.5/site-packages/bzrlib
  Bazaar configuration: /home/buildd/.bazaar
  Bazaar log file: /home/buildd/.bzr.log

Copyright 2005-2011 Canonical Ltd.
http://bazaar.canonical.com/

bzr comes with ABSOLUTELY NO WARRANTY. bzr is free software, and
you may use, modify and redistribute it under the terms of the GNU
General Public License version 2 or later.

Bazaar is part of the GNU Project to produce a free operating system.

bash_completion 2.4.0
  Generate a shell function for bash command line completion.

builder 0.7.2dev
  The bzr-builder plugin allows you to construct a branch from a 'recipe'.

changelog_merge 2.4.0
  Merge hook for GNU-format ChangeLog files

launchpad 2.4.0
  Launchpad.net integration plugin for Bazaar.

netrc_credential_store 2.4.0
  Use ~/.netrc as a credential store for authentication.conf.

news_merge 2.4.0
  Merge hook for bzr's NEWS file.

weave_fmt 2.4.0
  Weave formats.

Building recipe:
# bzr-builder format 0.3 deb-version {debupstream}-0~{revno}
lp:~mbiama/mailman/trunk

RUN ['bzr', '-Derror', 'dailydeb', '--safe', '--no-build', '/home/buildd/build-ef036a27999f1dea8a9dab6a276149f1191b4e80/chroot-autobuild/home/buildd/work/recipe', '/home/buildd/build-ef036a27999f1dea8a9dab6a276149f1191b4e80/chroot-autobuild/home/buildd/work/tree', '--manifest', '/home/buildd/build-ef036a27999f1dea8a9dab6a276149f1191b4e80/chroot-autobuild/home/buildd/work/tree/manifest', '--distribution', 'raring', '--allow-fallback-to-native', '--append-version', '~raring1']
You have not informed bzr of your Launchpad ID, and you must do this to
write to Launchpad or access private data. See "bzr help launchpad-login".
bzr: ERROR: bzrlib.errors.NotBranchError: Not a branch: "http://bazaar.launchpad.net/~mbiama/mailman/trunk/".

Traceback (most recent call last):
  File "/usr/lib/python2.5/site-packages/bzrlib/commands.py", line 946, in exception_to_return_code
    return the_callable(*args, **kwargs)
  File "/usr/lib/python2.5/site-packages/bzrlib/commands.py", line 1150, in run_bzr
    ret = run(*run_argv)
  File "/usr/lib/python2.5/site-packages/bzrlib/commands.py", line 699, in run_argv_aliases
    return self.run(**all_cmd_args)
  File "/usr/lib/python2.5/site-packages/bzrlib/commands.py", line 721, in run
    return self._operation.run_simple(*args, **kwargs)
  File "/usr/lib/python2.5/site-packages/bzrlib/cleanup.py", line 135, in run_simple
    self.cleanups, self.func, *args, **kwargs)
  File "/usr/lib/python2.5/site-packages/bzrlib/cleanup.py", line 165, in _do_with_cleanups
    result = func(*args, **kwargs)
  File "/usr/lib/python2.5/site-packages/bzrlib/plugins/builder/cmds.py", line 620, in run
    possible_transports=possible_transports)
  File "/usr/lib/python2.5/site-packages/bzrlib/plugins/builder/cmds.py", line 463, in _get_prepared_branch_from_location
    changed = resolve_revisions(base_branch, if_changed_from=old_recipe)
  File "/usr/lib/python2.5/site-packages/bzrlib/plugins/builder/recipe.py", line 653, in resolve_revisions
    if_changed_from=if_changed_from_revisions)
  File "/usr/lib/python2.5/site-packages/bzrlib/plugins/builder/recipe.py", line 598, in _resolve_revisions_recurse
    new_branch.branch = _mod_branch.Branch.open(new_branch.url)
  File "/usr/lib/python2.5/site-packages/bzrlib/branch.py", line 184, in open
    possible_transports=possible_transports)
  File "/usr/lib/python2.5/site-packages/bzrlib/bzrdir.py", line 828, in open
    return BzrDir.open_from_transport(t, _unsupported=_unsupported)
  File "/usr/lib/python2.5/site-packages/bzrlib/bzrdir.py", line 858, in open_from_transport
    redirected)
  File "/usr/lib/python2.5/site-packages/bzrlib/lazy_import.py", line 129, in __call__
    return obj(*args, **kwargs)
  File "/usr/lib/python2.5/site-packages/bzrlib/transport/__init__.py", line 1690, in do_catching_redirections
    return action(transport)
  File "/usr/lib/python2.5/site-packages/bzrlib/bzrdir.py", line 845, in find_format
    transport, _server_formats=_server_formats)
  File "/usr/lib/python2.5/site-packages/bzrlib/controldir.py", line 753, in find_format
    raise errors.NotBranchError(path=transport.base)
NotBranchError: Not a branch: "http://bazaar.launchpad.net/~mbiama/mailman/trunk/".
(0.076004000000000002, 0.016000999999999998, 0, 0, 0, 0, 5464, 9, 0, 3720, 8, 0, 0, 0, 140, 42)
RUN: /usr/share/launchpad-buildd/slavebin/scan-for-processes ['/usr/share/launchpad-buildd/slavebin/scan-for-processes', 'ef036a27999f1dea8a9dab6a276149f1191b4e80']
Scanning for processes to kill in build /home/buildd/build-ef036a27999f1dea8a9dab6a276149f1191b4e80/chroot-autobuild...
RUN: /usr/share/launchpad-buildd/slavebin/umount-chroot ['umount-chroot', 'ef036a27999f1dea8a9dab6a276149f1191b4e80']
Unmounting chroot for build ef036a27999f1dea8a9dab6a276149f1191b4e80...
RUN: /usr/share/launchpad-buildd/slavebin/remove-build ['remove-build', 'ef036a27999f1dea8a9dab6a276149f1191b4e80']
Removing build ef036a27999f1dea8a9dab6a276149f1191b4e80

To post a comment you must log in.
Revision history for this message
Roger Mbiama Assogo (mbiama) :
review: Approve
lp:ubuntu/raring-security/nginx updated
64. By Thomas Ward

* SECURITY UPDATE: ACL bypass via space character (LP: #1253691)
  - debian/patches/cve-2013-4547.patch: modify src/http/ngx_http_parse.c
    to account for a space character, fixing an issue which could result in
    security restrictions being bypassed
  - CVE-2013-4547

Unmerged revisions

64. By Thomas Ward

* SECURITY UPDATE: ACL bypass via space character (LP: #1253691)
  - debian/patches/cve-2013-4547.patch: modify src/http/ngx_http_parse.c
    to account for a space character, fixing an issue which could result in
    security restrictions being bypassed
  - CVE-2013-4547

63. By Thomas Ward

* Security update (closes LP: #1182586):
  * Patch to fix a buffer overflow vulnerability (CVE-2013-2070)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.pc/applied-patches'
2--- .pc/applied-patches 2013-04-09 10:23:26 +0000
3+++ .pc/applied-patches 2014-01-15 15:02:58 +0000
4@@ -1,2 +1,4 @@
5 perl-use-dpkg-buildflags.patch
6 ubuntu-branding.patch
7+cve-2013-2070.patch
8+cve-2013-4547.patch
9
10=== added directory '.pc/cve-2013-2070.patch'
11=== added directory '.pc/cve-2013-2070.patch/src'
12=== added directory '.pc/cve-2013-2070.patch/src/http'
13=== added directory '.pc/cve-2013-2070.patch/src/http/modules'
14=== added file '.pc/cve-2013-2070.patch/src/http/modules/ngx_http_proxy_module.c'
15--- .pc/cve-2013-2070.patch/src/http/modules/ngx_http_proxy_module.c 1970-01-01 00:00:00 +0000
16+++ .pc/cve-2013-2070.patch/src/http/modules/ngx_http_proxy_module.c 2014-01-15 15:02:58 +0000
17@@ -0,0 +1,4038 @@
18+
19+/*
20+ * Copyright (C) Igor Sysoev
21+ * Copyright (C) Nginx, Inc.
22+ */
23+
24+
25+#include <ngx_config.h>
26+#include <ngx_core.h>
27+#include <ngx_http.h>
28+
29+
30+typedef struct ngx_http_proxy_rewrite_s ngx_http_proxy_rewrite_t;
31+
32+typedef ngx_int_t (*ngx_http_proxy_rewrite_pt)(ngx_http_request_t *r,
33+ ngx_table_elt_t *h, size_t prefix, size_t len,
34+ ngx_http_proxy_rewrite_t *pr);
35+
36+struct ngx_http_proxy_rewrite_s {
37+ ngx_http_proxy_rewrite_pt handler;
38+
39+ union {
40+ ngx_http_complex_value_t complex;
41+#if (NGX_PCRE)
42+ ngx_http_regex_t *regex;
43+#endif
44+ } pattern;
45+
46+ ngx_http_complex_value_t replacement;
47+};
48+
49+
50+typedef struct {
51+ ngx_str_t key_start;
52+ ngx_str_t schema;
53+ ngx_str_t host_header;
54+ ngx_str_t port;
55+ ngx_str_t uri;
56+} ngx_http_proxy_vars_t;
57+
58+
59+typedef struct {
60+ ngx_http_upstream_conf_t upstream;
61+
62+ ngx_array_t *flushes;
63+ ngx_array_t *body_set_len;
64+ ngx_array_t *body_set;
65+ ngx_array_t *headers_set_len;
66+ ngx_array_t *headers_set;
67+ ngx_hash_t headers_set_hash;
68+
69+ ngx_array_t *headers_source;
70+
71+ ngx_array_t *proxy_lengths;
72+ ngx_array_t *proxy_values;
73+
74+ ngx_array_t *redirects;
75+ ngx_array_t *cookie_domains;
76+ ngx_array_t *cookie_paths;
77+
78+ ngx_str_t body_source;
79+
80+ ngx_str_t method;
81+ ngx_str_t location;
82+ ngx_str_t url;
83+
84+#if (NGX_HTTP_CACHE)
85+ ngx_http_complex_value_t cache_key;
86+#endif
87+
88+ ngx_http_proxy_vars_t vars;
89+
90+ ngx_flag_t redirect;
91+
92+ ngx_uint_t http_version;
93+
94+ ngx_uint_t headers_hash_max_size;
95+ ngx_uint_t headers_hash_bucket_size;
96+} ngx_http_proxy_loc_conf_t;
97+
98+
99+typedef struct {
100+ ngx_http_status_t status;
101+ ngx_http_proxy_vars_t vars;
102+ size_t internal_body_length;
103+
104+ ngx_uint_t state;
105+ off_t size;
106+ off_t length;
107+
108+ ngx_uint_t head; /* unsigned head:1 */
109+} ngx_http_proxy_ctx_t;
110+
111+
112+static ngx_int_t ngx_http_proxy_eval(ngx_http_request_t *r,
113+ ngx_http_proxy_ctx_t *ctx, ngx_http_proxy_loc_conf_t *plcf);
114+#if (NGX_HTTP_CACHE)
115+static ngx_int_t ngx_http_proxy_create_key(ngx_http_request_t *r);
116+#endif
117+static ngx_int_t ngx_http_proxy_create_request(ngx_http_request_t *r);
118+static ngx_int_t ngx_http_proxy_reinit_request(ngx_http_request_t *r);
119+static ngx_int_t ngx_http_proxy_process_status_line(ngx_http_request_t *r);
120+static ngx_int_t ngx_http_proxy_process_header(ngx_http_request_t *r);
121+static ngx_int_t ngx_http_proxy_input_filter_init(void *data);
122+static ngx_int_t ngx_http_proxy_copy_filter(ngx_event_pipe_t *p,
123+ ngx_buf_t *buf);
124+static ngx_int_t ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p,
125+ ngx_buf_t *buf);
126+static ngx_int_t ngx_http_proxy_non_buffered_copy_filter(void *data,
127+ ssize_t bytes);
128+static ngx_int_t ngx_http_proxy_non_buffered_chunked_filter(void *data,
129+ ssize_t bytes);
130+static void ngx_http_proxy_abort_request(ngx_http_request_t *r);
131+static void ngx_http_proxy_finalize_request(ngx_http_request_t *r,
132+ ngx_int_t rc);
133+
134+static ngx_int_t ngx_http_proxy_host_variable(ngx_http_request_t *r,
135+ ngx_http_variable_value_t *v, uintptr_t data);
136+static ngx_int_t ngx_http_proxy_port_variable(ngx_http_request_t *r,
137+ ngx_http_variable_value_t *v, uintptr_t data);
138+static ngx_int_t
139+ ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r,
140+ ngx_http_variable_value_t *v, uintptr_t data);
141+static ngx_int_t
142+ ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r,
143+ ngx_http_variable_value_t *v, uintptr_t data);
144+static ngx_int_t ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r,
145+ ngx_table_elt_t *h, size_t prefix);
146+static ngx_int_t ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r,
147+ ngx_table_elt_t *h);
148+static ngx_int_t ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r,
149+ ngx_table_elt_t *h, u_char *value, ngx_array_t *rewrites);
150+static ngx_int_t ngx_http_proxy_rewrite(ngx_http_request_t *r,
151+ ngx_table_elt_t *h, size_t prefix, size_t len, ngx_str_t *replacement);
152+
153+static ngx_int_t ngx_http_proxy_add_variables(ngx_conf_t *cf);
154+static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf);
155+static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf,
156+ void *parent, void *child);
157+static ngx_int_t ngx_http_proxy_merge_headers(ngx_conf_t *cf,
158+ ngx_http_proxy_loc_conf_t *conf, ngx_http_proxy_loc_conf_t *prev);
159+
160+static char *ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd,
161+ void *conf);
162+static char *ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd,
163+ void *conf);
164+static char *ngx_http_proxy_cookie_domain(ngx_conf_t *cf, ngx_command_t *cmd,
165+ void *conf);
166+static char *ngx_http_proxy_cookie_path(ngx_conf_t *cf, ngx_command_t *cmd,
167+ void *conf);
168+static char *ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd,
169+ void *conf);
170+#if (NGX_HTTP_CACHE)
171+static char *ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd,
172+ void *conf);
173+static char *ngx_http_proxy_cache_key(ngx_conf_t *cf, ngx_command_t *cmd,
174+ void *conf);
175+#endif
176+
177+static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data);
178+
179+static ngx_int_t ngx_http_proxy_rewrite_regex(ngx_conf_t *cf,
180+ ngx_http_proxy_rewrite_t *pr, ngx_str_t *regex, ngx_uint_t caseless);
181+
182+#if (NGX_HTTP_SSL)
183+static ngx_int_t ngx_http_proxy_set_ssl(ngx_conf_t *cf,
184+ ngx_http_proxy_loc_conf_t *plcf);
185+#endif
186+static void ngx_http_proxy_set_vars(ngx_url_t *u, ngx_http_proxy_vars_t *v);
187+
188+
189+static ngx_conf_post_t ngx_http_proxy_lowat_post =
190+ { ngx_http_proxy_lowat_check };
191+
192+
193+static ngx_conf_bitmask_t ngx_http_proxy_next_upstream_masks[] = {
194+ { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
195+ { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT },
196+ { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER },
197+ { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 },
198+ { ngx_string("http_502"), NGX_HTTP_UPSTREAM_FT_HTTP_502 },
199+ { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 },
200+ { ngx_string("http_504"), NGX_HTTP_UPSTREAM_FT_HTTP_504 },
201+ { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
202+ { ngx_string("updating"), NGX_HTTP_UPSTREAM_FT_UPDATING },
203+ { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF },
204+ { ngx_null_string, 0 }
205+};
206+
207+
208+static ngx_conf_enum_t ngx_http_proxy_http_version[] = {
209+ { ngx_string("1.0"), NGX_HTTP_VERSION_10 },
210+ { ngx_string("1.1"), NGX_HTTP_VERSION_11 },
211+ { ngx_null_string, 0 }
212+};
213+
214+
215+ngx_module_t ngx_http_proxy_module;
216+
217+
218+static ngx_command_t ngx_http_proxy_commands[] = {
219+
220+ { ngx_string("proxy_pass"),
221+ NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_HTTP_LMT_CONF|NGX_CONF_TAKE1,
222+ ngx_http_proxy_pass,
223+ NGX_HTTP_LOC_CONF_OFFSET,
224+ 0,
225+ NULL },
226+
227+ { ngx_string("proxy_redirect"),
228+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
229+ ngx_http_proxy_redirect,
230+ NGX_HTTP_LOC_CONF_OFFSET,
231+ 0,
232+ NULL },
233+
234+ { ngx_string("proxy_cookie_domain"),
235+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
236+ ngx_http_proxy_cookie_domain,
237+ NGX_HTTP_LOC_CONF_OFFSET,
238+ 0,
239+ NULL },
240+
241+ { ngx_string("proxy_cookie_path"),
242+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
243+ ngx_http_proxy_cookie_path,
244+ NGX_HTTP_LOC_CONF_OFFSET,
245+ 0,
246+ NULL },
247+
248+ { ngx_string("proxy_store"),
249+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
250+ ngx_http_proxy_store,
251+ NGX_HTTP_LOC_CONF_OFFSET,
252+ 0,
253+ NULL },
254+
255+ { ngx_string("proxy_store_access"),
256+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
257+ ngx_conf_set_access_slot,
258+ NGX_HTTP_LOC_CONF_OFFSET,
259+ offsetof(ngx_http_proxy_loc_conf_t, upstream.store_access),
260+ NULL },
261+
262+ { ngx_string("proxy_buffering"),
263+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
264+ ngx_conf_set_flag_slot,
265+ NGX_HTTP_LOC_CONF_OFFSET,
266+ offsetof(ngx_http_proxy_loc_conf_t, upstream.buffering),
267+ NULL },
268+
269+ { ngx_string("proxy_ignore_client_abort"),
270+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
271+ ngx_conf_set_flag_slot,
272+ NGX_HTTP_LOC_CONF_OFFSET,
273+ offsetof(ngx_http_proxy_loc_conf_t, upstream.ignore_client_abort),
274+ NULL },
275+
276+ { ngx_string("proxy_bind"),
277+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
278+ ngx_http_upstream_bind_set_slot,
279+ NGX_HTTP_LOC_CONF_OFFSET,
280+ offsetof(ngx_http_proxy_loc_conf_t, upstream.local),
281+ NULL },
282+
283+ { ngx_string("proxy_connect_timeout"),
284+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
285+ ngx_conf_set_msec_slot,
286+ NGX_HTTP_LOC_CONF_OFFSET,
287+ offsetof(ngx_http_proxy_loc_conf_t, upstream.connect_timeout),
288+ NULL },
289+
290+ { ngx_string("proxy_send_timeout"),
291+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
292+ ngx_conf_set_msec_slot,
293+ NGX_HTTP_LOC_CONF_OFFSET,
294+ offsetof(ngx_http_proxy_loc_conf_t, upstream.send_timeout),
295+ NULL },
296+
297+ { ngx_string("proxy_send_lowat"),
298+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
299+ ngx_conf_set_size_slot,
300+ NGX_HTTP_LOC_CONF_OFFSET,
301+ offsetof(ngx_http_proxy_loc_conf_t, upstream.send_lowat),
302+ &ngx_http_proxy_lowat_post },
303+
304+ { ngx_string("proxy_intercept_errors"),
305+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
306+ ngx_conf_set_flag_slot,
307+ NGX_HTTP_LOC_CONF_OFFSET,
308+ offsetof(ngx_http_proxy_loc_conf_t, upstream.intercept_errors),
309+ NULL },
310+
311+ { ngx_string("proxy_set_header"),
312+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
313+ ngx_conf_set_keyval_slot,
314+ NGX_HTTP_LOC_CONF_OFFSET,
315+ offsetof(ngx_http_proxy_loc_conf_t, headers_source),
316+ NULL },
317+
318+ { ngx_string("proxy_headers_hash_max_size"),
319+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
320+ ngx_conf_set_num_slot,
321+ NGX_HTTP_LOC_CONF_OFFSET,
322+ offsetof(ngx_http_proxy_loc_conf_t, headers_hash_max_size),
323+ NULL },
324+
325+ { ngx_string("proxy_headers_hash_bucket_size"),
326+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
327+ ngx_conf_set_num_slot,
328+ NGX_HTTP_LOC_CONF_OFFSET,
329+ offsetof(ngx_http_proxy_loc_conf_t, headers_hash_bucket_size),
330+ NULL },
331+
332+ { ngx_string("proxy_set_body"),
333+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
334+ ngx_conf_set_str_slot,
335+ NGX_HTTP_LOC_CONF_OFFSET,
336+ offsetof(ngx_http_proxy_loc_conf_t, body_source),
337+ NULL },
338+
339+ { ngx_string("proxy_method"),
340+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
341+ ngx_conf_set_str_slot,
342+ NGX_HTTP_LOC_CONF_OFFSET,
343+ offsetof(ngx_http_proxy_loc_conf_t, method),
344+ NULL },
345+
346+ { ngx_string("proxy_pass_request_headers"),
347+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
348+ ngx_conf_set_flag_slot,
349+ NGX_HTTP_LOC_CONF_OFFSET,
350+ offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_headers),
351+ NULL },
352+
353+ { ngx_string("proxy_pass_request_body"),
354+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
355+ ngx_conf_set_flag_slot,
356+ NGX_HTTP_LOC_CONF_OFFSET,
357+ offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_body),
358+ NULL },
359+
360+ { ngx_string("proxy_buffer_size"),
361+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
362+ ngx_conf_set_size_slot,
363+ NGX_HTTP_LOC_CONF_OFFSET,
364+ offsetof(ngx_http_proxy_loc_conf_t, upstream.buffer_size),
365+ NULL },
366+
367+ { ngx_string("proxy_read_timeout"),
368+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
369+ ngx_conf_set_msec_slot,
370+ NGX_HTTP_LOC_CONF_OFFSET,
371+ offsetof(ngx_http_proxy_loc_conf_t, upstream.read_timeout),
372+ NULL },
373+
374+ { ngx_string("proxy_buffers"),
375+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
376+ ngx_conf_set_bufs_slot,
377+ NGX_HTTP_LOC_CONF_OFFSET,
378+ offsetof(ngx_http_proxy_loc_conf_t, upstream.bufs),
379+ NULL },
380+
381+ { ngx_string("proxy_busy_buffers_size"),
382+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
383+ ngx_conf_set_size_slot,
384+ NGX_HTTP_LOC_CONF_OFFSET,
385+ offsetof(ngx_http_proxy_loc_conf_t, upstream.busy_buffers_size_conf),
386+ NULL },
387+
388+#if (NGX_HTTP_CACHE)
389+
390+ { ngx_string("proxy_cache"),
391+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
392+ ngx_http_proxy_cache,
393+ NGX_HTTP_LOC_CONF_OFFSET,
394+ 0,
395+ NULL },
396+
397+ { ngx_string("proxy_cache_key"),
398+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
399+ ngx_http_proxy_cache_key,
400+ NGX_HTTP_LOC_CONF_OFFSET,
401+ 0,
402+ NULL },
403+
404+ { ngx_string("proxy_cache_path"),
405+ NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE,
406+ ngx_http_file_cache_set_slot,
407+ 0,
408+ 0,
409+ &ngx_http_proxy_module },
410+
411+ { ngx_string("proxy_cache_bypass"),
412+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
413+ ngx_http_set_predicate_slot,
414+ NGX_HTTP_LOC_CONF_OFFSET,
415+ offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_bypass),
416+ NULL },
417+
418+ { ngx_string("proxy_no_cache"),
419+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
420+ ngx_http_set_predicate_slot,
421+ NGX_HTTP_LOC_CONF_OFFSET,
422+ offsetof(ngx_http_proxy_loc_conf_t, upstream.no_cache),
423+ NULL },
424+
425+ { ngx_string("proxy_cache_valid"),
426+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
427+ ngx_http_file_cache_valid_set_slot,
428+ NGX_HTTP_LOC_CONF_OFFSET,
429+ offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_valid),
430+ NULL },
431+
432+ { ngx_string("proxy_cache_min_uses"),
433+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
434+ ngx_conf_set_num_slot,
435+ NGX_HTTP_LOC_CONF_OFFSET,
436+ offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_min_uses),
437+ NULL },
438+
439+ { ngx_string("proxy_cache_use_stale"),
440+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
441+ ngx_conf_set_bitmask_slot,
442+ NGX_HTTP_LOC_CONF_OFFSET,
443+ offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_use_stale),
444+ &ngx_http_proxy_next_upstream_masks },
445+
446+ { ngx_string("proxy_cache_methods"),
447+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
448+ ngx_conf_set_bitmask_slot,
449+ NGX_HTTP_LOC_CONF_OFFSET,
450+ offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_methods),
451+ &ngx_http_upstream_cache_method_mask },
452+
453+ { ngx_string("proxy_cache_lock"),
454+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
455+ ngx_conf_set_flag_slot,
456+ NGX_HTTP_LOC_CONF_OFFSET,
457+ offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_lock),
458+ NULL },
459+
460+ { ngx_string("proxy_cache_lock_timeout"),
461+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
462+ ngx_conf_set_msec_slot,
463+ NGX_HTTP_LOC_CONF_OFFSET,
464+ offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_lock_timeout),
465+ NULL },
466+
467+#endif
468+
469+ { ngx_string("proxy_temp_path"),
470+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
471+ ngx_conf_set_path_slot,
472+ NGX_HTTP_LOC_CONF_OFFSET,
473+ offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_path),
474+ NULL },
475+
476+ { ngx_string("proxy_max_temp_file_size"),
477+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
478+ ngx_conf_set_size_slot,
479+ NGX_HTTP_LOC_CONF_OFFSET,
480+ offsetof(ngx_http_proxy_loc_conf_t, upstream.max_temp_file_size_conf),
481+ NULL },
482+
483+ { ngx_string("proxy_temp_file_write_size"),
484+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
485+ ngx_conf_set_size_slot,
486+ NGX_HTTP_LOC_CONF_OFFSET,
487+ offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_file_write_size_conf),
488+ NULL },
489+
490+ { ngx_string("proxy_next_upstream"),
491+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
492+ ngx_conf_set_bitmask_slot,
493+ NGX_HTTP_LOC_CONF_OFFSET,
494+ offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream),
495+ &ngx_http_proxy_next_upstream_masks },
496+
497+ { ngx_string("proxy_pass_header"),
498+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
499+ ngx_conf_set_str_array_slot,
500+ NGX_HTTP_LOC_CONF_OFFSET,
501+ offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_headers),
502+ NULL },
503+
504+ { ngx_string("proxy_hide_header"),
505+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
506+ ngx_conf_set_str_array_slot,
507+ NGX_HTTP_LOC_CONF_OFFSET,
508+ offsetof(ngx_http_proxy_loc_conf_t, upstream.hide_headers),
509+ NULL },
510+
511+ { ngx_string("proxy_ignore_headers"),
512+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
513+ ngx_conf_set_bitmask_slot,
514+ NGX_HTTP_LOC_CONF_OFFSET,
515+ offsetof(ngx_http_proxy_loc_conf_t, upstream.ignore_headers),
516+ &ngx_http_upstream_ignore_headers_masks },
517+
518+ { ngx_string("proxy_http_version"),
519+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
520+ ngx_conf_set_enum_slot,
521+ NGX_HTTP_LOC_CONF_OFFSET,
522+ offsetof(ngx_http_proxy_loc_conf_t, http_version),
523+ &ngx_http_proxy_http_version },
524+
525+#if (NGX_HTTP_SSL)
526+
527+ { ngx_string("proxy_ssl_session_reuse"),
528+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
529+ ngx_conf_set_flag_slot,
530+ NGX_HTTP_LOC_CONF_OFFSET,
531+ offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_session_reuse),
532+ NULL },
533+
534+#endif
535+
536+ ngx_null_command
537+};
538+
539+
540+static ngx_http_module_t ngx_http_proxy_module_ctx = {
541+ ngx_http_proxy_add_variables, /* preconfiguration */
542+ NULL, /* postconfiguration */
543+
544+ NULL, /* create main configuration */
545+ NULL, /* init main configuration */
546+
547+ NULL, /* create server configuration */
548+ NULL, /* merge server configuration */
549+
550+ ngx_http_proxy_create_loc_conf, /* create location configuration */
551+ ngx_http_proxy_merge_loc_conf /* merge location configuration */
552+};
553+
554+
555+ngx_module_t ngx_http_proxy_module = {
556+ NGX_MODULE_V1,
557+ &ngx_http_proxy_module_ctx, /* module context */
558+ ngx_http_proxy_commands, /* module directives */
559+ NGX_HTTP_MODULE, /* module type */
560+ NULL, /* init master */
561+ NULL, /* init module */
562+ NULL, /* init process */
563+ NULL, /* init thread */
564+ NULL, /* exit thread */
565+ NULL, /* exit process */
566+ NULL, /* exit master */
567+ NGX_MODULE_V1_PADDING
568+};
569+
570+
571+static char ngx_http_proxy_version[] = " HTTP/1.0" CRLF;
572+static char ngx_http_proxy_version_11[] = " HTTP/1.1" CRLF;
573+
574+
575+static ngx_keyval_t ngx_http_proxy_headers[] = {
576+ { ngx_string("Host"), ngx_string("$proxy_host") },
577+ { ngx_string("Connection"), ngx_string("close") },
578+ { ngx_string("Keep-Alive"), ngx_string("") },
579+ { ngx_string("Expect"), ngx_string("") },
580+ { ngx_string("Upgrade"), ngx_string("") },
581+ { ngx_null_string, ngx_null_string }
582+};
583+
584+
585+static ngx_str_t ngx_http_proxy_hide_headers[] = {
586+ ngx_string("Date"),
587+ ngx_string("Server"),
588+ ngx_string("X-Pad"),
589+ ngx_string("X-Accel-Expires"),
590+ ngx_string("X-Accel-Redirect"),
591+ ngx_string("X-Accel-Limit-Rate"),
592+ ngx_string("X-Accel-Buffering"),
593+ ngx_string("X-Accel-Charset"),
594+ ngx_null_string
595+};
596+
597+
598+#if (NGX_HTTP_CACHE)
599+
600+static ngx_keyval_t ngx_http_proxy_cache_headers[] = {
601+ { ngx_string("Host"), ngx_string("$proxy_host") },
602+ { ngx_string("Connection"), ngx_string("close") },
603+ { ngx_string("Keep-Alive"), ngx_string("") },
604+ { ngx_string("Expect"), ngx_string("") },
605+ { ngx_string("Upgrade"), ngx_string("") },
606+ { ngx_string("If-Modified-Since"), ngx_string("") },
607+ { ngx_string("If-Unmodified-Since"), ngx_string("") },
608+ { ngx_string("If-None-Match"), ngx_string("") },
609+ { ngx_string("If-Match"), ngx_string("") },
610+ { ngx_string("Range"), ngx_string("") },
611+ { ngx_string("If-Range"), ngx_string("") },
612+ { ngx_null_string, ngx_null_string }
613+};
614+
615+#endif
616+
617+
618+static ngx_http_variable_t ngx_http_proxy_vars[] = {
619+
620+ { ngx_string("proxy_host"), NULL, ngx_http_proxy_host_variable, 0,
621+ NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
622+
623+ { ngx_string("proxy_port"), NULL, ngx_http_proxy_port_variable, 0,
624+ NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
625+
626+ { ngx_string("proxy_add_x_forwarded_for"), NULL,
627+ ngx_http_proxy_add_x_forwarded_for_variable, 0, NGX_HTTP_VAR_NOHASH, 0 },
628+
629+#if 0
630+ { ngx_string("proxy_add_via"), NULL, NULL, 0, NGX_HTTP_VAR_NOHASH, 0 },
631+#endif
632+
633+ { ngx_string("proxy_internal_body_length"), NULL,
634+ ngx_http_proxy_internal_body_length_variable, 0, NGX_HTTP_VAR_NOHASH, 0 },
635+
636+ { ngx_null_string, NULL, NULL, 0, 0, 0 }
637+};
638+
639+
640+static ngx_path_init_t ngx_http_proxy_temp_path = {
641+ ngx_string(NGX_HTTP_PROXY_TEMP_PATH), { 1, 2, 0 }
642+};
643+
644+
645+static ngx_int_t
646+ngx_http_proxy_handler(ngx_http_request_t *r)
647+{
648+ ngx_int_t rc;
649+ ngx_http_upstream_t *u;
650+ ngx_http_proxy_ctx_t *ctx;
651+ ngx_http_proxy_loc_conf_t *plcf;
652+
653+ if (ngx_http_upstream_create(r) != NGX_OK) {
654+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
655+ }
656+
657+ ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_ctx_t));
658+ if (ctx == NULL) {
659+ return NGX_ERROR;
660+ }
661+
662+ ngx_http_set_ctx(r, ctx, ngx_http_proxy_module);
663+
664+ plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
665+
666+ u = r->upstream;
667+
668+ if (plcf->proxy_lengths == NULL) {
669+ ctx->vars = plcf->vars;
670+ u->schema = plcf->vars.schema;
671+#if (NGX_HTTP_SSL)
672+ u->ssl = (plcf->upstream.ssl != NULL);
673+#endif
674+
675+ } else {
676+ if (ngx_http_proxy_eval(r, ctx, plcf) != NGX_OK) {
677+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
678+ }
679+ }
680+
681+ u->output.tag = (ngx_buf_tag_t) &ngx_http_proxy_module;
682+
683+ u->conf = &plcf->upstream;
684+
685+#if (NGX_HTTP_CACHE)
686+ u->create_key = ngx_http_proxy_create_key;
687+#endif
688+ u->create_request = ngx_http_proxy_create_request;
689+ u->reinit_request = ngx_http_proxy_reinit_request;
690+ u->process_header = ngx_http_proxy_process_status_line;
691+ u->abort_request = ngx_http_proxy_abort_request;
692+ u->finalize_request = ngx_http_proxy_finalize_request;
693+ r->state = 0;
694+
695+ if (plcf->redirects) {
696+ u->rewrite_redirect = ngx_http_proxy_rewrite_redirect;
697+ }
698+
699+ if (plcf->cookie_domains || plcf->cookie_paths) {
700+ u->rewrite_cookie = ngx_http_proxy_rewrite_cookie;
701+ }
702+
703+ u->buffering = plcf->upstream.buffering;
704+
705+ u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
706+ if (u->pipe == NULL) {
707+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
708+ }
709+
710+ u->pipe->input_filter = ngx_http_proxy_copy_filter;
711+ u->pipe->input_ctx = r;
712+
713+ u->input_filter_init = ngx_http_proxy_input_filter_init;
714+ u->input_filter = ngx_http_proxy_non_buffered_copy_filter;
715+ u->input_filter_ctx = r;
716+
717+ u->accel = 1;
718+
719+ rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
720+
721+ if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
722+ return rc;
723+ }
724+
725+ return NGX_DONE;
726+}
727+
728+
729+static ngx_int_t
730+ngx_http_proxy_eval(ngx_http_request_t *r, ngx_http_proxy_ctx_t *ctx,
731+ ngx_http_proxy_loc_conf_t *plcf)
732+{
733+ u_char *p;
734+ size_t add;
735+ u_short port;
736+ ngx_str_t proxy;
737+ ngx_url_t url;
738+ ngx_http_upstream_t *u;
739+
740+ if (ngx_http_script_run(r, &proxy, plcf->proxy_lengths->elts, 0,
741+ plcf->proxy_values->elts)
742+ == NULL)
743+ {
744+ return NGX_ERROR;
745+ }
746+
747+ if (proxy.len > 7
748+ && ngx_strncasecmp(proxy.data, (u_char *) "http://", 7) == 0)
749+ {
750+ add = 7;
751+ port = 80;
752+
753+#if (NGX_HTTP_SSL)
754+
755+ } else if (proxy.len > 8
756+ && ngx_strncasecmp(proxy.data, (u_char *) "https://", 8) == 0)
757+ {
758+ add = 8;
759+ port = 443;
760+ r->upstream->ssl = 1;
761+
762+#endif
763+
764+ } else {
765+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
766+ "invalid URL prefix in \"%V\"", &proxy);
767+ return NGX_ERROR;
768+ }
769+
770+ u = r->upstream;
771+
772+ u->schema.len = add;
773+ u->schema.data = proxy.data;
774+
775+ ngx_memzero(&url, sizeof(ngx_url_t));
776+
777+ url.url.len = proxy.len - add;
778+ url.url.data = proxy.data + add;
779+ url.default_port = port;
780+ url.uri_part = 1;
781+ url.no_resolve = 1;
782+
783+ if (ngx_parse_url(r->pool, &url) != NGX_OK) {
784+ if (url.err) {
785+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
786+ "%s in upstream \"%V\"", url.err, &url.url);
787+ }
788+
789+ return NGX_ERROR;
790+ }
791+
792+ if (url.uri.len) {
793+ if (url.uri.data[0] == '?') {
794+ p = ngx_pnalloc(r->pool, url.uri.len + 1);
795+ if (p == NULL) {
796+ return NGX_ERROR;
797+ }
798+
799+ *p++ = '/';
800+ ngx_memcpy(p, url.uri.data, url.uri.len);
801+
802+ url.uri.len++;
803+ url.uri.data = p - 1;
804+ }
805+ }
806+
807+ ctx->vars.key_start = u->schema;
808+
809+ ngx_http_proxy_set_vars(&url, &ctx->vars);
810+
811+ u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
812+ if (u->resolved == NULL) {
813+ return NGX_ERROR;
814+ }
815+
816+ if (url.addrs && url.addrs[0].sockaddr) {
817+ u->resolved->sockaddr = url.addrs[0].sockaddr;
818+ u->resolved->socklen = url.addrs[0].socklen;
819+ u->resolved->naddrs = 1;
820+ u->resolved->host = url.addrs[0].name;
821+
822+ } else {
823+ u->resolved->host = url.host;
824+ u->resolved->port = (in_port_t) (url.no_port ? port : url.port);
825+ u->resolved->no_port = url.no_port;
826+ }
827+
828+ return NGX_OK;
829+}
830+
831+
832+#if (NGX_HTTP_CACHE)
833+
834+static ngx_int_t
835+ngx_http_proxy_create_key(ngx_http_request_t *r)
836+{
837+ size_t len, loc_len;
838+ u_char *p;
839+ uintptr_t escape;
840+ ngx_str_t *key;
841+ ngx_http_upstream_t *u;
842+ ngx_http_proxy_ctx_t *ctx;
843+ ngx_http_proxy_loc_conf_t *plcf;
844+
845+ u = r->upstream;
846+
847+ plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
848+
849+ ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
850+
851+ key = ngx_array_push(&r->cache->keys);
852+ if (key == NULL) {
853+ return NGX_ERROR;
854+ }
855+
856+ if (plcf->cache_key.value.len) {
857+
858+ if (ngx_http_complex_value(r, &plcf->cache_key, key) != NGX_OK) {
859+ return NGX_ERROR;
860+ }
861+
862+ return NGX_OK;
863+ }
864+
865+ *key = ctx->vars.key_start;
866+
867+ key = ngx_array_push(&r->cache->keys);
868+ if (key == NULL) {
869+ return NGX_ERROR;
870+ }
871+
872+ if (plcf->proxy_lengths && ctx->vars.uri.len) {
873+
874+ *key = ctx->vars.uri;
875+ u->uri = ctx->vars.uri;
876+
877+ return NGX_OK;
878+
879+ } else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri && r == r->main)
880+ {
881+ *key = r->unparsed_uri;
882+ u->uri = r->unparsed_uri;
883+
884+ return NGX_OK;
885+ }
886+
887+ loc_len = (r->valid_location && ctx->vars.uri.len) ? plcf->location.len : 0;
888+
889+ if (r->quoted_uri || r->internal) {
890+ escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len,
891+ r->uri.len - loc_len, NGX_ESCAPE_URI);
892+ } else {
893+ escape = 0;
894+ }
895+
896+ len = ctx->vars.uri.len + r->uri.len - loc_len + escape
897+ + sizeof("?") - 1 + r->args.len;
898+
899+ p = ngx_pnalloc(r->pool, len);
900+ if (p == NULL) {
901+ return NGX_ERROR;
902+ }
903+
904+ key->data = p;
905+
906+ if (r->valid_location) {
907+ p = ngx_copy(p, ctx->vars.uri.data, ctx->vars.uri.len);
908+ }
909+
910+ if (escape) {
911+ ngx_escape_uri(p, r->uri.data + loc_len,
912+ r->uri.len - loc_len, NGX_ESCAPE_URI);
913+ p += r->uri.len - loc_len + escape;
914+
915+ } else {
916+ p = ngx_copy(p, r->uri.data + loc_len, r->uri.len - loc_len);
917+ }
918+
919+ if (r->args.len > 0) {
920+ *p++ = '?';
921+ p = ngx_copy(p, r->args.data, r->args.len);
922+ }
923+
924+ key->len = p - key->data;
925+ u->uri = *key;
926+
927+ return NGX_OK;
928+}
929+
930+#endif
931+
932+
933+static ngx_int_t
934+ngx_http_proxy_create_request(ngx_http_request_t *r)
935+{
936+ size_t len, uri_len, loc_len, body_len;
937+ uintptr_t escape;
938+ ngx_buf_t *b;
939+ ngx_str_t method;
940+ ngx_uint_t i, unparsed_uri;
941+ ngx_chain_t *cl, *body;
942+ ngx_list_part_t *part;
943+ ngx_table_elt_t *header;
944+ ngx_http_upstream_t *u;
945+ ngx_http_proxy_ctx_t *ctx;
946+ ngx_http_script_code_pt code;
947+ ngx_http_script_engine_t e, le;
948+ ngx_http_proxy_loc_conf_t *plcf;
949+ ngx_http_script_len_code_pt lcode;
950+
951+ u = r->upstream;
952+
953+ plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
954+
955+ if (u->method.len) {
956+ /* HEAD was changed to GET to cache response */
957+ method = u->method;
958+ method.len++;
959+
960+ } else if (plcf->method.len) {
961+ method = plcf->method;
962+
963+ } else {
964+ method = r->method_name;
965+ method.len++;
966+ }
967+
968+ ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
969+
970+ if (method.len == 5
971+ && ngx_strncasecmp(method.data, (u_char *) "HEAD ", 5) == 0)
972+ {
973+ ctx->head = 1;
974+ }
975+
976+ len = method.len + sizeof(ngx_http_proxy_version) - 1 + sizeof(CRLF) - 1;
977+
978+ escape = 0;
979+ loc_len = 0;
980+ unparsed_uri = 0;
981+
982+ if (plcf->proxy_lengths && ctx->vars.uri.len) {
983+ uri_len = ctx->vars.uri.len;
984+
985+ } else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri && r == r->main)
986+ {
987+ unparsed_uri = 1;
988+ uri_len = r->unparsed_uri.len;
989+
990+ } else {
991+ loc_len = (r->valid_location && ctx->vars.uri.len) ?
992+ plcf->location.len : 0;
993+
994+ if (r->quoted_uri || r->space_in_uri || r->internal) {
995+ escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len,
996+ r->uri.len - loc_len, NGX_ESCAPE_URI);
997+ }
998+
999+ uri_len = ctx->vars.uri.len + r->uri.len - loc_len + escape
1000+ + sizeof("?") - 1 + r->args.len;
1001+ }
1002+
1003+ if (uri_len == 0) {
1004+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1005+ "zero length URI to proxy");
1006+ return NGX_ERROR;
1007+ }
1008+
1009+ len += uri_len;
1010+
1011+ ngx_http_script_flush_no_cacheable_variables(r, plcf->flushes);
1012+
1013+ if (plcf->body_set_len) {
1014+ le.ip = plcf->body_set_len->elts;
1015+ le.request = r;
1016+ le.flushed = 1;
1017+ body_len = 0;
1018+
1019+ while (*(uintptr_t *) le.ip) {
1020+ lcode = *(ngx_http_script_len_code_pt *) le.ip;
1021+ body_len += lcode(&le);
1022+ }
1023+
1024+ ctx->internal_body_length = body_len;
1025+ len += body_len;
1026+ }
1027+
1028+ le.ip = plcf->headers_set_len->elts;
1029+ le.request = r;
1030+ le.flushed = 1;
1031+
1032+ while (*(uintptr_t *) le.ip) {
1033+ while (*(uintptr_t *) le.ip) {
1034+ lcode = *(ngx_http_script_len_code_pt *) le.ip;
1035+ len += lcode(&le);
1036+ }
1037+ le.ip += sizeof(uintptr_t);
1038+ }
1039+
1040+
1041+ if (plcf->upstream.pass_request_headers) {
1042+ part = &r->headers_in.headers.part;
1043+ header = part->elts;
1044+
1045+ for (i = 0; /* void */; i++) {
1046+
1047+ if (i >= part->nelts) {
1048+ if (part->next == NULL) {
1049+ break;
1050+ }
1051+
1052+ part = part->next;
1053+ header = part->elts;
1054+ i = 0;
1055+ }
1056+
1057+ if (ngx_hash_find(&plcf->headers_set_hash, header[i].hash,
1058+ header[i].lowcase_key, header[i].key.len))
1059+ {
1060+ continue;
1061+ }
1062+
1063+ len += header[i].key.len + sizeof(": ") - 1
1064+ + header[i].value.len + sizeof(CRLF) - 1;
1065+ }
1066+ }
1067+
1068+
1069+ b = ngx_create_temp_buf(r->pool, len);
1070+ if (b == NULL) {
1071+ return NGX_ERROR;
1072+ }
1073+
1074+ cl = ngx_alloc_chain_link(r->pool);
1075+ if (cl == NULL) {
1076+ return NGX_ERROR;
1077+ }
1078+
1079+ cl->buf = b;
1080+
1081+
1082+ /* the request line */
1083+
1084+ b->last = ngx_copy(b->last, method.data, method.len);
1085+
1086+ u->uri.data = b->last;
1087+
1088+ if (plcf->proxy_lengths && ctx->vars.uri.len) {
1089+ b->last = ngx_copy(b->last, ctx->vars.uri.data, ctx->vars.uri.len);
1090+
1091+ } else if (unparsed_uri) {
1092+ b->last = ngx_copy(b->last, r->unparsed_uri.data, r->unparsed_uri.len);
1093+
1094+ } else {
1095+ if (r->valid_location) {
1096+ b->last = ngx_copy(b->last, ctx->vars.uri.data, ctx->vars.uri.len);
1097+ }
1098+
1099+ if (escape) {
1100+ ngx_escape_uri(b->last, r->uri.data + loc_len,
1101+ r->uri.len - loc_len, NGX_ESCAPE_URI);
1102+ b->last += r->uri.len - loc_len + escape;
1103+
1104+ } else {
1105+ b->last = ngx_copy(b->last, r->uri.data + loc_len,
1106+ r->uri.len - loc_len);
1107+ }
1108+
1109+ if (r->args.len > 0) {
1110+ *b->last++ = '?';
1111+ b->last = ngx_copy(b->last, r->args.data, r->args.len);
1112+ }
1113+ }
1114+
1115+ u->uri.len = b->last - u->uri.data;
1116+
1117+ if (plcf->http_version == NGX_HTTP_VERSION_11) {
1118+ b->last = ngx_cpymem(b->last, ngx_http_proxy_version_11,
1119+ sizeof(ngx_http_proxy_version_11) - 1);
1120+
1121+ } else {
1122+ b->last = ngx_cpymem(b->last, ngx_http_proxy_version,
1123+ sizeof(ngx_http_proxy_version) - 1);
1124+ }
1125+
1126+ ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
1127+
1128+ e.ip = plcf->headers_set->elts;
1129+ e.pos = b->last;
1130+ e.request = r;
1131+ e.flushed = 1;
1132+
1133+ le.ip = plcf->headers_set_len->elts;
1134+
1135+ while (*(uintptr_t *) le.ip) {
1136+ lcode = *(ngx_http_script_len_code_pt *) le.ip;
1137+
1138+ /* skip the header line name length */
1139+ (void) lcode(&le);
1140+
1141+ if (*(ngx_http_script_len_code_pt *) le.ip) {
1142+
1143+ for (len = 0; *(uintptr_t *) le.ip; len += lcode(&le)) {
1144+ lcode = *(ngx_http_script_len_code_pt *) le.ip;
1145+ }
1146+
1147+ e.skip = (len == sizeof(CRLF) - 1) ? 1 : 0;
1148+
1149+ } else {
1150+ e.skip = 0;
1151+ }
1152+
1153+ le.ip += sizeof(uintptr_t);
1154+
1155+ while (*(uintptr_t *) e.ip) {
1156+ code = *(ngx_http_script_code_pt *) e.ip;
1157+ code((ngx_http_script_engine_t *) &e);
1158+ }
1159+ e.ip += sizeof(uintptr_t);
1160+ }
1161+
1162+ b->last = e.pos;
1163+
1164+
1165+ if (plcf->upstream.pass_request_headers) {
1166+ part = &r->headers_in.headers.part;
1167+ header = part->elts;
1168+
1169+ for (i = 0; /* void */; i++) {
1170+
1171+ if (i >= part->nelts) {
1172+ if (part->next == NULL) {
1173+ break;
1174+ }
1175+
1176+ part = part->next;
1177+ header = part->elts;
1178+ i = 0;
1179+ }
1180+
1181+ if (ngx_hash_find(&plcf->headers_set_hash, header[i].hash,
1182+ header[i].lowcase_key, header[i].key.len))
1183+ {
1184+ continue;
1185+ }
1186+
1187+ b->last = ngx_copy(b->last, header[i].key.data, header[i].key.len);
1188+
1189+ *b->last++ = ':'; *b->last++ = ' ';
1190+
1191+ b->last = ngx_copy(b->last, header[i].value.data,
1192+ header[i].value.len);
1193+
1194+ *b->last++ = CR; *b->last++ = LF;
1195+
1196+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1197+ "http proxy header: \"%V: %V\"",
1198+ &header[i].key, &header[i].value);
1199+ }
1200+ }
1201+
1202+
1203+ /* add "\r\n" at the header end */
1204+ *b->last++ = CR; *b->last++ = LF;
1205+
1206+ if (plcf->body_set) {
1207+ e.ip = plcf->body_set->elts;
1208+ e.pos = b->last;
1209+
1210+ while (*(uintptr_t *) e.ip) {
1211+ code = *(ngx_http_script_code_pt *) e.ip;
1212+ code((ngx_http_script_engine_t *) &e);
1213+ }
1214+
1215+ b->last = e.pos;
1216+ }
1217+
1218+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1219+ "http proxy header:\n\"%*s\"",
1220+ (size_t) (b->last - b->pos), b->pos);
1221+
1222+ if (plcf->body_set == NULL && plcf->upstream.pass_request_body) {
1223+
1224+ body = u->request_bufs;
1225+ u->request_bufs = cl;
1226+
1227+ while (body) {
1228+ b = ngx_alloc_buf(r->pool);
1229+ if (b == NULL) {
1230+ return NGX_ERROR;
1231+ }
1232+
1233+ ngx_memcpy(b, body->buf, sizeof(ngx_buf_t));
1234+
1235+ cl->next = ngx_alloc_chain_link(r->pool);
1236+ if (cl->next == NULL) {
1237+ return NGX_ERROR;
1238+ }
1239+
1240+ cl = cl->next;
1241+ cl->buf = b;
1242+
1243+ body = body->next;
1244+ }
1245+
1246+ } else {
1247+ u->request_bufs = cl;
1248+ }
1249+
1250+ b->flush = 1;
1251+ cl->next = NULL;
1252+
1253+ return NGX_OK;
1254+}
1255+
1256+
1257+static ngx_int_t
1258+ngx_http_proxy_reinit_request(ngx_http_request_t *r)
1259+{
1260+ ngx_http_proxy_ctx_t *ctx;
1261+
1262+ ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1263+
1264+ if (ctx == NULL) {
1265+ return NGX_OK;
1266+ }
1267+
1268+ ctx->status.code = 0;
1269+ ctx->status.count = 0;
1270+ ctx->status.start = NULL;
1271+ ctx->status.end = NULL;
1272+ ctx->state = 0;
1273+
1274+ r->upstream->process_header = ngx_http_proxy_process_status_line;
1275+ r->upstream->pipe->input_filter = ngx_http_proxy_copy_filter;
1276+ r->upstream->input_filter = ngx_http_proxy_non_buffered_copy_filter;
1277+ r->state = 0;
1278+
1279+ return NGX_OK;
1280+}
1281+
1282+
1283+static ngx_int_t
1284+ngx_http_proxy_process_status_line(ngx_http_request_t *r)
1285+{
1286+ size_t len;
1287+ ngx_int_t rc;
1288+ ngx_http_upstream_t *u;
1289+ ngx_http_proxy_ctx_t *ctx;
1290+
1291+ ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1292+
1293+ if (ctx == NULL) {
1294+ return NGX_ERROR;
1295+ }
1296+
1297+ u = r->upstream;
1298+
1299+ rc = ngx_http_parse_status_line(r, &u->buffer, &ctx->status);
1300+
1301+ if (rc == NGX_AGAIN) {
1302+ return rc;
1303+ }
1304+
1305+ if (rc == NGX_ERROR) {
1306+
1307+#if (NGX_HTTP_CACHE)
1308+
1309+ if (r->cache) {
1310+ r->http_version = NGX_HTTP_VERSION_9;
1311+ return NGX_OK;
1312+ }
1313+
1314+#endif
1315+
1316+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1317+ "upstream sent no valid HTTP/1.0 header");
1318+
1319+#if 0
1320+ if (u->accel) {
1321+ return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1322+ }
1323+#endif
1324+
1325+ r->http_version = NGX_HTTP_VERSION_9;
1326+ u->state->status = NGX_HTTP_OK;
1327+ u->headers_in.connection_close = 1;
1328+
1329+ return NGX_OK;
1330+ }
1331+
1332+ if (u->state) {
1333+ u->state->status = ctx->status.code;
1334+ }
1335+
1336+ u->headers_in.status_n = ctx->status.code;
1337+
1338+ len = ctx->status.end - ctx->status.start;
1339+ u->headers_in.status_line.len = len;
1340+
1341+ u->headers_in.status_line.data = ngx_pnalloc(r->pool, len);
1342+ if (u->headers_in.status_line.data == NULL) {
1343+ return NGX_ERROR;
1344+ }
1345+
1346+ ngx_memcpy(u->headers_in.status_line.data, ctx->status.start, len);
1347+
1348+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1349+ "http proxy status %ui \"%V\"",
1350+ u->headers_in.status_n, &u->headers_in.status_line);
1351+
1352+ if (ctx->status.http_version < NGX_HTTP_VERSION_11) {
1353+ u->headers_in.connection_close = 1;
1354+ }
1355+
1356+ u->process_header = ngx_http_proxy_process_header;
1357+
1358+ return ngx_http_proxy_process_header(r);
1359+}
1360+
1361+
1362+static ngx_int_t
1363+ngx_http_proxy_process_header(ngx_http_request_t *r)
1364+{
1365+ ngx_int_t rc;
1366+ ngx_table_elt_t *h;
1367+ ngx_http_upstream_t *u;
1368+ ngx_http_proxy_ctx_t *ctx;
1369+ ngx_http_upstream_header_t *hh;
1370+ ngx_http_upstream_main_conf_t *umcf;
1371+
1372+ umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
1373+
1374+ for ( ;; ) {
1375+
1376+ rc = ngx_http_parse_header_line(r, &r->upstream->buffer, 1);
1377+
1378+ if (rc == NGX_OK) {
1379+
1380+ /* a header line has been parsed successfully */
1381+
1382+ h = ngx_list_push(&r->upstream->headers_in.headers);
1383+ if (h == NULL) {
1384+ return NGX_ERROR;
1385+ }
1386+
1387+ h->hash = r->header_hash;
1388+
1389+ h->key.len = r->header_name_end - r->header_name_start;
1390+ h->value.len = r->header_end - r->header_start;
1391+
1392+ h->key.data = ngx_pnalloc(r->pool,
1393+ h->key.len + 1 + h->value.len + 1 + h->key.len);
1394+ if (h->key.data == NULL) {
1395+ return NGX_ERROR;
1396+ }
1397+
1398+ h->value.data = h->key.data + h->key.len + 1;
1399+ h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1;
1400+
1401+ ngx_memcpy(h->key.data, r->header_name_start, h->key.len);
1402+ h->key.data[h->key.len] = '\0';
1403+ ngx_memcpy(h->value.data, r->header_start, h->value.len);
1404+ h->value.data[h->value.len] = '\0';
1405+
1406+ if (h->key.len == r->lowcase_index) {
1407+ ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len);
1408+
1409+ } else {
1410+ ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
1411+ }
1412+
1413+ hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
1414+ h->lowcase_key, h->key.len);
1415+
1416+ if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
1417+ return NGX_ERROR;
1418+ }
1419+
1420+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1421+ "http proxy header: \"%V: %V\"",
1422+ &h->key, &h->value);
1423+
1424+ continue;
1425+ }
1426+
1427+ if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
1428+
1429+ /* a whole header has been parsed successfully */
1430+
1431+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1432+ "http proxy header done");
1433+
1434+ /*
1435+ * if no "Server" and "Date" in header line,
1436+ * then add the special empty headers
1437+ */
1438+
1439+ if (r->upstream->headers_in.server == NULL) {
1440+ h = ngx_list_push(&r->upstream->headers_in.headers);
1441+ if (h == NULL) {
1442+ return NGX_ERROR;
1443+ }
1444+
1445+ h->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash(
1446+ ngx_hash('s', 'e'), 'r'), 'v'), 'e'), 'r');
1447+
1448+ ngx_str_set(&h->key, "Server");
1449+ ngx_str_null(&h->value);
1450+ h->lowcase_key = (u_char *) "server";
1451+ }
1452+
1453+ if (r->upstream->headers_in.date == NULL) {
1454+ h = ngx_list_push(&r->upstream->headers_in.headers);
1455+ if (h == NULL) {
1456+ return NGX_ERROR;
1457+ }
1458+
1459+ h->hash = ngx_hash(ngx_hash(ngx_hash('d', 'a'), 't'), 'e');
1460+
1461+ ngx_str_set(&h->key, "Date");
1462+ ngx_str_null(&h->value);
1463+ h->lowcase_key = (u_char *) "date";
1464+ }
1465+
1466+ /* clear content length if response is chunked */
1467+
1468+ u = r->upstream;
1469+
1470+ if (u->headers_in.chunked) {
1471+ u->headers_in.content_length_n = -1;
1472+ }
1473+
1474+ /*
1475+ * set u->keepalive if response has no body; this allows to keep
1476+ * connections alive in case of r->header_only or X-Accel-Redirect
1477+ */
1478+
1479+ ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1480+
1481+ if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
1482+ || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED
1483+ || ctx->head
1484+ || (!u->headers_in.chunked
1485+ && u->headers_in.content_length_n == 0))
1486+ {
1487+ u->keepalive = !u->headers_in.connection_close;
1488+ }
1489+
1490+ return NGX_OK;
1491+ }
1492+
1493+ if (rc == NGX_AGAIN) {
1494+ return NGX_AGAIN;
1495+ }
1496+
1497+ /* there was error while a header line parsing */
1498+
1499+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1500+ "upstream sent invalid header");
1501+
1502+ return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1503+ }
1504+}
1505+
1506+
1507+static ngx_int_t
1508+ngx_http_proxy_input_filter_init(void *data)
1509+{
1510+ ngx_http_request_t *r = data;
1511+ ngx_http_upstream_t *u;
1512+ ngx_http_proxy_ctx_t *ctx;
1513+
1514+ u = r->upstream;
1515+ ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1516+
1517+ if (ctx == NULL) {
1518+ return NGX_ERROR;
1519+ }
1520+
1521+ ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1522+ "http proxy filter init s:%d h:%d c:%d l:%O",
1523+ u->headers_in.status_n, ctx->head, u->headers_in.chunked,
1524+ u->headers_in.content_length_n);
1525+
1526+ /* as per RFC2616, 4.4 Message Length */
1527+
1528+ if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
1529+ || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED
1530+ || ctx->head)
1531+ {
1532+ /* 1xx, 204, and 304 and replies to HEAD requests */
1533+ /* no 1xx since we don't send Expect and Upgrade */
1534+
1535+ u->pipe->length = 0;
1536+ u->length = 0;
1537+ u->keepalive = !u->headers_in.connection_close;
1538+
1539+ } else if (u->headers_in.chunked) {
1540+ /* chunked */
1541+
1542+ u->pipe->input_filter = ngx_http_proxy_chunked_filter;
1543+ u->pipe->length = 3; /* "0" LF LF */
1544+
1545+ u->input_filter = ngx_http_proxy_non_buffered_chunked_filter;
1546+ u->length = -1;
1547+
1548+ } else if (u->headers_in.content_length_n == 0) {
1549+ /* empty body: special case as filter won't be called */
1550+
1551+ u->pipe->length = 0;
1552+ u->length = 0;
1553+ u->keepalive = !u->headers_in.connection_close;
1554+
1555+ } else {
1556+ /* content length or connection close */
1557+
1558+ u->pipe->length = u->headers_in.content_length_n;
1559+ u->length = u->headers_in.content_length_n;
1560+ }
1561+
1562+ return NGX_OK;
1563+}
1564+
1565+
1566+static ngx_int_t
1567+ngx_http_proxy_copy_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
1568+{
1569+ ngx_buf_t *b;
1570+ ngx_chain_t *cl;
1571+ ngx_http_request_t *r;
1572+
1573+ if (buf->pos == buf->last) {
1574+ return NGX_OK;
1575+ }
1576+
1577+ if (p->free) {
1578+ cl = p->free;
1579+ b = cl->buf;
1580+ p->free = cl->next;
1581+ ngx_free_chain(p->pool, cl);
1582+
1583+ } else {
1584+ b = ngx_alloc_buf(p->pool);
1585+ if (b == NULL) {
1586+ return NGX_ERROR;
1587+ }
1588+ }
1589+
1590+ ngx_memcpy(b, buf, sizeof(ngx_buf_t));
1591+ b->shadow = buf;
1592+ b->tag = p->tag;
1593+ b->last_shadow = 1;
1594+ b->recycled = 1;
1595+ buf->shadow = b;
1596+
1597+ cl = ngx_alloc_chain_link(p->pool);
1598+ if (cl == NULL) {
1599+ return NGX_ERROR;
1600+ }
1601+
1602+ cl->buf = b;
1603+ cl->next = NULL;
1604+
1605+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "input buf #%d", b->num);
1606+
1607+ if (p->in) {
1608+ *p->last_in = cl;
1609+ } else {
1610+ p->in = cl;
1611+ }
1612+ p->last_in = &cl->next;
1613+
1614+ if (p->length == -1) {
1615+ return NGX_OK;
1616+ }
1617+
1618+ p->length -= b->last - b->pos;
1619+
1620+ if (p->length == 0) {
1621+ r = p->input_ctx;
1622+ p->upstream_done = 1;
1623+ r->upstream->keepalive = !r->upstream->headers_in.connection_close;
1624+
1625+ } else if (p->length < 0) {
1626+ r = p->input_ctx;
1627+ p->upstream_done = 1;
1628+
1629+ ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
1630+ "upstream sent too much data");
1631+ }
1632+
1633+ return NGX_OK;
1634+}
1635+
1636+
1637+static ngx_inline ngx_int_t
1638+ngx_http_proxy_parse_chunked(ngx_http_request_t *r, ngx_buf_t *buf)
1639+{
1640+ u_char *pos, ch, c;
1641+ ngx_int_t rc;
1642+ ngx_http_proxy_ctx_t *ctx;
1643+ enum {
1644+ sw_chunk_start = 0,
1645+ sw_chunk_size,
1646+ sw_chunk_extension,
1647+ sw_chunk_extension_almost_done,
1648+ sw_chunk_data,
1649+ sw_after_data,
1650+ sw_after_data_almost_done,
1651+ sw_last_chunk_extension,
1652+ sw_last_chunk_extension_almost_done,
1653+ sw_trailer,
1654+ sw_trailer_almost_done,
1655+ sw_trailer_header,
1656+ sw_trailer_header_almost_done
1657+ } state;
1658+
1659+ ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1660+
1661+ if (ctx == NULL) {
1662+ return NGX_ERROR;
1663+ }
1664+
1665+ state = ctx->state;
1666+
1667+ if (state == sw_chunk_data && ctx->size == 0) {
1668+ state = sw_after_data;
1669+ }
1670+
1671+ rc = NGX_AGAIN;
1672+
1673+ for (pos = buf->pos; pos < buf->last; pos++) {
1674+
1675+ ch = *pos;
1676+
1677+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1678+ "http proxy chunked byte: %02Xd s:%d", ch, state);
1679+
1680+ switch (state) {
1681+
1682+ case sw_chunk_start:
1683+ if (ch >= '0' && ch <= '9') {
1684+ state = sw_chunk_size;
1685+ ctx->size = ch - '0';
1686+ break;
1687+ }
1688+
1689+ c = (u_char) (ch | 0x20);
1690+
1691+ if (c >= 'a' && c <= 'f') {
1692+ state = sw_chunk_size;
1693+ ctx->size = c - 'a' + 10;
1694+ break;
1695+ }
1696+
1697+ goto invalid;
1698+
1699+ case sw_chunk_size:
1700+ if (ch >= '0' && ch <= '9') {
1701+ ctx->size = ctx->size * 16 + (ch - '0');
1702+ break;
1703+ }
1704+
1705+ c = (u_char) (ch | 0x20);
1706+
1707+ if (c >= 'a' && c <= 'f') {
1708+ ctx->size = ctx->size * 16 + (c - 'a' + 10);
1709+ break;
1710+ }
1711+
1712+ if (ctx->size == 0) {
1713+
1714+ switch (ch) {
1715+ case CR:
1716+ state = sw_last_chunk_extension_almost_done;
1717+ break;
1718+ case LF:
1719+ state = sw_trailer;
1720+ break;
1721+ case ';':
1722+ case ' ':
1723+ case '\t':
1724+ state = sw_last_chunk_extension;
1725+ break;
1726+ default:
1727+ goto invalid;
1728+ }
1729+
1730+ break;
1731+ }
1732+
1733+ switch (ch) {
1734+ case CR:
1735+ state = sw_chunk_extension_almost_done;
1736+ break;
1737+ case LF:
1738+ state = sw_chunk_data;
1739+ break;
1740+ case ';':
1741+ case ' ':
1742+ case '\t':
1743+ state = sw_chunk_extension;
1744+ break;
1745+ default:
1746+ goto invalid;
1747+ }
1748+
1749+ break;
1750+
1751+ case sw_chunk_extension:
1752+ switch (ch) {
1753+ case CR:
1754+ state = sw_chunk_extension_almost_done;
1755+ break;
1756+ case LF:
1757+ state = sw_chunk_data;
1758+ }
1759+ break;
1760+
1761+ case sw_chunk_extension_almost_done:
1762+ if (ch == LF) {
1763+ state = sw_chunk_data;
1764+ break;
1765+ }
1766+ goto invalid;
1767+
1768+ case sw_chunk_data:
1769+ rc = NGX_OK;
1770+ goto data;
1771+
1772+ case sw_after_data:
1773+ switch (ch) {
1774+ case CR:
1775+ state = sw_after_data_almost_done;
1776+ break;
1777+ case LF:
1778+ state = sw_chunk_start;
1779+ }
1780+ break;
1781+
1782+ case sw_after_data_almost_done:
1783+ if (ch == LF) {
1784+ state = sw_chunk_start;
1785+ break;
1786+ }
1787+ goto invalid;
1788+
1789+ case sw_last_chunk_extension:
1790+ switch (ch) {
1791+ case CR:
1792+ state = sw_last_chunk_extension_almost_done;
1793+ break;
1794+ case LF:
1795+ state = sw_trailer;
1796+ }
1797+ break;
1798+
1799+ case sw_last_chunk_extension_almost_done:
1800+ if (ch == LF) {
1801+ state = sw_trailer;
1802+ break;
1803+ }
1804+ goto invalid;
1805+
1806+ case sw_trailer:
1807+ switch (ch) {
1808+ case CR:
1809+ state = sw_trailer_almost_done;
1810+ break;
1811+ case LF:
1812+ goto done;
1813+ default:
1814+ state = sw_trailer_header;
1815+ }
1816+ break;
1817+
1818+ case sw_trailer_almost_done:
1819+ if (ch == LF) {
1820+ goto done;
1821+ }
1822+ goto invalid;
1823+
1824+ case sw_trailer_header:
1825+ switch (ch) {
1826+ case CR:
1827+ state = sw_trailer_header_almost_done;
1828+ break;
1829+ case LF:
1830+ state = sw_trailer;
1831+ }
1832+ break;
1833+
1834+ case sw_trailer_header_almost_done:
1835+ if (ch == LF) {
1836+ state = sw_trailer;
1837+ break;
1838+ }
1839+ goto invalid;
1840+
1841+ }
1842+ }
1843+
1844+data:
1845+
1846+ ctx->state = state;
1847+ buf->pos = pos;
1848+
1849+ switch (state) {
1850+
1851+ case sw_chunk_start:
1852+ ctx->length = 3 /* "0" LF LF */;
1853+ break;
1854+ case sw_chunk_size:
1855+ ctx->length = 2 /* LF LF */
1856+ + (ctx->size ? ctx->size + 4 /* LF "0" LF LF */ : 0);
1857+ break;
1858+ case sw_chunk_extension:
1859+ case sw_chunk_extension_almost_done:
1860+ ctx->length = 1 /* LF */ + ctx->size + 4 /* LF "0" LF LF */;
1861+ break;
1862+ case sw_chunk_data:
1863+ ctx->length = ctx->size + 4 /* LF "0" LF LF */;
1864+ break;
1865+ case sw_after_data:
1866+ case sw_after_data_almost_done:
1867+ ctx->length = 4 /* LF "0" LF LF */;
1868+ break;
1869+ case sw_last_chunk_extension:
1870+ case sw_last_chunk_extension_almost_done:
1871+ ctx->length = 2 /* LF LF */;
1872+ break;
1873+ case sw_trailer:
1874+ case sw_trailer_almost_done:
1875+ ctx->length = 1 /* LF */;
1876+ break;
1877+ case sw_trailer_header:
1878+ case sw_trailer_header_almost_done:
1879+ ctx->length = 2 /* LF LF */;
1880+ break;
1881+
1882+ }
1883+
1884+ return rc;
1885+
1886+done:
1887+
1888+ return NGX_DONE;
1889+
1890+invalid:
1891+
1892+ return NGX_ERROR;
1893+}
1894+
1895+
1896+static ngx_int_t
1897+ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
1898+{
1899+ ngx_int_t rc;
1900+ ngx_buf_t *b, **prev;
1901+ ngx_chain_t *cl;
1902+ ngx_http_request_t *r;
1903+ ngx_http_proxy_ctx_t *ctx;
1904+
1905+ if (buf->pos == buf->last) {
1906+ return NGX_OK;
1907+ }
1908+
1909+ r = p->input_ctx;
1910+ ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1911+
1912+ if (ctx == NULL) {
1913+ return NGX_ERROR;
1914+ }
1915+
1916+ b = NULL;
1917+ prev = &buf->shadow;
1918+
1919+ for ( ;; ) {
1920+
1921+ rc = ngx_http_proxy_parse_chunked(r, buf);
1922+
1923+ if (rc == NGX_OK) {
1924+
1925+ /* a chunk has been parsed successfully */
1926+
1927+ if (p->free) {
1928+ cl = p->free;
1929+ b = cl->buf;
1930+ p->free = cl->next;
1931+ ngx_free_chain(p->pool, cl);
1932+
1933+ } else {
1934+ b = ngx_alloc_buf(p->pool);
1935+ if (b == NULL) {
1936+ return NGX_ERROR;
1937+ }
1938+ }
1939+
1940+ ngx_memzero(b, sizeof(ngx_buf_t));
1941+
1942+ b->pos = buf->pos;
1943+ b->start = buf->start;
1944+ b->end = buf->end;
1945+ b->tag = p->tag;
1946+ b->temporary = 1;
1947+ b->recycled = 1;
1948+
1949+ *prev = b;
1950+ prev = &b->shadow;
1951+
1952+ cl = ngx_alloc_chain_link(p->pool);
1953+ if (cl == NULL) {
1954+ return NGX_ERROR;
1955+ }
1956+
1957+ cl->buf = b;
1958+ cl->next = NULL;
1959+
1960+ if (p->in) {
1961+ *p->last_in = cl;
1962+ } else {
1963+ p->in = cl;
1964+ }
1965+ p->last_in = &cl->next;
1966+
1967+ /* STUB */ b->num = buf->num;
1968+
1969+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
1970+ "input buf #%d %p", b->num, b->pos);
1971+
1972+ if (buf->last - buf->pos >= ctx->size) {
1973+
1974+ buf->pos += ctx->size;
1975+ b->last = buf->pos;
1976+ ctx->size = 0;
1977+
1978+ continue;
1979+ }
1980+
1981+ ctx->size -= buf->last - buf->pos;
1982+ buf->pos = buf->last;
1983+ b->last = buf->last;
1984+
1985+ continue;
1986+ }
1987+
1988+ if (rc == NGX_DONE) {
1989+
1990+ /* a whole response has been parsed successfully */
1991+
1992+ p->upstream_done = 1;
1993+ r->upstream->keepalive = !r->upstream->headers_in.connection_close;
1994+
1995+ break;
1996+ }
1997+
1998+ if (rc == NGX_AGAIN) {
1999+
2000+ /* set p->length, minimal amount of data we want to see */
2001+
2002+ p->length = ctx->length;
2003+
2004+ break;
2005+ }
2006+
2007+ /* invalid response */
2008+
2009+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2010+ "upstream sent invalid chunked response");
2011+
2012+ return NGX_ERROR;
2013+ }
2014+
2015+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2016+ "http proxy chunked state %d, length %d",
2017+ ctx->state, p->length);
2018+
2019+ if (b) {
2020+ b->shadow = buf;
2021+ b->last_shadow = 1;
2022+
2023+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
2024+ "input buf %p %z", b->pos, b->last - b->pos);
2025+
2026+ return NGX_OK;
2027+ }
2028+
2029+ /* there is no data record in the buf, add it to free chain */
2030+
2031+ if (ngx_event_pipe_add_free_buf(p, buf) != NGX_OK) {
2032+ return NGX_ERROR;
2033+ }
2034+
2035+ return NGX_OK;
2036+}
2037+
2038+
2039+static ngx_int_t
2040+ngx_http_proxy_non_buffered_copy_filter(void *data, ssize_t bytes)
2041+{
2042+ ngx_http_request_t *r = data;
2043+
2044+ ngx_buf_t *b;
2045+ ngx_chain_t *cl, **ll;
2046+ ngx_http_upstream_t *u;
2047+
2048+ u = r->upstream;
2049+
2050+ for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
2051+ ll = &cl->next;
2052+ }
2053+
2054+ cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
2055+ if (cl == NULL) {
2056+ return NGX_ERROR;
2057+ }
2058+
2059+ *ll = cl;
2060+
2061+ cl->buf->flush = 1;
2062+ cl->buf->memory = 1;
2063+
2064+ b = &u->buffer;
2065+
2066+ cl->buf->pos = b->last;
2067+ b->last += bytes;
2068+ cl->buf->last = b->last;
2069+ cl->buf->tag = u->output.tag;
2070+
2071+ if (u->length == -1) {
2072+ return NGX_OK;
2073+ }
2074+
2075+ u->length -= bytes;
2076+
2077+ if (u->length == 0) {
2078+ u->keepalive = !u->headers_in.connection_close;
2079+ }
2080+
2081+ return NGX_OK;
2082+}
2083+
2084+
2085+static ngx_int_t
2086+ngx_http_proxy_non_buffered_chunked_filter(void *data, ssize_t bytes)
2087+{
2088+ ngx_http_request_t *r = data;
2089+
2090+ ngx_int_t rc;
2091+ ngx_buf_t *b, *buf;
2092+ ngx_chain_t *cl, **ll;
2093+ ngx_http_upstream_t *u;
2094+ ngx_http_proxy_ctx_t *ctx;
2095+
2096+ ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
2097+
2098+ if (ctx == NULL) {
2099+ return NGX_ERROR;
2100+ }
2101+
2102+ u = r->upstream;
2103+ buf = &u->buffer;
2104+
2105+ buf->pos = buf->last;
2106+ buf->last += bytes;
2107+
2108+ for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
2109+ ll = &cl->next;
2110+ }
2111+
2112+ for ( ;; ) {
2113+
2114+ rc = ngx_http_proxy_parse_chunked(r, buf);
2115+
2116+ if (rc == NGX_OK) {
2117+
2118+ /* a chunk has been parsed successfully */
2119+
2120+ cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
2121+ if (cl == NULL) {
2122+ return NGX_ERROR;
2123+ }
2124+
2125+ *ll = cl;
2126+ ll = &cl->next;
2127+
2128+ b = cl->buf;
2129+
2130+ b->flush = 1;
2131+ b->memory = 1;
2132+
2133+ b->pos = buf->pos;
2134+ b->tag = u->output.tag;
2135+
2136+ if (buf->last - buf->pos >= ctx->size) {
2137+ buf->pos += ctx->size;
2138+ b->last = buf->pos;
2139+ ctx->size = 0;
2140+
2141+ } else {
2142+ ctx->size -= buf->last - buf->pos;
2143+ buf->pos = buf->last;
2144+ b->last = buf->last;
2145+ }
2146+
2147+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2148+ "http proxy out buf %p %z",
2149+ b->pos, b->last - b->pos);
2150+
2151+ continue;
2152+ }
2153+
2154+ if (rc == NGX_DONE) {
2155+
2156+ /* a whole response has been parsed successfully */
2157+
2158+ u->keepalive = !u->headers_in.connection_close;
2159+ u->length = 0;
2160+
2161+ break;
2162+ }
2163+
2164+ if (rc == NGX_AGAIN) {
2165+ break;
2166+ }
2167+
2168+ /* invalid response */
2169+
2170+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2171+ "upstream sent invalid chunked response");
2172+
2173+ return NGX_ERROR;
2174+ }
2175+
2176+ /* provide continuous buffer for subrequests in memory */
2177+
2178+ if (r->subrequest_in_memory) {
2179+
2180+ cl = u->out_bufs;
2181+
2182+ if (cl) {
2183+ buf->pos = cl->buf->pos;
2184+ }
2185+
2186+ buf->last = buf->pos;
2187+
2188+ for (cl = u->out_bufs; cl; cl = cl->next) {
2189+ ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2190+ "http proxy in memory %p-%p %uz",
2191+ cl->buf->pos, cl->buf->last, ngx_buf_size(cl->buf));
2192+
2193+ if (buf->last == cl->buf->pos) {
2194+ buf->last = cl->buf->last;
2195+ continue;
2196+ }
2197+
2198+ buf->last = ngx_movemem(buf->last, cl->buf->pos,
2199+ cl->buf->last - cl->buf->pos);
2200+
2201+ cl->buf->pos = buf->last - (cl->buf->last - cl->buf->pos);
2202+ cl->buf->last = buf->last;
2203+ }
2204+ }
2205+
2206+ return NGX_OK;
2207+}
2208+
2209+
2210+static void
2211+ngx_http_proxy_abort_request(ngx_http_request_t *r)
2212+{
2213+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2214+ "abort http proxy request");
2215+
2216+ return;
2217+}
2218+
2219+
2220+static void
2221+ngx_http_proxy_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
2222+{
2223+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2224+ "finalize http proxy request");
2225+
2226+ return;
2227+}
2228+
2229+
2230+static ngx_int_t
2231+ngx_http_proxy_host_variable(ngx_http_request_t *r,
2232+ ngx_http_variable_value_t *v, uintptr_t data)
2233+{
2234+ ngx_http_proxy_ctx_t *ctx;
2235+
2236+ ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
2237+
2238+ if (ctx == NULL) {
2239+ v->not_found = 1;
2240+ return NGX_OK;
2241+ }
2242+
2243+ v->len = ctx->vars.host_header.len;
2244+ v->valid = 1;
2245+ v->no_cacheable = 0;
2246+ v->not_found = 0;
2247+ v->data = ctx->vars.host_header.data;
2248+
2249+ return NGX_OK;
2250+}
2251+
2252+
2253+static ngx_int_t
2254+ngx_http_proxy_port_variable(ngx_http_request_t *r,
2255+ ngx_http_variable_value_t *v, uintptr_t data)
2256+{
2257+ ngx_http_proxy_ctx_t *ctx;
2258+
2259+ ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
2260+
2261+ if (ctx == NULL) {
2262+ v->not_found = 1;
2263+ return NGX_OK;
2264+ }
2265+
2266+ v->len = ctx->vars.port.len;
2267+ v->valid = 1;
2268+ v->no_cacheable = 0;
2269+ v->not_found = 0;
2270+ v->data = ctx->vars.port.data;
2271+
2272+ return NGX_OK;
2273+}
2274+
2275+
2276+static ngx_int_t
2277+ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r,
2278+ ngx_http_variable_value_t *v, uintptr_t data)
2279+{
2280+ u_char *p;
2281+
2282+ v->valid = 1;
2283+ v->no_cacheable = 0;
2284+ v->not_found = 0;
2285+
2286+ if (r->headers_in.x_forwarded_for == NULL) {
2287+ v->len = r->connection->addr_text.len;
2288+ v->data = r->connection->addr_text.data;
2289+ return NGX_OK;
2290+ }
2291+
2292+ v->len = r->headers_in.x_forwarded_for->value.len
2293+ + sizeof(", ") - 1 + r->connection->addr_text.len;
2294+
2295+ p = ngx_pnalloc(r->pool, v->len);
2296+ if (p == NULL) {
2297+ return NGX_ERROR;
2298+ }
2299+
2300+ v->data = p;
2301+
2302+ p = ngx_copy(p, r->headers_in.x_forwarded_for->value.data,
2303+ r->headers_in.x_forwarded_for->value.len);
2304+
2305+ *p++ = ','; *p++ = ' ';
2306+
2307+ ngx_memcpy(p, r->connection->addr_text.data, r->connection->addr_text.len);
2308+
2309+ return NGX_OK;
2310+}
2311+
2312+
2313+static ngx_int_t
2314+ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r,
2315+ ngx_http_variable_value_t *v, uintptr_t data)
2316+{
2317+ ngx_http_proxy_ctx_t *ctx;
2318+
2319+ ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
2320+
2321+ if (ctx == NULL) {
2322+ v->not_found = 1;
2323+ return NGX_OK;
2324+ }
2325+
2326+ v->valid = 1;
2327+ v->no_cacheable = 0;
2328+ v->not_found = 0;
2329+
2330+ v->data = ngx_pnalloc(r->connection->pool, NGX_SIZE_T_LEN);
2331+
2332+ if (v->data == NULL) {
2333+ return NGX_ERROR;
2334+ }
2335+
2336+ v->len = ngx_sprintf(v->data, "%uz", ctx->internal_body_length) - v->data;
2337+
2338+ return NGX_OK;
2339+}
2340+
2341+
2342+static ngx_int_t
2343+ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, ngx_table_elt_t *h,
2344+ size_t prefix)
2345+{
2346+ size_t len;
2347+ ngx_int_t rc;
2348+ ngx_uint_t i;
2349+ ngx_http_proxy_rewrite_t *pr;
2350+ ngx_http_proxy_loc_conf_t *plcf;
2351+
2352+ plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
2353+
2354+ pr = plcf->redirects->elts;
2355+
2356+ if (pr == NULL) {
2357+ return NGX_DECLINED;
2358+ }
2359+
2360+ len = h->value.len - prefix;
2361+
2362+ for (i = 0; i < plcf->redirects->nelts; i++) {
2363+ rc = pr[i].handler(r, h, prefix, len, &pr[i]);
2364+
2365+ if (rc != NGX_DECLINED) {
2366+ return rc;
2367+ }
2368+ }
2369+
2370+ return NGX_DECLINED;
2371+}
2372+
2373+
2374+static ngx_int_t
2375+ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r, ngx_table_elt_t *h)
2376+{
2377+ size_t prefix;
2378+ u_char *p;
2379+ ngx_int_t rc, rv;
2380+ ngx_http_proxy_loc_conf_t *plcf;
2381+
2382+ p = (u_char *) ngx_strchr(h->value.data, ';');
2383+ if (p == NULL) {
2384+ return NGX_DECLINED;
2385+ }
2386+
2387+ prefix = p + 1 - h->value.data;
2388+
2389+ rv = NGX_DECLINED;
2390+
2391+ plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
2392+
2393+ if (plcf->cookie_domains) {
2394+ p = ngx_strcasestrn(h->value.data + prefix, "domain=", 7 - 1);
2395+
2396+ if (p) {
2397+ rc = ngx_http_proxy_rewrite_cookie_value(r, h, p + 7,
2398+ plcf->cookie_domains);
2399+ if (rc == NGX_ERROR) {
2400+ return NGX_ERROR;
2401+ }
2402+
2403+ if (rc != NGX_DECLINED) {
2404+ rv = rc;
2405+ }
2406+ }
2407+ }
2408+
2409+ if (plcf->cookie_paths) {
2410+ p = ngx_strcasestrn(h->value.data + prefix, "path=", 5 - 1);
2411+
2412+ if (p) {
2413+ rc = ngx_http_proxy_rewrite_cookie_value(r, h, p + 5,
2414+ plcf->cookie_paths);
2415+ if (rc == NGX_ERROR) {
2416+ return NGX_ERROR;
2417+ }
2418+
2419+ if (rc != NGX_DECLINED) {
2420+ rv = rc;
2421+ }
2422+ }
2423+ }
2424+
2425+ return rv;
2426+}
2427+
2428+
2429+static ngx_int_t
2430+ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r, ngx_table_elt_t *h,
2431+ u_char *value, ngx_array_t *rewrites)
2432+{
2433+ size_t len, prefix;
2434+ u_char *p;
2435+ ngx_int_t rc;
2436+ ngx_uint_t i;
2437+ ngx_http_proxy_rewrite_t *pr;
2438+
2439+ prefix = value - h->value.data;
2440+
2441+ p = (u_char *) ngx_strchr(value, ';');
2442+
2443+ len = p ? (size_t) (p - value) : (h->value.len - prefix);
2444+
2445+ pr = rewrites->elts;
2446+
2447+ for (i = 0; i < rewrites->nelts; i++) {
2448+ rc = pr[i].handler(r, h, prefix, len, &pr[i]);
2449+
2450+ if (rc != NGX_DECLINED) {
2451+ return rc;
2452+ }
2453+ }
2454+
2455+ return NGX_DECLINED;
2456+}
2457+
2458+
2459+static ngx_int_t
2460+ngx_http_proxy_rewrite_complex_handler(ngx_http_request_t *r,
2461+ ngx_table_elt_t *h, size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
2462+{
2463+ ngx_str_t pattern, replacement;
2464+
2465+ if (ngx_http_complex_value(r, &pr->pattern.complex, &pattern) != NGX_OK) {
2466+ return NGX_ERROR;
2467+ }
2468+
2469+ if (pattern.len > len
2470+ || ngx_rstrncmp(h->value.data + prefix, pattern.data,
2471+ pattern.len) != 0)
2472+ {
2473+ return NGX_DECLINED;
2474+ }
2475+
2476+ if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
2477+ return NGX_ERROR;
2478+ }
2479+
2480+ return ngx_http_proxy_rewrite(r, h, prefix, pattern.len, &replacement);
2481+}
2482+
2483+
2484+#if (NGX_PCRE)
2485+
2486+static ngx_int_t
2487+ngx_http_proxy_rewrite_regex_handler(ngx_http_request_t *r, ngx_table_elt_t *h,
2488+ size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
2489+{
2490+ ngx_str_t pattern, replacement;
2491+
2492+ pattern.len = len;
2493+ pattern.data = h->value.data + prefix;
2494+
2495+ if (ngx_http_regex_exec(r, pr->pattern.regex, &pattern) != NGX_OK) {
2496+ return NGX_DECLINED;
2497+ }
2498+
2499+ if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
2500+ return NGX_ERROR;
2501+ }
2502+
2503+ if (prefix == 0 && h->value.len == len) {
2504+ h->value = replacement;
2505+ return NGX_OK;
2506+ }
2507+
2508+ return ngx_http_proxy_rewrite(r, h, prefix, len, &replacement);
2509+}
2510+
2511+#endif
2512+
2513+
2514+static ngx_int_t
2515+ngx_http_proxy_rewrite_domain_handler(ngx_http_request_t *r,
2516+ ngx_table_elt_t *h, size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
2517+{
2518+ u_char *p;
2519+ ngx_str_t pattern, replacement;
2520+
2521+ if (ngx_http_complex_value(r, &pr->pattern.complex, &pattern) != NGX_OK) {
2522+ return NGX_ERROR;
2523+ }
2524+
2525+ p = h->value.data + prefix;
2526+
2527+ if (p[0] == '.') {
2528+ p++;
2529+ prefix++;
2530+ len--;
2531+ }
2532+
2533+ if (pattern.len != len || ngx_rstrncasecmp(pattern.data, p, len) != 0) {
2534+ return NGX_DECLINED;
2535+ }
2536+
2537+ if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
2538+ return NGX_ERROR;
2539+ }
2540+
2541+ return ngx_http_proxy_rewrite(r, h, prefix, len, &replacement);
2542+}
2543+
2544+
2545+static ngx_int_t
2546+ngx_http_proxy_rewrite(ngx_http_request_t *r, ngx_table_elt_t *h, size_t prefix,
2547+ size_t len, ngx_str_t *replacement)
2548+{
2549+ u_char *p, *data;
2550+ size_t new_len;
2551+
2552+ new_len = replacement->len + h->value.len - len;
2553+
2554+ if (replacement->len > len) {
2555+
2556+ data = ngx_pnalloc(r->pool, new_len);
2557+ if (data == NULL) {
2558+ return NGX_ERROR;
2559+ }
2560+
2561+ p = ngx_copy(data, h->value.data, prefix);
2562+ p = ngx_copy(p, replacement->data, replacement->len);
2563+
2564+ ngx_memcpy(p, h->value.data + prefix + len,
2565+ h->value.len - len - prefix);
2566+
2567+ h->value.data = data;
2568+
2569+ } else {
2570+ p = ngx_copy(h->value.data + prefix, replacement->data,
2571+ replacement->len);
2572+
2573+ ngx_memmove(p, h->value.data + prefix + len,
2574+ h->value.len - len - prefix);
2575+ }
2576+
2577+ h->value.len = new_len;
2578+
2579+ return NGX_OK;
2580+}
2581+
2582+
2583+static ngx_int_t
2584+ngx_http_proxy_add_variables(ngx_conf_t *cf)
2585+{
2586+ ngx_http_variable_t *var, *v;
2587+
2588+ for (v = ngx_http_proxy_vars; v->name.len; v++) {
2589+ var = ngx_http_add_variable(cf, &v->name, v->flags);
2590+ if (var == NULL) {
2591+ return NGX_ERROR;
2592+ }
2593+
2594+ var->get_handler = v->get_handler;
2595+ var->data = v->data;
2596+ }
2597+
2598+ return NGX_OK;
2599+}
2600+
2601+
2602+static void *
2603+ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
2604+{
2605+ ngx_http_proxy_loc_conf_t *conf;
2606+
2607+ conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_loc_conf_t));
2608+ if (conf == NULL) {
2609+ return NULL;
2610+ }
2611+
2612+ /*
2613+ * set by ngx_pcalloc():
2614+ *
2615+ * conf->upstream.bufs.num = 0;
2616+ * conf->upstream.ignore_headers = 0;
2617+ * conf->upstream.next_upstream = 0;
2618+ * conf->upstream.cache_use_stale = 0;
2619+ * conf->upstream.cache_methods = 0;
2620+ * conf->upstream.temp_path = NULL;
2621+ * conf->upstream.hide_headers_hash = { NULL, 0 };
2622+ * conf->upstream.uri = { 0, NULL };
2623+ * conf->upstream.location = NULL;
2624+ * conf->upstream.store_lengths = NULL;
2625+ * conf->upstream.store_values = NULL;
2626+ *
2627+ * conf->method = NULL;
2628+ * conf->headers_source = NULL;
2629+ * conf->headers_set_len = NULL;
2630+ * conf->headers_set = NULL;
2631+ * conf->headers_set_hash = NULL;
2632+ * conf->body_set_len = NULL;
2633+ * conf->body_set = NULL;
2634+ * conf->body_source = { 0, NULL };
2635+ * conf->redirects = NULL;
2636+ */
2637+
2638+ conf->upstream.store = NGX_CONF_UNSET;
2639+ conf->upstream.store_access = NGX_CONF_UNSET_UINT;
2640+ conf->upstream.buffering = NGX_CONF_UNSET;
2641+ conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
2642+
2643+ conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
2644+ conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
2645+ conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
2646+
2647+ conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
2648+ conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
2649+
2650+ conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE;
2651+ conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
2652+ conf->upstream.temp_file_write_size_conf = NGX_CONF_UNSET_SIZE;
2653+
2654+ conf->upstream.pass_request_headers = NGX_CONF_UNSET;
2655+ conf->upstream.pass_request_body = NGX_CONF_UNSET;
2656+
2657+#if (NGX_HTTP_CACHE)
2658+ conf->upstream.cache = NGX_CONF_UNSET_PTR;
2659+ conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
2660+ conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
2661+ conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
2662+ conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
2663+ conf->upstream.cache_lock = NGX_CONF_UNSET;
2664+ conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
2665+#endif
2666+
2667+ conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
2668+ conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;
2669+
2670+ conf->upstream.intercept_errors = NGX_CONF_UNSET;
2671+#if (NGX_HTTP_SSL)
2672+ conf->upstream.ssl_session_reuse = NGX_CONF_UNSET;
2673+#endif
2674+
2675+ /* "proxy_cyclic_temp_file" is disabled */
2676+ conf->upstream.cyclic_temp_file = 0;
2677+
2678+ conf->redirect = NGX_CONF_UNSET;
2679+ conf->upstream.change_buffering = 1;
2680+
2681+ conf->cookie_domains = NGX_CONF_UNSET_PTR;
2682+ conf->cookie_paths = NGX_CONF_UNSET_PTR;
2683+
2684+ conf->http_version = NGX_CONF_UNSET_UINT;
2685+
2686+ conf->headers_hash_max_size = NGX_CONF_UNSET_UINT;
2687+ conf->headers_hash_bucket_size = NGX_CONF_UNSET_UINT;
2688+
2689+ ngx_str_set(&conf->upstream.module, "proxy");
2690+
2691+ return conf;
2692+}
2693+
2694+
2695+static char *
2696+ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
2697+{
2698+ ngx_http_proxy_loc_conf_t *prev = parent;
2699+ ngx_http_proxy_loc_conf_t *conf = child;
2700+
2701+ u_char *p;
2702+ size_t size;
2703+ ngx_hash_init_t hash;
2704+ ngx_http_core_loc_conf_t *clcf;
2705+ ngx_http_proxy_rewrite_t *pr;
2706+ ngx_http_script_compile_t sc;
2707+
2708+ if (conf->upstream.store != 0) {
2709+ ngx_conf_merge_value(conf->upstream.store,
2710+ prev->upstream.store, 0);
2711+
2712+ if (conf->upstream.store_lengths == NULL) {
2713+ conf->upstream.store_lengths = prev->upstream.store_lengths;
2714+ conf->upstream.store_values = prev->upstream.store_values;
2715+ }
2716+ }
2717+
2718+ ngx_conf_merge_uint_value(conf->upstream.store_access,
2719+ prev->upstream.store_access, 0600);
2720+
2721+ ngx_conf_merge_value(conf->upstream.buffering,
2722+ prev->upstream.buffering, 1);
2723+
2724+ ngx_conf_merge_value(conf->upstream.ignore_client_abort,
2725+ prev->upstream.ignore_client_abort, 0);
2726+
2727+ ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
2728+ prev->upstream.connect_timeout, 60000);
2729+
2730+ ngx_conf_merge_msec_value(conf->upstream.send_timeout,
2731+ prev->upstream.send_timeout, 60000);
2732+
2733+ ngx_conf_merge_msec_value(conf->upstream.read_timeout,
2734+ prev->upstream.read_timeout, 60000);
2735+
2736+ ngx_conf_merge_size_value(conf->upstream.send_lowat,
2737+ prev->upstream.send_lowat, 0);
2738+
2739+ ngx_conf_merge_size_value(conf->upstream.buffer_size,
2740+ prev->upstream.buffer_size,
2741+ (size_t) ngx_pagesize);
2742+
2743+ ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
2744+ 8, ngx_pagesize);
2745+
2746+ if (conf->upstream.bufs.num < 2) {
2747+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2748+ "there must be at least 2 \"proxy_buffers\"");
2749+ return NGX_CONF_ERROR;
2750+ }
2751+
2752+
2753+ size = conf->upstream.buffer_size;
2754+ if (size < conf->upstream.bufs.size) {
2755+ size = conf->upstream.bufs.size;
2756+ }
2757+
2758+
2759+ ngx_conf_merge_size_value(conf->upstream.busy_buffers_size_conf,
2760+ prev->upstream.busy_buffers_size_conf,
2761+ NGX_CONF_UNSET_SIZE);
2762+
2763+ if (conf->upstream.busy_buffers_size_conf == NGX_CONF_UNSET_SIZE) {
2764+ conf->upstream.busy_buffers_size = 2 * size;
2765+ } else {
2766+ conf->upstream.busy_buffers_size =
2767+ conf->upstream.busy_buffers_size_conf;
2768+ }
2769+
2770+ if (conf->upstream.busy_buffers_size < size) {
2771+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2772+ "\"proxy_busy_buffers_size\" must be equal to or greater than "
2773+ "the maximum of the value of \"proxy_buffer_size\" and "
2774+ "one of the \"proxy_buffers\"");
2775+
2776+ return NGX_CONF_ERROR;
2777+ }
2778+
2779+ if (conf->upstream.busy_buffers_size
2780+ > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size)
2781+ {
2782+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2783+ "\"proxy_busy_buffers_size\" must be less than "
2784+ "the size of all \"proxy_buffers\" minus one buffer");
2785+
2786+ return NGX_CONF_ERROR;
2787+ }
2788+
2789+
2790+ ngx_conf_merge_size_value(conf->upstream.temp_file_write_size_conf,
2791+ prev->upstream.temp_file_write_size_conf,
2792+ NGX_CONF_UNSET_SIZE);
2793+
2794+ if (conf->upstream.temp_file_write_size_conf == NGX_CONF_UNSET_SIZE) {
2795+ conf->upstream.temp_file_write_size = 2 * size;
2796+ } else {
2797+ conf->upstream.temp_file_write_size =
2798+ conf->upstream.temp_file_write_size_conf;
2799+ }
2800+
2801+ if (conf->upstream.temp_file_write_size < size) {
2802+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2803+ "\"proxy_temp_file_write_size\" must be equal to or greater "
2804+ "than the maximum of the value of \"proxy_buffer_size\" and "
2805+ "one of the \"proxy_buffers\"");
2806+
2807+ return NGX_CONF_ERROR;
2808+ }
2809+
2810+ ngx_conf_merge_size_value(conf->upstream.max_temp_file_size_conf,
2811+ prev->upstream.max_temp_file_size_conf,
2812+ NGX_CONF_UNSET_SIZE);
2813+
2814+ if (conf->upstream.max_temp_file_size_conf == NGX_CONF_UNSET_SIZE) {
2815+ conf->upstream.max_temp_file_size = 1024 * 1024 * 1024;
2816+ } else {
2817+ conf->upstream.max_temp_file_size =
2818+ conf->upstream.max_temp_file_size_conf;
2819+ }
2820+
2821+ if (conf->upstream.max_temp_file_size != 0
2822+ && conf->upstream.max_temp_file_size < size)
2823+ {
2824+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2825+ "\"proxy_max_temp_file_size\" must be equal to zero to disable "
2826+ "temporary files usage or must be equal to or greater than "
2827+ "the maximum of the value of \"proxy_buffer_size\" and "
2828+ "one of the \"proxy_buffers\"");
2829+
2830+ return NGX_CONF_ERROR;
2831+ }
2832+
2833+
2834+ ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers,
2835+ prev->upstream.ignore_headers,
2836+ NGX_CONF_BITMASK_SET);
2837+
2838+
2839+ ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
2840+ prev->upstream.next_upstream,
2841+ (NGX_CONF_BITMASK_SET
2842+ |NGX_HTTP_UPSTREAM_FT_ERROR
2843+ |NGX_HTTP_UPSTREAM_FT_TIMEOUT));
2844+
2845+ if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
2846+ conf->upstream.next_upstream = NGX_CONF_BITMASK_SET
2847+ |NGX_HTTP_UPSTREAM_FT_OFF;
2848+ }
2849+
2850+ if (ngx_conf_merge_path_value(cf, &conf->upstream.temp_path,
2851+ prev->upstream.temp_path,
2852+ &ngx_http_proxy_temp_path)
2853+ != NGX_OK)
2854+ {
2855+ return NGX_CONF_ERROR;
2856+ }
2857+
2858+
2859+#if (NGX_HTTP_CACHE)
2860+
2861+ ngx_conf_merge_ptr_value(conf->upstream.cache,
2862+ prev->upstream.cache, NULL);
2863+
2864+ if (conf->upstream.cache && conf->upstream.cache->data == NULL) {
2865+ ngx_shm_zone_t *shm_zone;
2866+
2867+ shm_zone = conf->upstream.cache;
2868+
2869+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2870+ "\"proxy_cache\" zone \"%V\" is unknown",
2871+ &shm_zone->shm.name);
2872+
2873+ return NGX_CONF_ERROR;
2874+ }
2875+
2876+ ngx_conf_merge_uint_value(conf->upstream.cache_min_uses,
2877+ prev->upstream.cache_min_uses, 1);
2878+
2879+ ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale,
2880+ prev->upstream.cache_use_stale,
2881+ (NGX_CONF_BITMASK_SET
2882+ |NGX_HTTP_UPSTREAM_FT_OFF));
2883+
2884+ if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_OFF) {
2885+ conf->upstream.cache_use_stale = NGX_CONF_BITMASK_SET
2886+ |NGX_HTTP_UPSTREAM_FT_OFF;
2887+ }
2888+
2889+ if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_ERROR) {
2890+ conf->upstream.cache_use_stale |= NGX_HTTP_UPSTREAM_FT_NOLIVE;
2891+ }
2892+
2893+ if (conf->upstream.cache_methods == 0) {
2894+ conf->upstream.cache_methods = prev->upstream.cache_methods;
2895+ }
2896+
2897+ conf->upstream.cache_methods |= NGX_HTTP_GET|NGX_HTTP_HEAD;
2898+
2899+ ngx_conf_merge_ptr_value(conf->upstream.cache_bypass,
2900+ prev->upstream.cache_bypass, NULL);
2901+
2902+ ngx_conf_merge_ptr_value(conf->upstream.no_cache,
2903+ prev->upstream.no_cache, NULL);
2904+
2905+ if (conf->upstream.no_cache && conf->upstream.cache_bypass == NULL) {
2906+ ngx_log_error(NGX_LOG_WARN, cf->log, 0,
2907+ "\"proxy_no_cache\" functionality has been changed in 0.8.46, "
2908+ "now it should be used together with \"proxy_cache_bypass\"");
2909+ }
2910+
2911+ ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
2912+ prev->upstream.cache_valid, NULL);
2913+
2914+ if (conf->cache_key.value.data == NULL) {
2915+ conf->cache_key = prev->cache_key;
2916+ }
2917+
2918+ ngx_conf_merge_value(conf->upstream.cache_lock,
2919+ prev->upstream.cache_lock, 0);
2920+
2921+ ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
2922+ prev->upstream.cache_lock_timeout, 5000);
2923+
2924+#endif
2925+
2926+ if (conf->method.len == 0) {
2927+ conf->method = prev->method;
2928+
2929+ } else {
2930+ conf->method.data[conf->method.len] = ' ';
2931+ conf->method.len++;
2932+ }
2933+
2934+ ngx_conf_merge_value(conf->upstream.pass_request_headers,
2935+ prev->upstream.pass_request_headers, 1);
2936+ ngx_conf_merge_value(conf->upstream.pass_request_body,
2937+ prev->upstream.pass_request_body, 1);
2938+
2939+ ngx_conf_merge_value(conf->upstream.intercept_errors,
2940+ prev->upstream.intercept_errors, 0);
2941+
2942+#if (NGX_HTTP_SSL)
2943+ ngx_conf_merge_value(conf->upstream.ssl_session_reuse,
2944+ prev->upstream.ssl_session_reuse, 1);
2945+#endif
2946+
2947+ ngx_conf_merge_value(conf->redirect, prev->redirect, 1);
2948+
2949+ if (conf->redirect) {
2950+
2951+ if (conf->redirects == NULL) {
2952+ conf->redirects = prev->redirects;
2953+ }
2954+
2955+ if (conf->redirects == NULL && conf->url.data) {
2956+
2957+ conf->redirects = ngx_array_create(cf->pool, 1,
2958+ sizeof(ngx_http_proxy_rewrite_t));
2959+ if (conf->redirects == NULL) {
2960+ return NGX_CONF_ERROR;
2961+ }
2962+
2963+ pr = ngx_array_push(conf->redirects);
2964+ if (pr == NULL) {
2965+ return NGX_CONF_ERROR;
2966+ }
2967+
2968+ ngx_memzero(&pr->pattern.complex,
2969+ sizeof(ngx_http_complex_value_t));
2970+
2971+ ngx_memzero(&pr->replacement, sizeof(ngx_http_complex_value_t));
2972+
2973+ pr->handler = ngx_http_proxy_rewrite_complex_handler;
2974+
2975+ if (conf->vars.uri.len) {
2976+ pr->pattern.complex.value = conf->url;
2977+ pr->replacement.value = conf->location;
2978+
2979+ } else {
2980+ pr->pattern.complex.value.len = conf->url.len
2981+ + sizeof("/") - 1;
2982+
2983+ p = ngx_pnalloc(cf->pool, pr->pattern.complex.value.len);
2984+ if (p == NULL) {
2985+ return NGX_CONF_ERROR;
2986+ }
2987+
2988+ pr->pattern.complex.value.data = p;
2989+
2990+ p = ngx_cpymem(p, conf->url.data, conf->url.len);
2991+ *p = '/';
2992+
2993+ ngx_str_set(&pr->replacement.value, "/");
2994+ }
2995+ }
2996+ }
2997+
2998+ ngx_conf_merge_ptr_value(conf->cookie_domains, prev->cookie_domains, NULL);
2999+
3000+ ngx_conf_merge_ptr_value(conf->cookie_paths, prev->cookie_paths, NULL);
3001+
3002+#if (NGX_HTTP_SSL)
3003+ if (conf->upstream.ssl == NULL) {
3004+ conf->upstream.ssl = prev->upstream.ssl;
3005+ }
3006+#endif
3007+
3008+ ngx_conf_merge_uint_value(conf->http_version, prev->http_version,
3009+ NGX_HTTP_VERSION_10);
3010+
3011+ ngx_conf_merge_uint_value(conf->headers_hash_max_size,
3012+ prev->headers_hash_max_size, 512);
3013+
3014+ ngx_conf_merge_uint_value(conf->headers_hash_bucket_size,
3015+ prev->headers_hash_bucket_size, 64);
3016+
3017+ conf->headers_hash_bucket_size = ngx_align(conf->headers_hash_bucket_size,
3018+ ngx_cacheline_size);
3019+
3020+ hash.max_size = conf->headers_hash_max_size;
3021+ hash.bucket_size = conf->headers_hash_bucket_size;
3022+ hash.name = "proxy_headers_hash";
3023+
3024+ if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
3025+ &prev->upstream, ngx_http_proxy_hide_headers, &hash)
3026+ != NGX_OK)
3027+ {
3028+ return NGX_CONF_ERROR;
3029+ }
3030+
3031+ if (conf->upstream.upstream == NULL) {
3032+ conf->upstream.upstream = prev->upstream.upstream;
3033+ conf->vars = prev->vars;
3034+ }
3035+
3036+ if (conf->proxy_lengths == NULL) {
3037+ conf->proxy_lengths = prev->proxy_lengths;
3038+ conf->proxy_values = prev->proxy_values;
3039+ }
3040+
3041+ if (conf->upstream.upstream || conf->proxy_lengths) {
3042+ clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
3043+ if (clcf->handler == NULL && clcf->lmt_excpt) {
3044+ clcf->handler = ngx_http_proxy_handler;
3045+ conf->location = prev->location;
3046+ }
3047+ }
3048+
3049+ if (conf->body_source.data == NULL) {
3050+ conf->body_source = prev->body_source;
3051+ conf->body_set_len = prev->body_set_len;
3052+ conf->body_set = prev->body_set;
3053+ }
3054+
3055+ if (conf->body_source.data && conf->body_set_len == NULL) {
3056+
3057+ ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
3058+
3059+ sc.cf = cf;
3060+ sc.source = &conf->body_source;
3061+ sc.flushes = &conf->flushes;
3062+ sc.lengths = &conf->body_set_len;
3063+ sc.values = &conf->body_set;
3064+ sc.complete_lengths = 1;
3065+ sc.complete_values = 1;
3066+
3067+ if (ngx_http_script_compile(&sc) != NGX_OK) {
3068+ return NGX_CONF_ERROR;
3069+ }
3070+ }
3071+
3072+ if (ngx_http_proxy_merge_headers(cf, conf, prev) != NGX_OK) {
3073+ return NGX_CONF_ERROR;
3074+ }
3075+
3076+ return NGX_CONF_OK;
3077+}
3078+
3079+
3080+static ngx_int_t
3081+ngx_http_proxy_merge_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf,
3082+ ngx_http_proxy_loc_conf_t *prev)
3083+{
3084+ u_char *p;
3085+ size_t size;
3086+ uintptr_t *code;
3087+ ngx_uint_t i;
3088+ ngx_array_t headers_names, headers_merged;
3089+ ngx_keyval_t *src, *s, *h;
3090+ ngx_hash_key_t *hk;
3091+ ngx_hash_init_t hash;
3092+ ngx_http_script_compile_t sc;
3093+ ngx_http_script_copy_code_t *copy;
3094+
3095+ if (conf->headers_source == NULL) {
3096+ conf->flushes = prev->flushes;
3097+ conf->headers_set_len = prev->headers_set_len;
3098+ conf->headers_set = prev->headers_set;
3099+ conf->headers_set_hash = prev->headers_set_hash;
3100+ conf->headers_source = prev->headers_source;
3101+ }
3102+
3103+ if (conf->headers_set_hash.buckets
3104+ && ((conf->body_source.data == NULL)
3105+ == (prev->body_source.data == NULL))
3106+#if (NGX_HTTP_CACHE)
3107+ && ((conf->upstream.cache == NULL) == (prev->upstream.cache == NULL))
3108+#endif
3109+ )
3110+ {
3111+ return NGX_OK;
3112+ }
3113+
3114+
3115+ if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
3116+ != NGX_OK)
3117+ {
3118+ return NGX_ERROR;
3119+ }
3120+
3121+ if (ngx_array_init(&headers_merged, cf->temp_pool, 4, sizeof(ngx_keyval_t))
3122+ != NGX_OK)
3123+ {
3124+ return NGX_ERROR;
3125+ }
3126+
3127+ if (conf->headers_source == NULL) {
3128+ conf->headers_source = ngx_array_create(cf->pool, 4,
3129+ sizeof(ngx_keyval_t));
3130+ if (conf->headers_source == NULL) {
3131+ return NGX_ERROR;
3132+ }
3133+ }
3134+
3135+ conf->headers_set_len = ngx_array_create(cf->pool, 64, 1);
3136+ if (conf->headers_set_len == NULL) {
3137+ return NGX_ERROR;
3138+ }
3139+
3140+ conf->headers_set = ngx_array_create(cf->pool, 512, 1);
3141+ if (conf->headers_set == NULL) {
3142+ return NGX_ERROR;
3143+ }
3144+
3145+
3146+#if (NGX_HTTP_CACHE)
3147+
3148+ h = conf->upstream.cache ? ngx_http_proxy_cache_headers:
3149+ ngx_http_proxy_headers;
3150+#else
3151+
3152+ h = ngx_http_proxy_headers;
3153+
3154+#endif
3155+
3156+ src = conf->headers_source->elts;
3157+ for (i = 0; i < conf->headers_source->nelts; i++) {
3158+
3159+ s = ngx_array_push(&headers_merged);
3160+ if (s == NULL) {
3161+ return NGX_ERROR;
3162+ }
3163+
3164+ *s = src[i];
3165+ }
3166+
3167+ while (h->key.len) {
3168+
3169+ src = headers_merged.elts;
3170+ for (i = 0; i < headers_merged.nelts; i++) {
3171+ if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
3172+ goto next;
3173+ }
3174+ }
3175+
3176+ s = ngx_array_push(&headers_merged);
3177+ if (s == NULL) {
3178+ return NGX_ERROR;
3179+ }
3180+
3181+ *s = *h;
3182+
3183+ next:
3184+
3185+ h++;
3186+ }
3187+
3188+ if (conf->body_source.data) {
3189+ s = ngx_array_push(&headers_merged);
3190+ if (s == NULL) {
3191+ return NGX_ERROR;
3192+ }
3193+
3194+ ngx_str_set(&s->key, "Content-Length");
3195+ ngx_str_set(&s->value, "$proxy_internal_body_length");
3196+ }
3197+
3198+
3199+ src = headers_merged.elts;
3200+ for (i = 0; i < headers_merged.nelts; i++) {
3201+
3202+ hk = ngx_array_push(&headers_names);
3203+ if (hk == NULL) {
3204+ return NGX_ERROR;
3205+ }
3206+
3207+ hk->key = src[i].key;
3208+ hk->key_hash = ngx_hash_key_lc(src[i].key.data, src[i].key.len);
3209+ hk->value = (void *) 1;
3210+
3211+ if (src[i].value.len == 0) {
3212+ continue;
3213+ }
3214+
3215+ if (ngx_http_script_variables_count(&src[i].value) == 0) {
3216+ copy = ngx_array_push_n(conf->headers_set_len,
3217+ sizeof(ngx_http_script_copy_code_t));
3218+ if (copy == NULL) {
3219+ return NGX_ERROR;
3220+ }
3221+
3222+ copy->code = (ngx_http_script_code_pt)
3223+ ngx_http_script_copy_len_code;
3224+ copy->len = src[i].key.len + sizeof(": ") - 1
3225+ + src[i].value.len + sizeof(CRLF) - 1;
3226+
3227+
3228+ size = (sizeof(ngx_http_script_copy_code_t)
3229+ + src[i].key.len + sizeof(": ") - 1
3230+ + src[i].value.len + sizeof(CRLF) - 1
3231+ + sizeof(uintptr_t) - 1)
3232+ & ~(sizeof(uintptr_t) - 1);
3233+
3234+ copy = ngx_array_push_n(conf->headers_set, size);
3235+ if (copy == NULL) {
3236+ return NGX_ERROR;
3237+ }
3238+
3239+ copy->code = ngx_http_script_copy_code;
3240+ copy->len = src[i].key.len + sizeof(": ") - 1
3241+ + src[i].value.len + sizeof(CRLF) - 1;
3242+
3243+ p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
3244+
3245+ p = ngx_cpymem(p, src[i].key.data, src[i].key.len);
3246+ *p++ = ':'; *p++ = ' ';
3247+ p = ngx_cpymem(p, src[i].value.data, src[i].value.len);
3248+ *p++ = CR; *p = LF;
3249+
3250+ } else {
3251+ copy = ngx_array_push_n(conf->headers_set_len,
3252+ sizeof(ngx_http_script_copy_code_t));
3253+ if (copy == NULL) {
3254+ return NGX_ERROR;
3255+ }
3256+
3257+ copy->code = (ngx_http_script_code_pt)
3258+ ngx_http_script_copy_len_code;
3259+ copy->len = src[i].key.len + sizeof(": ") - 1;
3260+
3261+
3262+ size = (sizeof(ngx_http_script_copy_code_t)
3263+ + src[i].key.len + sizeof(": ") - 1 + sizeof(uintptr_t) - 1)
3264+ & ~(sizeof(uintptr_t) - 1);
3265+
3266+ copy = ngx_array_push_n(conf->headers_set, size);
3267+ if (copy == NULL) {
3268+ return NGX_ERROR;
3269+ }
3270+
3271+ copy->code = ngx_http_script_copy_code;
3272+ copy->len = src[i].key.len + sizeof(": ") - 1;
3273+
3274+ p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
3275+ p = ngx_cpymem(p, src[i].key.data, src[i].key.len);
3276+ *p++ = ':'; *p = ' ';
3277+
3278+
3279+ ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
3280+
3281+ sc.cf = cf;
3282+ sc.source = &src[i].value;
3283+ sc.flushes = &conf->flushes;
3284+ sc.lengths = &conf->headers_set_len;
3285+ sc.values = &conf->headers_set;
3286+
3287+ if (ngx_http_script_compile(&sc) != NGX_OK) {
3288+ return NGX_ERROR;
3289+ }
3290+
3291+
3292+ copy = ngx_array_push_n(conf->headers_set_len,
3293+ sizeof(ngx_http_script_copy_code_t));
3294+ if (copy == NULL) {
3295+ return NGX_ERROR;
3296+ }
3297+
3298+ copy->code = (ngx_http_script_code_pt)
3299+ ngx_http_script_copy_len_code;
3300+ copy->len = sizeof(CRLF) - 1;
3301+
3302+
3303+ size = (sizeof(ngx_http_script_copy_code_t)
3304+ + sizeof(CRLF) - 1 + sizeof(uintptr_t) - 1)
3305+ & ~(sizeof(uintptr_t) - 1);
3306+
3307+ copy = ngx_array_push_n(conf->headers_set, size);
3308+ if (copy == NULL) {
3309+ return NGX_ERROR;
3310+ }
3311+
3312+ copy->code = ngx_http_script_copy_code;
3313+ copy->len = sizeof(CRLF) - 1;
3314+
3315+ p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
3316+ *p++ = CR; *p = LF;
3317+ }
3318+
3319+ code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t));
3320+ if (code == NULL) {
3321+ return NGX_ERROR;
3322+ }
3323+
3324+ *code = (uintptr_t) NULL;
3325+
3326+ code = ngx_array_push_n(conf->headers_set, sizeof(uintptr_t));
3327+ if (code == NULL) {
3328+ return NGX_ERROR;
3329+ }
3330+
3331+ *code = (uintptr_t) NULL;
3332+ }
3333+
3334+ code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t));
3335+ if (code == NULL) {
3336+ return NGX_ERROR;
3337+ }
3338+
3339+ *code = (uintptr_t) NULL;
3340+
3341+
3342+ hash.hash = &conf->headers_set_hash;
3343+ hash.key = ngx_hash_key_lc;
3344+ hash.max_size = conf->headers_hash_max_size;
3345+ hash.bucket_size = conf->headers_hash_bucket_size;
3346+ hash.name = "proxy_headers_hash";
3347+ hash.pool = cf->pool;
3348+ hash.temp_pool = NULL;
3349+
3350+ return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
3351+}
3352+
3353+
3354+static char *
3355+ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3356+{
3357+ ngx_http_proxy_loc_conf_t *plcf = conf;
3358+
3359+ size_t add;
3360+ u_short port;
3361+ ngx_str_t *value, *url;
3362+ ngx_url_t u;
3363+ ngx_uint_t n;
3364+ ngx_http_core_loc_conf_t *clcf;
3365+ ngx_http_script_compile_t sc;
3366+
3367+ if (plcf->upstream.upstream || plcf->proxy_lengths) {
3368+ return "is duplicate";
3369+ }
3370+
3371+ clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
3372+
3373+ clcf->handler = ngx_http_proxy_handler;
3374+
3375+ if (clcf->name.data[clcf->name.len - 1] == '/') {
3376+ clcf->auto_redirect = 1;
3377+ }
3378+
3379+ value = cf->args->elts;
3380+
3381+ url = &value[1];
3382+
3383+ n = ngx_http_script_variables_count(url);
3384+
3385+ if (n) {
3386+
3387+ ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
3388+
3389+ sc.cf = cf;
3390+ sc.source = url;
3391+ sc.lengths = &plcf->proxy_lengths;
3392+ sc.values = &plcf->proxy_values;
3393+ sc.variables = n;
3394+ sc.complete_lengths = 1;
3395+ sc.complete_values = 1;
3396+
3397+ if (ngx_http_script_compile(&sc) != NGX_OK) {
3398+ return NGX_CONF_ERROR;
3399+ }
3400+
3401+#if (NGX_HTTP_SSL)
3402+ if (ngx_http_proxy_set_ssl(cf, plcf) != NGX_OK) {
3403+ return NGX_CONF_ERROR;
3404+ }
3405+#endif
3406+
3407+ return NGX_CONF_OK;
3408+ }
3409+
3410+ if (ngx_strncasecmp(url->data, (u_char *) "http://", 7) == 0) {
3411+ add = 7;
3412+ port = 80;
3413+
3414+ } else if (ngx_strncasecmp(url->data, (u_char *) "https://", 8) == 0) {
3415+
3416+#if (NGX_HTTP_SSL)
3417+ if (ngx_http_proxy_set_ssl(cf, plcf) != NGX_OK) {
3418+ return NGX_CONF_ERROR;
3419+ }
3420+
3421+ add = 8;
3422+ port = 443;
3423+#else
3424+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3425+ "https protocol requires SSL support");
3426+ return NGX_CONF_ERROR;
3427+#endif
3428+
3429+ } else {
3430+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid URL prefix");
3431+ return NGX_CONF_ERROR;
3432+ }
3433+
3434+ ngx_memzero(&u, sizeof(ngx_url_t));
3435+
3436+ u.url.len = url->len - add;
3437+ u.url.data = url->data + add;
3438+ u.default_port = port;
3439+ u.uri_part = 1;
3440+ u.no_resolve = 1;
3441+
3442+ plcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
3443+ if (plcf->upstream.upstream == NULL) {
3444+ return NGX_CONF_ERROR;
3445+ }
3446+
3447+ plcf->vars.schema.len = add;
3448+ plcf->vars.schema.data = url->data;
3449+ plcf->vars.key_start = plcf->vars.schema;
3450+
3451+ ngx_http_proxy_set_vars(&u, &plcf->vars);
3452+
3453+ plcf->location = clcf->name;
3454+
3455+ if (clcf->named
3456+#if (NGX_PCRE)
3457+ || clcf->regex
3458+#endif
3459+ || clcf->noname)
3460+ {
3461+ if (plcf->vars.uri.len) {
3462+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3463+ "\"proxy_pass\" cannot have URI part in "
3464+ "location given by regular expression, "
3465+ "or inside named location, "
3466+ "or inside \"if\" statement, "
3467+ "or inside \"limit_except\" block");
3468+ return NGX_CONF_ERROR;
3469+ }
3470+
3471+ plcf->location.len = 0;
3472+ }
3473+
3474+ plcf->url = *url;
3475+
3476+ return NGX_CONF_OK;
3477+}
3478+
3479+
3480+static char *
3481+ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3482+{
3483+ ngx_http_proxy_loc_conf_t *plcf = conf;
3484+
3485+ u_char *p;
3486+ ngx_str_t *value;
3487+ ngx_http_proxy_rewrite_t *pr;
3488+ ngx_http_compile_complex_value_t ccv;
3489+
3490+ if (plcf->redirect == 0) {
3491+ return NGX_CONF_OK;
3492+ }
3493+
3494+ plcf->redirect = 1;
3495+
3496+ value = cf->args->elts;
3497+
3498+ if (cf->args->nelts == 2) {
3499+ if (ngx_strcmp(value[1].data, "off") == 0) {
3500+ plcf->redirect = 0;
3501+ plcf->redirects = NULL;
3502+ return NGX_CONF_OK;
3503+ }
3504+
3505+ if (ngx_strcmp(value[1].data, "false") == 0) {
3506+ ngx_conf_log_error(NGX_LOG_ERR, cf, 0,
3507+ "invalid parameter \"false\", use \"off\" instead");
3508+ plcf->redirect = 0;
3509+ plcf->redirects = NULL;
3510+ return NGX_CONF_OK;
3511+ }
3512+
3513+ if (ngx_strcmp(value[1].data, "default") != 0) {
3514+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3515+ "invalid parameter \"%V\"", &value[1]);
3516+ return NGX_CONF_ERROR;
3517+ }
3518+ }
3519+
3520+ if (plcf->redirects == NULL) {
3521+ plcf->redirects = ngx_array_create(cf->pool, 1,
3522+ sizeof(ngx_http_proxy_rewrite_t));
3523+ if (plcf->redirects == NULL) {
3524+ return NGX_CONF_ERROR;
3525+ }
3526+ }
3527+
3528+ pr = ngx_array_push(plcf->redirects);
3529+ if (pr == NULL) {
3530+ return NGX_CONF_ERROR;
3531+ }
3532+
3533+ if (ngx_strcmp(value[1].data, "default") == 0) {
3534+ if (plcf->proxy_lengths) {
3535+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3536+ "\"proxy_redirect default\" cannot be used "
3537+ "with \"proxy_pass\" directive with variables");
3538+ return NGX_CONF_ERROR;
3539+ }
3540+
3541+ if (plcf->url.data == NULL) {
3542+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3543+ "\"proxy_redirect default\" should be placed "
3544+ "after the \"proxy_pass\" directive");
3545+ return NGX_CONF_ERROR;
3546+ }
3547+
3548+ pr->handler = ngx_http_proxy_rewrite_complex_handler;
3549+
3550+ ngx_memzero(&pr->pattern.complex, sizeof(ngx_http_complex_value_t));
3551+
3552+ ngx_memzero(&pr->replacement, sizeof(ngx_http_complex_value_t));
3553+
3554+ if (plcf->vars.uri.len) {
3555+ pr->pattern.complex.value = plcf->url;
3556+ pr->replacement.value = plcf->location;
3557+
3558+ } else {
3559+ pr->pattern.complex.value.len = plcf->url.len + sizeof("/") - 1;
3560+
3561+ p = ngx_pnalloc(cf->pool, pr->pattern.complex.value.len);
3562+ if (p == NULL) {
3563+ return NGX_CONF_ERROR;
3564+ }
3565+
3566+ pr->pattern.complex.value.data = p;
3567+
3568+ p = ngx_cpymem(p, plcf->url.data, plcf->url.len);
3569+ *p = '/';
3570+
3571+ ngx_str_set(&pr->replacement.value, "/");
3572+ }
3573+
3574+ return NGX_CONF_OK;
3575+ }
3576+
3577+
3578+ if (value[1].data[0] == '~') {
3579+ value[1].len--;
3580+ value[1].data++;
3581+
3582+ if (value[1].data[0] == '*') {
3583+ value[1].len--;
3584+ value[1].data++;
3585+
3586+ if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) {
3587+ return NGX_CONF_ERROR;
3588+ }
3589+
3590+ } else {
3591+ if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 0) != NGX_OK) {
3592+ return NGX_CONF_ERROR;
3593+ }
3594+ }
3595+
3596+ } else {
3597+
3598+ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3599+
3600+ ccv.cf = cf;
3601+ ccv.value = &value[1];
3602+ ccv.complex_value = &pr->pattern.complex;
3603+
3604+ if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3605+ return NGX_CONF_ERROR;
3606+ }
3607+
3608+ pr->handler = ngx_http_proxy_rewrite_complex_handler;
3609+ }
3610+
3611+
3612+ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3613+
3614+ ccv.cf = cf;
3615+ ccv.value = &value[2];
3616+ ccv.complex_value = &pr->replacement;
3617+
3618+ if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3619+ return NGX_CONF_ERROR;
3620+ }
3621+
3622+ return NGX_CONF_OK;
3623+}
3624+
3625+
3626+static char *
3627+ngx_http_proxy_cookie_domain(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3628+{
3629+ ngx_http_proxy_loc_conf_t *plcf = conf;
3630+
3631+ ngx_str_t *value;
3632+ ngx_http_proxy_rewrite_t *pr;
3633+ ngx_http_compile_complex_value_t ccv;
3634+
3635+ if (plcf->cookie_domains == NULL) {
3636+ return NGX_CONF_OK;
3637+ }
3638+
3639+ value = cf->args->elts;
3640+
3641+ if (cf->args->nelts == 2) {
3642+
3643+ if (ngx_strcmp(value[1].data, "off") == 0) {
3644+ plcf->cookie_domains = NULL;
3645+ return NGX_CONF_OK;
3646+ }
3647+
3648+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3649+ "invalid parameter \"%V\"", &value[1]);
3650+ return NGX_CONF_ERROR;
3651+ }
3652+
3653+ if (plcf->cookie_domains == NGX_CONF_UNSET_PTR) {
3654+ plcf->cookie_domains = ngx_array_create(cf->pool, 1,
3655+ sizeof(ngx_http_proxy_rewrite_t));
3656+ if (plcf->cookie_domains == NULL) {
3657+ return NGX_CONF_ERROR;
3658+ }
3659+ }
3660+
3661+ pr = ngx_array_push(plcf->cookie_domains);
3662+ if (pr == NULL) {
3663+ return NGX_CONF_ERROR;
3664+ }
3665+
3666+ if (value[1].data[0] == '~') {
3667+ value[1].len--;
3668+ value[1].data++;
3669+
3670+ if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) {
3671+ return NGX_CONF_ERROR;
3672+ }
3673+
3674+ } else {
3675+
3676+ if (value[1].data[0] == '.') {
3677+ value[1].len--;
3678+ value[1].data++;
3679+ }
3680+
3681+ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3682+
3683+ ccv.cf = cf;
3684+ ccv.value = &value[1];
3685+ ccv.complex_value = &pr->pattern.complex;
3686+
3687+ if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3688+ return NGX_CONF_ERROR;
3689+ }
3690+
3691+ pr->handler = ngx_http_proxy_rewrite_domain_handler;
3692+
3693+ if (value[2].data[0] == '.') {
3694+ value[2].len--;
3695+ value[2].data++;
3696+ }
3697+ }
3698+
3699+ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3700+
3701+ ccv.cf = cf;
3702+ ccv.value = &value[2];
3703+ ccv.complex_value = &pr->replacement;
3704+
3705+ if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3706+ return NGX_CONF_ERROR;
3707+ }
3708+
3709+ return NGX_CONF_OK;
3710+}
3711+
3712+
3713+static char *
3714+ngx_http_proxy_cookie_path(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3715+{
3716+ ngx_http_proxy_loc_conf_t *plcf = conf;
3717+
3718+ ngx_str_t *value;
3719+ ngx_http_proxy_rewrite_t *pr;
3720+ ngx_http_compile_complex_value_t ccv;
3721+
3722+ if (plcf->cookie_paths == NULL) {
3723+ return NGX_CONF_OK;
3724+ }
3725+
3726+ value = cf->args->elts;
3727+
3728+ if (cf->args->nelts == 2) {
3729+
3730+ if (ngx_strcmp(value[1].data, "off") == 0) {
3731+ plcf->cookie_paths = NULL;
3732+ return NGX_CONF_OK;
3733+ }
3734+
3735+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3736+ "invalid parameter \"%V\"", &value[1]);
3737+ return NGX_CONF_ERROR;
3738+ }
3739+
3740+ if (plcf->cookie_paths == NGX_CONF_UNSET_PTR) {
3741+ plcf->cookie_paths = ngx_array_create(cf->pool, 1,
3742+ sizeof(ngx_http_proxy_rewrite_t));
3743+ if (plcf->cookie_paths == NULL) {
3744+ return NGX_CONF_ERROR;
3745+ }
3746+ }
3747+
3748+ pr = ngx_array_push(plcf->cookie_paths);
3749+ if (pr == NULL) {
3750+ return NGX_CONF_ERROR;
3751+ }
3752+
3753+ if (value[1].data[0] == '~') {
3754+ value[1].len--;
3755+ value[1].data++;
3756+
3757+ if (value[1].data[0] == '*') {
3758+ value[1].len--;
3759+ value[1].data++;
3760+
3761+ if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) {
3762+ return NGX_CONF_ERROR;
3763+ }
3764+
3765+ } else {
3766+ if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 0) != NGX_OK) {
3767+ return NGX_CONF_ERROR;
3768+ }
3769+ }
3770+
3771+ } else {
3772+
3773+ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3774+
3775+ ccv.cf = cf;
3776+ ccv.value = &value[1];
3777+ ccv.complex_value = &pr->pattern.complex;
3778+
3779+ if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3780+ return NGX_CONF_ERROR;
3781+ }
3782+
3783+ pr->handler = ngx_http_proxy_rewrite_complex_handler;
3784+ }
3785+
3786+ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3787+
3788+ ccv.cf = cf;
3789+ ccv.value = &value[2];
3790+ ccv.complex_value = &pr->replacement;
3791+
3792+ if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3793+ return NGX_CONF_ERROR;
3794+ }
3795+
3796+ return NGX_CONF_OK;
3797+}
3798+
3799+
3800+static ngx_int_t
3801+ngx_http_proxy_rewrite_regex(ngx_conf_t *cf, ngx_http_proxy_rewrite_t *pr,
3802+ ngx_str_t *regex, ngx_uint_t caseless)
3803+{
3804+#if (NGX_PCRE)
3805+ u_char errstr[NGX_MAX_CONF_ERRSTR];
3806+ ngx_regex_compile_t rc;
3807+
3808+ ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
3809+
3810+ rc.pattern = *regex;
3811+ rc.err.len = NGX_MAX_CONF_ERRSTR;
3812+ rc.err.data = errstr;
3813+
3814+ if (caseless) {
3815+ rc.options = NGX_REGEX_CASELESS;
3816+ }
3817+
3818+ pr->pattern.regex = ngx_http_regex_compile(cf, &rc);
3819+ if (pr->pattern.regex == NULL) {
3820+ return NGX_ERROR;
3821+ }
3822+
3823+ pr->handler = ngx_http_proxy_rewrite_regex_handler;
3824+
3825+ return NGX_OK;
3826+
3827+#else
3828+
3829+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3830+ "using regex \"%V\" requires PCRE library", regex);
3831+ return NGX_ERROR;
3832+
3833+#endif
3834+}
3835+
3836+
3837+static char *
3838+ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3839+{
3840+ ngx_http_proxy_loc_conf_t *plcf = conf;
3841+
3842+ ngx_str_t *value;
3843+ ngx_http_script_compile_t sc;
3844+
3845+ if (plcf->upstream.store != NGX_CONF_UNSET
3846+ || plcf->upstream.store_lengths)
3847+ {
3848+ return "is duplicate";
3849+ }
3850+
3851+ value = cf->args->elts;
3852+
3853+ if (ngx_strcmp(value[1].data, "off") == 0) {
3854+ plcf->upstream.store = 0;
3855+ return NGX_CONF_OK;
3856+ }
3857+
3858+#if (NGX_HTTP_CACHE)
3859+
3860+ if (plcf->upstream.cache != NGX_CONF_UNSET_PTR
3861+ && plcf->upstream.cache != NULL)
3862+ {
3863+ return "is incompatible with \"proxy_cache\"";
3864+ }
3865+
3866+#endif
3867+
3868+ if (ngx_strcmp(value[1].data, "on") == 0) {
3869+ plcf->upstream.store = 1;
3870+ return NGX_CONF_OK;
3871+ }
3872+
3873+ /* include the terminating '\0' into script */
3874+ value[1].len++;
3875+
3876+ ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
3877+
3878+ sc.cf = cf;
3879+ sc.source = &value[1];
3880+ sc.lengths = &plcf->upstream.store_lengths;
3881+ sc.values = &plcf->upstream.store_values;
3882+ sc.variables = ngx_http_script_variables_count(&value[1]);
3883+ sc.complete_lengths = 1;
3884+ sc.complete_values = 1;
3885+
3886+ if (ngx_http_script_compile(&sc) != NGX_OK) {
3887+ return NGX_CONF_ERROR;
3888+ }
3889+
3890+ return NGX_CONF_OK;
3891+}
3892+
3893+
3894+#if (NGX_HTTP_CACHE)
3895+
3896+static char *
3897+ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3898+{
3899+ ngx_http_proxy_loc_conf_t *plcf = conf;
3900+
3901+ ngx_str_t *value;
3902+
3903+ value = cf->args->elts;
3904+
3905+ if (plcf->upstream.cache != NGX_CONF_UNSET_PTR) {
3906+ return "is duplicate";
3907+ }
3908+
3909+ if (ngx_strcmp(value[1].data, "off") == 0) {
3910+ plcf->upstream.cache = NULL;
3911+ return NGX_CONF_OK;
3912+ }
3913+
3914+ if (plcf->upstream.store > 0 || plcf->upstream.store_lengths) {
3915+ return "is incompatible with \"proxy_store\"";
3916+ }
3917+
3918+ plcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0,
3919+ &ngx_http_proxy_module);
3920+ if (plcf->upstream.cache == NULL) {
3921+ return NGX_CONF_ERROR;
3922+ }
3923+
3924+ return NGX_CONF_OK;
3925+}
3926+
3927+
3928+static char *
3929+ngx_http_proxy_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3930+{
3931+ ngx_http_proxy_loc_conf_t *plcf = conf;
3932+
3933+ ngx_str_t *value;
3934+ ngx_http_compile_complex_value_t ccv;
3935+
3936+ value = cf->args->elts;
3937+
3938+ if (plcf->cache_key.value.len) {
3939+ return "is duplicate";
3940+ }
3941+
3942+ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3943+
3944+ ccv.cf = cf;
3945+ ccv.value = &value[1];
3946+ ccv.complex_value = &plcf->cache_key;
3947+
3948+ if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3949+ return NGX_CONF_ERROR;
3950+ }
3951+
3952+ return NGX_CONF_OK;
3953+}
3954+
3955+#endif
3956+
3957+
3958+static char *
3959+ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data)
3960+{
3961+#if (NGX_FREEBSD)
3962+ ssize_t *np = data;
3963+
3964+ if ((u_long) *np >= ngx_freebsd_net_inet_tcp_sendspace) {
3965+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3966+ "\"proxy_send_lowat\" must be less than %d "
3967+ "(sysctl net.inet.tcp.sendspace)",
3968+ ngx_freebsd_net_inet_tcp_sendspace);
3969+
3970+ return NGX_CONF_ERROR;
3971+ }
3972+
3973+#elif !(NGX_HAVE_SO_SNDLOWAT)
3974+ ssize_t *np = data;
3975+
3976+ ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
3977+ "\"proxy_send_lowat\" is not supported, ignored");
3978+
3979+ *np = 0;
3980+
3981+#endif
3982+
3983+ return NGX_CONF_OK;
3984+}
3985+
3986+
3987+#if (NGX_HTTP_SSL)
3988+
3989+static ngx_int_t
3990+ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf)
3991+{
3992+ ngx_pool_cleanup_t *cln;
3993+
3994+ plcf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t));
3995+ if (plcf->upstream.ssl == NULL) {
3996+ return NGX_ERROR;
3997+ }
3998+
3999+ plcf->upstream.ssl->log = cf->log;
4000+
4001+ if (ngx_ssl_create(plcf->upstream.ssl,
4002+ NGX_SSL_SSLv2|NGX_SSL_SSLv3|NGX_SSL_TLSv1
4003+ |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2,
4004+ NULL)
4005+ != NGX_OK)
4006+ {
4007+ return NGX_ERROR;
4008+ }
4009+
4010+ cln = ngx_pool_cleanup_add(cf->pool, 0);
4011+ if (cln == NULL) {
4012+ return NGX_ERROR;
4013+ }
4014+
4015+ cln->handler = ngx_ssl_cleanup_ctx;
4016+ cln->data = plcf->upstream.ssl;
4017+
4018+ return NGX_OK;
4019+}
4020+
4021+#endif
4022+
4023+
4024+static void
4025+ngx_http_proxy_set_vars(ngx_url_t *u, ngx_http_proxy_vars_t *v)
4026+{
4027+ if (u->family != AF_UNIX) {
4028+
4029+ if (u->no_port || u->port == u->default_port) {
4030+
4031+ v->host_header = u->host;
4032+
4033+ if (u->default_port == 80) {
4034+ ngx_str_set(&v->port, "80");
4035+
4036+ } else {
4037+ ngx_str_set(&v->port, "443");
4038+ }
4039+
4040+ } else {
4041+ v->host_header.len = u->host.len + 1 + u->port_text.len;
4042+ v->host_header.data = u->host.data;
4043+ v->port = u->port_text;
4044+ }
4045+
4046+ v->key_start.len += v->host_header.len;
4047+
4048+ } else {
4049+ ngx_str_set(&v->host_header, "localhost");
4050+ ngx_str_null(&v->port);
4051+ v->key_start.len += sizeof("unix:") - 1 + u->host.len + 1;
4052+ }
4053+
4054+ v->uri = u->uri;
4055+}
4056
4057=== added directory '.pc/cve-2013-4547.patch'
4058=== added directory '.pc/cve-2013-4547.patch/src'
4059=== added directory '.pc/cve-2013-4547.patch/src/http'
4060=== added file '.pc/cve-2013-4547.patch/src/http/ngx_http_parse.c'
4061--- .pc/cve-2013-4547.patch/src/http/ngx_http_parse.c 1970-01-01 00:00:00 +0000
4062+++ .pc/cve-2013-4547.patch/src/http/ngx_http_parse.c 2014-01-15 15:02:58 +0000
4063@@ -0,0 +1,1820 @@
4064+
4065+/*
4066+ * Copyright (C) Igor Sysoev
4067+ * Copyright (C) Nginx, Inc.
4068+ */
4069+
4070+
4071+#include <ngx_config.h>
4072+#include <ngx_core.h>
4073+#include <ngx_http.h>
4074+
4075+
4076+static uint32_t usual[] = {
4077+ 0xffffdbfe, /* 1111 1111 1111 1111 1101 1011 1111 1110 */
4078+
4079+ /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
4080+ 0x7fff37d6, /* 0111 1111 1111 1111 0011 0111 1101 0110 */
4081+
4082+ /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
4083+#if (NGX_WIN32)
4084+ 0xefffffff, /* 1110 1111 1111 1111 1111 1111 1111 1111 */
4085+#else
4086+ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
4087+#endif
4088+
4089+ /* ~}| {zyx wvut srqp onml kjih gfed cba` */
4090+ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
4091+
4092+ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
4093+ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
4094+ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
4095+ 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
4096+};
4097+
4098+
4099+#if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED)
4100+
4101+#define ngx_str3_cmp(m, c0, c1, c2, c3) \
4102+ *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0)
4103+
4104+#define ngx_str3Ocmp(m, c0, c1, c2, c3) \
4105+ *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0)
4106+
4107+#define ngx_str4cmp(m, c0, c1, c2, c3) \
4108+ *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0)
4109+
4110+#define ngx_str5cmp(m, c0, c1, c2, c3, c4) \
4111+ *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \
4112+ && m[4] == c4
4113+
4114+#define ngx_str6cmp(m, c0, c1, c2, c3, c4, c5) \
4115+ *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \
4116+ && (((uint32_t *) m)[1] & 0xffff) == ((c5 << 8) | c4)
4117+
4118+#define ngx_str7_cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \
4119+ *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \
4120+ && ((uint32_t *) m)[1] == ((c7 << 24) | (c6 << 16) | (c5 << 8) | c4)
4121+
4122+#define ngx_str8cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \
4123+ *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \
4124+ && ((uint32_t *) m)[1] == ((c7 << 24) | (c6 << 16) | (c5 << 8) | c4)
4125+
4126+#define ngx_str9cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8) \
4127+ *(uint32_t *) m == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \
4128+ && ((uint32_t *) m)[1] == ((c7 << 24) | (c6 << 16) | (c5 << 8) | c4) \
4129+ && m[8] == c8
4130+
4131+#else /* !(NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED) */
4132+
4133+#define ngx_str3_cmp(m, c0, c1, c2, c3) \
4134+ m[0] == c0 && m[1] == c1 && m[2] == c2
4135+
4136+#define ngx_str3Ocmp(m, c0, c1, c2, c3) \
4137+ m[0] == c0 && m[2] == c2 && m[3] == c3
4138+
4139+#define ngx_str4cmp(m, c0, c1, c2, c3) \
4140+ m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3
4141+
4142+#define ngx_str5cmp(m, c0, c1, c2, c3, c4) \
4143+ m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 && m[4] == c4
4144+
4145+#define ngx_str6cmp(m, c0, c1, c2, c3, c4, c5) \
4146+ m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \
4147+ && m[4] == c4 && m[5] == c5
4148+
4149+#define ngx_str7_cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \
4150+ m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \
4151+ && m[4] == c4 && m[5] == c5 && m[6] == c6
4152+
4153+#define ngx_str8cmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \
4154+ m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \
4155+ && m[4] == c4 && m[5] == c5 && m[6] == c6 && m[7] == c7
4156+
4157+#define ngx_str9cmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8) \
4158+ m[0] == c0 && m[1] == c1 && m[2] == c2 && m[3] == c3 \
4159+ && m[4] == c4 && m[5] == c5 && m[6] == c6 && m[7] == c7 && m[8] == c8
4160+
4161+#endif
4162+
4163+
4164+/* gcc, icc, msvc and others compile these switches as an jump table */
4165+
4166+ngx_int_t
4167+ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b)
4168+{
4169+ u_char c, ch, *p, *m;
4170+ enum {
4171+ sw_start = 0,
4172+ sw_method,
4173+ sw_spaces_before_uri,
4174+ sw_schema,
4175+ sw_schema_slash,
4176+ sw_schema_slash_slash,
4177+ sw_host_start,
4178+ sw_host,
4179+ sw_host_end,
4180+ sw_host_ip_literal,
4181+ sw_port,
4182+ sw_host_http_09,
4183+ sw_after_slash_in_uri,
4184+ sw_check_uri,
4185+ sw_check_uri_http_09,
4186+ sw_uri,
4187+ sw_http_09,
4188+ sw_http_H,
4189+ sw_http_HT,
4190+ sw_http_HTT,
4191+ sw_http_HTTP,
4192+ sw_first_major_digit,
4193+ sw_major_digit,
4194+ sw_first_minor_digit,
4195+ sw_minor_digit,
4196+ sw_spaces_after_digit,
4197+ sw_almost_done
4198+ } state;
4199+
4200+ state = r->state;
4201+
4202+ for (p = b->pos; p < b->last; p++) {
4203+ ch = *p;
4204+
4205+ switch (state) {
4206+
4207+ /* HTTP methods: GET, HEAD, POST */
4208+ case sw_start:
4209+ r->request_start = p;
4210+
4211+ if (ch == CR || ch == LF) {
4212+ break;
4213+ }
4214+
4215+ if ((ch < 'A' || ch > 'Z') && ch != '_') {
4216+ return NGX_HTTP_PARSE_INVALID_METHOD;
4217+ }
4218+
4219+ state = sw_method;
4220+ break;
4221+
4222+ case sw_method:
4223+ if (ch == ' ') {
4224+ r->method_end = p - 1;
4225+ m = r->request_start;
4226+
4227+ switch (p - m) {
4228+
4229+ case 3:
4230+ if (ngx_str3_cmp(m, 'G', 'E', 'T', ' ')) {
4231+ r->method = NGX_HTTP_GET;
4232+ break;
4233+ }
4234+
4235+ if (ngx_str3_cmp(m, 'P', 'U', 'T', ' ')) {
4236+ r->method = NGX_HTTP_PUT;
4237+ break;
4238+ }
4239+
4240+ break;
4241+
4242+ case 4:
4243+ if (m[1] == 'O') {
4244+
4245+ if (ngx_str3Ocmp(m, 'P', 'O', 'S', 'T')) {
4246+ r->method = NGX_HTTP_POST;
4247+ break;
4248+ }
4249+
4250+ if (ngx_str3Ocmp(m, 'C', 'O', 'P', 'Y')) {
4251+ r->method = NGX_HTTP_COPY;
4252+ break;
4253+ }
4254+
4255+ if (ngx_str3Ocmp(m, 'M', 'O', 'V', 'E')) {
4256+ r->method = NGX_HTTP_MOVE;
4257+ break;
4258+ }
4259+
4260+ if (ngx_str3Ocmp(m, 'L', 'O', 'C', 'K')) {
4261+ r->method = NGX_HTTP_LOCK;
4262+ break;
4263+ }
4264+
4265+ } else {
4266+
4267+ if (ngx_str4cmp(m, 'H', 'E', 'A', 'D')) {
4268+ r->method = NGX_HTTP_HEAD;
4269+ break;
4270+ }
4271+ }
4272+
4273+ break;
4274+
4275+ case 5:
4276+ if (ngx_str5cmp(m, 'M', 'K', 'C', 'O', 'L')) {
4277+ r->method = NGX_HTTP_MKCOL;
4278+ }
4279+
4280+ if (ngx_str5cmp(m, 'P', 'A', 'T', 'C', 'H')) {
4281+ r->method = NGX_HTTP_PATCH;
4282+ }
4283+
4284+ if (ngx_str5cmp(m, 'T', 'R', 'A', 'C', 'E')) {
4285+ r->method = NGX_HTTP_TRACE;
4286+ }
4287+
4288+ break;
4289+
4290+ case 6:
4291+ if (ngx_str6cmp(m, 'D', 'E', 'L', 'E', 'T', 'E')) {
4292+ r->method = NGX_HTTP_DELETE;
4293+ break;
4294+ }
4295+
4296+ if (ngx_str6cmp(m, 'U', 'N', 'L', 'O', 'C', 'K')) {
4297+ r->method = NGX_HTTP_UNLOCK;
4298+ break;
4299+ }
4300+
4301+ break;
4302+
4303+ case 7:
4304+ if (ngx_str7_cmp(m, 'O', 'P', 'T', 'I', 'O', 'N', 'S', ' '))
4305+ {
4306+ r->method = NGX_HTTP_OPTIONS;
4307+ }
4308+
4309+ break;
4310+
4311+ case 8:
4312+ if (ngx_str8cmp(m, 'P', 'R', 'O', 'P', 'F', 'I', 'N', 'D'))
4313+ {
4314+ r->method = NGX_HTTP_PROPFIND;
4315+ }
4316+
4317+ break;
4318+
4319+ case 9:
4320+ if (ngx_str9cmp(m,
4321+ 'P', 'R', 'O', 'P', 'P', 'A', 'T', 'C', 'H'))
4322+ {
4323+ r->method = NGX_HTTP_PROPPATCH;
4324+ }
4325+
4326+ break;
4327+ }
4328+
4329+ state = sw_spaces_before_uri;
4330+ break;
4331+ }
4332+
4333+ if ((ch < 'A' || ch > 'Z') && ch != '_') {
4334+ return NGX_HTTP_PARSE_INVALID_METHOD;
4335+ }
4336+
4337+ break;
4338+
4339+ /* space* before URI */
4340+ case sw_spaces_before_uri:
4341+
4342+ if (ch == '/') {
4343+ r->uri_start = p;
4344+ state = sw_after_slash_in_uri;
4345+ break;
4346+ }
4347+
4348+ c = (u_char) (ch | 0x20);
4349+ if (c >= 'a' && c <= 'z') {
4350+ r->schema_start = p;
4351+ state = sw_schema;
4352+ break;
4353+ }
4354+
4355+ switch (ch) {
4356+ case ' ':
4357+ break;
4358+ default:
4359+ return NGX_HTTP_PARSE_INVALID_REQUEST;
4360+ }
4361+ break;
4362+
4363+ case sw_schema:
4364+
4365+ c = (u_char) (ch | 0x20);
4366+ if (c >= 'a' && c <= 'z') {
4367+ break;
4368+ }
4369+
4370+ switch (ch) {
4371+ case ':':
4372+ r->schema_end = p;
4373+ state = sw_schema_slash;
4374+ break;
4375+ default:
4376+ return NGX_HTTP_PARSE_INVALID_REQUEST;
4377+ }
4378+ break;
4379+
4380+ case sw_schema_slash:
4381+ switch (ch) {
4382+ case '/':
4383+ state = sw_schema_slash_slash;
4384+ break;
4385+ default:
4386+ return NGX_HTTP_PARSE_INVALID_REQUEST;
4387+ }
4388+ break;
4389+
4390+ case sw_schema_slash_slash:
4391+ switch (ch) {
4392+ case '/':
4393+ state = sw_host_start;
4394+ break;
4395+ default:
4396+ return NGX_HTTP_PARSE_INVALID_REQUEST;
4397+ }
4398+ break;
4399+
4400+ case sw_host_start:
4401+
4402+ r->host_start = p;
4403+
4404+ if (ch == '[') {
4405+ state = sw_host_ip_literal;
4406+ break;
4407+ }
4408+
4409+ state = sw_host;
4410+
4411+ /* fall through */
4412+
4413+ case sw_host:
4414+
4415+ c = (u_char) (ch | 0x20);
4416+ if (c >= 'a' && c <= 'z') {
4417+ break;
4418+ }
4419+
4420+ if ((ch >= '0' && ch <= '9') || ch == '.' || ch == '-') {
4421+ break;
4422+ }
4423+
4424+ /* fall through */
4425+
4426+ case sw_host_end:
4427+
4428+ r->host_end = p;
4429+
4430+ switch (ch) {
4431+ case ':':
4432+ state = sw_port;
4433+ break;
4434+ case '/':
4435+ r->uri_start = p;
4436+ state = sw_after_slash_in_uri;
4437+ break;
4438+ case ' ':
4439+ /*
4440+ * use single "/" from request line to preserve pointers,
4441+ * if request line will be copied to large client buffer
4442+ */
4443+ r->uri_start = r->schema_end + 1;
4444+ r->uri_end = r->schema_end + 2;
4445+ state = sw_host_http_09;
4446+ break;
4447+ default:
4448+ return NGX_HTTP_PARSE_INVALID_REQUEST;
4449+ }
4450+ break;
4451+
4452+ case sw_host_ip_literal:
4453+
4454+ if (ch >= '0' && ch <= '9') {
4455+ break;
4456+ }
4457+
4458+ c = (u_char) (ch | 0x20);
4459+ if (c >= 'a' && c <= 'z') {
4460+ break;
4461+ }
4462+
4463+ switch (ch) {
4464+ case ':':
4465+ break;
4466+ case ']':
4467+ state = sw_host_end;
4468+ break;
4469+ case '-':
4470+ case '.':
4471+ case '_':
4472+ case '~':
4473+ /* unreserved */
4474+ break;
4475+ case '!':
4476+ case '$':
4477+ case '&':
4478+ case '\'':
4479+ case '(':
4480+ case ')':
4481+ case '*':
4482+ case '+':
4483+ case ',':
4484+ case ';':
4485+ case '=':
4486+ /* sub-delims */
4487+ break;
4488+ default:
4489+ return NGX_HTTP_PARSE_INVALID_REQUEST;
4490+ }
4491+ break;
4492+
4493+ case sw_port:
4494+ if (ch >= '0' && ch <= '9') {
4495+ break;
4496+ }
4497+
4498+ switch (ch) {
4499+ case '/':
4500+ r->port_end = p;
4501+ r->uri_start = p;
4502+ state = sw_after_slash_in_uri;
4503+ break;
4504+ case ' ':
4505+ r->port_end = p;
4506+ /*
4507+ * use single "/" from request line to preserve pointers,
4508+ * if request line will be copied to large client buffer
4509+ */
4510+ r->uri_start = r->schema_end + 1;
4511+ r->uri_end = r->schema_end + 2;
4512+ state = sw_host_http_09;
4513+ break;
4514+ default:
4515+ return NGX_HTTP_PARSE_INVALID_REQUEST;
4516+ }
4517+ break;
4518+
4519+ /* space+ after "http://host[:port] " */
4520+ case sw_host_http_09:
4521+ switch (ch) {
4522+ case ' ':
4523+ break;
4524+ case CR:
4525+ r->http_minor = 9;
4526+ state = sw_almost_done;
4527+ break;
4528+ case LF:
4529+ r->http_minor = 9;
4530+ goto done;
4531+ case 'H':
4532+ r->http_protocol.data = p;
4533+ state = sw_http_H;
4534+ break;
4535+ default:
4536+ return NGX_HTTP_PARSE_INVALID_REQUEST;
4537+ }
4538+ break;
4539+
4540+
4541+ /* check "/.", "//", "%", and "\" (Win32) in URI */
4542+ case sw_after_slash_in_uri:
4543+
4544+ if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
4545+ state = sw_check_uri;
4546+ break;
4547+ }
4548+
4549+ switch (ch) {
4550+ case ' ':
4551+ r->uri_end = p;
4552+ state = sw_check_uri_http_09;
4553+ break;
4554+ case CR:
4555+ r->uri_end = p;
4556+ r->http_minor = 9;
4557+ state = sw_almost_done;
4558+ break;
4559+ case LF:
4560+ r->uri_end = p;
4561+ r->http_minor = 9;
4562+ goto done;
4563+ case '.':
4564+ r->complex_uri = 1;
4565+ state = sw_uri;
4566+ break;
4567+ case '%':
4568+ r->quoted_uri = 1;
4569+ state = sw_uri;
4570+ break;
4571+ case '/':
4572+ r->complex_uri = 1;
4573+ state = sw_uri;
4574+ break;
4575+#if (NGX_WIN32)
4576+ case '\\':
4577+ r->complex_uri = 1;
4578+ state = sw_uri;
4579+ break;
4580+#endif
4581+ case '?':
4582+ r->args_start = p + 1;
4583+ state = sw_uri;
4584+ break;
4585+ case '#':
4586+ r->complex_uri = 1;
4587+ state = sw_uri;
4588+ break;
4589+ case '+':
4590+ r->plus_in_uri = 1;
4591+ break;
4592+ case '\0':
4593+ return NGX_HTTP_PARSE_INVALID_REQUEST;
4594+ default:
4595+ state = sw_check_uri;
4596+ break;
4597+ }
4598+ break;
4599+
4600+ /* check "/", "%" and "\" (Win32) in URI */
4601+ case sw_check_uri:
4602+
4603+ if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
4604+ break;
4605+ }
4606+
4607+ switch (ch) {
4608+ case '/':
4609+#if (NGX_WIN32)
4610+ if (r->uri_ext == p) {
4611+ r->complex_uri = 1;
4612+ state = sw_uri;
4613+ break;
4614+ }
4615+#endif
4616+ r->uri_ext = NULL;
4617+ state = sw_after_slash_in_uri;
4618+ break;
4619+ case '.':
4620+ r->uri_ext = p + 1;
4621+ break;
4622+ case ' ':
4623+ r->uri_end = p;
4624+ state = sw_check_uri_http_09;
4625+ break;
4626+ case CR:
4627+ r->uri_end = p;
4628+ r->http_minor = 9;
4629+ state = sw_almost_done;
4630+ break;
4631+ case LF:
4632+ r->uri_end = p;
4633+ r->http_minor = 9;
4634+ goto done;
4635+#if (NGX_WIN32)
4636+ case '\\':
4637+ r->complex_uri = 1;
4638+ state = sw_after_slash_in_uri;
4639+ break;
4640+#endif
4641+ case '%':
4642+ r->quoted_uri = 1;
4643+ state = sw_uri;
4644+ break;
4645+ case '?':
4646+ r->args_start = p + 1;
4647+ state = sw_uri;
4648+ break;
4649+ case '#':
4650+ r->complex_uri = 1;
4651+ state = sw_uri;
4652+ break;
4653+ case '+':
4654+ r->plus_in_uri = 1;
4655+ break;
4656+ case '\0':
4657+ return NGX_HTTP_PARSE_INVALID_REQUEST;
4658+ }
4659+ break;
4660+
4661+ /* space+ after URI */
4662+ case sw_check_uri_http_09:
4663+ switch (ch) {
4664+ case ' ':
4665+ break;
4666+ case CR:
4667+ r->http_minor = 9;
4668+ state = sw_almost_done;
4669+ break;
4670+ case LF:
4671+ r->http_minor = 9;
4672+ goto done;
4673+ case 'H':
4674+ r->http_protocol.data = p;
4675+ state = sw_http_H;
4676+ break;
4677+ default:
4678+ r->space_in_uri = 1;
4679+ state = sw_check_uri;
4680+ break;
4681+ }
4682+ break;
4683+
4684+
4685+ /* URI */
4686+ case sw_uri:
4687+
4688+ if (usual[ch >> 5] & (1 << (ch & 0x1f))) {
4689+ break;
4690+ }
4691+
4692+ switch (ch) {
4693+ case ' ':
4694+ r->uri_end = p;
4695+ state = sw_http_09;
4696+ break;
4697+ case CR:
4698+ r->uri_end = p;
4699+ r->http_minor = 9;
4700+ state = sw_almost_done;
4701+ break;
4702+ case LF:
4703+ r->uri_end = p;
4704+ r->http_minor = 9;
4705+ goto done;
4706+ case '#':
4707+ r->complex_uri = 1;
4708+ break;
4709+ case '\0':
4710+ return NGX_HTTP_PARSE_INVALID_REQUEST;
4711+ }
4712+ break;
4713+
4714+ /* space+ after URI */
4715+ case sw_http_09:
4716+ switch (ch) {
4717+ case ' ':
4718+ break;
4719+ case CR:
4720+ r->http_minor = 9;
4721+ state = sw_almost_done;
4722+ break;
4723+ case LF:
4724+ r->http_minor = 9;
4725+ goto done;
4726+ case 'H':
4727+ r->http_protocol.data = p;
4728+ state = sw_http_H;
4729+ break;
4730+ default:
4731+ r->space_in_uri = 1;
4732+ state = sw_uri;
4733+ break;
4734+ }
4735+ break;
4736+
4737+ case sw_http_H:
4738+ switch (ch) {
4739+ case 'T':
4740+ state = sw_http_HT;
4741+ break;
4742+ default:
4743+ return NGX_HTTP_PARSE_INVALID_REQUEST;
4744+ }
4745+ break;
4746+
4747+ case sw_http_HT:
4748+ switch (ch) {
4749+ case 'T':
4750+ state = sw_http_HTT;
4751+ break;
4752+ default:
4753+ return NGX_HTTP_PARSE_INVALID_REQUEST;
4754+ }
4755+ break;
4756+
4757+ case sw_http_HTT:
4758+ switch (ch) {
4759+ case 'P':
4760+ state = sw_http_HTTP;
4761+ break;
4762+ default:
4763+ return NGX_HTTP_PARSE_INVALID_REQUEST;
4764+ }
4765+ break;
4766+
4767+ case sw_http_HTTP:
4768+ switch (ch) {
4769+ case '/':
4770+ state = sw_first_major_digit;
4771+ break;
4772+ default:
4773+ return NGX_HTTP_PARSE_INVALID_REQUEST;
4774+ }
4775+ break;
4776+
4777+ /* first digit of major HTTP version */
4778+ case sw_first_major_digit:
4779+ if (ch < '1' || ch > '9') {
4780+ return NGX_HTTP_PARSE_INVALID_REQUEST;
4781+ }
4782+
4783+ r->http_major = ch - '0';
4784+ state = sw_major_digit;
4785+ break;
4786+
4787+ /* major HTTP version or dot */
4788+ case sw_major_digit:
4789+ if (ch == '.') {
4790+ state = sw_first_minor_digit;
4791+ break;
4792+ }
4793+
4794+ if (ch < '0' || ch > '9') {
4795+ return NGX_HTTP_PARSE_INVALID_REQUEST;
4796+ }
4797+
4798+ r->http_major = r->http_major * 10 + ch - '0';
4799+ break;
4800+
4801+ /* first digit of minor HTTP version */
4802+ case sw_first_minor_digit:
4803+ if (ch < '0' || ch > '9') {
4804+ return NGX_HTTP_PARSE_INVALID_REQUEST;
4805+ }
4806+
4807+ r->http_minor = ch - '0';
4808+ state = sw_minor_digit;
4809+ break;
4810+
4811+ /* minor HTTP version or end of request line */
4812+ case sw_minor_digit:
4813+ if (ch == CR) {
4814+ state = sw_almost_done;
4815+ break;
4816+ }
4817+
4818+ if (ch == LF) {
4819+ goto done;
4820+ }
4821+
4822+ if (ch == ' ') {
4823+ state = sw_spaces_after_digit;
4824+ break;
4825+ }
4826+
4827+ if (ch < '0' || ch > '9') {
4828+ return NGX_HTTP_PARSE_INVALID_REQUEST;
4829+ }
4830+
4831+ r->http_minor = r->http_minor * 10 + ch - '0';
4832+ break;
4833+
4834+ case sw_spaces_after_digit:
4835+ switch (ch) {
4836+ case ' ':
4837+ break;
4838+ case CR:
4839+ state = sw_almost_done;
4840+ break;
4841+ case LF:
4842+ goto done;
4843+ default:
4844+ return NGX_HTTP_PARSE_INVALID_REQUEST;
4845+ }
4846+ break;
4847+
4848+ /* end of request line */
4849+ case sw_almost_done:
4850+ r->request_end = p - 1;
4851+ switch (ch) {
4852+ case LF:
4853+ goto done;
4854+ default:
4855+ return NGX_HTTP_PARSE_INVALID_REQUEST;
4856+ }
4857+ }
4858+ }
4859+
4860+ b->pos = p;
4861+ r->state = state;
4862+
4863+ return NGX_AGAIN;
4864+
4865+done:
4866+
4867+ b->pos = p + 1;
4868+
4869+ if (r->request_end == NULL) {
4870+ r->request_end = p;
4871+ }
4872+
4873+ r->http_version = r->http_major * 1000 + r->http_minor;
4874+ r->state = sw_start;
4875+
4876+ if (r->http_version == 9 && r->method != NGX_HTTP_GET) {
4877+ return NGX_HTTP_PARSE_INVALID_09_METHOD;
4878+ }
4879+
4880+ return NGX_OK;
4881+}
4882+
4883+
4884+ngx_int_t
4885+ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b,
4886+ ngx_uint_t allow_underscores)
4887+{
4888+ u_char c, ch, *p;
4889+ ngx_uint_t hash, i;
4890+ enum {
4891+ sw_start = 0,
4892+ sw_name,
4893+ sw_space_before_value,
4894+ sw_value,
4895+ sw_space_after_value,
4896+ sw_ignore_line,
4897+ sw_almost_done,
4898+ sw_header_almost_done
4899+ } state;
4900+
4901+ /* the last '\0' is not needed because string is zero terminated */
4902+
4903+ static u_char lowcase[] =
4904+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
4905+ "\0\0\0\0\0\0\0\0\0\0\0\0\0-\0\0" "0123456789\0\0\0\0\0\0"
4906+ "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0\0"
4907+ "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0\0"
4908+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
4909+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
4910+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
4911+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
4912+
4913+ state = r->state;
4914+ hash = r->header_hash;
4915+ i = r->lowcase_index;
4916+
4917+ for (p = b->pos; p < b->last; p++) {
4918+ ch = *p;
4919+
4920+ switch (state) {
4921+
4922+ /* first char */
4923+ case sw_start:
4924+ r->header_name_start = p;
4925+ r->invalid_header = 0;
4926+
4927+ switch (ch) {
4928+ case CR:
4929+ r->header_end = p;
4930+ state = sw_header_almost_done;
4931+ break;
4932+ case LF:
4933+ r->header_end = p;
4934+ goto header_done;
4935+ default:
4936+ state = sw_name;
4937+
4938+ c = lowcase[ch];
4939+
4940+ if (c) {
4941+ hash = ngx_hash(0, c);
4942+ r->lowcase_header[0] = c;
4943+ i = 1;
4944+ break;
4945+ }
4946+
4947+ if (ch == '\0') {
4948+ return NGX_HTTP_PARSE_INVALID_HEADER;
4949+ }
4950+
4951+ r->invalid_header = 1;
4952+
4953+ break;
4954+
4955+ }
4956+ break;
4957+
4958+ /* header name */
4959+ case sw_name:
4960+ c = lowcase[ch];
4961+
4962+ if (c) {
4963+ hash = ngx_hash(hash, c);
4964+ r->lowcase_header[i++] = c;
4965+ i &= (NGX_HTTP_LC_HEADER_LEN - 1);
4966+ break;
4967+ }
4968+
4969+ if (ch == '_') {
4970+ if (allow_underscores) {
4971+ hash = ngx_hash(hash, ch);
4972+ r->lowcase_header[i++] = ch;
4973+ i &= (NGX_HTTP_LC_HEADER_LEN - 1);
4974+
4975+ } else {
4976+ r->invalid_header = 1;
4977+ }
4978+
4979+ break;
4980+ }
4981+
4982+ if (ch == ':') {
4983+ r->header_name_end = p;
4984+ state = sw_space_before_value;
4985+ break;
4986+ }
4987+
4988+ if (ch == CR) {
4989+ r->header_name_end = p;
4990+ r->header_start = p;
4991+ r->header_end = p;
4992+ state = sw_almost_done;
4993+ break;
4994+ }
4995+
4996+ if (ch == LF) {
4997+ r->header_name_end = p;
4998+ r->header_start = p;
4999+ r->header_end = p;
5000+ goto done;
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to all changes: