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

Subscribers

People subscribed via source and target branches

to all changes: