├── LICENSE ├── README ├── changes ├── config └── ngx_hmux_module.c /LICENSE: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011-2017 Netease, Inc. 3 | * All rights reserved. 4 | * 5 | * This module is licensed under the BSD license. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 1. Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 | * SUCH DAMAGE. 27 | */ 28 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Name 2 | nginx_hmux_module - Support HMUX protocol proxy with Nginx. 3 | 4 | Synopsis 5 | 6 | events { 7 | use epoll; 8 | epoll_events 4096; 9 | worker_connections 8192; 10 | accept_mutex off; 11 | } 12 | 13 | http { 14 | 15 | upstream resins{ 16 | server xxx.xxx.xxx.xxx:6800; 17 | keepalive 1024; 18 | } 19 | 20 | server { 21 | listen xxxx; 22 | server_name xxx.xxx.com; 23 | location / { 24 | hmux_pass resins; 25 | } 26 | } 27 | } 28 | 29 | Description 30 | With this module, Nginx can directly connect to Resin using the HMUX protocol, with backend connections maintained as keepalive. The motivation for creating this module is to leverage Nginx's high performance and robustness. 31 | 32 | Directives 33 | hmux_buffers 34 | syntax: *hmux_buffers the_number is_size;* 35 | 36 | default: *hmux_buffers 8 4k/8k;* 37 | 38 | context: *http, server, location* 39 | 40 | This directive sets the number and the size of the buffers into which the reply from 41 | the hmux process in the backend is read. By default, the size of each buffer is equal 42 | to the OS page size. Depending on the platform and architecture this value is one of 43 | 4k, 8k or 16k. 44 | 45 | hmux_buffer_size 46 | syntax: *hmux_buffer_size the_size;* 47 | 48 | default: *hmux_buffer_size 4k/8k;* 49 | 50 | context: *http, server, location* 51 | 52 | This directive sets the buffer size for reading the header of the backend hmux 53 | process. By default, the buffer size is equal to the size of one buffer in 54 | hmux_buffers. This directive allows you to set it to an arbitrary value. 55 | 56 | hmux_cache 57 | The usage is the same as fastcgi_cache. 58 | 59 | hmux_cache_key 60 | Same as fastcgi_cache_key. 61 | 62 | hmux_cache_methods 63 | Same as fastcgi_cache_methods. 64 | 65 | hmux_cache_min_uses 66 | Same as fastcgi_cache_min_uses. 67 | 68 | hmux_cache_path 69 | Same as fastcgi_cache_path. 70 | 71 | hmux_cache_use_stale 72 | Same as fastcgi_cache_use_stale. 73 | 74 | hmux_cache_valid 75 | Same as fastcgi_cache_valid. 76 | 77 | hmux_connect_timeout 78 | syntax: *hmux_connect_timeout time;* 79 | 80 | default: *hmux_connect_timeout 60s;* 81 | 82 | context: *http, server, location* 83 | 84 | Directive sets timeout period for connection with hmux-server. 85 | It should be noted that this value can't exceed 75 seconds. 86 | 87 | hmux_header_packet_buffer_size 88 | syntax: *hmux_header packet_buffer_size;* 89 | 90 | default: *hmux_header_packet_buffer_size 8k;* 91 | 92 | context: *http, server, location* 93 | 94 | Set the buffer size of Forward Request packet. The range is (0, 2^16). 95 | 96 | hmux_hide_header 97 | syntax: *hmux_hide_header name;* 98 | 99 | context: *http, server, location* 100 | 101 | By default, Nginx does not pass headers "Status" and "X-Accel-..." from 102 | the hmux process back to the client. This directive can be used to hide 103 | other headers as well. 104 | 105 | If the headers "Status" and "X-Accel-..." must be provided, then it is 106 | necessary to use directive hmux_pass_header to force them to be returned 107 | to the client. 108 | 109 | hmux_ignore_headers 110 | syntax: *hmux_ignore_headers name [name ...];* 111 | 112 | default: *none* 113 | 114 | context: *http, server, location* 115 | 116 | This directive forbids processing of the named headers from the hmux-server reply. 117 | It is possible to specify headers like "X-Accel-Redirect", "X-Accel-Expires", "Expires" or "Cache-Control". 118 | 119 | hmux_ignore_client_abort 120 | syntax: *hmux_ignore_client_abort on|off;* 121 | 122 | default: *hmux_ignore_client_abort off;* 123 | 124 | context: *http, server, location* 125 | 126 | This directive determines if current request to the hmux-server must be 127 | aborted in case the client aborts the request to the server. 128 | 129 | hmux_intercept_errors 130 | syntax: *hmux_intercept_errors on|off;* 131 | 132 | default: *hmux_intercept_errors off;* 133 | 134 | context: *http, server, location* 135 | 136 | This directive determines whether or not to transfer 4xx and 5xx errors 137 | back to the client or to allow Nginx to answer with directive 138 | error_page. 139 | 140 | Note: You need to explicitly define the error_page handler for this for 141 | it to be useful. As Igor says, "Nginx does not intercept an error if 142 | there is no custom handler for it, it does not show its default pages. 143 | This allows to intercept some errors, while passing others as are." 144 | 145 | hmux_next_upstream 146 | syntax: *hmux_next_upstream [error|timeout|invalid_header|http_500|http_503|http_404|non_idempotent|off];* 147 | 148 | default: *hmux_next_upstream error timeout;* 149 | 150 | context: *http, server, location* 151 | 152 | This directive defines in which cases request will be passed to the next server: 153 | 154 | error - an error occurred during connection to the server, 155 | passing request to it or reading server respond header; 156 | timeout - a timeout occurred during connection to the server, 157 | passing request to it or reading server respond header; 158 | invalid_header - server returned empty or invalid answer; 159 | http_500 - a server returned a response with the code 500; 160 | http_502 - a server returned a response with the code 502; 161 | http_503 - a server returned a response with the code 503; 162 | http_504 - a server returned a response with the code 504; 163 | http_404 - a server returned a response with the code 404; 164 | non_idempotent - normally, requests with a non-idempotent method (POST, LOCK, PATCH) 165 | are not passed to the next server if a request has been sent to an 166 | upstream server (Nginx 1.9.13); enabling this option explicitly 167 | allows retrying such requests; 168 | off - explicitly forbids passing request to the next server; 169 | It should be clear that passing request to the next server is possible 170 | only if no data have been yet returned to the client. So, if the error 171 | or timeout occurred during the data transmission to the client it's 172 | too late to fix it. 173 | 174 | hmux_next_upstream_timeout 175 | syntax: *hmux_next_upstream_timeout time;* 176 | 177 | default: *hmux_next_upstream_timeout 0s;* 178 | 179 | context: *http, server, location* 180 | 181 | This directive appeared in Nginx version 1.7.5. 182 | 183 | hmux_next_upstream_tries 184 | syntax: *hmux_next_upstream_tries number;* 185 | 186 | default: *hmux_next_upstream_tries 0;* 187 | 188 | context: *http, server, location* 189 | 190 | This directive appeared in Nginx version 1.7.5. 191 | 192 | 193 | hmux_max_data_packet_size 194 | syntax: *hmux_max_data_packet_size size;* 195 | 196 | default: *hmux_max_data_packet_size 8k;* 197 | 198 | context: *http, server, location* 199 | 200 | Set the maximum size of hmux's Data packet. The range is [8k, 2^16]; 201 | 202 | hmux_max_temp_file_size 203 | syntax: *hmux_max_temp_file_size size;* 204 | 205 | default: *hmux_max_temp_file_size 1G;* 206 | 207 | context: *http, server, location, if* 208 | 209 | The maximum size of a temporary file when the content is larger than the 210 | proxy buffer. If file is larger than this size, it will be served 211 | synchronously from upstream server rather than buffered to disk. 212 | 213 | If hmux_max_temp_file_size is equal to zero, temporary files usage will 214 | be disabled. 215 | 216 | hmux_pass 217 | syntax: *hmux_pass hmux-server* 218 | 219 | default: *none* 220 | 221 | context: *location, if in location* 222 | 223 | Directive assigns the port or socket on which the hmux-server is 224 | listening. Port can be indicated by itself or as an address and port, 225 | for example: 226 | 227 | hmux_pass localhost:6800; 228 | 229 | using a Unix domain socket: 230 | 231 | hmux_pass unix:/tmp/hmux.socket; 232 | 233 | You may also use an upstream block. 234 | 235 | upstream backend { 236 | 237 | server localhost:6800; 238 | 239 | } 240 | 241 | hmux_pass backend; 242 | 243 | hmux_pass_header 244 | syntax: *hmux_pass_header name;* 245 | 246 | context: *http, server, location* 247 | 248 | This directive explicitly allows to pass named headers to the client. 249 | 250 | hmux_pass_request_headers 251 | syntax: *hmux_pass_request_headers [ on | off ];* 252 | 253 | default: *hmux_pass_request_headers on;* 254 | 255 | context: *http, server, location* 256 | 257 | Permits to pass request header fields from the client to server. 258 | 259 | hmux_pass_request_body 260 | syntax: *hmux_pass_request_body [ on | off ] ;* 261 | 262 | default: *hmux_pass_request_body on;* 263 | 264 | context: *http, server, location* 265 | 266 | Permits to pass request body from the client to server. 267 | 268 | hmux_read_timeout 269 | syntax: *hmux_read_timeout time;* 270 | 271 | default: *hmux_read_timeout_time 60* 272 | 273 | context: *http, server, location* 274 | 275 | Directive sets the amount of time for upstream to wait for a hmux process 276 | to send data. Change this directive if you have long running hmux 277 | processes that do not produce output until they have finished 278 | processing. If you are seeing an upstream timed out error in the error 279 | log, then increase this parameter to something more appropriate. 280 | 281 | hmux_send_lowat 282 | syntax: *hmux_send_lowat [ on | off ];* 283 | 284 | default: *hmux_send_lowat off;* 285 | 286 | context: *http, server, location, if* 287 | 288 | This directive set SO_SNDLOWAT. This directive is only available on 289 | FreeBSD 290 | 291 | hmux_send_timeout 292 | syntax: *hmux_send_timeout time;* 293 | 294 | default: *hmux_send_timeout 60;* 295 | 296 | context: *http, server, location* 297 | 298 | Directive sets the amount of time for upstream to wait for a hmux process 299 | to send data. Change this directive if you have long running hmux processes 300 | that do not produce output until they have finished processing. If you are 301 | seeing an upstream timed out error in the error log, then increase this parameter 302 | to something more appropriate. 303 | 304 | Directive specifies request timeout to the server. The timeout is calculated 305 | between two write operations, not for the whole request. If no data have been 306 | written during this period then serve closes the connection. 307 | 308 | hmux_store 309 | syntax: *hmux_store [on | off | path] ;* 310 | 311 | default: *hmux_store off;* 312 | 313 | context: *http, server, location* 314 | 315 | This directive sets the path in which upstream files are stored. The 316 | parameter "on" preserves files in accordance with path specified in 317 | directives *alias* or *root*. The parameter "off" forbids storing. 318 | Furthermore, the name of the path can be clearly assigned with the aid 319 | of the line with the variables: 320 | 321 | hmux_store /data/www$original_uri; 322 | 323 | The time of modification for the file will be set to the date of 324 | "Last-Modified" header in the response. To be able to safe files in this 325 | directory it is necessary that the path is under the directory with 326 | temporary files, given by directive hmux_temp_path for the data location. 327 | 328 | This directive can be used for creating the local copies for dynamic 329 | output of the backend which is not very often changed, for example: 330 | 331 | location /images/ { 332 | 333 | root /data/www; 334 | error_page 404 = @fetch; 335 | 336 | } 337 | 338 | location @fetch { 339 | 340 | internal; 341 | hmux_pass backend; 342 | hmux_store on; 343 | hmux_store_access user:rw group:rw all:r; 344 | hmux_temp_path /data/temp; 345 | 346 | root /data/www; 347 | } 348 | 349 | To be clear hmux_store is not a cache, it's rather mirror on demand. 350 | 351 | hmux_store_access 352 | syntax: *hmux_store_access users:permissions [users:permission ...];* 353 | 354 | default: *hmux_store_access user:rw;* 355 | 356 | context: *http, server, location* 357 | 358 | This directive assigns the permissions for the created files and 359 | directories, for example: 360 | 361 | hmux_store_access user:rw group:rw all:r; 362 | 363 | If any rights for groups or all are assigned, then it is not necessary 364 | to assign rights for user: 365 | 366 | hmux_store_access group:rw all:r; 367 | 368 | hmux_temp_file_write_size 369 | syntax: *hmux_temp_file_write_size size;* 370 | 371 | default: *hmux_temp_file_write_size ["#hmux buffer size"] * 2;* 372 | 373 | context: *http, server, location, if* 374 | 375 | Sets the amount of data that will be flushed to the hmux_temp_path when writing. 376 | It may be used to prevent a worker process blocking for too long while spooling data. 377 | 378 | hmux_x_forwarded_for 379 | syntax: *hmux_x_forwarded_for [ on | off ];* 380 | 381 | default: *hmux_x_forwarded_for off;* 382 | 383 | context: *http, server, location* 384 | 385 | This directive explicitly allows to pass the X-Forwarded-For header to the backend. 386 | 387 | keepalive 388 | syntax: *keepalive 389 | 390 | default: *none* 391 | 392 | context: *upstream* 393 | 394 | Parameters: 395 | 396 | - 397 | Maximum number of connections to cache. If there isn't enough room 398 | to cache new connections - last recently used connections will be 399 | kicked off the cache. 400 | 401 | The instruction is for keeping alive between Nginx and Resin. 402 | It may not work when Nginx has multiple processes,if not working,you should 403 | set accept_mutex off; 404 | 405 | Installation 406 | Download the latest version of the release tarball of this module from 407 | github (git clone http://github.com/wangbin579/nginx-hmux-module) 408 | 409 | Grab the Nginx source code from nginx.org (). 410 | 411 | For example, the version 1.2.3, and then build the source with this module: 412 | 413 | $wget 'http://nginx.org/download/nginx-1.2.3.tar.gz' 414 | $tar -xzvf nginx-1.2.3.tar.gz 415 | $cd nginx-1.2.3/ 416 | $./configure --add-module=/path/to/hmux/directory 417 | $make 418 | $make install 419 | 420 | Note: 421 | This module is for Nginx 1.1.4+ 422 | 423 | 424 | Known Issues 425 | SSL proxy to backend is not supported 426 | 427 | Changelogs 428 | v0.1 429 | first release 430 | v0.5 431 | fixed keepalive problems for Nginx 1.1.14 or above 432 | v0.7 433 | added "HTTPS ON" for https 434 | 435 | Authors 436 | Bin Wang 437 | 438 | License 439 | This README template is from agentzh (). 440 | 441 | I borrowed a lot of codes from fastcgi module of Nginx and 442 | the design of Nginx's nginx_ajp_module 443 | (). Thanks 444 | for their hard work. 445 | 446 | This module is licensed under the BSD license. 447 | 448 | Redistribution and use in source and binary forms, with or without 449 | modification, are permitted provided that the following conditions are 450 | met: 451 | 452 | Redistributions of source code must retain the above copyright notice, 453 | this list of conditions and the following disclaimer. 454 | Redistributions in binary form must reproduce the above copyright 455 | notice, this list of conditions and the following disclaimer in the 456 | documentation and/or other materials provided with the distribution. 457 | 458 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 459 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 460 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 461 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 462 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 463 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 464 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 465 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 466 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 467 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 468 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 469 | 470 | 471 | -------------------------------------------------------------------------------- /changes: -------------------------------------------------------------------------------- 1 | Changes with nginx_hmux_module 2010-04-11 2 | 3 | *) Initial public release 4 | -------------------------------------------------------------------------------- /config: -------------------------------------------------------------------------------- 1 | ngx_addon_name=ngx_hmux_module 2 | if test -n "$ngx_module_link"; then 3 | ngx_module_type=HTTP 4 | ngx_module_name=ngx_hmux_module 5 | ngx_module_srcs="$ngx_addon_dir/ngx_hmux_module.c" 6 | . auto/module 7 | else 8 | HTTP_MODULES="$HTTP_MODULES ngx_hmux_module" 9 | NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_hmux_module.c" 10 | fi 11 | -------------------------------------------------------------------------------- /ngx_hmux_module.c: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------------- 2 | * Description: implements resin's mod_caucho function for nginx 3 | * Version: 1.3 4 | * Author: bin wang 5 | * Company: NetEase 6 | * Mail: wangbin579@gmail.com 7 | * Attension: 8 | * 1) it is tested in linux only 9 | * 2) we have already tested eight projects for this module: 10 | * resin-doc 11 | * jackrabbit 12 | * hudson 13 | * jetspeed 14 | * geoserver 15 | * VQWiki 16 | * struts2-showcase 17 | * spring-security-samples 18 | * all are easily deployed in resin (web war) 19 | * 3) this module references yaoweibin's nginx ajp module 20 | * 4) if you use keepalive module,you should set accept_mutex 21 | * off in multiprocess environment 22 | * 5) if you have any problems or bugs, please contact me 23 | * 24 | * The following describes the hmux protocol implemented in this module 25 | * 26 | * hmux protocol 27 | * A GET request: 28 | * Frontend Backend 29 | * CSE_METHOD 30 | * ... 31 | * CSE_HEADER/CSE_VALUE 32 | * CSE_END 33 | * CSE_DATA 34 | * CSE_DATA 35 | * CSE_END 36 | * 37 | * Short POST: 38 | * Frontend Backend 39 | * CSE_METHOD 40 | * ... 41 | * CSE_HEADER/CSE_VALUE 42 | * CSE_DATA 43 | * CSE_END 44 | * CSE_DATA 45 | * CSE_DATA 46 | * CSE_END 47 | * 48 | * Long POST: 49 | * Frontend Backend 50 | * CSE_METHOD 51 | * ... 52 | * CSE_HEADER/CSE_VALUE 53 | * CSE_DATA 54 | * CSE_DATA (optional) #here we buffer resp data 55 | * CSE_DATA 56 | * CSE_ACK 57 | * CSE_DATA (optional) #here we buffer resp data 58 | * CSE_DATA 59 | * CSE_ACK 60 | * CSE_END 61 | * CSE_DATA 62 | * CSE_END 63 | * 64 | * 65 | *---------------------------------------------------------------------------*/ 66 | 67 | #include 68 | #include 69 | #include 70 | #include 71 | 72 | 73 | #define HMUX_CHANNEL 'C' 74 | #define HMUX_ACK 'A' 75 | #define HMUX_ERROR 'E' 76 | #define HMUX_YIELD 'Y' 77 | #define HMUX_QUIT 'Q' 78 | #define HMUX_EXIT 'X' 79 | 80 | #define HMUX_DATA 'D' 81 | #define HMUX_URL 'U' 82 | #define HMUX_STRING 'S' 83 | #define HMUX_HEADER 'H' 84 | #define HMUX_META_HEADER 'M' 85 | #define HMUX_PROTOCOL 'P' 86 | 87 | #define CSE_NULL '?' 88 | #define CSE_PATH_INFO 'b' 89 | #define CSE_PROTOCOL 'c' 90 | #define CSE_REMOTE_USER 'd' 91 | #define CSE_QUERY_STRING 'e' 92 | #define CSE_SERVER_PORT 'g' 93 | #define CSE_REMOTE_HOST 'h' 94 | #define CSE_REMOTE_ADDR 'i' 95 | #define CSE_REMOTE_PORT 'j' 96 | #define CSE_REAL_PATH 'k' 97 | #define CSE_AUTH_TYPE 'n' 98 | #define CSE_URI 'o' 99 | #define CSE_CONTENT_LENGTH 'p' 100 | #define CSE_CONTENT_TYPE 'q' 101 | #define CSE_IS_SECURE 'r' 102 | #define CSE_SESSION_GROUP 's' 103 | #define CSE_CLIENT_CERT 't' 104 | #define CSE_SERVER_TYPE 'u' 105 | 106 | #define HMUX_METHOD 'm' 107 | #define HMUX_FLUSH 'f' 108 | #define HMUX_SERVER_NAME 'v' 109 | #define HMUX_STATUS 's' 110 | #define HMUX_CLUSTER 'c' 111 | #define HMUX_SRUN 's' 112 | #define HMUX_SRUN_BACKUP 'b' 113 | #define HMUX_SRUN_SSL 'e' 114 | #define HMUX_UNAVAILABLE 'u' 115 | #define HMUX_WEB_APP_UNAVAILABLE 'U' 116 | 117 | #define CSE_HEADER 'H' 118 | #define CSE_VALUE 'V' 119 | 120 | #define CSE_STATUS 'S' 121 | #define CSE_SEND_HEADER 'G' 122 | 123 | #define CSE_PING 'P' 124 | #define CSE_QUERY 'Q' 125 | 126 | #define CSE_ACK 'A' 127 | #define CSE_DATA 'D' 128 | #define CSE_FLUSH 'F' 129 | #define CSE_KEEPALIVE 'K' 130 | #define CSE_END 'Z' 131 | #define CSE_CLOSE 'X' 132 | 133 | #define HMUX_CMD_SZ 8 134 | #define HMUX_DATA_SEG_SZ 8 135 | #define HMUX_META_DATA_LEN 3 136 | #define HMUX_MSG_BUFFER_SZ 8192 137 | #define HMUX_MAX_BUFFER_SZ 65536 138 | 139 | #define HMUX_DISPATCH_PROTOCOL 0x102 140 | #define HMUX_QUERY 0x102 141 | #define HMUX_EOVERFLOW 1001 142 | 143 | #define NGX_HMUX_END 1 144 | 145 | ngx_module_t ngx_hmux_module; 146 | typedef struct hmux_msg_s hmux_msg_t; 147 | 148 | 149 | struct hmux_msg_s 150 | { 151 | ngx_buf_t *buf; 152 | }; 153 | 154 | 155 | typedef struct { 156 | ngx_http_upstream_conf_t upstream; 157 | size_t hmux_header_packet_buffer_size_conf; 158 | size_t max_hmux_data_packet_size_conf; 159 | ngx_flag_t hmux_set_header_x_forwarded_for; 160 | ngx_array_t *hmux_lengths; 161 | ngx_array_t *hmux_values; 162 | #if (NGX_HTTP_CACHE) 163 | ngx_http_complex_value_t cache_key; 164 | #endif 165 | 166 | } ngx_hmux_loc_conf_t; 167 | 168 | 169 | typedef enum { 170 | ngx_hmux_st_init_state = 0, 171 | ngx_hmux_st_forward_request_sent, 172 | ngx_hmux_st_request_body_data_sending, 173 | ngx_hmux_st_request_send_all_done, 174 | ngx_hmux_st_response_recv_headers, 175 | ngx_hmux_st_response_parse_headers_done, 176 | ngx_hmux_st_response_headers_sent, 177 | ngx_hmux_st_response_body_data_sending, 178 | ngx_hmux_st_response_end 179 | } ngx_hmux_state_e; 180 | 181 | typedef struct { 182 | hmux_msg_t msg; 183 | ngx_hmux_state_e state; 184 | /* 185 | * this is for fixing the problem 186 | * when request content length is not equal to content-length 187 | */ 188 | off_t req_body_send_len; 189 | 190 | off_t req_body_len; 191 | /* request body which has not been sent to the backend */ 192 | ngx_chain_t *req_body; 193 | /* buffer for Long POST disposure */ 194 | ngx_chain_t *resp_body; 195 | /* for input filter disposure */ 196 | void *undisposed; 197 | size_t undisposed_size; 198 | /* the response body chunk packet's length */ 199 | int resp_chunk_len; 200 | int buf_next_read_offset; 201 | unsigned int req_body_sent_over:1; 202 | unsigned int head_send_flag:1; 203 | unsigned int long_post_flag:1; 204 | unsigned int flush_flag:1; 205 | unsigned int restore_flag:1; 206 | unsigned int code:8; 207 | unsigned int mend_flag:8; 208 | } ngx_hmux_ctx_t; 209 | 210 | 211 | 212 | #if (NGX_HTTP_CACHE) 213 | static ngx_int_t ngx_hmux_create_key(ngx_http_request_t *r); 214 | #endif 215 | static ngx_int_t ngx_hmux_eval(ngx_http_request_t *r, 216 | ngx_hmux_loc_conf_t *hlcf); 217 | static ngx_int_t ngx_hmux_create_request(ngx_http_request_t *r); 218 | static ngx_int_t ngx_hmux_reinit_request(ngx_http_request_t *r); 219 | static ngx_int_t ngx_hmux_process_header(ngx_http_request_t *r); 220 | static ngx_int_t ngx_hmux_input_filter_init(void *data); 221 | static ngx_int_t ngx_hmux_input_filter(ngx_event_pipe_t *p, 222 | ngx_buf_t *buf); 223 | static void ngx_hmux_abort_request(ngx_http_request_t *r); 224 | static void ngx_hmux_finalize_request(ngx_http_request_t *r, 225 | ngx_int_t rc); 226 | 227 | static ngx_int_t ngx_http_upstream_send_request_body(ngx_http_request_t *r, 228 | ngx_http_upstream_t *u); 229 | static ngx_chain_t *hmux_data_msg_send_body(ngx_http_request_t *r, 230 | size_t max_size, ngx_chain_t **body); 231 | static void ngx_http_upstream_send_request_body_handler(ngx_http_request_t *r, 232 | ngx_http_upstream_t *u); 233 | static void ngx_http_upstream_dummy_handler(ngx_http_request_t *r, 234 | ngx_http_upstream_t *u); 235 | 236 | #if (NGX_HTTP_CACHE) 237 | static char *ngx_hmux_cache(ngx_conf_t *cf, ngx_command_t *cmd, 238 | void *conf); 239 | static char *ngx_hmux_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, 240 | void *conf); 241 | #endif 242 | static char *ngx_hmux_pass(ngx_conf_t *cf, ngx_command_t *cmd, 243 | void *conf); 244 | static char *ngx_hmux_store(ngx_conf_t *cf, ngx_command_t *cmd, 245 | void *conf); 246 | static char *ngx_hmux_lowat_check(ngx_conf_t *cf, void *post, 247 | void *data); 248 | static char *ngx_hmux_upstream_max_fails_unsupported(ngx_conf_t *cf, 249 | ngx_command_t *cmd, void *conf); 250 | static char *ngx_hmux_upstream_fail_timeout_unsupported(ngx_conf_t *cf, 251 | ngx_command_t *cmd, void *conf); 252 | static ngx_int_t ngx_hmux_get_x_forwarded_for_value(ngx_http_request_t *r, 253 | ngx_str_t *v, uintptr_t data); 254 | 255 | static void *ngx_hmux_create_loc_conf(ngx_conf_t *cf); 256 | static char *ngx_hmux_merge_loc_conf(ngx_conf_t *cf, void *parent, 257 | void *child); 258 | static int hmux_log_overflow(ngx_uint_t level, hmux_msg_t *msg, 259 | const char *context); 260 | 261 | /* 262 | * protocol functions 263 | */ 264 | static ngx_int_t hmux_start_channel(hmux_msg_t *msg, 265 | unsigned short channel); 266 | static ngx_int_t hmux_write_string(hmux_msg_t *msg, 267 | char code, ngx_str_t *value); 268 | 269 | static ngx_int_t hmux_read_len(hmux_msg_t *msg, int *rlen); 270 | static ngx_int_t hmux_read_byte(hmux_msg_t *s, u_char *rvalue); 271 | static ngx_int_t hmux_read_string(hmux_msg_t *msg, ngx_str_t *rvalue); 272 | 273 | static hmux_msg_t *hmux_msg_reuse(hmux_msg_t *msg); 274 | static ngx_int_t hmux_data_msg_begin(hmux_msg_t *msg, size_t size); 275 | static ngx_chain_t *hmux_cmd_msg(ngx_hmux_ctx_t *ctx, ngx_http_request_t *r, 276 | u_char code); 277 | static ngx_int_t hmux_msg_create_buffer(ngx_pool_t *pool, size_t size, 278 | hmux_msg_t *msg); 279 | 280 | static ngx_int_t hmux_marshal_into_msg(hmux_msg_t *msg, 281 | ngx_http_request_t *r, ngx_hmux_loc_conf_t *hlcf); 282 | 283 | static ngx_int_t hmux_unmarshal_response(hmux_msg_t *msg, 284 | ngx_http_request_t *r, ngx_hmux_loc_conf_t *hlcf); 285 | 286 | 287 | static ngx_conf_post_t ngx_hmux_lowat_post = { ngx_hmux_lowat_check }; 288 | 289 | static ngx_conf_bitmask_t ngx_hmux_next_upstream_masks[] = { 290 | { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR }, 291 | { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT }, 292 | { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER }, 293 | #if defined(nginx_version) && nginx_version >= 1009013 294 | { ngx_string("non_idempotent"), NGX_HTTP_UPSTREAM_FT_NON_IDEMPOTENT }, 295 | #endif 296 | { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 }, 297 | { ngx_string("http_502"), NGX_HTTP_UPSTREAM_FT_HTTP_502 }, 298 | { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 }, 299 | { ngx_string("http_504"), NGX_HTTP_UPSTREAM_FT_HTTP_504 }, 300 | { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 }, 301 | { ngx_string("updating"), NGX_HTTP_UPSTREAM_FT_UPDATING }, 302 | { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF }, 303 | { ngx_null_string, 0 } 304 | }; 305 | 306 | static ngx_path_init_t ngx_hmux_temp_path = { 307 | ngx_string("hmux_temp"), { 1, 2, 0 } 308 | }; 309 | 310 | 311 | static ngx_str_t ngx_hmux_hide_headers[] = { 312 | ngx_string("Status"), 313 | ngx_string("X-Accel-Expires"), 314 | ngx_string("X-Accel-Redirect"), 315 | ngx_string("X-Accel-Limit-Rate"), 316 | ngx_string("X-Accel-Buffering"), 317 | ngx_string("X-Accel-Charset"), 318 | ngx_null_string 319 | }; 320 | 321 | #if (NGX_HTTP_CACHE) 322 | static ngx_str_t ngx_hmux_hide_cache_headers[] = { 323 | ngx_string("Status"), 324 | ngx_string("X-Accel-Expires"), 325 | ngx_string("X-Accel-Redirect"), 326 | ngx_string("X-Accel-Limit-Rate"), 327 | ngx_string("X-Accel-Buffering"), 328 | ngx_string("X-Accel-Charset"), 329 | ngx_string("Set-Cookie"), 330 | ngx_string("P3P"), 331 | ngx_null_string 332 | }; 333 | #endif 334 | 335 | 336 | static ngx_command_t ngx_hmux_commands[] = { 337 | 338 | { ngx_string("hmux_pass"), 339 | NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1, 340 | ngx_hmux_pass, 341 | NGX_HTTP_LOC_CONF_OFFSET, 342 | 0, 343 | NULL }, 344 | 345 | { ngx_string("hmux_header_packet_buffer_size"), 346 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 347 | ngx_conf_set_size_slot, 348 | NGX_HTTP_LOC_CONF_OFFSET, 349 | offsetof(ngx_hmux_loc_conf_t, hmux_header_packet_buffer_size_conf), 350 | NULL }, 351 | 352 | { ngx_string("hmux_max_data_packet_size"), 353 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 354 | ngx_conf_set_str_slot, 355 | NGX_HTTP_LOC_CONF_OFFSET, 356 | offsetof(ngx_hmux_loc_conf_t, max_hmux_data_packet_size_conf), 357 | NULL }, 358 | 359 | { ngx_string("hmux_store"), 360 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 361 | ngx_hmux_store, 362 | NGX_HTTP_LOC_CONF_OFFSET, 363 | 0, 364 | NULL }, 365 | 366 | { ngx_string("hmux_store_access"), 367 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123, 368 | ngx_conf_set_access_slot, 369 | NGX_HTTP_LOC_CONF_OFFSET, 370 | offsetof(ngx_hmux_loc_conf_t, upstream.store_access), 371 | NULL }, 372 | 373 | { ngx_string("hmux_ignore_client_abort"), 374 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, 375 | ngx_conf_set_flag_slot, 376 | NGX_HTTP_LOC_CONF_OFFSET, 377 | offsetof(ngx_hmux_loc_conf_t, upstream.ignore_client_abort), 378 | NULL }, 379 | 380 | { ngx_string("hmux_connect_timeout"), 381 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 382 | ngx_conf_set_msec_slot, 383 | NGX_HTTP_LOC_CONF_OFFSET, 384 | offsetof(ngx_hmux_loc_conf_t, upstream.connect_timeout), 385 | NULL }, 386 | 387 | { ngx_string("hmux_send_timeout"), 388 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 389 | ngx_conf_set_msec_slot, 390 | NGX_HTTP_LOC_CONF_OFFSET, 391 | offsetof(ngx_hmux_loc_conf_t, upstream.send_timeout), 392 | NULL }, 393 | 394 | { ngx_string("hmux_send_lowat"), 395 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 396 | ngx_conf_set_size_slot, 397 | NGX_HTTP_LOC_CONF_OFFSET, 398 | offsetof(ngx_hmux_loc_conf_t, upstream.send_lowat), 399 | &ngx_hmux_lowat_post }, 400 | 401 | { ngx_string("hmux_buffer_size"), 402 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 403 | ngx_conf_set_size_slot, 404 | NGX_HTTP_LOC_CONF_OFFSET, 405 | offsetof(ngx_hmux_loc_conf_t, upstream.buffer_size), 406 | NULL }, 407 | 408 | { ngx_string("hmux_pass_request_headers"), 409 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, 410 | ngx_conf_set_flag_slot, 411 | NGX_HTTP_LOC_CONF_OFFSET, 412 | offsetof(ngx_hmux_loc_conf_t, upstream.pass_request_headers), 413 | NULL }, 414 | 415 | { ngx_string("hmux_pass_request_body"), 416 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, 417 | ngx_conf_set_flag_slot, 418 | NGX_HTTP_LOC_CONF_OFFSET, 419 | offsetof(ngx_hmux_loc_conf_t, upstream.pass_request_body), 420 | NULL }, 421 | 422 | { ngx_string("hmux_intercept_errors"), 423 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, 424 | ngx_conf_set_flag_slot, 425 | NGX_HTTP_LOC_CONF_OFFSET, 426 | offsetof(ngx_hmux_loc_conf_t, upstream.intercept_errors), 427 | NULL }, 428 | 429 | { ngx_string("hmux_read_timeout"), 430 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 431 | ngx_conf_set_msec_slot, 432 | NGX_HTTP_LOC_CONF_OFFSET, 433 | offsetof(ngx_hmux_loc_conf_t, upstream.read_timeout), 434 | NULL }, 435 | 436 | #if defined(nginx_version) && nginx_version >= 1007005 437 | { ngx_string("hmux_next_upstream_tries"), 438 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 439 | ngx_conf_set_num_slot, 440 | NGX_HTTP_LOC_CONF_OFFSET, 441 | offsetof(ngx_hmux_loc_conf_t, upstream.next_upstream_tries), 442 | NULL }, 443 | 444 | { ngx_string("hmux_next_upstream_timeout"), 445 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 446 | ngx_conf_set_msec_slot, 447 | NGX_HTTP_LOC_CONF_OFFSET, 448 | offsetof(ngx_hmux_loc_conf_t, upstream.next_upstream_timeout), 449 | NULL }, 450 | #endif 451 | 452 | { ngx_string("hmux_buffers"), 453 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, 454 | ngx_conf_set_bufs_slot, 455 | NGX_HTTP_LOC_CONF_OFFSET, 456 | offsetof(ngx_hmux_loc_conf_t, upstream.bufs), 457 | NULL }, 458 | 459 | { ngx_string("hmux_busy_buffers_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_hmux_loc_conf_t, upstream.busy_buffers_size_conf), 464 | NULL }, 465 | 466 | #if (NGX_HTTP_CACHE) 467 | { ngx_string("hmux_cache"), 468 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, 469 | ngx_hmux_cache, 470 | NGX_HTTP_LOC_CONF_OFFSET, 471 | 0, 472 | NULL }, 473 | 474 | { ngx_string("hmux_cache_key"), 475 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, 476 | ngx_hmux_cache_key, 477 | NGX_HTTP_LOC_CONF_OFFSET, 478 | 0, 479 | NULL }, 480 | 481 | { ngx_string("hmux_cache_path"), 482 | NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE, 483 | ngx_http_file_cache_set_slot, 484 | 0, 485 | 0, 486 | &ngx_hmux_module }, 487 | 488 | { ngx_string("hmux_cache_valid"), 489 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, 490 | ngx_http_file_cache_valid_set_slot, 491 | NGX_HTTP_LOC_CONF_OFFSET, 492 | offsetof(ngx_hmux_loc_conf_t, upstream.cache_valid), 493 | NULL }, 494 | 495 | { ngx_string("hmux_cache_min_uses"), 496 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 497 | ngx_conf_set_num_slot, 498 | NGX_HTTP_LOC_CONF_OFFSET, 499 | offsetof(ngx_hmux_loc_conf_t, upstream.cache_min_uses), 500 | NULL }, 501 | 502 | { ngx_string("hmux_cache_use_stale"), 503 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, 504 | ngx_conf_set_bitmask_slot, 505 | NGX_HTTP_LOC_CONF_OFFSET, 506 | offsetof(ngx_hmux_loc_conf_t, upstream.cache_use_stale), 507 | &ngx_hmux_next_upstream_masks }, 508 | 509 | { ngx_string("hmux_cache_methods"), 510 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, 511 | ngx_conf_set_bitmask_slot, 512 | NGX_HTTP_LOC_CONF_OFFSET, 513 | offsetof(ngx_hmux_loc_conf_t, upstream.cache_methods), 514 | &ngx_http_upstream_cache_method_mask }, 515 | #endif 516 | 517 | { ngx_string("hmux_temp_path"), 518 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234, 519 | ngx_conf_set_path_slot, 520 | NGX_HTTP_LOC_CONF_OFFSET, 521 | offsetof(ngx_hmux_loc_conf_t, upstream.temp_path), 522 | NULL }, 523 | 524 | { ngx_string("hmux_max_temp_file_size"), 525 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 526 | ngx_conf_set_size_slot, 527 | NGX_HTTP_LOC_CONF_OFFSET, 528 | offsetof(ngx_hmux_loc_conf_t, upstream.max_temp_file_size_conf), 529 | NULL }, 530 | 531 | { ngx_string("hmux_temp_file_write_size"), 532 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 533 | ngx_conf_set_size_slot, 534 | NGX_HTTP_LOC_CONF_OFFSET, 535 | offsetof(ngx_hmux_loc_conf_t, upstream.temp_file_write_size_conf), 536 | NULL }, 537 | 538 | { ngx_string("hmux_next_upstream"), 539 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, 540 | ngx_conf_set_bitmask_slot, 541 | NGX_HTTP_LOC_CONF_OFFSET, 542 | offsetof(ngx_hmux_loc_conf_t, upstream.next_upstream), 543 | &ngx_hmux_next_upstream_masks }, 544 | 545 | { ngx_string("hmux_upstream_max_fails"), 546 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 547 | ngx_hmux_upstream_max_fails_unsupported, 548 | 0, 549 | 0, 550 | NULL }, 551 | 552 | { ngx_string("hmux_upstream_fail_timeout"), 553 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 554 | ngx_hmux_upstream_fail_timeout_unsupported, 555 | 0, 556 | 0, 557 | NULL }, 558 | 559 | { ngx_string("hmux_pass_header"), 560 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, 561 | ngx_conf_set_str_array_slot, 562 | NGX_HTTP_LOC_CONF_OFFSET, 563 | offsetof(ngx_hmux_loc_conf_t, upstream.pass_headers), 564 | NULL }, 565 | 566 | { ngx_string("hmux_hide_header"), 567 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, 568 | ngx_conf_set_str_array_slot, 569 | NGX_HTTP_LOC_CONF_OFFSET, 570 | offsetof(ngx_hmux_loc_conf_t, upstream.hide_headers), 571 | NULL }, 572 | 573 | { ngx_string("hmux_ignore_headers"), 574 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, 575 | ngx_conf_set_bitmask_slot, 576 | NGX_HTTP_LOC_CONF_OFFSET, 577 | offsetof(ngx_hmux_loc_conf_t, upstream.ignore_headers), 578 | &ngx_http_upstream_ignore_headers_masks}, 579 | 580 | { ngx_string("hmux_x_forwarded_for"), 581 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, 582 | ngx_conf_set_flag_slot, 583 | NGX_HTTP_LOC_CONF_OFFSET, 584 | offsetof(ngx_hmux_loc_conf_t, hmux_set_header_x_forwarded_for), 585 | NULL }, 586 | 587 | 588 | ngx_null_command 589 | }; 590 | 591 | 592 | static ngx_http_module_t ngx_hmux_module_ctx = { 593 | NULL, /* preconfiguration */ 594 | NULL, /* postconfiguration */ 595 | 596 | NULL, /* create main configuration */ 597 | NULL, /* init main configuration */ 598 | 599 | NULL, /* create server configuration */ 600 | NULL, /* merge server configuration */ 601 | 602 | ngx_hmux_create_loc_conf, /* create location configuration */ 603 | ngx_hmux_merge_loc_conf /* merge location configuration */ 604 | }; 605 | 606 | 607 | ngx_module_t ngx_hmux_module = { 608 | NGX_MODULE_V1, 609 | &ngx_hmux_module_ctx, /* module context */ 610 | ngx_hmux_commands, /* module directives */ 611 | NGX_HTTP_MODULE, /* module type */ 612 | NULL, /* init master */ 613 | NULL, /* init module */ 614 | NULL, /* init process */ 615 | NULL, /* init thread */ 616 | NULL, /* exit thread */ 617 | NULL, /* exit process */ 618 | NULL, /* exit master */ 619 | NGX_MODULE_V1_PADDING 620 | }; 621 | 622 | ngx_int_t 623 | ngx_hmux_handler(ngx_http_request_t *r) 624 | { 625 | ngx_int_t rc; 626 | ngx_http_upstream_t *u; 627 | ngx_hmux_ctx_t *ctx; 628 | ngx_hmux_loc_conf_t *hlcf; 629 | 630 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 631 | "enter hmux handler:%V", &r->uri); 632 | 633 | if (r->subrequest_in_memory) { 634 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 635 | "ngx_hmux_module does not support " 636 | "subrequest in memory"); 637 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 638 | } 639 | 640 | if (ngx_http_set_content_type(r) != NGX_OK) { 641 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 642 | } 643 | 644 | if (ngx_http_upstream_create(r) != NGX_OK) { 645 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 646 | } 647 | 648 | ctx = ngx_pcalloc(r->pool, sizeof(ngx_hmux_ctx_t)); 649 | if (ctx == NULL) { 650 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 651 | } 652 | 653 | if (r->headers_in.content_length_n > 0) { 654 | ctx->req_body_len = r->headers_in.content_length_n; 655 | } 656 | 657 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 658 | "set req_body_len:%d", ctx->req_body_len); 659 | 660 | ctx->state = ngx_hmux_st_init_state; 661 | 662 | ngx_http_set_ctx(r, ctx, ngx_hmux_module); 663 | 664 | hlcf = ngx_http_get_module_loc_conf(r, ngx_hmux_module); 665 | 666 | if (hlcf->hmux_lengths) { 667 | if (ngx_hmux_eval(r, hlcf) != NGX_OK) { 668 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 669 | } 670 | } 671 | 672 | u = r->upstream; 673 | u->schema.len = sizeof("hmux://") - 1; 674 | u->schema.data = (u_char *) "hmux://"; 675 | u->output.tag = (ngx_buf_tag_t) &ngx_hmux_module; 676 | u->conf = &hlcf->upstream; 677 | #if (NGX_HTTP_CACHE) 678 | u->create_key = ngx_hmux_create_key; 679 | #endif 680 | 681 | u->create_request = ngx_hmux_create_request; 682 | u->reinit_request = ngx_hmux_reinit_request; 683 | u->process_header = ngx_hmux_process_header; 684 | u->abort_request = ngx_hmux_abort_request; 685 | u->finalize_request = ngx_hmux_finalize_request; 686 | 687 | u->buffering = 1; 688 | 689 | u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t)); 690 | if (u->pipe == NULL) { 691 | return NGX_HTTP_INTERNAL_SERVER_ERROR; 692 | } 693 | 694 | u->pipe->input_filter = ngx_hmux_input_filter; 695 | u->pipe->input_ctx = r; 696 | u->input_filter_init = ngx_hmux_input_filter_init; 697 | 698 | rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init); 699 | 700 | if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { 701 | return rc; 702 | } 703 | 704 | return NGX_DONE; 705 | } 706 | 707 | 708 | static ngx_int_t 709 | ngx_hmux_eval(ngx_http_request_t *r, ngx_hmux_loc_conf_t *hlcf) 710 | { 711 | ngx_url_t u; 712 | 713 | ngx_memzero(&u, sizeof(ngx_url_t)); 714 | 715 | if (ngx_http_script_run(r, &u.url, hlcf->hmux_lengths->elts, 0, 716 | hlcf->hmux_values->elts) == NULL) 717 | { 718 | return NGX_ERROR; 719 | } 720 | 721 | u.no_resolve = 1; 722 | 723 | if (ngx_parse_url(r->pool, &u) != NGX_OK) { 724 | if (u.err) { 725 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 726 | "%s in upstream \"%V\"", u.err, &u.url); 727 | } 728 | 729 | return NGX_ERROR; 730 | } 731 | 732 | r->upstream->resolved = ngx_pcalloc(r->pool, 733 | sizeof(ngx_http_upstream_resolved_t)); 734 | if (r->upstream->resolved == NULL) { 735 | return NGX_ERROR; 736 | } 737 | 738 | #if defined(nginx_version) && nginx_version >= 1011006 739 | if (u.addrs) { 740 | r->upstream->resolved->sockaddr = u.addrs[0].sockaddr; 741 | r->upstream->resolved->socklen = u.addrs[0].socklen; 742 | r->upstream->resolved->naddrs = 1; 743 | r->upstream->resolved->name = u.addrs[0].name; 744 | } 745 | 746 | r->upstream->resolved->host = u.host; 747 | #else 748 | if (u.addrs && u.addrs[0].sockaddr) { 749 | r->upstream->resolved->sockaddr = u.addrs[0].sockaddr; 750 | r->upstream->resolved->socklen = u.addrs[0].socklen; 751 | r->upstream->resolved->naddrs = 1; 752 | r->upstream->resolved->host = u.addrs[0].name; 753 | 754 | } else { 755 | r->upstream->resolved->host = u.host; 756 | } 757 | #endif 758 | 759 | r->upstream->resolved->port = u.port; 760 | r->upstream->resolved->no_port = u.no_port; 761 | 762 | return NGX_OK; 763 | } 764 | 765 | #if (NGX_HTTP_CACHE) 766 | static ngx_int_t 767 | ngx_hmux_create_key(ngx_http_request_t *r) 768 | { 769 | ngx_str_t *key; 770 | ngx_hmux_loc_conf_t *hlcf; 771 | 772 | key = ngx_array_push(&r->cache->keys); 773 | if (key == NULL) { 774 | return NGX_ERROR; 775 | } 776 | 777 | hlcf = ngx_http_get_module_loc_conf(r, ngx_hmux_module); 778 | 779 | if (ngx_http_complex_value(r, &hlcf->cache_key, key) != NGX_OK) { 780 | return NGX_ERROR; 781 | } 782 | 783 | return NGX_OK; 784 | } 785 | #endif 786 | 787 | static ngx_int_t 788 | ngx_hmux_create_request(ngx_http_request_t *r) 789 | { 790 | ngx_int_t rc, need_send_body = 0; 791 | hmux_msg_t *msg; 792 | ngx_chain_t *cl, *last; 793 | ngx_hmux_ctx_t *ctx; 794 | ngx_hmux_loc_conf_t *hlcf; 795 | 796 | ctx = ngx_http_get_module_ctx(r, ngx_hmux_module); 797 | hlcf = ngx_http_get_module_loc_conf(r, ngx_hmux_module); 798 | 799 | if (ctx == NULL || hlcf == NULL) { 800 | return NGX_ERROR; 801 | } 802 | 803 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 804 | "create req,req_body_len:%d", ctx->req_body_len); 805 | 806 | msg = hmux_msg_reuse(&ctx->msg); 807 | 808 | /* creates buffer for header */ 809 | if (NGX_OK != hmux_msg_create_buffer(r->pool, 810 | hlcf->hmux_header_packet_buffer_size_conf, msg)) { 811 | return NGX_ERROR; 812 | } 813 | 814 | rc = hmux_marshal_into_msg(msg, r, hlcf); 815 | if (rc != NGX_OK) { 816 | ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, 817 | "hmux_header_packet_buffer_size may be too small:%uz", 818 | hlcf->hmux_header_packet_buffer_size_conf); 819 | 820 | return rc; 821 | } 822 | 823 | cl = ngx_alloc_chain_link(r->pool); 824 | if (cl == NULL) { 825 | return NGX_ERROR; 826 | } 827 | 828 | cl->buf = msg->buf; 829 | cl->buf->flush = 1; 830 | 831 | ctx->state = ngx_hmux_st_forward_request_sent; 832 | 833 | if (hlcf->upstream.pass_request_body) { 834 | ctx->req_body = r->upstream->request_bufs; 835 | if (ctx->req_body != NULL && ctx->req_body->buf != NULL) { 836 | if (ctx->req_body->buf->in_file) { 837 | if (ctx->req_body->buf->file_pos != 838 | ctx->req_body->buf->file_last) 839 | { 840 | need_send_body = 1; 841 | } 842 | 843 | } else { 844 | if (ctx->req_body->buf->pos != ctx->req_body->buf->last) { 845 | need_send_body = 1; 846 | } 847 | } 848 | } 849 | if (!need_send_body) { 850 | if (ctx->req_body != NULL) { 851 | if (ctx->req_body->buf != NULL) { 852 | ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, 853 | "It has body but need_send_body is false"); 854 | } else { 855 | ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, 856 | "strange here, ctx->req_body->buf is null"); 857 | } 858 | } 859 | } 860 | } 861 | 862 | r->upstream->request_bufs = cl; 863 | 864 | if (need_send_body) { 865 | cl->next = hmux_data_msg_send_body(r, 866 | hlcf->max_hmux_data_packet_size_conf, &ctx->req_body); 867 | 868 | last = cl; 869 | while (last->next != NULL) { 870 | last = last->next; 871 | } 872 | 873 | if (ctx->req_body != NULL && !ctx->req_body_sent_over) { 874 | /* it has body data left for sending */ 875 | ctx->state = ngx_hmux_st_request_body_data_sending; 876 | last->next = hmux_cmd_msg(ctx, r, HMUX_YIELD); 877 | } else { 878 | ctx->state = ngx_hmux_st_request_send_all_done; 879 | last->next = hmux_cmd_msg(ctx, r, HMUX_QUIT); 880 | ctx->req_body_sent_over = 1; 881 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 882 | "req body sent done:%V", &r->uri); 883 | } 884 | 885 | } else { 886 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 887 | "no need to send req_body:%V", &r->uri); 888 | ctx->req_body_sent_over = 1; 889 | ctx->state = ngx_hmux_st_request_send_all_done; 890 | cl->next = hmux_cmd_msg(ctx, r, HMUX_QUIT); 891 | } 892 | 893 | return NGX_OK; 894 | } 895 | 896 | 897 | static ngx_int_t 898 | ngx_hmux_reinit_request(ngx_http_request_t *r) 899 | { 900 | ngx_hmux_ctx_t *ctx; 901 | ngx_hmux_loc_conf_t *hlcf; 902 | 903 | ctx = ngx_http_get_module_ctx(r, ngx_hmux_module); 904 | hlcf = ngx_http_get_module_loc_conf(r, ngx_hmux_module); 905 | 906 | if (ctx == NULL || hlcf == NULL) { 907 | return NGX_ERROR; 908 | } 909 | 910 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 911 | "reinit req,req_body_len:%d", ctx->req_body_len); 912 | 913 | memset(ctx, 0, sizeof(ngx_hmux_ctx_t)); 914 | 915 | ctx->state = ngx_hmux_st_init_state; 916 | 917 | hmux_msg_reuse(&ctx->msg); 918 | 919 | return NGX_OK; 920 | } 921 | 922 | 923 | static ngx_int_t 924 | ngx_hmux_process_header(ngx_http_request_t *r) 925 | { 926 | ngx_hmux_ctx_t *ctx; 927 | ngx_hmux_loc_conf_t *hlcf; 928 | 929 | ctx = ngx_http_get_module_ctx(r, ngx_hmux_module); 930 | hlcf = ngx_http_get_module_loc_conf(r, ngx_hmux_module); 931 | 932 | if (ctx == NULL || hlcf == NULL) { 933 | return NGX_ERROR; 934 | } 935 | 936 | ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, 937 | "ngx_hmux_process_header: state(%d)", ctx->state); 938 | 939 | return hmux_unmarshal_response(&ctx->msg, r, hlcf); 940 | } 941 | 942 | 943 | static ngx_int_t 944 | ngx_http_upstream_send_request_body(ngx_http_request_t *r, 945 | ngx_http_upstream_t *u) 946 | { 947 | ngx_int_t rc; 948 | ngx_chain_t *cl, *last; 949 | hmux_msg_t *msg; 950 | ngx_connection_t *c; 951 | ngx_hmux_ctx_t *ctx; 952 | ngx_hmux_loc_conf_t *hlcf; 953 | 954 | c = u->peer.connection; 955 | 956 | ctx = ngx_http_get_module_ctx(r, ngx_hmux_module); 957 | hlcf = ngx_http_get_module_loc_conf(r, ngx_hmux_module); 958 | 959 | if (ctx == NULL || hlcf == NULL) 960 | { 961 | return NGX_ERROR; 962 | } 963 | 964 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 965 | "send req body,req_body_len:%d", ctx->req_body_len); 966 | 967 | cl = hmux_data_msg_send_body(r, hlcf->max_hmux_data_packet_size_conf, 968 | &ctx->req_body); 969 | 970 | if (u->output.in == NULL && u->output.busy == NULL) { 971 | if (cl == NULL) { 972 | msg = hmux_msg_reuse(&ctx->msg); 973 | 974 | hmux_data_msg_begin(msg, 0); 975 | 976 | cl = ngx_alloc_chain_link(r->pool); 977 | if (cl == NULL ) { 978 | return NGX_ERROR; 979 | } 980 | 981 | cl->buf = msg->buf; 982 | cl->next = NULL; 983 | } 984 | } 985 | 986 | last = cl; 987 | while (last->next != NULL) { 988 | last = last->next; 989 | } 990 | 991 | if (ctx->req_body != NULL && !ctx->req_body_sent_over) { 992 | ctx->state = ngx_hmux_st_request_body_data_sending; 993 | last->next = hmux_cmd_msg(ctx, r, HMUX_YIELD); 994 | } else { 995 | last->next = hmux_cmd_msg(ctx, r, HMUX_QUIT); 996 | ctx->state = ngx_hmux_st_request_send_all_done; 997 | ctx->req_body_sent_over = 1; 998 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 999 | "req body sent over:%V", &r->uri); 1000 | 1001 | } 1002 | 1003 | c->log->action = "sending request body again to upstream"; 1004 | 1005 | rc = ngx_output_chain(&u->output, cl); 1006 | 1007 | if (NGX_ERROR == rc) { 1008 | return NGX_ERROR; 1009 | } 1010 | 1011 | if (c->write->timer_set) { 1012 | ngx_del_timer(c->write); 1013 | } 1014 | 1015 | if (rc == NGX_AGAIN) { 1016 | ngx_add_timer(c->write, u->conf->send_timeout); 1017 | 1018 | if (ngx_handle_write_event(c->write, u->conf->send_lowat) != NGX_OK) { 1019 | return NGX_ERROR; 1020 | } 1021 | 1022 | u->write_event_handler = ngx_http_upstream_send_request_body_handler; 1023 | 1024 | return NGX_AGAIN; 1025 | } 1026 | 1027 | if (NGX_TCP_NOPUSH_SET == c->tcp_nopush) { 1028 | if (NGX_ERROR == ngx_tcp_push(c->fd)) { 1029 | ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno, 1030 | ngx_tcp_push_n " failed"); 1031 | return NGX_ERROR; 1032 | } 1033 | 1034 | c->tcp_nopush = NGX_TCP_NOPUSH_UNSET; 1035 | } 1036 | 1037 | ngx_add_timer(c->read, u->conf->read_timeout); 1038 | 1039 | if (ngx_handle_write_event(c->write, 0) != NGX_OK) { 1040 | return NGX_ERROR; 1041 | } 1042 | 1043 | u->write_event_handler = ngx_http_upstream_dummy_handler; 1044 | 1045 | return NGX_OK; 1046 | } 1047 | 1048 | 1049 | ngx_chain_t * 1050 | hmux_data_msg_send_body(ngx_http_request_t *r, size_t max_size, 1051 | ngx_chain_t **body) 1052 | { 1053 | off_t act_f_pos; 1054 | size_t size, actual_size, base_size, 1055 | added_size, redundant_size; 1056 | u_char *act_pos; 1057 | ngx_int_t rc; 1058 | ngx_buf_t *b_in, *b_out; 1059 | ngx_chain_t *out, *cl, *in; 1060 | hmux_msg_t *msg; 1061 | ngx_hmux_ctx_t *ctx; 1062 | 1063 | ctx = ngx_http_get_module_ctx(r, ngx_hmux_module); 1064 | 1065 | if (body == NULL || *body == NULL || ctx == NULL) { 1066 | return NULL; 1067 | } 1068 | 1069 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, 1070 | r->connection->log, 0, "hmux_data_msg_send_body"); 1071 | 1072 | msg = hmux_msg_reuse(&ctx->msg); 1073 | if ((rc = hmux_msg_create_buffer(r->pool, HMUX_DATA_SEG_SZ, msg)) 1074 | != NGX_OK) 1075 | { 1076 | return NULL; 1077 | } 1078 | 1079 | out = cl = ngx_alloc_chain_link(r->pool); 1080 | if (cl == NULL) { 1081 | return NULL; 1082 | } 1083 | 1084 | cl->buf = msg->buf; 1085 | max_size = max_size-HMUX_META_DATA_LEN; 1086 | size = 0; 1087 | actual_size = 0; 1088 | base_size = 0; 1089 | redundant_size = 0; 1090 | added_size = 0; 1091 | in = *body; 1092 | 1093 | b_out = NULL; 1094 | while (in) { 1095 | b_in = in->buf; 1096 | 1097 | b_out = ngx_alloc_buf(r->pool); 1098 | if (b_out == NULL) { 1099 | return NULL; 1100 | } 1101 | 1102 | ngx_memcpy(b_out, b_in, sizeof(ngx_buf_t)); 1103 | base_size = size; 1104 | if (b_in->in_file) { 1105 | 1106 | act_f_pos = b_in->file_pos; 1107 | 1108 | if (ctx->buf_next_read_offset) { 1109 | act_f_pos += ctx->buf_next_read_offset; 1110 | } 1111 | 1112 | if ((size_t) (b_in->file_last - act_f_pos) <= 1113 | (max_size - size)) 1114 | { 1115 | b_out->file_pos = act_f_pos; 1116 | b_out->file_last = b_in->file_last; 1117 | size += (b_out->file_last - b_out->file_pos); 1118 | 1119 | } else if ((size_t) (b_in->file_last - act_f_pos) > 1120 | (max_size-size)) 1121 | { 1122 | b_out->file_pos = act_f_pos; 1123 | ctx->buf_next_read_offset += (max_size - size); 1124 | b_out->file_last = b_out->file_pos + (max_size - size); 1125 | size += (b_out->file_last - b_out->file_pos); 1126 | 1127 | } 1128 | } else { 1129 | act_pos = b_in->pos; 1130 | 1131 | if (ctx->buf_next_read_offset) { 1132 | act_pos += ctx->buf_next_read_offset; 1133 | } 1134 | 1135 | if ((size_t) (b_in->last - act_pos) <= (max_size - size)) { 1136 | 1137 | b_out->pos = act_pos; 1138 | b_out->last = b_in->last; 1139 | size += b_out->last - b_out->pos; 1140 | 1141 | } else if ((size_t) (b_in->last - act_pos) > (max_size - size)) { 1142 | 1143 | b_out->pos = act_pos; 1144 | b_out->last = b_out->pos + (max_size - size); 1145 | ctx->buf_next_read_offset += (max_size - size); 1146 | size += (b_out->last - b_out->pos); 1147 | } 1148 | } 1149 | 1150 | added_size = size - base_size; 1151 | actual_size += added_size; 1152 | ctx->req_body_send_len += added_size; 1153 | if (!r->chunked && ctx->req_body_len > 0) { 1154 | if (ctx->req_body_send_len > ctx->req_body_len) { 1155 | ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, 1156 | "request body length is large than content-length"); 1157 | 1158 | redundant_size = ctx->req_body_send_len - ctx->req_body_len; 1159 | 1160 | if (b_out->pos + redundant_size < b_out->last) { 1161 | 1162 | b_out->last = b_out->last-redundant_size; 1163 | ctx->req_body_send_len = ctx->req_body_send_len - 1164 | redundant_size; 1165 | actual_size = actual_size - redundant_size; 1166 | 1167 | } else { 1168 | 1169 | b_out->last = b_out->pos; 1170 | ctx->req_body_send_len = ctx->req_body_send_len - 1171 | added_size; 1172 | 1173 | actual_size = actual_size - added_size; 1174 | } 1175 | } else if (ctx->req_body_send_len == ctx->req_body_len) { 1176 | ctx->req_body_sent_over = 1; 1177 | b_out->last_buf = 1; 1178 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 1179 | 0, "req_body_send_len finally equals req_body_len"); 1180 | } 1181 | } else { 1182 | ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, 1183 | "chunked from client or has not req body len"); 1184 | } 1185 | 1186 | cl->next = ngx_alloc_chain_link(r->pool); 1187 | if (cl->next == NULL) { 1188 | return NULL; 1189 | } 1190 | 1191 | cl = cl->next; 1192 | cl->buf = b_out; 1193 | 1194 | if (size >= max_size) { 1195 | break; 1196 | } else { 1197 | in = in->next; 1198 | ctx->buf_next_read_offset = 0; 1199 | } 1200 | } 1201 | 1202 | *body = in; 1203 | cl->next = NULL; 1204 | ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 1205 | "send len:%d, body len:%d", ctx->req_body_send_len, 1206 | ctx->req_body_len); 1207 | 1208 | if (ctx->req_body_send_len == ctx->req_body_len) { 1209 | if (!ctx->req_body_sent_over) { 1210 | if (in != NULL) { 1211 | ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, 1212 | "not set req_body_sent_over before"); 1213 | } 1214 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 1215 | "hmux_data_msg_send_body over:%V", &r->uri); 1216 | 1217 | ctx->req_body_sent_over = 1; 1218 | } 1219 | if (b_out != NULL && !b_out->last_buf) { 1220 | b_out->last_buf = 1; 1221 | } 1222 | } 1223 | 1224 | hmux_data_msg_begin(msg, actual_size); 1225 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 1226 | "actual size:%d", actual_size); 1227 | 1228 | return out; 1229 | } 1230 | 1231 | 1232 | static void 1233 | ngx_http_upstream_send_request_body_handler(ngx_http_request_t *r, 1234 | ngx_http_upstream_t *u) 1235 | { 1236 | ngx_int_t rc; 1237 | 1238 | rc = ngx_http_upstream_send_request_body(r, u); 1239 | 1240 | if (rc == NGX_OK) { 1241 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 1242 | "ngx_http_upstream_send_request_body error"); 1243 | } 1244 | } 1245 | 1246 | 1247 | static void 1248 | ngx_http_upstream_dummy_handler(ngx_http_request_t *r, 1249 | ngx_http_upstream_t *u) 1250 | { 1251 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 1252 | "hmux upstream dummy handler"); 1253 | return; 1254 | } 1255 | 1256 | static ngx_int_t 1257 | ngx_hmux_restore_request_body(ngx_http_request_t *r) 1258 | { 1259 | ngx_buf_t *buf, *next; 1260 | ngx_chain_t *cl; 1261 | 1262 | if (r->request_body == NULL 1263 | || r->request_body->bufs == NULL 1264 | || r->request_body->temp_file) 1265 | { 1266 | return NGX_OK; 1267 | } 1268 | 1269 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 1270 | "restore req body"); 1271 | 1272 | cl = r->request_body->bufs; 1273 | buf = cl->buf; 1274 | buf->pos = buf->start; 1275 | 1276 | if (cl->next != NULL) { 1277 | next = cl->next->buf; 1278 | next->pos = next->start; 1279 | } 1280 | return NGX_OK; 1281 | } 1282 | 1283 | static ngx_int_t 1284 | ngx_hmux_input_filter_init(void *data) 1285 | { 1286 | ngx_http_request_t *r = data; 1287 | r->upstream->pipe->length = (off_t) NGX_HMUX_END; 1288 | 1289 | return NGX_OK; 1290 | } 1291 | 1292 | /* processing response data here */ 1293 | static ngx_int_t 1294 | ngx_hmux_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf) 1295 | { 1296 | int len, need_read_resp_data, omit_flag, need_more_data; 1297 | u_char *pos, code; 1298 | ngx_int_t rc; 1299 | ngx_str_t str; 1300 | ngx_buf_t *b, **prev, *flush_buf, *mended_buf, *work_buf; 1301 | hmux_msg_t *msg; 1302 | ngx_chain_t *cl,*tmp_cl; 1303 | ngx_hmux_ctx_t *ctx; 1304 | ngx_http_request_t *r; 1305 | 1306 | r = p->input_ctx; 1307 | ctx = ngx_http_get_module_ctx(r, ngx_hmux_module); 1308 | if (!ctx->restore_flag) { 1309 | ctx->restore_flag = 1; 1310 | ngx_hmux_restore_request_body(r); 1311 | } 1312 | 1313 | if (buf->pos == buf->last) { 1314 | ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, 1315 | "zero buffer"); 1316 | return NGX_OK; 1317 | } 1318 | 1319 | need_read_resp_data = 0; 1320 | omit_flag = 0; 1321 | b = NULL; 1322 | pos = NULL; 1323 | need_more_data = 0; 1324 | prev = &buf->shadow; 1325 | flush_buf = NULL; 1326 | msg = hmux_msg_reuse(&ctx->msg); 1327 | 1328 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 1329 | "enter input filter ,req_body_len:%d", ctx->req_body_len); 1330 | 1331 | 1332 | if (ctx->undisposed != NULL) { 1333 | ctx->mend_flag = ctx->mend_flag + 1; 1334 | /* mend preread data to buf */ 1335 | len = ctx->undisposed_size + (buf->last - buf->pos); 1336 | mended_buf = ngx_create_temp_buf(r->pool, len); 1337 | if (mended_buf == NULL) { 1338 | return NGX_ERROR; 1339 | } 1340 | ngx_memcpy(mended_buf->pos, ctx->undisposed, ctx->undisposed_size); 1341 | ngx_memcpy(mended_buf->pos + ctx->undisposed_size, 1342 | buf->pos, (buf->last - buf->pos)); 1343 | mended_buf->last = mended_buf->pos + len; 1344 | ctx->undisposed = NULL; 1345 | ctx->undisposed_size = 0; 1346 | work_buf = mended_buf; 1347 | 1348 | work_buf->num = buf->num; 1349 | work_buf->temporary = buf->temporary; 1350 | work_buf->shadow = buf->shadow; 1351 | work_buf->tag = buf->tag; 1352 | work_buf->memory = buf->memory; 1353 | work_buf->recycled = buf->recycled; 1354 | work_buf->flush = buf->flush; 1355 | work_buf->last_buf = buf->last_buf; 1356 | work_buf->last_in_chain = buf->last_in_chain; 1357 | work_buf->last_shadow = buf->last_shadow; 1358 | 1359 | } else { 1360 | work_buf = buf; 1361 | } 1362 | 1363 | msg->buf = work_buf; 1364 | 1365 | while (work_buf->pos < work_buf->last) { 1366 | 1367 | if (0 == ctx->resp_chunk_len) { 1368 | pos = work_buf->pos; 1369 | rc = hmux_read_byte(msg, &code); 1370 | if (rc != NGX_OK) { 1371 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 1372 | "overflow when receiving command in filter"); 1373 | ctx->undisposed_size = work_buf->last-pos; 1374 | ctx->undisposed = ngx_pcalloc(r->pool, ctx->undisposed_size); 1375 | memcpy(ctx->undisposed, pos, ctx->undisposed_size); 1376 | break; 1377 | } 1378 | 1379 | switch (code) { 1380 | case HMUX_DATA: 1381 | need_read_resp_data = 1; 1382 | break; 1383 | 1384 | case HMUX_FLUSH: 1385 | rc = hmux_read_len(msg, &len); 1386 | if (rc != NGX_OK) { 1387 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 1388 | "overflow when receiving flush cmd in filter"); 1389 | need_more_data = 1; 1390 | ctx->mend_flag = ctx->mend_flag + 1; 1391 | break; 1392 | } 1393 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 1394 | "accept hmux flush command in filter"); 1395 | ctx->flush_flag = 1; 1396 | omit_flag = 1; 1397 | break; 1398 | case HMUX_ACK: 1399 | rc = hmux_read_len(msg, &len); 1400 | if (rc != NGX_OK) { 1401 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 1402 | "overflow when receiving ack command"); 1403 | need_more_data = 1; 1404 | ctx->mend_flag = ctx->mend_flag + 1; 1405 | break; 1406 | } 1407 | ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, 1408 | "accept hmux ack command in filter"); 1409 | break; 1410 | case HMUX_QUIT: 1411 | case HMUX_EXIT: 1412 | p->upstream_done = 1; 1413 | ctx->state = ngx_hmux_st_response_end; 1414 | ctx->code = code; 1415 | if (ctx->mend_flag) { 1416 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 1417 | "ok for overflow recving data in filter:%d", 1418 | ctx->mend_flag); 1419 | } 1420 | return NGX_OK; 1421 | 1422 | default: 1423 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 1424 | "accept default command in filter:%d", code); 1425 | 1426 | if (code > 127) { 1427 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 1428 | "receive command more than 127 in filter"); 1429 | return NGX_ERROR; 1430 | } 1431 | rc = hmux_read_string(msg, &str); 1432 | if (rc != NGX_OK) { 1433 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 1434 | "overflow when receiving default in filter"); 1435 | need_more_data = 1; 1436 | ctx->mend_flag=ctx->mend_flag + 1; 1437 | } 1438 | break; 1439 | } 1440 | 1441 | if (need_read_resp_data) { 1442 | rc = hmux_read_len(msg, &ctx->resp_chunk_len); 1443 | if (rc != NGX_OK) { 1444 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 1445 | "overflow when receiving data length in filter"); 1446 | need_more_data = 1; 1447 | ctx->mend_flag = ctx->mend_flag + 1; 1448 | } 1449 | need_read_resp_data = 0; 1450 | } 1451 | } 1452 | 1453 | if (need_more_data) { 1454 | ctx->undisposed_size = work_buf->last-pos; 1455 | ctx->undisposed = ngx_pcalloc(r->pool, ctx->undisposed_size); 1456 | memcpy(ctx->undisposed, pos, ctx->undisposed_size); 1457 | break; 1458 | } 1459 | 1460 | if (omit_flag) { 1461 | omit_flag = 0; 1462 | if (ctx->flush_flag && flush_buf != NULL) { 1463 | flush_buf->flush = 1; 1464 | flush_buf = NULL; 1465 | ctx->flush_flag = 0; 1466 | } 1467 | continue; 1468 | } 1469 | 1470 | if (p->free) { 1471 | b = p->free->buf; 1472 | p->free = p->free->next; 1473 | } else { 1474 | b = ngx_alloc_buf(p->pool); 1475 | if (b == NULL) { 1476 | return NGX_ERROR; 1477 | } 1478 | } 1479 | 1480 | ngx_memzero(b, sizeof(ngx_buf_t)); 1481 | 1482 | b->pos = work_buf->pos; 1483 | b->start = work_buf->start; 1484 | b->end = work_buf->end; 1485 | b->tag = p->tag; 1486 | b->temporary = 1; 1487 | b->recycled = 1; 1488 | 1489 | *prev = b; 1490 | flush_buf = b; 1491 | prev = &b->shadow; 1492 | 1493 | cl = ngx_alloc_chain_link(p->pool); 1494 | if (cl == NULL) { 1495 | return NGX_ERROR; 1496 | } 1497 | 1498 | cl->buf = b; 1499 | cl->next = NULL; 1500 | 1501 | if (p->in) { 1502 | *p->last_in = cl; 1503 | } else { 1504 | if (ctx->long_post_flag) { 1505 | ctx->long_post_flag = 0; 1506 | /* add buffered response data */ 1507 | tmp_cl = ctx->resp_body; 1508 | tmp_cl->buf->tag = p->tag; 1509 | 1510 | while (tmp_cl->next != NULL) { 1511 | tmp_cl = tmp_cl->next; 1512 | tmp_cl->buf->tag = p->tag; 1513 | 1514 | } 1515 | 1516 | p->in = ctx->resp_body; 1517 | tmp_cl->next = cl; 1518 | } else { 1519 | p->in = cl; 1520 | } 1521 | } 1522 | 1523 | p->last_in = &cl->next; 1524 | /* STUB */ b->num = work_buf->num; 1525 | if (work_buf->pos + ctx->resp_chunk_len < work_buf->last) { 1526 | work_buf->pos += ctx->resp_chunk_len; 1527 | b->last = work_buf->pos; 1528 | ctx->resp_chunk_len = 0; 1529 | } else { 1530 | ctx->resp_chunk_len -= work_buf->last - work_buf->pos; 1531 | work_buf->pos = work_buf->last; 1532 | b->last = work_buf->last; 1533 | } 1534 | 1535 | } 1536 | 1537 | if (b) { 1538 | b->shadow = work_buf; 1539 | b->last_shadow = 1; 1540 | b->flush = 1; 1541 | ngx_log_debug2(NGX_LOG_DEBUG, p->log, 0, 1542 | "input buf %s %z", b->pos, b->last - b->pos); 1543 | 1544 | return NGX_OK; 1545 | } 1546 | 1547 | if (ngx_event_pipe_add_free_buf(p, buf) != NGX_OK) { 1548 | return NGX_ERROR; 1549 | } 1550 | 1551 | return NGX_OK; 1552 | } 1553 | 1554 | 1555 | static void 1556 | ngx_hmux_abort_request(ngx_http_request_t *r) 1557 | { 1558 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 1559 | "abort http hmux request"); 1560 | return; 1561 | } 1562 | 1563 | 1564 | static void 1565 | ngx_hmux_finalize_request(ngx_http_request_t *r, ngx_int_t rc) 1566 | { 1567 | 1568 | ngx_hmux_ctx_t *ctx; 1569 | ngx_http_upstream_t *u; 1570 | 1571 | u = r->upstream; 1572 | ctx = ngx_http_get_module_ctx(r, ngx_hmux_module); 1573 | 1574 | ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 1575 | "finalize req,req_body_len:%d, uri:%V", ctx->req_body_len, &r->uri); 1576 | 1577 | if (u != NULL) { 1578 | ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 1579 | "keepalive:%d, uri:%V", ctx->req_body_len, &r->uri); 1580 | 1581 | if (HMUX_QUIT == ctx->code) { 1582 | u->length = 0; 1583 | #if defined(nginx_version) && nginx_version >= 1001004 1584 | u->keepalive = 1; 1585 | #endif 1586 | } else { 1587 | #if defined(nginx_version) && nginx_version >= 1001004 1588 | u->keepalive = 0; 1589 | u->length = 0; 1590 | #endif 1591 | } 1592 | } 1593 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 1594 | "finalize http hmux request"); 1595 | 1596 | return; 1597 | } 1598 | 1599 | /*******************protocol functions begin ************************/ 1600 | 1601 | static ngx_int_t 1602 | hmux_start_channel(hmux_msg_t *msg, unsigned short channel) 1603 | { 1604 | ngx_buf_t *buf; 1605 | 1606 | buf = msg->buf; 1607 | 1608 | if ((buf->last + 1 + sizeof(unsigned short)) > buf->end) { 1609 | return hmux_log_overflow(NGX_LOG_WARN, msg, "hmux_start_channel"); 1610 | } 1611 | 1612 | *buf->last++ = (u_char) (HMUX_CHANNEL); 1613 | *buf->last++ = (u_char) ((channel >> 8) & 0xff); 1614 | *buf->last++ = (u_char) (channel & 0xff); 1615 | 1616 | return NGX_OK; 1617 | 1618 | } 1619 | 1620 | static ngx_int_t 1621 | hmux_write_string(hmux_msg_t *msg, char code, ngx_str_t *value) 1622 | { 1623 | ngx_buf_t *buf; 1624 | 1625 | buf = msg->buf; 1626 | 1627 | if ((buf->last + 1 + 2 + value->len) > buf->end) { 1628 | return hmux_log_overflow(NGX_LOG_WARN, msg, "hmux_write_string"); 1629 | } 1630 | 1631 | *buf->last++ = (u_char) (code); 1632 | *buf->last++ = (u_char) ((value->len >> 8) & 0xff); 1633 | *buf->last++ = (u_char) ((value->len) & 0xff); 1634 | ngx_memcpy(buf->last, value->data, value->len); 1635 | 1636 | buf->last += value->len; 1637 | 1638 | return NGX_OK; 1639 | } 1640 | 1641 | static ngx_int_t 1642 | hmux_read_byte(hmux_msg_t *msg, u_char *rvalue) 1643 | { 1644 | if ((msg->buf->pos + 1) > msg->buf->last) { 1645 | return hmux_log_overflow(NGX_LOG_INFO, msg, "hmux_read_byte"); 1646 | } 1647 | 1648 | *rvalue = *msg->buf->pos++; 1649 | 1650 | return NGX_OK; 1651 | } 1652 | 1653 | static ngx_int_t 1654 | hmux_read_len(hmux_msg_t *msg, int *rlen) 1655 | { 1656 | int l1, l2; 1657 | u_char tmp; 1658 | ngx_int_t rc; 1659 | 1660 | rc = hmux_read_byte(msg, &tmp) & 0xff; 1661 | if (rc != NGX_OK) { 1662 | return rc; 1663 | } 1664 | 1665 | l1 = tmp; 1666 | 1667 | rc = hmux_read_byte(msg, &tmp) & 0xff; 1668 | if (rc != NGX_OK) { 1669 | return rc; 1670 | } 1671 | l2 = tmp; 1672 | 1673 | *rlen = (l1 << 8) + l2; 1674 | 1675 | return NGX_OK; 1676 | } 1677 | 1678 | static ngx_int_t 1679 | hmux_read_string(hmux_msg_t *msg, ngx_str_t *rvalue) 1680 | { 1681 | int size; 1682 | u_char *start; 1683 | ngx_int_t rc; 1684 | ngx_buf_t *buf; 1685 | 1686 | buf = msg->buf; 1687 | 1688 | rc= hmux_read_len(msg, &size); 1689 | if (rc != NGX_OK) { 1690 | return rc; 1691 | } 1692 | 1693 | start = buf->pos; 1694 | 1695 | if (start + size > buf->last) { 1696 | return hmux_log_overflow(NGX_LOG_INFO, msg, "hmux_read_string"); 1697 | } 1698 | 1699 | buf->pos += (size_t) size; 1700 | rvalue->data = start; 1701 | rvalue->len = size; 1702 | 1703 | return NGX_OK; 1704 | } 1705 | 1706 | static hmux_msg_t * 1707 | hmux_msg_reuse(hmux_msg_t *msg) 1708 | { 1709 | memset(msg, 0, sizeof(hmux_msg_t)); 1710 | return msg; 1711 | } 1712 | 1713 | static ngx_int_t 1714 | hmux_data_msg_begin(hmux_msg_t *msg, size_t size) 1715 | { 1716 | ngx_buf_t *buf; 1717 | 1718 | buf = msg->buf; 1719 | 1720 | if ((buf->last + 1 + 2) > buf->end) { 1721 | return hmux_log_overflow(NGX_LOG_WARN, msg, "hmux_data_msg_begin"); 1722 | } 1723 | 1724 | *buf->last++ = (u_char) (HMUX_DATA); 1725 | *buf->last++ = (u_char) ((size >> 8) & 0xff); 1726 | *buf->last++ = (u_char) (size & 0xff); 1727 | 1728 | return NGX_OK; 1729 | 1730 | } 1731 | 1732 | static ngx_chain_t * 1733 | hmux_cmd_msg(ngx_hmux_ctx_t *ctx, ngx_http_request_t *r, u_char code) 1734 | { 1735 | ngx_buf_t *buf; 1736 | hmux_msg_t *msg; 1737 | ngx_chain_t *cl; 1738 | 1739 | msg = hmux_msg_reuse(&ctx->msg); 1740 | /* create buffer for yield command */ 1741 | if (NGX_OK != hmux_msg_create_buffer(r->pool, HMUX_CMD_SZ, msg)) { 1742 | return NULL; 1743 | } 1744 | 1745 | cl = ngx_alloc_chain_link(r->pool); 1746 | if (cl == NULL) { 1747 | return NULL; 1748 | } 1749 | cl->next = NULL; 1750 | cl->buf = msg->buf; 1751 | cl->buf->flush = 1; 1752 | 1753 | 1754 | buf = msg->buf; 1755 | 1756 | if ((buf->last + 1) > buf->end) { 1757 | return NULL; 1758 | } 1759 | 1760 | *buf->last++ = (u_char)(code); 1761 | 1762 | return cl; 1763 | 1764 | } 1765 | 1766 | 1767 | static ngx_int_t 1768 | hmux_msg_create_buffer(ngx_pool_t *pool, size_t size, 1769 | hmux_msg_t *msg) 1770 | { 1771 | msg->buf = ngx_create_temp_buf(pool, size); 1772 | if (msg->buf == NULL) { 1773 | return NGX_ERROR; 1774 | } 1775 | 1776 | return NGX_OK; 1777 | } 1778 | 1779 | /* this method is only valid when through hmux module */ 1780 | static ngx_int_t 1781 | check_url_valid(char *url, size_t len) 1782 | { 1783 | size_t i; 1784 | char buf[65536]; 1785 | 1786 | if (len >= sizeof(buf)) { 1787 | return NGX_HTTP_FORBIDDEN; 1788 | } 1789 | 1790 | memset(buf, '\0', sizeof(buf)); 1791 | 1792 | for (i = 0; i < len ; i++) { 1793 | buf[i] = ngx_tolower(url[i]); 1794 | } 1795 | 1796 | if (NULL != strstr(buf, "web-inf")) { 1797 | return NGX_HTTP_FORBIDDEN; 1798 | } 1799 | 1800 | if (NULL != strstr(buf, "meta-inf")) { 1801 | return NGX_HTTP_FORBIDDEN; 1802 | } 1803 | 1804 | if (NULL != strstr(buf, ".war")) { 1805 | return NGX_HTTP_FORBIDDEN; 1806 | } 1807 | 1808 | return NGX_OK; 1809 | 1810 | } 1811 | 1812 | static ngx_int_t 1813 | write_env(hmux_msg_t *msg, ngx_http_request_t *r) 1814 | { 1815 | char buf[65536]; 1816 | u_char ch; 1817 | ngx_int_t rc; 1818 | ngx_str_t *uri, *host, *remote_host, *remote_addr, 1819 | transfer_url, port_str; 1820 | unsigned int i, j; 1821 | int port; 1822 | struct sockaddr_in *addr; 1823 | 1824 | uri = &r->uri; 1825 | j = 0; 1826 | for (i = 0; (ch = uri->data[i]) && ch != '?' && (j + 3) < sizeof(buf) 1827 | && i < uri->len; i++) 1828 | { 1829 | if ('%' == ch ) { 1830 | buf[j++] = '%'; 1831 | buf[j++] = '2'; 1832 | buf[j++] = '5'; 1833 | } else { 1834 | buf[j++] = ch; 1835 | } 1836 | } 1837 | 1838 | buf[j] = 0; 1839 | 1840 | transfer_url.len = strlen(buf); 1841 | transfer_url.data = (u_char *) buf; 1842 | 1843 | /* check url validation */ 1844 | rc = check_url_valid(buf, transfer_url.len); 1845 | if (rc != NGX_OK) { 1846 | ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, 1847 | "url is not valid"); 1848 | return rc; 1849 | } 1850 | 1851 | /* writes transferred url */ 1852 | rc = hmux_write_string(msg, HMUX_URL, &transfer_url); 1853 | if (rc != NGX_OK) { 1854 | return rc; 1855 | } 1856 | 1857 | /* writes method name */ 1858 | rc = hmux_write_string(msg, HMUX_METHOD, &r->method_name); 1859 | if (rc != NGX_OK) { 1860 | return rc; 1861 | } 1862 | 1863 | /* writes protocol */ 1864 | rc = hmux_write_string(msg, CSE_PROTOCOL, &r->http_protocol); 1865 | if (rc != NGX_OK) { 1866 | return rc; 1867 | } 1868 | 1869 | /* writes args */ 1870 | if (r->args.len > 0) { 1871 | rc = hmux_write_string(msg, CSE_QUERY_STRING, &r->args); 1872 | if (rc != NGX_OK) { 1873 | return rc; 1874 | } 1875 | } 1876 | 1877 | /* writes the server name */ 1878 | host = &(r->headers_in.server); 1879 | rc = hmux_write_string(msg, HMUX_SERVER_NAME, host); 1880 | if (rc != NGX_OK) { 1881 | return rc; 1882 | } 1883 | 1884 | /* writes server port */ 1885 | addr = (struct sockaddr_in *) r->connection->local_sockaddr; 1886 | port = ntohs(addr->sin_port); 1887 | sprintf(buf, "%u", port); 1888 | port_str.len = strlen(buf); 1889 | port_str.data = (u_char *) buf; 1890 | rc = hmux_write_string(msg, CSE_SERVER_PORT, &port_str); 1891 | if (rc != NGX_OK) { 1892 | return rc; 1893 | } 1894 | 1895 | remote_host = remote_addr = &r->connection->addr_text; 1896 | 1897 | /* writes remote address */ 1898 | rc = hmux_write_string(msg, CSE_REMOTE_ADDR, remote_addr); 1899 | if (rc != NGX_OK) { 1900 | return rc; 1901 | } 1902 | 1903 | /* writes remote host */ 1904 | rc = hmux_write_string(msg, CSE_REMOTE_HOST, remote_host); 1905 | if (rc != NGX_OK) { 1906 | return rc; 1907 | } 1908 | 1909 | addr = (struct sockaddr_in *) r->connection->sockaddr; 1910 | port = ntohs(addr->sin_port); 1911 | sprintf(buf, "%u", port); 1912 | port_str.len = strlen(buf); 1913 | port_str.data = (u_char *) buf; 1914 | 1915 | /* write remote port */ 1916 | rc = hmux_write_string(msg, CSE_REMOTE_PORT, &port_str); 1917 | if (rc != NGX_OK) { 1918 | return rc; 1919 | } 1920 | 1921 | if (r->headers_in.user.len != 0) { 1922 | /* write remote user */ 1923 | rc = hmux_write_string(msg, CSE_REMOTE_USER, &r->headers_in.user); 1924 | if (rc != NGX_OK) { 1925 | return rc; 1926 | } 1927 | } 1928 | if (r->headers_in.authorization != NULL && 1929 | r->headers_in.authorization->value.len != 0) 1930 | { 1931 | /* write auth type */ 1932 | rc = hmux_write_string(msg, CSE_AUTH_TYPE, 1933 | &r->headers_in.authorization->value); 1934 | if (rc != NGX_OK) { 1935 | return rc; 1936 | } 1937 | } 1938 | 1939 | return NGX_OK; 1940 | } 1941 | 1942 | 1943 | static ngx_int_t 1944 | write_headers(hmux_msg_t *msg, ngx_http_request_t *r, 1945 | ngx_hmux_loc_conf_t *hlcf) 1946 | { 1947 | ngx_int_t rc; 1948 | unsigned int i; 1949 | ngx_list_part_t *part; 1950 | ngx_table_elt_t *header; 1951 | 1952 | part = &r->headers_in.headers.part; 1953 | header = part->elts; 1954 | 1955 | for (i = 0; i < part->nelts; i++) { 1956 | 1957 | if (0 == header[i].key.len || 0 == header[i].value.len) { 1958 | continue; 1959 | } 1960 | 1961 | if (! strncasecmp((char*)header[i].key.data, "Content-Type", 1962 | sizeof("Content-Type"))) 1963 | { 1964 | rc = hmux_write_string(msg, CSE_CONTENT_TYPE, &header[i].value); 1965 | if (rc != NGX_OK) { 1966 | return rc; 1967 | } 1968 | 1969 | } else if (! strncasecmp((char*)header[i].key.data, "Content-Length", 1970 | sizeof("Content-Length"))) 1971 | { 1972 | rc = hmux_write_string(msg, CSE_CONTENT_LENGTH, &header[i].value); 1973 | if (rc != NGX_OK) { 1974 | return rc; 1975 | } 1976 | 1977 | } else if (! strncasecmp((char*)header[i].key.data, 1978 | "Expect", sizeof("Expect"))) { 1979 | /* expect=continue-100 shouldn't be passed to backend */ 1980 | } else { 1981 | if (!strncasecmp((char*)header[i].key.data, "X-Forwarded-For", 1982 | sizeof("X-Forwarded-For"))) 1983 | { 1984 | if ((NGX_CONF_UNSET != hlcf->hmux_set_header_x_forwarded_for ) 1985 | && (hlcf->hmux_set_header_x_forwarded_for)) 1986 | { 1987 | /* dont output X-Forwarded-For here */ 1988 | continue; 1989 | } 1990 | } 1991 | 1992 | rc = hmux_write_string(msg, HMUX_HEADER, &header[i].key); 1993 | if (rc != NGX_OK) { 1994 | return rc; 1995 | } 1996 | 1997 | rc = hmux_write_string(msg, HMUX_STRING, &header[i].value); 1998 | if (rc != NGX_OK) { 1999 | return rc; 2000 | } 2001 | } 2002 | } 2003 | 2004 | return NGX_OK; 2005 | } 2006 | 2007 | static ngx_int_t 2008 | write_added_headers(hmux_msg_t *msg, ngx_http_request_t *r, 2009 | ngx_hmux_loc_conf_t *hlcf) 2010 | { 2011 | ngx_int_t rc; 2012 | #if (NGX_HTTP_SSL) 2013 | ngx_str_t ctl; 2014 | #endif 2015 | ngx_str_t key, value; 2016 | 2017 | if ( (NGX_CONF_UNSET != hlcf->hmux_set_header_x_forwarded_for ) 2018 | && (hlcf->hmux_set_header_x_forwarded_for)) 2019 | { 2020 | rc = ngx_hmux_get_x_forwarded_for_value(r, &value, 0); 2021 | if (NGX_OK != rc) { 2022 | return rc; 2023 | } 2024 | key.len = sizeof("X-Forwarded-For") - 1; 2025 | key.data = (u_char *) "X-Forwarded-For"; 2026 | rc = hmux_write_string(msg, HMUX_HEADER, &key); 2027 | if (rc != NGX_OK) { 2028 | return rc; 2029 | } 2030 | rc = hmux_write_string(msg, HMUX_STRING, &value); 2031 | if (rc != NGX_OK) { 2032 | return rc; 2033 | } 2034 | } 2035 | 2036 | #if (NGX_HTTP_SSL) 2037 | if (r->connection->ssl) { 2038 | ctl.len = sizeof("") - 1; 2039 | ctl.data = (u_char *) ""; 2040 | rc = hmux_write_string(msg, CSE_IS_SECURE, &ctl); 2041 | if (rc != NGX_OK) { 2042 | return rc; 2043 | } 2044 | key.len = sizeof("HTTPS") - 1; 2045 | key.data = (u_char *) "HTTPS"; 2046 | rc = hmux_write_string(msg, HMUX_HEADER, &key); 2047 | if (rc != NGX_OK) { 2048 | return rc; 2049 | } 2050 | value.len = sizeof("on") - 1; 2051 | value.data = (u_char *) "on"; 2052 | rc = hmux_write_string(msg, HMUX_STRING, &value); 2053 | if (rc != NGX_OK) { 2054 | return rc; 2055 | } 2056 | } 2057 | #endif 2058 | 2059 | return NGX_OK; 2060 | } 2061 | 2062 | 2063 | static ngx_int_t hmux_marshal_into_msg(hmux_msg_t *msg, 2064 | ngx_http_request_t *r, ngx_hmux_loc_conf_t *hlcf) 2065 | { 2066 | ngx_int_t rc; 2067 | 2068 | rc = hmux_start_channel(msg, 1); 2069 | if (rc != NGX_OK) { 2070 | return rc; 2071 | } 2072 | 2073 | rc = write_env(msg, r); 2074 | if (rc != NGX_OK) { 2075 | return rc; 2076 | } 2077 | 2078 | /* pass headers */ 2079 | if (hlcf->upstream.pass_request_headers) { 2080 | 2081 | rc = write_headers(msg, r, hlcf); 2082 | if (rc != NGX_OK) { 2083 | return rc; 2084 | } 2085 | 2086 | rc = write_added_headers(msg, r , hlcf); 2087 | if (rc != NGX_OK) { 2088 | return rc; 2089 | } 2090 | } 2091 | 2092 | return NGX_OK; 2093 | 2094 | } 2095 | 2096 | static ngx_int_t 2097 | ngx_atoi2(u_char *line, size_t n) 2098 | { 2099 | ngx_int_t value; 2100 | 2101 | if (n == 0) { 2102 | return NGX_ERROR; 2103 | } 2104 | 2105 | for (value = 0; n--; line++) { 2106 | if (*line < '0' || *line > '9') { 2107 | break; 2108 | } 2109 | 2110 | value = value * 10 + (*line - '0'); 2111 | } 2112 | 2113 | if (value < 0) { 2114 | return NGX_ERROR; 2115 | } else { 2116 | return value; 2117 | } 2118 | } 2119 | 2120 | /* mainly process response header here */ 2121 | static ngx_int_t hmux_unmarshal_response(hmux_msg_t *msg, 2122 | ngx_http_request_t *r, ngx_hmux_loc_conf_t *hlcf) 2123 | { 2124 | int over, len, data_len; 2125 | u_char code, *pos; 2126 | ngx_buf_t *buf,*b; 2127 | ngx_int_t rc; 2128 | ngx_str_t str, str2; 2129 | ngx_chain_t *cl,*tmp; 2130 | ngx_hmux_ctx_t *ctx; 2131 | ngx_table_elt_t *h; 2132 | ngx_http_upstream_t *u; 2133 | ngx_hmux_loc_conf_t *conf; 2134 | ngx_http_upstream_header_t *hh; 2135 | ngx_http_upstream_main_conf_t *umcf; 2136 | 2137 | code = HMUX_QUIT; 2138 | ctx = ngx_http_get_module_ctx(r, ngx_hmux_module); 2139 | conf = ngx_http_get_module_loc_conf(r, ngx_hmux_module); 2140 | umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module); 2141 | over = 0; 2142 | u = r->upstream; 2143 | 2144 | 2145 | if (ctx == NULL || conf == NULL || umcf == NULL) { 2146 | return NGX_ERROR; 2147 | } 2148 | ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, 2149 | "hmux_unmarshal_response: state(%d)", ctx->state); 2150 | buf = msg->buf = &u->buffer; 2151 | 2152 | do { 2153 | pos = buf->pos; 2154 | #if (NGX_HTTP_CACHE) 2155 | if (pos == buf->last) { 2156 | if (r->cache) { 2157 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 2158 | "header from cache is over"); 2159 | return NGX_OK; 2160 | } 2161 | } 2162 | #endif 2163 | rc = hmux_read_byte(msg, &code); 2164 | if (rc != NGX_OK) { 2165 | buf->pos = pos; 2166 | return NGX_AGAIN; 2167 | } 2168 | 2169 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 2170 | "accept command:%d in unmarshal", code); 2171 | 2172 | switch(code) { 2173 | case HMUX_CHANNEL: 2174 | 2175 | rc = hmux_read_len(msg, &len); 2176 | if (rc != NGX_OK) { 2177 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 2178 | "overflow when receiving channel command"); 2179 | buf->pos = pos; 2180 | return NGX_AGAIN; 2181 | } 2182 | break; 2183 | 2184 | case HMUX_ACK: 2185 | 2186 | rc = hmux_read_len(msg, &len); 2187 | if (rc != NGX_OK) { 2188 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 2189 | "overflow when receiving ack command"); 2190 | buf->pos = pos; 2191 | return NGX_AGAIN; 2192 | } 2193 | over = 1; 2194 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 2195 | "accept hmux ack command"); 2196 | break; 2197 | 2198 | case HMUX_STATUS: 2199 | 2200 | rc = hmux_read_string(msg, &str); 2201 | if (rc != NGX_OK) { 2202 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 2203 | "overflow when receiving status command"); 2204 | buf->pos = pos; 2205 | return NGX_AGAIN; 2206 | } 2207 | u->headers_in.status_line.data = ngx_pstrdup(r->pool, &str); 2208 | u->headers_in.status_line.len = str.len; 2209 | u->headers_in.status_n = ngx_atoi2(str.data, str.len); 2210 | if (u->state) { 2211 | u->state->status = u->headers_in.status_n; 2212 | } 2213 | break; 2214 | 2215 | case HMUX_HEADER: 2216 | 2217 | rc = hmux_read_string(msg, &str); 2218 | if (rc != NGX_OK) { 2219 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 2220 | "overflow when receiving header command 1"); 2221 | buf->pos = pos; 2222 | return NGX_AGAIN; 2223 | } 2224 | 2225 | rc = hmux_read_byte(msg, &code); 2226 | if (rc != NGX_OK) { 2227 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 2228 | "overflow when receiving header command 2"); 2229 | buf->pos = pos; 2230 | return NGX_AGAIN; 2231 | } 2232 | 2233 | rc = hmux_read_string(msg, &str2); 2234 | if (rc != NGX_OK) { 2235 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 2236 | "overflow when receiving header command 3"); 2237 | buf->pos = pos; 2238 | return NGX_AGAIN; 2239 | } 2240 | 2241 | h = ngx_list_push(&u->headers_in.headers); 2242 | if (h == NULL) { 2243 | return NGX_ERROR; 2244 | } 2245 | h->key = str; 2246 | h->value = str2; 2247 | h->lowcase_key = ngx_pnalloc(r->pool, h->key.len); 2248 | if (h->lowcase_key == NULL) { 2249 | return NGX_ERROR; 2250 | } 2251 | h->hash = ngx_hash_strlow(h->lowcase_key, h->key.data, 2252 | h->key.len); 2253 | 2254 | hh = ngx_hash_find(&umcf->headers_in_hash, h->hash, 2255 | h->lowcase_key, h->key.len); 2256 | ngx_log_error(NGX_LOG_DEBUG, r->connection->log,0, 2257 | "head key and value:\"%V: %V\"",&h->key, &h->value); 2258 | if (hh && hh->handler(r, h, hh->offset) != NGX_OK) { 2259 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 2260 | " hh->handler error: \"%V: %V\"", 2261 | &h->key, &h->value); 2262 | 2263 | return NGX_ERROR; 2264 | } 2265 | 2266 | break; 2267 | 2268 | case HMUX_META_HEADER: 2269 | 2270 | rc = hmux_read_string(msg, &str); 2271 | if (rc != NGX_OK) { 2272 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 2273 | "overflow when receiving meta header command"); 2274 | buf->pos = pos; 2275 | return NGX_AGAIN; 2276 | } 2277 | 2278 | rc = hmux_read_byte(msg, &code); 2279 | if (rc != NGX_OK) { 2280 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 2281 | "overflow when receiving meta header command"); 2282 | buf->pos = pos; 2283 | return NGX_AGAIN; 2284 | } 2285 | 2286 | rc = hmux_read_string(msg, &str); 2287 | if (rc != NGX_OK) { 2288 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 2289 | "overflow when receiving meta header command"); 2290 | buf->pos = pos; 2291 | return NGX_AGAIN; 2292 | } 2293 | 2294 | break; 2295 | 2296 | case HMUX_DATA: 2297 | 2298 | if (ctx->req_body != NULL && !ctx->req_body_sent_over) { 2299 | 2300 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 2301 | "recv resp data before having sent the post data"); 2302 | 2303 | ctx->long_post_flag = 1; 2304 | rc = hmux_read_string(msg, &str); 2305 | if (rc != NGX_OK) { 2306 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 2307 | "overflow when recving data cmd in unmarshal"); 2308 | buf->pos = pos; 2309 | return NGX_AGAIN; 2310 | } 2311 | 2312 | cl = ngx_alloc_chain_link(r->pool); 2313 | if (cl == NULL) { 2314 | return NGX_ERROR; 2315 | } 2316 | 2317 | b = ngx_calloc_buf(r->pool); 2318 | if (b == NULL) { 2319 | return NGX_ERROR; 2320 | } 2321 | 2322 | cl->buf = b; 2323 | cl->next = NULL; 2324 | 2325 | b->pos = ngx_pstrdup(r->pool, &str); 2326 | b->last = b->pos + str.len; 2327 | b->end = b->last; 2328 | b->memory = 1; 2329 | b->temporary = 1; 2330 | b->recycled = 1; 2331 | if (ctx->resp_body == NULL) { 2332 | ctx->resp_body = cl; 2333 | } else { 2334 | tmp = ctx->resp_body; 2335 | while (tmp->next != NULL) { 2336 | tmp = tmp->next; 2337 | } 2338 | tmp->next = cl; 2339 | } 2340 | data_len = u->buffer.last - u->buffer.pos; 2341 | u->buffer.pos = u->buffer.pos - str.len - 2 - 1; 2342 | ngx_memcpy(u->buffer.pos, u->buffer.pos + 3 + str.len, 2343 | data_len); 2344 | u->buffer.last = u->buffer.pos + data_len; 2345 | 2346 | } else { 2347 | if (!ctx->req_body_sent_over) { 2348 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 2349 | "remain req body not sending when recv resp"); 2350 | } 2351 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 2352 | "pure resp processing"); 2353 | ctx->head_send_flag = 0; 2354 | msg->buf->pos--; 2355 | over = 1; 2356 | ctx->state = ngx_hmux_st_response_body_data_sending; 2357 | } 2358 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 2359 | "accept hmux data command in unmarshal"); 2360 | 2361 | break; 2362 | 2363 | case HMUX_FLUSH: 2364 | 2365 | ctx->flush_flag = 1; 2366 | rc = hmux_read_len(msg, &len); 2367 | if (rc != NGX_OK) { 2368 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 2369 | "overflow when receiving flush cmd in unmarshal"); 2370 | return NGX_AGAIN; 2371 | } 2372 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 2373 | "accept hmux flush command in unmarshal"); 2374 | break; 2375 | 2376 | case CSE_KEEPALIVE: 2377 | 2378 | rc = hmux_read_len(msg, &len); 2379 | if (rc != NGX_OK) { 2380 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 2381 | "overflow when receiving keepalive command"); 2382 | return NGX_AGAIN; 2383 | } 2384 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 2385 | "accept hmux keepalive command in unmarshal"); 2386 | break; 2387 | 2388 | case CSE_SEND_HEADER: 2389 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 2390 | "accept SEND_HEADER command"); 2391 | 2392 | ctx->head_send_flag = 1; 2393 | rc = hmux_read_len(msg, &len); 2394 | if (rc != NGX_OK) { 2395 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 2396 | "overflow when receiving send header command"); 2397 | return NGX_AGAIN; 2398 | } 2399 | #if (NGX_HTTP_CACHE) 2400 | if (r->cache) { 2401 | return NGX_OK; 2402 | } 2403 | #endif 2404 | ctx->state = ngx_hmux_st_response_parse_headers_done; 2405 | break; 2406 | 2407 | case HMUX_QUIT: 2408 | case HMUX_EXIT: 2409 | ctx->code = code; 2410 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 2411 | "accept EXIT or QUIT command in unmarshal"); 2412 | over = 1; 2413 | break; 2414 | 2415 | default: 2416 | 2417 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 2418 | "accept default command in unmarshal"); 2419 | 2420 | if ( code > 127) { 2421 | return NGX_ERROR; 2422 | } 2423 | rc = hmux_read_string(msg, &str); 2424 | if (rc != NGX_OK) { 2425 | ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 2426 | "overflow when receiving default command"); 2427 | return NGX_AGAIN; 2428 | } 2429 | 2430 | ngx_log_debug2(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, 2431 | "accept hmux default command:%s %z in unmarshal", 2432 | str.data, str.len); 2433 | break; 2434 | } 2435 | 2436 | } while (!over); 2437 | 2438 | if (HMUX_ACK == code) { 2439 | if (ctx->req_body != NULL && !ctx->req_body_sent_over) { 2440 | 2441 | data_len = u->buffer.last - u->buffer.pos; 2442 | u->buffer.pos = u->buffer.pos - 3; 2443 | ngx_memcpy(u->buffer.pos, u->buffer.pos + 3, data_len); 2444 | u->buffer.last = u->buffer.pos + data_len; 2445 | rc = ngx_http_upstream_send_request_body(r, u); 2446 | if (rc != NGX_OK) { 2447 | return rc; 2448 | } 2449 | 2450 | } 2451 | return NGX_AGAIN; 2452 | } 2453 | 2454 | if (ctx->head_send_flag && code == HMUX_QUIT) { 2455 | r->header_only = 1; 2456 | /* for sending to client quickly */ 2457 | r->headers_out.content_length_n = 0; 2458 | u->headers_in.content_length_n = 0; 2459 | } 2460 | 2461 | return NGX_OK; 2462 | } 2463 | 2464 | 2465 | /*******************protocol functions end************************/ 2466 | 2467 | 2468 | static char * 2469 | ngx_hmux_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 2470 | { 2471 | 2472 | size_t add; 2473 | u_short port; 2474 | ngx_url_t u; 2475 | ngx_str_t *value, *url; 2476 | ngx_uint_t n; 2477 | ngx_hmux_loc_conf_t *hlcf = conf; 2478 | ngx_http_core_loc_conf_t *clcf; 2479 | ngx_http_script_compile_t sc; 2480 | 2481 | if (hlcf->upstream.upstream || hlcf->hmux_lengths) { 2482 | return "is duplicate"; 2483 | } 2484 | 2485 | clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 2486 | 2487 | clcf->handler = ngx_hmux_handler; 2488 | 2489 | if ('/' == clcf->name.data[clcf->name.len - 1]) { 2490 | clcf->auto_redirect = 1; 2491 | } 2492 | 2493 | value = cf->args->elts; 2494 | 2495 | url = &value[1]; 2496 | 2497 | n = ngx_http_script_variables_count(url); 2498 | 2499 | if (n) { 2500 | 2501 | ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); 2502 | 2503 | sc.cf = cf; 2504 | sc.source = url; 2505 | sc.lengths = &hlcf->hmux_lengths; 2506 | sc.values = &hlcf->hmux_values; 2507 | sc.variables = n; 2508 | sc.complete_lengths = 1; 2509 | sc.complete_values = 1; 2510 | 2511 | if (ngx_http_script_compile(&sc) != NGX_OK) { 2512 | return NGX_CONF_ERROR; 2513 | } 2514 | 2515 | return NGX_CONF_OK; 2516 | } 2517 | 2518 | add = port = 0; 2519 | if (ngx_strncasecmp(url->data, (u_char *) "hmux://", 7) == 0) { 2520 | add = 7; 2521 | port = 6800; 2522 | } 2523 | 2524 | ngx_memzero(&u, sizeof(ngx_url_t)); 2525 | 2526 | u.url.len = url->len - add; 2527 | u.url.data = url->data + add; 2528 | u.default_port = port; 2529 | u.uri_part = 1; 2530 | u.no_resolve = 1; 2531 | 2532 | hlcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0); 2533 | if (hlcf->upstream.upstream == NULL) { 2534 | return NGX_CONF_ERROR; 2535 | } 2536 | 2537 | return NGX_CONF_OK; 2538 | } 2539 | 2540 | 2541 | static char * 2542 | ngx_hmux_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 2543 | { 2544 | ngx_str_t *value; 2545 | ngx_hmux_loc_conf_t *hlcf = conf; 2546 | ngx_http_script_compile_t sc; 2547 | 2548 | if (hlcf->upstream.store != NGX_CONF_UNSET 2549 | || hlcf->upstream.store_lengths) 2550 | { 2551 | return "is duplicate"; 2552 | } 2553 | 2554 | value = cf->args->elts; 2555 | 2556 | if (ngx_strcmp(value[1].data, "off") == 0) { 2557 | hlcf->upstream.store = 0; 2558 | return NGX_CONF_OK; 2559 | } 2560 | 2561 | #if (NGX_HTTP_CACHE) 2562 | #if (nginx_version >= 1007009) 2563 | if (hlcf->upstream.cache > 0) 2564 | #else 2565 | if (hlcf->upstream.cache != NGX_CONF_UNSET_PTR 2566 | && hlcf->upstream.cache != NULL) 2567 | #endif 2568 | { 2569 | return "is incompatible with \"hmux_cache\""; 2570 | } 2571 | #endif 2572 | 2573 | if (ngx_strcmp(value[1].data, "on") == 0) { 2574 | hlcf->upstream.store = 1; 2575 | return NGX_CONF_OK; 2576 | } 2577 | 2578 | /* include the terminating '\0' into script */ 2579 | value[1].len++; 2580 | 2581 | ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); 2582 | 2583 | sc.cf = cf; 2584 | sc.source = &value[1]; 2585 | sc.lengths = &hlcf->upstream.store_lengths; 2586 | sc.values = &hlcf->upstream.store_values; 2587 | sc.variables = ngx_http_script_variables_count(&value[1]); 2588 | sc.complete_lengths = 1; 2589 | sc.complete_values = 1; 2590 | 2591 | if (ngx_http_script_compile(&sc) != NGX_OK) { 2592 | return NGX_CONF_ERROR; 2593 | } 2594 | 2595 | return NGX_CONF_OK; 2596 | } 2597 | 2598 | 2599 | static char * 2600 | ngx_hmux_lowat_check(ngx_conf_t *cf, void *post, void *data) 2601 | { 2602 | 2603 | #if !(NGX_HAVE_SO_SNDLOWAT) 2604 | ssize_t *np = data; 2605 | 2606 | ngx_conf_log_error(NGX_LOG_WARN, cf, 0, 2607 | "\"hmux_send_lowat\" is not supported, ignored"); 2608 | 2609 | *np = 0; 2610 | 2611 | #endif 2612 | 2613 | return NGX_CONF_OK; 2614 | } 2615 | 2616 | #if (NGX_HTTP_CACHE) 2617 | static char * 2618 | ngx_hmux_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 2619 | { 2620 | 2621 | ngx_str_t *value; 2622 | ngx_hmux_loc_conf_t *hlcf = conf; 2623 | #if (nginx_version >= 1007009) 2624 | ngx_http_complex_value_t cv; 2625 | ngx_http_compile_complex_value_t ccv; 2626 | #endif 2627 | 2628 | value = cf->args->elts; 2629 | #if (nginx_version >= 1007009) 2630 | if (hlcf->upstream.cache != NGX_CONF_UNSET) 2631 | #else 2632 | if (hlcf->upstream.cache != NGX_CONF_UNSET_PTR) 2633 | #endif 2634 | { 2635 | return "is duplicate"; 2636 | } 2637 | 2638 | if (ngx_strcmp(value[1].data, "off") == 0) { 2639 | #if (nginx_version >= 1007009) 2640 | hlcf->upstream.cache = 0; 2641 | #else 2642 | hlcf->upstream.cache = NULL; 2643 | #endif 2644 | return NGX_CONF_OK; 2645 | } 2646 | 2647 | if (hlcf->upstream.store > 0 || hlcf->upstream.store_lengths) { 2648 | return "is incompatible with \"hmux_store\""; 2649 | } 2650 | 2651 | #if (nginx_version >= 1007009) 2652 | hlcf->upstream.cache = 1; 2653 | ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); 2654 | ccv.cf = cf; 2655 | ccv.value = &value[1]; 2656 | ccv.complex_value = &cv; 2657 | 2658 | if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { 2659 | return NGX_CONF_ERROR; 2660 | } 2661 | 2662 | if (cv.lengths != NULL) { 2663 | hlcf->upstream.cache_value = ngx_palloc(cf->pool, 2664 | sizeof(ngx_http_complex_value_t)); 2665 | if (hlcf->upstream.cache_value == NULL) { 2666 | return NGX_CONF_ERROR; 2667 | } 2668 | *hlcf->upstream.cache_value = cv; 2669 | return NGX_CONF_OK; 2670 | } 2671 | 2672 | hlcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0, 2673 | &ngx_hmux_module); 2674 | 2675 | if (hlcf->upstream.cache_zone == NULL) { 2676 | return NGX_CONF_ERROR; 2677 | } 2678 | #else 2679 | hlcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0, 2680 | &ngx_hmux_module); 2681 | 2682 | if (hlcf->upstream.cache == NULL) { 2683 | return NGX_CONF_ERROR; 2684 | } 2685 | #endif 2686 | return NGX_CONF_OK; 2687 | } 2688 | 2689 | static char * 2690 | ngx_hmux_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 2691 | { 2692 | ngx_hmux_loc_conf_t *hlcf = conf; 2693 | ngx_str_t *value; 2694 | ngx_http_compile_complex_value_t ccv; 2695 | 2696 | value = cf->args->elts; 2697 | 2698 | if (hlcf->cache_key.value.len) { 2699 | return "is duplicate"; 2700 | } 2701 | 2702 | ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); 2703 | 2704 | ccv.cf = cf; 2705 | ccv.value = &value[1]; 2706 | ccv.complex_value = &hlcf->cache_key; 2707 | 2708 | if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { 2709 | return NGX_CONF_ERROR; 2710 | } 2711 | 2712 | return NGX_CONF_OK; 2713 | } 2714 | 2715 | #endif 2716 | 2717 | 2718 | static char * 2719 | ngx_hmux_upstream_max_fails_unsupported(ngx_conf_t *cf, 2720 | ngx_command_t *cmd, void *conf) 2721 | { 2722 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 2723 | "\"hmux_upstream_max_fails\" is not supported, " 2724 | "use the \"max_fails\" parameter of the \"server\" directive ", 2725 | "inside the \"upstream\" block"); 2726 | 2727 | return NGX_CONF_ERROR; 2728 | } 2729 | 2730 | 2731 | static char * 2732 | ngx_hmux_upstream_fail_timeout_unsupported(ngx_conf_t *cf, 2733 | ngx_command_t *cmd, void *conf) 2734 | { 2735 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 2736 | "\"hmux_upstream_fail_timeout\" is not supported, " 2737 | "use the \"fail_timeout\" parameter of the \"server\" directive ", 2738 | "inside the \"upstream\" block"); 2739 | 2740 | return NGX_CONF_ERROR; 2741 | } 2742 | 2743 | 2744 | static void * 2745 | ngx_hmux_create_loc_conf(ngx_conf_t *cf) 2746 | { 2747 | ngx_hmux_loc_conf_t *conf; 2748 | 2749 | conf = ngx_pcalloc(cf->pool, sizeof(ngx_hmux_loc_conf_t)); 2750 | if (conf == NULL) { 2751 | return NULL; 2752 | } 2753 | 2754 | /* 2755 | * set by ngx_pcalloc(): 2756 | * 2757 | * conf->upstream.bufs.num = 0; 2758 | * conf->upstream.ignore_headers = 0; 2759 | * conf->upstream.next_upstream = 0; 2760 | * conf->upstream.cache_use_stale = 0; 2761 | * conf->upstream.cache_methods = 0; 2762 | * conf->upstream.temp_path = NULL; 2763 | * conf->upstream.hide_headers_hash = { NULL, 0 }; 2764 | * conf->upstream.uri = { 0, NULL }; 2765 | * conf->upstream.location = NULL; 2766 | * conf->upstream.store_lengths = NULL; 2767 | * conf->upstream.store_values = NULL; 2768 | * 2769 | */ 2770 | 2771 | conf->hmux_header_packet_buffer_size_conf = NGX_CONF_UNSET_SIZE; 2772 | conf->max_hmux_data_packet_size_conf = NGX_CONF_UNSET_SIZE; 2773 | conf->hmux_set_header_x_forwarded_for= NGX_CONF_UNSET; 2774 | 2775 | conf->upstream.store = NGX_CONF_UNSET; 2776 | conf->upstream.store_access = NGX_CONF_UNSET_UINT; 2777 | conf->upstream.buffering = NGX_CONF_UNSET; 2778 | conf->upstream.ignore_client_abort = NGX_CONF_UNSET; 2779 | 2780 | conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC; 2781 | conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC; 2782 | conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC; 2783 | #if defined(nginx_version) && nginx_version >= 1007005 2784 | conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT; 2785 | conf->upstream.next_upstream_timeout = NGX_CONF_UNSET_MSEC; 2786 | #endif 2787 | 2788 | conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE; 2789 | conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE; 2790 | 2791 | conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE; 2792 | conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE; 2793 | conf->upstream.temp_file_write_size_conf = NGX_CONF_UNSET_SIZE; 2794 | 2795 | conf->upstream.pass_request_headers = NGX_CONF_UNSET; 2796 | conf->upstream.pass_request_body = NGX_CONF_UNSET; 2797 | 2798 | #if (NGX_HTTP_CACHE) 2799 | #if (nginx_version >= 1007009) 2800 | conf->upstream.cache = NGX_CONF_UNSET; 2801 | #else 2802 | conf->upstream.cache = NGX_CONF_UNSET_PTR; 2803 | #endif 2804 | conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT; 2805 | conf->upstream.cache_valid = NGX_CONF_UNSET_PTR; 2806 | #endif 2807 | 2808 | conf->upstream.hide_headers = NGX_CONF_UNSET_PTR; 2809 | conf->upstream.pass_headers = NGX_CONF_UNSET_PTR; 2810 | 2811 | conf->upstream.intercept_errors = NGX_CONF_UNSET; 2812 | 2813 | /* "hmux_cyclic_temp_file" is disabled */ 2814 | conf->upstream.cyclic_temp_file = 0; 2815 | 2816 | return conf; 2817 | } 2818 | 2819 | 2820 | static char * 2821 | ngx_hmux_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) 2822 | { 2823 | size_t size; 2824 | ngx_str_t *h; 2825 | ngx_hash_init_t hash; 2826 | ngx_hmux_loc_conf_t *prev, *conf; 2827 | 2828 | prev = parent; 2829 | conf = child; 2830 | 2831 | if (conf->upstream.store != 0) { 2832 | ngx_conf_merge_value(conf->upstream.store, 2833 | prev->upstream.store, 0); 2834 | 2835 | if (conf->upstream.store_lengths == NULL) { 2836 | conf->upstream.store_lengths = prev->upstream.store_lengths; 2837 | conf->upstream.store_values = prev->upstream.store_values; 2838 | } 2839 | } 2840 | 2841 | ngx_conf_merge_size_value(conf->hmux_header_packet_buffer_size_conf, 2842 | prev->hmux_header_packet_buffer_size_conf, 2843 | (size_t) HMUX_MSG_BUFFER_SZ); 2844 | 2845 | ngx_conf_merge_size_value(conf->max_hmux_data_packet_size_conf, 2846 | prev->max_hmux_data_packet_size_conf, 2847 | (size_t) HMUX_MSG_BUFFER_SZ); 2848 | 2849 | ngx_conf_merge_value(conf->hmux_set_header_x_forwarded_for, 2850 | prev->hmux_set_header_x_forwarded_for, 0); 2851 | 2852 | ngx_conf_merge_uint_value(conf->upstream.store_access, 2853 | prev->upstream.store_access, 0600); 2854 | 2855 | ngx_conf_merge_value(conf->upstream.buffering, 2856 | prev->upstream.buffering, 1); 2857 | 2858 | ngx_conf_merge_value(conf->upstream.ignore_client_abort, 2859 | prev->upstream.ignore_client_abort, 0); 2860 | 2861 | ngx_conf_merge_msec_value(conf->upstream.connect_timeout, 2862 | prev->upstream.connect_timeout, 60000); 2863 | 2864 | ngx_conf_merge_msec_value(conf->upstream.send_timeout, 2865 | prev->upstream.send_timeout, 60000); 2866 | 2867 | ngx_conf_merge_msec_value(conf->upstream.read_timeout, 2868 | prev->upstream.read_timeout, 60000); 2869 | 2870 | #if defined(nginx_version) && nginx_version >= 1007005 2871 | ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries, 2872 | prev->upstream.next_upstream_tries, 0); 2873 | ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout, 2874 | prev->upstream.next_upstream_timeout, 0); 2875 | #endif 2876 | 2877 | ngx_conf_merge_size_value(conf->upstream.send_lowat, 2878 | prev->upstream.send_lowat, 0); 2879 | 2880 | ngx_conf_merge_size_value(conf->upstream.buffer_size, 2881 | prev->upstream.buffer_size, 2882 | (size_t) ngx_pagesize); 2883 | 2884 | ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs, 2885 | 8, ngx_pagesize); 2886 | 2887 | if (conf->upstream.bufs.num < 2) { 2888 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 2889 | "there must be at least 2 \"hmux_buffers\""); 2890 | return NGX_CONF_ERROR; 2891 | } 2892 | 2893 | if (conf->hmux_header_packet_buffer_size_conf > HMUX_MAX_BUFFER_SZ) { 2894 | conf->hmux_header_packet_buffer_size_conf = HMUX_MAX_BUFFER_SZ; 2895 | } 2896 | 2897 | if (conf->max_hmux_data_packet_size_conf < HMUX_MSG_BUFFER_SZ) { 2898 | conf->max_hmux_data_packet_size_conf = HMUX_MSG_BUFFER_SZ; 2899 | } 2900 | else if (conf->max_hmux_data_packet_size_conf > HMUX_MAX_BUFFER_SZ ) { 2901 | conf->max_hmux_data_packet_size_conf = HMUX_MAX_BUFFER_SZ; 2902 | } 2903 | 2904 | size = conf->upstream.buffer_size; 2905 | if (size < conf->upstream.bufs.size) { 2906 | size = conf->upstream.bufs.size; 2907 | } 2908 | 2909 | ngx_conf_merge_size_value(conf->upstream.busy_buffers_size_conf, 2910 | prev->upstream.busy_buffers_size_conf, 2911 | NGX_CONF_UNSET_SIZE); 2912 | 2913 | if (conf->upstream.busy_buffers_size_conf == NGX_CONF_UNSET_SIZE) { 2914 | conf->upstream.busy_buffers_size = 2 * size; 2915 | } else { 2916 | conf->upstream.busy_buffers_size = 2917 | conf->upstream.busy_buffers_size_conf; 2918 | } 2919 | 2920 | if (conf->upstream.busy_buffers_size < size) { 2921 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 2922 | "\"hmux_busy_buffers_size\" must be equal or bigger than " 2923 | "maximum of the value of \"hmux_buffer_size\" and " 2924 | "one of the \"hmux_buffers\""); 2925 | 2926 | return NGX_CONF_ERROR; 2927 | } 2928 | 2929 | if (conf->upstream.busy_buffers_size 2930 | > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size) 2931 | { 2932 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 2933 | "\"hmux_busy_buffers_size\" must be less than " 2934 | "the size of all \"hmux_buffers\" minus one buffer"); 2935 | 2936 | return NGX_CONF_ERROR; 2937 | } 2938 | 2939 | ngx_conf_merge_size_value(conf->upstream.temp_file_write_size_conf, 2940 | prev->upstream.temp_file_write_size_conf, 2941 | NGX_CONF_UNSET_SIZE); 2942 | 2943 | if (conf->upstream.temp_file_write_size_conf == NGX_CONF_UNSET_SIZE) { 2944 | conf->upstream.temp_file_write_size = 2 * size; 2945 | } else { 2946 | conf->upstream.temp_file_write_size = 2947 | conf->upstream.temp_file_write_size_conf; 2948 | } 2949 | 2950 | if (conf->upstream.temp_file_write_size < size) { 2951 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 2952 | "\"hmux_temp_file_write_size\" must be equal or bigger than " 2953 | "maximum of the value of \"hmux_buffer_size\" and " 2954 | "one of the \"hmux_buffers\""); 2955 | 2956 | return NGX_CONF_ERROR; 2957 | } 2958 | 2959 | ngx_conf_merge_size_value(conf->upstream.max_temp_file_size_conf, 2960 | prev->upstream.max_temp_file_size_conf, 2961 | NGX_CONF_UNSET_SIZE); 2962 | 2963 | if (conf->upstream.max_temp_file_size_conf == NGX_CONF_UNSET_SIZE) { 2964 | conf->upstream.max_temp_file_size = 1024 * 1024 * 1024; 2965 | } else { 2966 | conf->upstream.max_temp_file_size = 2967 | conf->upstream.max_temp_file_size_conf; 2968 | } 2969 | 2970 | if (conf->upstream.max_temp_file_size != 0 2971 | && conf->upstream.max_temp_file_size < size) 2972 | { 2973 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 2974 | "\"hmux_max_temp_file_size\" must be equal to zero to disable " 2975 | "the temporary files usage or must be equal or bigger than " 2976 | "maximum of the value of \"hmux_buffer_size\" and " 2977 | "one of the \"hmux_buffers\""); 2978 | 2979 | return NGX_CONF_ERROR; 2980 | } 2981 | 2982 | ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers, 2983 | prev->upstream.ignore_headers, 2984 | NGX_CONF_BITMASK_SET); 2985 | 2986 | ngx_conf_merge_bitmask_value(conf->upstream.next_upstream, 2987 | prev->upstream.next_upstream, 2988 | (NGX_CONF_BITMASK_SET 2989 | |NGX_HTTP_UPSTREAM_FT_ERROR 2990 | |NGX_HTTP_UPSTREAM_FT_TIMEOUT)); 2991 | 2992 | if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) { 2993 | conf->upstream.next_upstream = NGX_CONF_BITMASK_SET 2994 | |NGX_HTTP_UPSTREAM_FT_OFF; 2995 | } 2996 | 2997 | if (ngx_conf_merge_path_value(cf, &conf->upstream.temp_path, 2998 | prev->upstream.temp_path, 2999 | &ngx_hmux_temp_path) 3000 | != NGX_OK) 3001 | { 3002 | return NGX_CONF_ERROR; 3003 | } 3004 | 3005 | #if (NGX_HTTP_CACHE) 3006 | #if (nginx_version >= 1007009) 3007 | if (conf->upstream.cache == NGX_CONF_UNSET) { 3008 | ngx_conf_merge_value(conf->upstream.cache, 3009 | prev->upstream.cache, 0); 3010 | conf->upstream.cache_zone = prev->upstream.cache_zone; 3011 | conf->upstream.cache_value = prev->upstream.cache_value; 3012 | } 3013 | 3014 | if (conf->upstream.cache_zone && conf->upstream.cache_zone->data == NULL) { 3015 | ngx_shm_zone_t *shm_zone; 3016 | shm_zone = conf->upstream.cache_zone; 3017 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 3018 | "\"hmux_cache\" zone \"%V\" is unknown, " 3019 | "Maybe you haven't set the hmux_cache_path", 3020 | &shm_zone->shm.name); 3021 | 3022 | return NGX_CONF_ERROR; 3023 | } 3024 | #else 3025 | ngx_conf_merge_ptr_value(conf->upstream.cache, 3026 | prev->upstream.cache, NULL); 3027 | 3028 | if (conf->upstream.cache && conf->upstream.cache->data == NULL) { 3029 | ngx_shm_zone_t *shm_zone; 3030 | 3031 | shm_zone = conf->upstream.cache; 3032 | 3033 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 3034 | "\"hmux_cache\" zone \"%V\" is unknown, " 3035 | "Maybe you haven't set the hmux_cache_path", 3036 | &shm_zone->shm.name); 3037 | 3038 | return NGX_CONF_ERROR; 3039 | } 3040 | #endif 3041 | 3042 | ngx_conf_merge_uint_value(conf->upstream.cache_min_uses, 3043 | prev->upstream.cache_min_uses, 1); 3044 | 3045 | ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale, 3046 | prev->upstream.cache_use_stale, (NGX_CONF_BITMASK_SET 3047 | |NGX_HTTP_UPSTREAM_FT_OFF)); 3048 | if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_OFF) { 3049 | conf->upstream.cache_use_stale = NGX_CONF_BITMASK_SET 3050 | |NGX_HTTP_UPSTREAM_FT_OFF; 3051 | } 3052 | 3053 | if (conf->upstream.cache_methods == 0) { 3054 | conf->upstream.cache_methods = prev->upstream.cache_methods; 3055 | } 3056 | 3057 | conf->upstream.cache_methods |= NGX_HTTP_GET|NGX_HTTP_HEAD; 3058 | 3059 | ngx_conf_merge_ptr_value(conf->upstream.cache_valid, 3060 | prev->upstream.cache_valid, NULL); 3061 | 3062 | if (conf->cache_key.value.data == NULL) { 3063 | conf->cache_key = prev->cache_key; 3064 | } 3065 | 3066 | #endif 3067 | 3068 | ngx_conf_merge_value(conf->upstream.pass_request_headers, 3069 | prev->upstream.pass_request_headers, 1); 3070 | ngx_conf_merge_value(conf->upstream.pass_request_body, 3071 | prev->upstream.pass_request_body, 1); 3072 | 3073 | ngx_conf_merge_value(conf->upstream.intercept_errors, 3074 | prev->upstream.intercept_errors, 0); 3075 | 3076 | hash.max_size = 512; 3077 | hash.bucket_size = ngx_align(64, ngx_cacheline_size); 3078 | hash.name = "hmux_hide_headers_hash"; 3079 | 3080 | #if (NGX_HTTP_CACHE) 3081 | h = conf->upstream.cache ? ngx_hmux_hide_cache_headers: 3082 | ngx_hmux_hide_headers; 3083 | #else 3084 | h = ngx_hmux_hide_headers; 3085 | #endif 3086 | 3087 | if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream, 3088 | &prev->upstream, h, &hash) 3089 | != NGX_OK) 3090 | { 3091 | return NGX_CONF_ERROR; 3092 | } 3093 | 3094 | if (conf->upstream.upstream == NULL) { 3095 | conf->upstream.upstream = prev->upstream.upstream; 3096 | } 3097 | 3098 | if (conf->hmux_lengths == NULL) { 3099 | conf->hmux_lengths = prev->hmux_lengths; 3100 | conf->hmux_values = prev->hmux_values; 3101 | } 3102 | 3103 | return NGX_CONF_OK; 3104 | } 3105 | 3106 | #if defined(nginx_version) && nginx_version >= 1004000 3107 | static ngx_int_t 3108 | ngx_hmux_get_x_forwarded_for_value(ngx_http_request_t *r, 3109 | ngx_str_t *v, uintptr_t data) 3110 | { 3111 | size_t len; 3112 | u_char *p; 3113 | ngx_uint_t i, n; 3114 | ngx_table_elt_t **h; 3115 | 3116 | n = r->headers_in.x_forwarded_for.nelts; 3117 | h = r->headers_in.x_forwarded_for.elts; 3118 | 3119 | len = 0; 3120 | 3121 | for (i = 0; i < n; i++) { 3122 | len += h[i]->value.len + sizeof(", ") - 1; 3123 | } 3124 | 3125 | if (len == 0) { 3126 | v->len = r->connection->addr_text.len; 3127 | v->data = r->connection->addr_text.data; 3128 | return NGX_OK; 3129 | } 3130 | 3131 | len += r->connection->addr_text.len; 3132 | 3133 | p = ngx_pnalloc(r->pool, len); 3134 | if (p == NULL) { 3135 | return NGX_ERROR; 3136 | } 3137 | 3138 | v->len = len; 3139 | v->data = p; 3140 | 3141 | for (i = 0; i < n; i++) { 3142 | p = ngx_copy(p, h[i]->value.data, h[i]->value.len); 3143 | *p++ = ','; *p++ = ' '; 3144 | } 3145 | 3146 | ngx_memcpy(p, r->connection->addr_text.data, r->connection->addr_text.len); 3147 | 3148 | return NGX_OK; 3149 | 3150 | } 3151 | 3152 | #else 3153 | static ngx_int_t 3154 | ngx_hmux_get_x_forwarded_for_value(ngx_http_request_t *r, 3155 | ngx_str_t *v, uintptr_t data) 3156 | { 3157 | u_char *p; 3158 | 3159 | if (r->headers_in.x_forwarded_for == NULL) { 3160 | v->len = r->connection->addr_text.len; 3161 | v->data = r->connection->addr_text.data; 3162 | return NGX_OK; 3163 | } 3164 | 3165 | v->len = r->headers_in.x_forwarded_for->value.len 3166 | + sizeof(", ") - 1 + r->connection->addr_text.len; 3167 | 3168 | p = ngx_pnalloc(r->pool, v->len); 3169 | if (p == NULL) { 3170 | return NGX_ERROR; 3171 | } 3172 | 3173 | v->data = p; 3174 | 3175 | p = ngx_copy(p, r->headers_in.x_forwarded_for->value.data, 3176 | r->headers_in.x_forwarded_for->value.len); 3177 | 3178 | *p++ = ','; *p++ = ' '; 3179 | 3180 | ngx_memcpy(p, r->connection->addr_text.data, r->connection->addr_text.len); 3181 | 3182 | return NGX_OK; 3183 | } 3184 | #endif 3185 | 3186 | static int 3187 | hmux_log_overflow(ngx_uint_t level, hmux_msg_t *msg, const char *context) 3188 | { 3189 | ngx_log_error(level, ngx_cycle->log, 0, 3190 | "%s(): BufferOverflowException pos:%p, last:%p, end:%p", 3191 | context, msg->buf->pos, msg->buf->last, msg->buf->end); 3192 | 3193 | return HMUX_EOVERFLOW; 3194 | } 3195 | 3196 | --------------------------------------------------------------------------------