12 13 14class TestProxy(TestApplicationPython): 15 prerequisites = {'modules': {'python': 'any'}} 16 17 SERVER_PORT = 7999 18 19 @staticmethod 20 def run_server(server_port): 21 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 22 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 23 24 server_address = ('', server_port) 25 sock.bind(server_address) 26 sock.listen(5) 27 28 def recvall(sock): 29 buff_size = 4096 30 data = b'' 31 while True: 32 part = sock.recv(buff_size) 33 data += part 34 if len(part) < buff_size: 35 break 36 return data 37 38 req = b"""HTTP/1.1 200 OK 39Content-Length: 10 40 41""" 42 43 while True: 44 connection, client_address = sock.accept() 45 46 data = recvall(connection).decode() 47 48 to_send = req 49 50 m = re.search(r'X-Len: (\d+)', data) 51 if m: 52 to_send += b'X' * int(m.group(1)) 53 54 connection.sendall(to_send) 55 56 connection.close() 57 58 def get_http10(self, *args, **kwargs): 59 return self.get(*args, http_10=True, **kwargs) 60 61 def post_http10(self, *args, **kwargs): 62 return self.post(*args, http_10=True, **kwargs) 63 64 def setup_method(self): 65 run_process(self.run_server, self.SERVER_PORT) 66 waitforsocket(self.SERVER_PORT) 67 68 assert 'success' in self.conf( 69 { 70 "listeners": { 71 "*:7080": {"pass": "routes"}, 72 "*:7081": {"pass": "applications/mirror"}, 73 }, 74 "routes": [{"action": {"proxy": "http://127.0.0.1:7081"}}], 75 "applications": { 76 "mirror": { 77 "type": "python", 78 "processes": {"spare": 0}, 79 "path": option.test_dir + "/python/mirror", 80 "working_directory": option.test_dir 81 + "/python/mirror", 82 "module": "wsgi", 83 }, 84 "custom_header": { 85 "type": "python", 86 "processes": {"spare": 0}, 87 "path": option.test_dir + "/python/custom_header", 88 "working_directory": option.test_dir 89 + "/python/custom_header", 90 "module": "wsgi", 91 }, 92 "delayed": { 93 "type": "python", 94 "processes": {"spare": 0}, 95 "path": option.test_dir + "/python/delayed", 96 "working_directory": option.test_dir 97 + "/python/delayed", 98 "module": "wsgi", 99 }, 100 }, 101 } 102 ), 'proxy initial configuration' 103 104 def test_proxy_http10(self): 105 for _ in range(10): 106 assert self.get_http10()['status'] == 200, 'status' 107 108 def test_proxy_chain(self): 109 assert 'success' in self.conf( 110 { 111 "listeners": { 112 "*:7080": {"pass": "routes/first"}, 113 "*:7081": {"pass": "routes/second"}, 114 "*:7082": {"pass": "routes/third"}, 115 "*:7083": {"pass": "routes/fourth"}, 116 "*:7084": {"pass": "routes/fifth"}, 117 "*:7085": {"pass": "applications/mirror"}, 118 }, 119 "routes": { 120 "first": [{"action": {"proxy": "http://127.0.0.1:7081"}}], 121 "second": [{"action": {"proxy": "http://127.0.0.1:7082"}}], 122 "third": [{"action": {"proxy": "http://127.0.0.1:7083"}}], 123 "fourth": [{"action": {"proxy": "http://127.0.0.1:7084"}}], 124 "fifth": [{"action": {"proxy": "http://127.0.0.1:7085"}}], 125 }, 126 "applications": { 127 "mirror": { 128 "type": "python", 129 "processes": {"spare": 0}, 130 "path": option.test_dir + "/python/mirror", 131 "working_directory": option.test_dir 132 + "/python/mirror", 133 "module": "wsgi", 134 } 135 }, 136 } 137 ), 'proxy chain configuration' 138 139 assert self.get_http10()['status'] == 200, 'status' 140 141 def test_proxy_body(self): 142 payload = '0123456789' 143 for _ in range(10): 144 resp = self.post_http10(body=payload) 145 146 assert resp['status'] == 200, 'status' 147 assert resp['body'] == payload, 'body' 148 149 payload = 'X' * 4096 150 for _ in range(10): 151 resp = self.post_http10(body=payload) 152 153 assert resp['status'] == 200, 'status' 154 assert resp['body'] == payload, 'body' 155 156 payload = 'X' * 4097 157 for _ in range(10): 158 resp = self.post_http10(body=payload) 159 160 assert resp['status'] == 200, 'status' 161 assert resp['body'] == payload, 'body' 162 163 payload = 'X' * 4096 * 256 164 for _ in range(10): 165 resp = self.post_http10(body=payload, read_buffer_size=4096 * 128) 166 167 assert resp['status'] == 200, 'status' 168 assert resp['body'] == payload, 'body' 169 170 payload = 'X' * 4096 * 257 171 for _ in range(10): 172 resp = self.post_http10(body=payload, read_buffer_size=4096 * 128) 173 174 assert resp['status'] == 200, 'status' 175 assert resp['body'] == payload, 'body' 176 177 self.conf({'http': {'max_body_size': 32 * 1024 * 1024}}, 'settings') 178 179 payload = '0123456789abcdef' * 32 * 64 * 1024 180 resp = self.post_http10(body=payload, read_buffer_size=1024 * 1024) 181 assert resp['status'] == 200, 'status' 182 assert resp['body'] == payload, 'body' 183 184 def test_proxy_parallel(self): 185 payload = 'X' * 4096 * 257 186 buff_size = 4096 * 258 187 188 socks = [] 189 for i in range(10): 190 _, sock = self.post_http10( 191 body=payload + str(i), 192 start=True, 193 no_recv=True, 194 read_buffer_size=buff_size, 195 ) 196 socks.append(sock) 197 198 for i in range(10): 199 resp = self.recvall(socks[i], buff_size=buff_size).decode() 200 socks[i].close() 201 202 resp = self._resp_to_dict(resp) 203 204 assert resp['status'] == 200, 'status' 205 assert resp['body'] == payload + str(i), 'body' 206 207 def test_proxy_header(self): 208 assert 'success' in self.conf( 209 {"pass": "applications/custom_header"}, 'listeners/*:7081' 210 ), 'custom_header configure' 211 212 header_value = 'blah' 213 assert ( 214 self.get_http10( 215 headers={'Host': 'localhost', 'Custom-Header': header_value} 216 )['headers']['Custom-Header'] 217 == header_value 218 ), 'custom header' 219 220 header_value = r'(),/:;<=>?@[\]{}\t !#$%&\'*+-.^_`|~' 221 assert ( 222 self.get_http10( 223 headers={'Host': 'localhost', 'Custom-Header': header_value} 224 )['headers']['Custom-Header'] 225 == header_value 226 ), 'custom header 2' 227 228 header_value = 'X' * 4096 229 assert ( 230 self.get_http10( 231 headers={'Host': 'localhost', 'Custom-Header': header_value} 232 )['headers']['Custom-Header'] 233 == header_value 234 ), 'custom header 3' 235 236 header_value = 'X' * 8191 237 assert ( 238 self.get_http10( 239 headers={'Host': 'localhost', 'Custom-Header': header_value} 240 )['headers']['Custom-Header'] 241 == header_value 242 ), 'custom header 4' 243 244 header_value = 'X' * 8192 245 assert ( 246 self.get_http10( 247 headers={'Host': 'localhost', 'Custom-Header': header_value} 248 )['status'] 249 == 431 250 ), 'custom header 5' 251 252 def test_proxy_fragmented(self): 253 _, sock = self.http( 254 b"""GET / HTT""", raw=True, start=True, no_recv=True 255 ) 256 257 time.sleep(1) 258 259 sock.sendall("P/1.0\r\nHost: localhos".encode()) 260 261 time.sleep(1) 262 263 sock.sendall("t\r\n\r\n".encode()) 264 265 assert re.search( 266 '200 OK', self.recvall(sock).decode() 267 ), 'fragmented send' 268 sock.close() 269 270 def test_proxy_fragmented_close(self): 271 _, sock = self.http( 272 b"""GET / HTT""", raw=True, start=True, no_recv=True 273 ) 274 275 time.sleep(1) 276 277 sock.sendall("P/1.0\r\nHo".encode()) 278 279 sock.close() 280 281 def test_proxy_fragmented_body(self): 282 _, sock = self.http( 283 b"""GET / HTT""", raw=True, start=True, no_recv=True 284 ) 285 286 time.sleep(1) 287 288 sock.sendall("P/1.0\r\nHost: localhost\r\n".encode()) 289 sock.sendall("Content-Length: 30000\r\n".encode()) 290 291 time.sleep(1) 292 293 sock.sendall("\r\n".encode()) 294 sock.sendall(("X" * 10000).encode()) 295 296 time.sleep(1) 297 298 sock.sendall(("X" * 10000).encode()) 299 300 time.sleep(1) 301 302 sock.sendall(("X" * 10000).encode()) 303 304 resp = self._resp_to_dict(self.recvall(sock).decode()) 305 sock.close() 306 307 assert resp['status'] == 200, 'status' 308 assert resp['body'] == "X" * 30000, 'body' 309 310 def test_proxy_fragmented_body_close(self): 311 _, sock = self.http( 312 b"""GET / HTT""", raw=True, start=True, no_recv=True 313 ) 314 315 time.sleep(1) 316 317 sock.sendall("P/1.0\r\nHost: localhost\r\n".encode()) 318 sock.sendall("Content-Length: 30000\r\n".encode()) 319 320 time.sleep(1) 321 322 sock.sendall("\r\n".encode()) 323 sock.sendall(("X" * 10000).encode()) 324 325 sock.close() 326 327 def test_proxy_nowhere(self): 328 assert 'success' in self.conf( 329 [{"action": {"proxy": "http://127.0.0.1:7082"}}], 'routes' 330 ), 'proxy path changed' 331 332 assert self.get_http10()['status'] == 502, 'status' 333 334 def test_proxy_ipv6(self): 335 assert 'success' in self.conf( 336 { 337 "*:7080": {"pass": "routes"}, 338 "[::1]:7081": {'application': 'mirror'}, 339 }, 340 'listeners', 341 ), 'add ipv6 listener configure' 342 343 assert 'success' in self.conf( 344 [{"action": {"proxy": "http://[::1]:7081"}}], 'routes' 345 ), 'proxy ipv6 configure' 346 347 assert self.get_http10()['status'] == 200, 'status' 348 349 def test_proxy_unix(self, temp_dir): 350 addr = temp_dir + '/sock' 351 352 assert 'success' in self.conf( 353 { 354 "*:7080": {"pass": "routes"}, 355 "unix:" + addr: {'application': 'mirror'}, 356 }, 357 'listeners', 358 ), 'add unix listener configure' 359 360 assert 'success' in self.conf( 361 [{"action": {"proxy": 'http://unix:' + addr}}], 'routes' 362 ), 'proxy unix configure' 363 364 assert self.get_http10()['status'] == 200, 'status' 365 366 def test_proxy_delayed(self): 367 assert 'success' in self.conf( 368 {"pass": "applications/delayed"}, 'listeners/*:7081' 369 ), 'delayed configure' 370 371 body = '0123456789' * 1000 372 resp = self.post_http10( 373 headers={ 374 'Host': 'localhost', 375 'Content-Type': 'text/html', 376 'Content-Length': str(len(body)), 377 'X-Parts': '2', 378 'X-Delay': '1', 379 }, 380 body=body, 381 ) 382 383 assert resp['status'] == 200, 'status' 384 assert resp['body'] == body, 'body' 385 386 resp = self.post_http10( 387 headers={ 388 'Host': 'localhost', 389 'Content-Type': 'text/html', 390 'Content-Length': str(len(body)), 391 'X-Parts': '2', 392 'X-Delay': '1', 393 }, 394 body=body, 395 ) 396 397 assert resp['status'] == 200, 'status' 398 assert resp['body'] == body, 'body' 399 400 def test_proxy_delayed_close(self): 401 assert 'success' in self.conf( 402 {"pass": "applications/delayed"}, 'listeners/*:7081' 403 ), 'delayed configure' 404 405 _, sock = self.post_http10( 406 headers={ 407 'Host': 'localhost', 408 'Content-Type': 'text/html', 409 'Content-Length': '10000', 410 'X-Parts': '3', 411 'X-Delay': '1', 412 }, 413 body='0123456789' * 1000, 414 start=True, 415 no_recv=True, 416 ) 417 418 assert re.search('200 OK', sock.recv(100).decode()), 'first' 419 sock.close() 420 421 _, sock = self.post_http10( 422 headers={ 423 'Host': 'localhost', 424 'Content-Type': 'text/html', 425 'Content-Length': '10000', 426 'X-Parts': '3', 427 'X-Delay': '1', 428 }, 429 body='0123456789' * 1000, 430 start=True, 431 no_recv=True, 432 ) 433 434 assert re.search('200 OK', sock.recv(100).decode()), 'second' 435 sock.close() 436 437 @pytest.mark.skip('not yet') 438 def test_proxy_content_length(self): 439 assert 'success' in self.conf( 440 [ 441 { 442 "action": { 443 "proxy": "http://127.0.0.1:" + str(self.SERVER_PORT) 444 } 445 } 446 ], 447 'routes', 448 ), 'proxy backend configure' 449 450 resp = self.get_http10() 451 assert len(resp['body']) == 0, 'body lt Content-Length 0' 452 453 resp = self.get_http10(headers={'Host': 'localhost', 'X-Len': '5'}) 454 assert len(resp['body']) == 5, 'body lt Content-Length 5' 455 456 resp = self.get_http10(headers={'Host': 'localhost', 'X-Len': '9'}) 457 assert len(resp['body']) == 9, 'body lt Content-Length 9' 458 459 resp = self.get_http10(headers={'Host': 'localhost', 'X-Len': '11'}) 460 assert len(resp['body']) == 10, 'body gt Content-Length 11' 461 462 resp = self.get_http10(headers={'Host': 'localhost', 'X-Len': '15'}) 463 assert len(resp['body']) == 10, 'body gt Content-Length 15' 464 465 def test_proxy_invalid(self): 466 def check_proxy(proxy): 467 assert 'error' in \ 468 self.conf([{"action": {"proxy": proxy}}], 'routes'), \ 469 'proxy invalid' 470 471 check_proxy('blah') 472 check_proxy('/blah') 473 check_proxy('unix:/blah') 474 check_proxy('http://blah') 475 check_proxy('http://127.0.0.1') 476 check_proxy('http://127.0.0.1:') 477 check_proxy('http://127.0.0.1:blah') 478 check_proxy('http://127.0.0.1:-1') 479 check_proxy('http://127.0.0.1:7080b') 480 check_proxy('http://[]') 481 check_proxy('http://[]:7080') 482 check_proxy('http://[:]:7080') 483 check_proxy('http://[::7080') 484 485 def test_proxy_loop(self): 486 skip_alert( 487 r'socket.*failed', 488 r'accept.*failed', 489 r'new connections are not accepted', 490 ) 491 self.conf( 492 { 493 "listeners": { 494 "*:7080": {"pass": "routes"}, 495 "*:7081": {"pass": "applications/mirror"}, 496 "*:7082": {"pass": "routes"}, 497 }, 498 "routes": [{"action": {"proxy": "http://127.0.0.1:7082"}}], 499 "applications": { 500 "mirror": { 501 "type": "python", 502 "processes": {"spare": 0}, 503 "path": option.test_dir + "/python/mirror", 504 "working_directory": option.test_dir + "/python/mirror", 505 "module": "wsgi", 506 }, 507 }, 508 } 509 ) 510 511 self.get_http10(no_recv=True) 512 self.get_http10(read_timeout=1)
| 12 13 14class TestProxy(TestApplicationPython): 15 prerequisites = {'modules': {'python': 'any'}} 16 17 SERVER_PORT = 7999 18 19 @staticmethod 20 def run_server(server_port): 21 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 22 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 23 24 server_address = ('', server_port) 25 sock.bind(server_address) 26 sock.listen(5) 27 28 def recvall(sock): 29 buff_size = 4096 30 data = b'' 31 while True: 32 part = sock.recv(buff_size) 33 data += part 34 if len(part) < buff_size: 35 break 36 return data 37 38 req = b"""HTTP/1.1 200 OK 39Content-Length: 10 40 41""" 42 43 while True: 44 connection, client_address = sock.accept() 45 46 data = recvall(connection).decode() 47 48 to_send = req 49 50 m = re.search(r'X-Len: (\d+)', data) 51 if m: 52 to_send += b'X' * int(m.group(1)) 53 54 connection.sendall(to_send) 55 56 connection.close() 57 58 def get_http10(self, *args, **kwargs): 59 return self.get(*args, http_10=True, **kwargs) 60 61 def post_http10(self, *args, **kwargs): 62 return self.post(*args, http_10=True, **kwargs) 63 64 def setup_method(self): 65 run_process(self.run_server, self.SERVER_PORT) 66 waitforsocket(self.SERVER_PORT) 67 68 assert 'success' in self.conf( 69 { 70 "listeners": { 71 "*:7080": {"pass": "routes"}, 72 "*:7081": {"pass": "applications/mirror"}, 73 }, 74 "routes": [{"action": {"proxy": "http://127.0.0.1:7081"}}], 75 "applications": { 76 "mirror": { 77 "type": "python", 78 "processes": {"spare": 0}, 79 "path": option.test_dir + "/python/mirror", 80 "working_directory": option.test_dir 81 + "/python/mirror", 82 "module": "wsgi", 83 }, 84 "custom_header": { 85 "type": "python", 86 "processes": {"spare": 0}, 87 "path": option.test_dir + "/python/custom_header", 88 "working_directory": option.test_dir 89 + "/python/custom_header", 90 "module": "wsgi", 91 }, 92 "delayed": { 93 "type": "python", 94 "processes": {"spare": 0}, 95 "path": option.test_dir + "/python/delayed", 96 "working_directory": option.test_dir 97 + "/python/delayed", 98 "module": "wsgi", 99 }, 100 }, 101 } 102 ), 'proxy initial configuration' 103 104 def test_proxy_http10(self): 105 for _ in range(10): 106 assert self.get_http10()['status'] == 200, 'status' 107 108 def test_proxy_chain(self): 109 assert 'success' in self.conf( 110 { 111 "listeners": { 112 "*:7080": {"pass": "routes/first"}, 113 "*:7081": {"pass": "routes/second"}, 114 "*:7082": {"pass": "routes/third"}, 115 "*:7083": {"pass": "routes/fourth"}, 116 "*:7084": {"pass": "routes/fifth"}, 117 "*:7085": {"pass": "applications/mirror"}, 118 }, 119 "routes": { 120 "first": [{"action": {"proxy": "http://127.0.0.1:7081"}}], 121 "second": [{"action": {"proxy": "http://127.0.0.1:7082"}}], 122 "third": [{"action": {"proxy": "http://127.0.0.1:7083"}}], 123 "fourth": [{"action": {"proxy": "http://127.0.0.1:7084"}}], 124 "fifth": [{"action": {"proxy": "http://127.0.0.1:7085"}}], 125 }, 126 "applications": { 127 "mirror": { 128 "type": "python", 129 "processes": {"spare": 0}, 130 "path": option.test_dir + "/python/mirror", 131 "working_directory": option.test_dir 132 + "/python/mirror", 133 "module": "wsgi", 134 } 135 }, 136 } 137 ), 'proxy chain configuration' 138 139 assert self.get_http10()['status'] == 200, 'status' 140 141 def test_proxy_body(self): 142 payload = '0123456789' 143 for _ in range(10): 144 resp = self.post_http10(body=payload) 145 146 assert resp['status'] == 200, 'status' 147 assert resp['body'] == payload, 'body' 148 149 payload = 'X' * 4096 150 for _ in range(10): 151 resp = self.post_http10(body=payload) 152 153 assert resp['status'] == 200, 'status' 154 assert resp['body'] == payload, 'body' 155 156 payload = 'X' * 4097 157 for _ in range(10): 158 resp = self.post_http10(body=payload) 159 160 assert resp['status'] == 200, 'status' 161 assert resp['body'] == payload, 'body' 162 163 payload = 'X' * 4096 * 256 164 for _ in range(10): 165 resp = self.post_http10(body=payload, read_buffer_size=4096 * 128) 166 167 assert resp['status'] == 200, 'status' 168 assert resp['body'] == payload, 'body' 169 170 payload = 'X' * 4096 * 257 171 for _ in range(10): 172 resp = self.post_http10(body=payload, read_buffer_size=4096 * 128) 173 174 assert resp['status'] == 200, 'status' 175 assert resp['body'] == payload, 'body' 176 177 self.conf({'http': {'max_body_size': 32 * 1024 * 1024}}, 'settings') 178 179 payload = '0123456789abcdef' * 32 * 64 * 1024 180 resp = self.post_http10(body=payload, read_buffer_size=1024 * 1024) 181 assert resp['status'] == 200, 'status' 182 assert resp['body'] == payload, 'body' 183 184 def test_proxy_parallel(self): 185 payload = 'X' * 4096 * 257 186 buff_size = 4096 * 258 187 188 socks = [] 189 for i in range(10): 190 _, sock = self.post_http10( 191 body=payload + str(i), 192 start=True, 193 no_recv=True, 194 read_buffer_size=buff_size, 195 ) 196 socks.append(sock) 197 198 for i in range(10): 199 resp = self.recvall(socks[i], buff_size=buff_size).decode() 200 socks[i].close() 201 202 resp = self._resp_to_dict(resp) 203 204 assert resp['status'] == 200, 'status' 205 assert resp['body'] == payload + str(i), 'body' 206 207 def test_proxy_header(self): 208 assert 'success' in self.conf( 209 {"pass": "applications/custom_header"}, 'listeners/*:7081' 210 ), 'custom_header configure' 211 212 header_value = 'blah' 213 assert ( 214 self.get_http10( 215 headers={'Host': 'localhost', 'Custom-Header': header_value} 216 )['headers']['Custom-Header'] 217 == header_value 218 ), 'custom header' 219 220 header_value = r'(),/:;<=>?@[\]{}\t !#$%&\'*+-.^_`|~' 221 assert ( 222 self.get_http10( 223 headers={'Host': 'localhost', 'Custom-Header': header_value} 224 )['headers']['Custom-Header'] 225 == header_value 226 ), 'custom header 2' 227 228 header_value = 'X' * 4096 229 assert ( 230 self.get_http10( 231 headers={'Host': 'localhost', 'Custom-Header': header_value} 232 )['headers']['Custom-Header'] 233 == header_value 234 ), 'custom header 3' 235 236 header_value = 'X' * 8191 237 assert ( 238 self.get_http10( 239 headers={'Host': 'localhost', 'Custom-Header': header_value} 240 )['headers']['Custom-Header'] 241 == header_value 242 ), 'custom header 4' 243 244 header_value = 'X' * 8192 245 assert ( 246 self.get_http10( 247 headers={'Host': 'localhost', 'Custom-Header': header_value} 248 )['status'] 249 == 431 250 ), 'custom header 5' 251 252 def test_proxy_fragmented(self): 253 _, sock = self.http( 254 b"""GET / HTT""", raw=True, start=True, no_recv=True 255 ) 256 257 time.sleep(1) 258 259 sock.sendall("P/1.0\r\nHost: localhos".encode()) 260 261 time.sleep(1) 262 263 sock.sendall("t\r\n\r\n".encode()) 264 265 assert re.search( 266 '200 OK', self.recvall(sock).decode() 267 ), 'fragmented send' 268 sock.close() 269 270 def test_proxy_fragmented_close(self): 271 _, sock = self.http( 272 b"""GET / HTT""", raw=True, start=True, no_recv=True 273 ) 274 275 time.sleep(1) 276 277 sock.sendall("P/1.0\r\nHo".encode()) 278 279 sock.close() 280 281 def test_proxy_fragmented_body(self): 282 _, sock = self.http( 283 b"""GET / HTT""", raw=True, start=True, no_recv=True 284 ) 285 286 time.sleep(1) 287 288 sock.sendall("P/1.0\r\nHost: localhost\r\n".encode()) 289 sock.sendall("Content-Length: 30000\r\n".encode()) 290 291 time.sleep(1) 292 293 sock.sendall("\r\n".encode()) 294 sock.sendall(("X" * 10000).encode()) 295 296 time.sleep(1) 297 298 sock.sendall(("X" * 10000).encode()) 299 300 time.sleep(1) 301 302 sock.sendall(("X" * 10000).encode()) 303 304 resp = self._resp_to_dict(self.recvall(sock).decode()) 305 sock.close() 306 307 assert resp['status'] == 200, 'status' 308 assert resp['body'] == "X" * 30000, 'body' 309 310 def test_proxy_fragmented_body_close(self): 311 _, sock = self.http( 312 b"""GET / HTT""", raw=True, start=True, no_recv=True 313 ) 314 315 time.sleep(1) 316 317 sock.sendall("P/1.0\r\nHost: localhost\r\n".encode()) 318 sock.sendall("Content-Length: 30000\r\n".encode()) 319 320 time.sleep(1) 321 322 sock.sendall("\r\n".encode()) 323 sock.sendall(("X" * 10000).encode()) 324 325 sock.close() 326 327 def test_proxy_nowhere(self): 328 assert 'success' in self.conf( 329 [{"action": {"proxy": "http://127.0.0.1:7082"}}], 'routes' 330 ), 'proxy path changed' 331 332 assert self.get_http10()['status'] == 502, 'status' 333 334 def test_proxy_ipv6(self): 335 assert 'success' in self.conf( 336 { 337 "*:7080": {"pass": "routes"}, 338 "[::1]:7081": {'application': 'mirror'}, 339 }, 340 'listeners', 341 ), 'add ipv6 listener configure' 342 343 assert 'success' in self.conf( 344 [{"action": {"proxy": "http://[::1]:7081"}}], 'routes' 345 ), 'proxy ipv6 configure' 346 347 assert self.get_http10()['status'] == 200, 'status' 348 349 def test_proxy_unix(self, temp_dir): 350 addr = temp_dir + '/sock' 351 352 assert 'success' in self.conf( 353 { 354 "*:7080": {"pass": "routes"}, 355 "unix:" + addr: {'application': 'mirror'}, 356 }, 357 'listeners', 358 ), 'add unix listener configure' 359 360 assert 'success' in self.conf( 361 [{"action": {"proxy": 'http://unix:' + addr}}], 'routes' 362 ), 'proxy unix configure' 363 364 assert self.get_http10()['status'] == 200, 'status' 365 366 def test_proxy_delayed(self): 367 assert 'success' in self.conf( 368 {"pass": "applications/delayed"}, 'listeners/*:7081' 369 ), 'delayed configure' 370 371 body = '0123456789' * 1000 372 resp = self.post_http10( 373 headers={ 374 'Host': 'localhost', 375 'Content-Type': 'text/html', 376 'Content-Length': str(len(body)), 377 'X-Parts': '2', 378 'X-Delay': '1', 379 }, 380 body=body, 381 ) 382 383 assert resp['status'] == 200, 'status' 384 assert resp['body'] == body, 'body' 385 386 resp = self.post_http10( 387 headers={ 388 'Host': 'localhost', 389 'Content-Type': 'text/html', 390 'Content-Length': str(len(body)), 391 'X-Parts': '2', 392 'X-Delay': '1', 393 }, 394 body=body, 395 ) 396 397 assert resp['status'] == 200, 'status' 398 assert resp['body'] == body, 'body' 399 400 def test_proxy_delayed_close(self): 401 assert 'success' in self.conf( 402 {"pass": "applications/delayed"}, 'listeners/*:7081' 403 ), 'delayed configure' 404 405 _, sock = self.post_http10( 406 headers={ 407 'Host': 'localhost', 408 'Content-Type': 'text/html', 409 'Content-Length': '10000', 410 'X-Parts': '3', 411 'X-Delay': '1', 412 }, 413 body='0123456789' * 1000, 414 start=True, 415 no_recv=True, 416 ) 417 418 assert re.search('200 OK', sock.recv(100).decode()), 'first' 419 sock.close() 420 421 _, sock = self.post_http10( 422 headers={ 423 'Host': 'localhost', 424 'Content-Type': 'text/html', 425 'Content-Length': '10000', 426 'X-Parts': '3', 427 'X-Delay': '1', 428 }, 429 body='0123456789' * 1000, 430 start=True, 431 no_recv=True, 432 ) 433 434 assert re.search('200 OK', sock.recv(100).decode()), 'second' 435 sock.close() 436 437 @pytest.mark.skip('not yet') 438 def test_proxy_content_length(self): 439 assert 'success' in self.conf( 440 [ 441 { 442 "action": { 443 "proxy": "http://127.0.0.1:" + str(self.SERVER_PORT) 444 } 445 } 446 ], 447 'routes', 448 ), 'proxy backend configure' 449 450 resp = self.get_http10() 451 assert len(resp['body']) == 0, 'body lt Content-Length 0' 452 453 resp = self.get_http10(headers={'Host': 'localhost', 'X-Len': '5'}) 454 assert len(resp['body']) == 5, 'body lt Content-Length 5' 455 456 resp = self.get_http10(headers={'Host': 'localhost', 'X-Len': '9'}) 457 assert len(resp['body']) == 9, 'body lt Content-Length 9' 458 459 resp = self.get_http10(headers={'Host': 'localhost', 'X-Len': '11'}) 460 assert len(resp['body']) == 10, 'body gt Content-Length 11' 461 462 resp = self.get_http10(headers={'Host': 'localhost', 'X-Len': '15'}) 463 assert len(resp['body']) == 10, 'body gt Content-Length 15' 464 465 def test_proxy_invalid(self): 466 def check_proxy(proxy): 467 assert 'error' in \ 468 self.conf([{"action": {"proxy": proxy}}], 'routes'), \ 469 'proxy invalid' 470 471 check_proxy('blah') 472 check_proxy('/blah') 473 check_proxy('unix:/blah') 474 check_proxy('http://blah') 475 check_proxy('http://127.0.0.1') 476 check_proxy('http://127.0.0.1:') 477 check_proxy('http://127.0.0.1:blah') 478 check_proxy('http://127.0.0.1:-1') 479 check_proxy('http://127.0.0.1:7080b') 480 check_proxy('http://[]') 481 check_proxy('http://[]:7080') 482 check_proxy('http://[:]:7080') 483 check_proxy('http://[::7080') 484 485 def test_proxy_loop(self): 486 skip_alert( 487 r'socket.*failed', 488 r'accept.*failed', 489 r'new connections are not accepted', 490 ) 491 self.conf( 492 { 493 "listeners": { 494 "*:7080": {"pass": "routes"}, 495 "*:7081": {"pass": "applications/mirror"}, 496 "*:7082": {"pass": "routes"}, 497 }, 498 "routes": [{"action": {"proxy": "http://127.0.0.1:7082"}}], 499 "applications": { 500 "mirror": { 501 "type": "python", 502 "processes": {"spare": 0}, 503 "path": option.test_dir + "/python/mirror", 504 "working_directory": option.test_dir + "/python/mirror", 505 "module": "wsgi", 506 }, 507 }, 508 } 509 ) 510 511 self.get_http10(no_recv=True) 512 self.get_http10(read_timeout=1)
|