2011-06-10 22:20:21 +00:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
from base import *
|
|
|
|
from requests import *
|
2019-08-24 23:22:16 +00:00
|
|
|
import socketserver
|
|
|
|
import threading
|
|
|
|
|
|
|
|
class HttpBackendHandler(socketserver.StreamRequestHandler):
|
|
|
|
def handle(self):
|
|
|
|
keepalive = True
|
|
|
|
while True:
|
|
|
|
reqline = self.rfile.readline().decode('utf-8').rstrip()
|
|
|
|
# eprint("Request line: " + repr(reqline))
|
|
|
|
reqline = reqline.split(' ', 3)
|
|
|
|
if len(reqline) != 3 or reqline[0].upper() != 'GET':
|
|
|
|
self.wfile.write(b"HTTP/1.0 400 Bad request\r\n\r\n")
|
|
|
|
return
|
|
|
|
keepalive_default = True
|
|
|
|
if reqline[2].upper() != "HTTP/1.1":
|
|
|
|
keepalive = False
|
|
|
|
keepalive_default = False
|
2019-08-24 23:52:57 +00:00
|
|
|
if reqline[1].startswith("/keepalive"):
|
|
|
|
# simulate broken backend (HTTP/1.0 incompatible)
|
|
|
|
keepalive = True
|
|
|
|
keepalive_default = True
|
2019-08-24 23:22:16 +00:00
|
|
|
# read headers; and GET has no body
|
|
|
|
while True:
|
|
|
|
hdr = self.rfile.readline().decode('utf-8').rstrip()
|
|
|
|
if hdr == "": break
|
|
|
|
hdr = hdr.split(':', 2)
|
|
|
|
if hdr[0].lower() == "connection":
|
|
|
|
keepalive = (hdr[1].strip().lower() == "keep-alive")
|
2019-08-25 11:07:49 +00:00
|
|
|
if reqline[1].startswith("/upgrade/custom"):
|
|
|
|
self.wfile.write(b"HTTP/1.1 101 Switching Protocols\r\nConnection: Upgrade\r\nUpgrade: custom\r\n\r\nHello World!")
|
|
|
|
return
|
2019-08-25 22:28:48 +00:00
|
|
|
if reqline[1].startswith("/chunked/delay"):
|
|
|
|
import time
|
|
|
|
self.wfile.write(b"HTTP/1.1 200 Ok\r\nTransfer-Encoding: chunked\r\n\r\n4\r\nHi")
|
|
|
|
time.sleep(0.1)
|
|
|
|
self.wfile.write(b"!\n")
|
|
|
|
time.sleep(0.1)
|
|
|
|
self.wfile.write(b"\r\n0\r\n\r\n")
|
|
|
|
continue
|
2021-07-18 09:59:15 +00:00
|
|
|
if reqline[1].startswith("/nolength"):
|
|
|
|
self.wfile.write(b"HTTP/1.1 200 OK\r\n\r\nHello world")
|
|
|
|
self.finish()
|
|
|
|
return
|
2019-08-25 22:28:48 +00:00
|
|
|
|
2019-08-24 23:22:16 +00:00
|
|
|
# send response
|
|
|
|
resp_body = reqline[1].encode('utf-8')
|
|
|
|
clen = "Content-Length: {}\r\n".format(len(resp_body)).encode('utf-8')
|
|
|
|
ka = b""
|
|
|
|
if keepalive != keepalive_default:
|
|
|
|
if keepalive:
|
|
|
|
ka = b"Connection: keep-alive\r\n"
|
|
|
|
else:
|
|
|
|
ka = b"Connection: close\r\n"
|
|
|
|
resp = b"HTTP/1.1 200 OK\r\n" + ka + clen + b"\r\n" + resp_body
|
|
|
|
# eprint("Backend response: " + repr(resp_body))
|
|
|
|
self.wfile.write(resp)
|
|
|
|
if not keepalive:
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
class HttpBackend(socketserver.ThreadingMixIn, socketserver.TCPServer):
|
|
|
|
allow_reuse_address = True
|
|
|
|
def __init__(self):
|
|
|
|
self.port = Env.port + 3
|
|
|
|
super().__init__(('127.0.0.2', self.port), HttpBackendHandler)
|
|
|
|
|
|
|
|
self.listen_thread = threading.Thread(target = self.serve_forever, name = "HttpBackend-{}".format(self.port))
|
|
|
|
self.listen_thread.daemon = True
|
|
|
|
self.listen_thread.start()
|
2011-06-10 22:20:21 +00:00
|
|
|
|
|
|
|
class TestSimple(CurlRequest):
|
|
|
|
URL = "/test.txt"
|
|
|
|
EXPECT_RESPONSE_CODE = 200
|
2019-08-24 23:22:16 +00:00
|
|
|
EXPECT_RESPONSE_BODY = TEST_TXT
|
|
|
|
EXPECT_RESPONSE_HEADERS = [("Content-Type", "text/plain; charset=utf-8")]
|
2014-06-06 09:57:41 +00:00
|
|
|
config = """
|
|
|
|
req_header.overwrite "Host" => "basic-gets";
|
|
|
|
self_proxy;
|
|
|
|
"""
|
|
|
|
no_docroot = True
|
2011-06-10 22:20:21 +00:00
|
|
|
|
2019-08-24 23:22:16 +00:00
|
|
|
# backend gets encoded %2F
|
2014-06-06 10:08:16 +00:00
|
|
|
class TestProxiedRewrittenEncodedURL(CurlRequest):
|
2014-06-06 11:41:30 +00:00
|
|
|
URL = "/foo%2Ffile?abc"
|
|
|
|
EXPECT_RESPONSE_BODY = "/dest%2Ffile?abc"
|
2014-06-06 10:08:16 +00:00
|
|
|
EXPECT_RESPONSE_CODE = 200
|
|
|
|
no_docroot = True
|
|
|
|
config = """
|
2019-08-24 23:22:16 +00:00
|
|
|
rewrite_raw "/foo(.*)" => "/dest$1";
|
|
|
|
backend_proxy;
|
2014-06-06 10:08:16 +00:00
|
|
|
"""
|
|
|
|
|
2019-08-24 23:22:16 +00:00
|
|
|
# backend gets decoded %2F
|
2014-06-06 10:08:16 +00:00
|
|
|
class TestProxiedRewrittenDecodedURL(CurlRequest):
|
2014-06-06 11:41:30 +00:00
|
|
|
URL = "/foo%2Ffile?abc"
|
2019-08-24 23:22:16 +00:00
|
|
|
EXPECT_RESPONSE_BODY = "/dest/file?abc"
|
2014-06-06 10:08:16 +00:00
|
|
|
EXPECT_RESPONSE_CODE = 200
|
|
|
|
no_docroot = True
|
|
|
|
config = """
|
2019-08-24 23:22:16 +00:00
|
|
|
rewrite "/foo(.*)" => "/dest$1";
|
|
|
|
backend_proxy;
|
2014-06-06 10:08:16 +00:00
|
|
|
"""
|
|
|
|
|
2019-08-25 11:07:49 +00:00
|
|
|
# fake a backend forcing keep-alive mode
|
2019-08-24 23:52:57 +00:00
|
|
|
class TestBackendForcedKeepalive(CurlRequest):
|
|
|
|
URL = "/keepalive"
|
|
|
|
EXPECT_RESPONSE_BODY = "/keepalive"
|
|
|
|
EXPECT_RESPONSE_CODE = 200
|
|
|
|
no_docroot = True
|
|
|
|
config = """
|
|
|
|
backend_proxy;
|
|
|
|
"""
|
|
|
|
|
2019-08-25 11:07:49 +00:00
|
|
|
# have backend "Upgrade"
|
|
|
|
class TestBackendUpgrade(CurlRequest):
|
|
|
|
URL = "/upgrade/custom"
|
|
|
|
EXPECT_RESPONSE_BODY = "Hello World!"
|
|
|
|
EXPECT_RESPONSE_CODE = 101
|
|
|
|
no_docroot = True
|
|
|
|
config = """
|
|
|
|
backend_proxy;
|
|
|
|
"""
|
|
|
|
|
2019-08-25 22:28:48 +00:00
|
|
|
class TestBackendDelayedChunk(CurlRequest):
|
|
|
|
URL = "/chunked/delay"
|
|
|
|
EXPECT_RESPONSE_BODY = "Hi!\n"
|
|
|
|
EXPECT_RESPONSE_CODE = 200
|
|
|
|
no_docroot = True
|
|
|
|
config = """
|
|
|
|
backend_proxy;
|
|
|
|
"""
|
|
|
|
|
2021-07-18 09:59:15 +00:00
|
|
|
class TestBackendNoLength(CurlRequest):
|
|
|
|
URL = "/nolength"
|
|
|
|
EXPECT_RESPONSE_BODY = "Hello world"
|
|
|
|
EXPECT_RESPONSE_CODE = 200
|
|
|
|
no_docroot = True
|
|
|
|
config = """
|
|
|
|
backend_proxy;
|
|
|
|
"""
|
|
|
|
|
2011-06-10 22:20:21 +00:00
|
|
|
class Test(GroupTest):
|
|
|
|
group = [
|
|
|
|
TestSimple,
|
2014-06-06 10:08:16 +00:00
|
|
|
TestProxiedRewrittenEncodedURL,
|
|
|
|
TestProxiedRewrittenDecodedURL,
|
2019-08-24 23:52:57 +00:00
|
|
|
TestBackendForcedKeepalive,
|
2019-08-25 11:07:49 +00:00
|
|
|
TestBackendUpgrade,
|
2019-08-25 22:28:48 +00:00
|
|
|
TestBackendDelayedChunk,
|
2021-07-18 09:59:15 +00:00
|
|
|
TestBackendNoLength,
|
2011-06-10 22:20:21 +00:00
|
|
|
]
|
2014-06-06 09:57:41 +00:00
|
|
|
|
2011-06-10 22:20:21 +00:00
|
|
|
def Prepare(self):
|
2019-08-24 23:22:16 +00:00
|
|
|
self.http_backend = HttpBackend()
|
2011-06-10 22:20:21 +00:00
|
|
|
self.plain_config = """
|
|
|
|
setup {{ module_load "mod_proxy"; }}
|
|
|
|
|
2014-06-06 09:57:41 +00:00
|
|
|
self_proxy = {{
|
|
|
|
proxy "127.0.0.2:{self_port}";
|
2011-08-28 09:57:31 +00:00
|
|
|
}};
|
2019-08-24 23:22:16 +00:00
|
|
|
backend_proxy = {{
|
|
|
|
proxy "127.0.0.2:{backend_port}";
|
|
|
|
}};
|
|
|
|
""".format(
|
|
|
|
self_port = Env.port,
|
|
|
|
backend_port = self.http_backend.port,
|
|
|
|
)
|
|
|
|
|
|
|
|
def Cleanup(self):
|
|
|
|
self.http_backend.shutdown()
|