def test_custom_callbacks(self): """ Test the handlers in a real proxy request. """ conf = proxy.Conf() conf.host = "jsonplaceholder.typicode.com" conf.scheme = "https" conf.port = 443 req = proxy.Req() req.method = "GET" on_save_addition = "added by the on_save callback\n" on_done_addition = "added by the on_done callback\n" def on_save(self, fh, res): res.headers["Content-Type"] = "text/plain" res.body = on_save_addition def on_done(self): self.res.headers["Content-Type"] = "text/plain" self.res.body += on_done_addition p = proxy.Proxy(self.conf_path, req) # Patching for tests p.conf = conf p.on_done = types.MethodType(on_done, p) p.on_save = types.MethodType(on_save, p) p.proxy() self.assertEqual(p.res.body, "{}{}".format(on_save_addition, on_done_addition))
def test_json_response(self): test_input_json = """{ "method": "GET", "path_query": "/posts?userId=1" }""" req = proxy.Req() req.method = 'GET' req.path_query = '' req.headers = {'Accept': 'application/json'} # Use custom callbacks def on_save(res, fh, conf): pass def on_done(res): res = res.__dict__ self.assertEqual(res['status'], 200) self.p = proxy.Proxy(self.conf, req, on_save) self.p.on_done = on_done self.p.proxy() saved_stdout = sys.stdout try: out = StringIO() sys.stdout = out main.__main__(test_input_json, self.p) output = out.getvalue().strip() finally: sys.stdout = saved_stdout response = json.loads(output) for item in json.loads(response['body']): self.assertEqual(item['userId'], 1)
def __main__(incoming, p): # deserialize incoming request client_req = None try: client_req = json.loads(incoming) except json.decoder.JSONDecodeError: p.simple_error(400, 'Invalid JSON in request') p.on_done(p.res) # build request oject req = proxy.Req() try: req.method = client_req['method'] req.path_query = client_req['path_query'] except KeyError: p.simple_error(400, 'Missing keys in request') p.on_done(p.res) if "headers" in client_req: req.headers = client_req['headers'] if "body" in client_req: req.body = client_req['body'] # complete proxy object p.req = req p.on_save = callbacks.on_save p.on_done = callbacks.on_done p.proxy()
def test_version(self): req = proxy.Req() req.method = "GET" req.path_query = "" req.headers = {"Accept": "application/json"} p = proxy.Proxy(self.conf_path) p.proxy() self.assertEqual(p.res.version, version.version)
def test_version(self): req = proxy.Req() req.method = 'GET' req.path_query = '' req.headers = {'Accept': 'application/json'} p = proxy.Proxy() p.proxy() self.assertEqual(p.res.version, version.version)
def test_400_if_callback_not_set(self): req = proxy.Req() req.method = 'GET' req.path_query = '' req.headers = {'Accept': 'application/json'} p = proxy.Proxy() p.proxy() self.assertEqual(p.res.status, 400)
def test_proxy_400_no_handler(self): req = proxy.Req() req.method = 'GET' req.path_query = 'http://badpath.lol/path' req.headers = {'Accept': 'application/json'} p = proxy.Proxy(self.conf, req) p.proxy() self.assertEqual(p.res.status, 400) self.assertEqual(p.res.headers['Content-Type'], 'application/json') self.assertIn('Request callback is not set', p.res.body)
def test_proxy_basic_functionality(self): req = proxy.Req() req.method = 'GET' req.path_query = '' req.headers = {'Accept': 'application/json'} p = proxy.Proxy(self.conf, req, self.on_save) p.proxy() self.assertEqual(p.res.status, 200) self.assertEqual(p.res.body, json.dumps({'filename': self.fn})) self.assertEqual(p.res.headers['Content-Type'], 'application/json')
def test_proxy_produces_404(self): req = proxy.Req() req.method = "GET" req.path_query = "/notfound" req.headers = {"Accept": "application/json"} p = proxy.Proxy(self.conf_path, req) p.proxy() self.assertEqual(p.res.status, 404) self.assertEqual(p.res.headers["Content-Type"], "application/json")
def test_proxy_500_misconfiguration(self): req = proxy.Req() req.method = "GET" req.path_query = "/posts/1" req.headers = {"Accept": "application/json"} p = proxy.Proxy(self.conf_path, req) p.proxy() self.assertEqual(p.res.status, 500) self.assertEqual(p.res.headers["Content-Type"], "application/json") self.assertIn("Proxy error while generating URL to request", p.res.body)
def test_default_callbacks(self): test_input = { "method": "GET", "path_query": "", } p = proxy.Proxy(self.conf_path, proxy.Req()) p.on_done = unittest.mock.MagicMock() p.on_save = unittest.mock.MagicMock() main.__main__(json.dumps(test_input), p) self.assertEqual(p.on_save.call_count, 1) self.assertEqual(p.on_done.call_count, 1)
def test_input_headers(self): test_input = { "method": "GET", "path_query": "/posts?userId=1", "headers": {"X-Test-Header": "th"}, } def on_save(self, fh, res): pass p = proxy.Proxy(self.conf_path, proxy.Req()) main.__main__(json.dumps(test_input), p) self.assertEqual(p.req.headers, test_input["headers"])
def test_proxy_400_bad_path(self): req = proxy.Req() req.method = "GET" req.path_query = "http://badpath.lol/path" req.headers = {"Accept": "application/json"} p = proxy.Proxy(self.conf_path, req) p.proxy() self.assertEqual(p.res.status, 400) self.assertEqual(p.res.headers["Content-Type"], "application/json") self.assertIn("Path provided in request did not look valid", p.res.body)
def test_proxy_produces_404(self): req = proxy.Req() req.method = 'GET' req.path_query = '/notfound' req.headers = {'Accept': 'application/json'} p = proxy.Proxy(self.conf, req) p.on_save = self.on_save p.on_done = self.on_done p.proxy() self.assertEqual(p.res.status, 404) self.assertEqual(p.res.headers['Content-Type'], 'application/json')
def test_proxy_200_valid_path(self): req = proxy.Req() req.method = 'GET' req.path_query = '/posts/1' req.headers = {'Accept': 'application/json'} p = proxy.Proxy(self.conf, req, self.on_save) p.proxy() self.assertEqual(p.res.status, 200) self.assertIn('application/json', p.res.headers['Content-Type']) body = json.loads(p.res.body) self.assertEqual(body['userId'], 1)
def test_proxy_500_misconfiguration(self): req = proxy.Req() req.method = 'GET' req.path_query = '/posts/1' req.headers = {'Accept': 'application/json'} p = proxy.Proxy(self.conf, req, self.on_save) p.proxy() self.assertEqual(p.res.status, 500) self.assertEqual(p.res.headers['Content-Type'], 'application/json') self.assertIn('Proxy error while generating URL to request', p.res.body)
def test_proxy_200_valid_path(self): req = proxy.Req() req.method = "GET" req.path_query = "/posts/1" req.headers = {"Accept": "application/json"} p = proxy.Proxy(self.conf_path, req) p.proxy() self.assertEqual(p.res.status, 200) self.assertIn("application/json", p.res.headers["Content-Type"]) body = json.loads(p.res.body) self.assertEqual(body["userId"], 1)
def test_proxy_handles_query_params_gracefully(self): req = proxy.Req() req.method = 'GET' req.path_query = '/posts?userId=1' req.headers = {'Accept': 'application/json'} p = proxy.Proxy(self.conf, req, self.on_save) p.proxy() self.assertEqual(p.res.status, 200) self.assertIn('application/json', p.res.headers['Content-Type']) body = json.loads(p.res.body) for item in body: self.assertEqual(item['userId'], 1)
def test_proxy_handles_query_params_gracefully(self): req = proxy.Req() req.method = "GET" req.path_query = "/posts?userId=1" req.headers = {"Accept": "application/json"} p = proxy.Proxy(self.conf_path, req) p.proxy() self.assertEqual(p.res.status, 200) self.assertIn("application/json", p.res.headers["Content-Type"]) body = json.loads(p.res.body) for item in body: self.assertEqual(item["userId"], 1)
def test_proxy_400_bad_path(self): req = proxy.Req() req.method = 'GET' req.path_query = 'http://badpath.lol/path' req.headers = {'Accept': 'application/json'} p = proxy.Proxy(self.conf, req) p.on_save = self.on_save p.on_done = self.on_done p.proxy() self.assertEqual(p.res.status, 400) self.assertEqual(p.res.headers['Content-Type'], 'application/json') self.assertIn('Path provided in request did not look valid', p.res.body)
def test_error_response(self): test_input_json = """"foo": "bar", "baz": "bliff" }""" def on_save(fh, res, conf): pass def on_done(res): res = res.__dict__ self.assertEqual(res['status'], 400) sys.exit(1) self.p = proxy.Proxy(self.conf, proxy.Req(), on_save) self.p.on_done = on_done with self.assertRaises(SystemExit): self.p.proxy() main.__main__(test_input_json, self.p)
def test_input_body(self): test_input = { "method": "POST", "path_query": "/posts", "body": {"id": 42, "title": "test"}, } def on_save(self, fh, res): pass p = proxy.Proxy(self.conf_path, proxy.Req()) # Patching on_save for tests p.on_save = types.MethodType(on_save, p) main.__main__(json.dumps(test_input), p) self.assertEqual(p.req.body, test_input["body"])
def test_input_invalid_json(self): test_input_json = """"foo": "bar", "baz": "bliff" }""" def on_save(self, fh, res): pass def on_done(self): res = self.res.__dict__ assert res["status"] == 400 sys.exit(1) p = proxy.Proxy(self.conf_path, proxy.Req()) # patching on_save and on_done for tests p.on_done = types.MethodType(on_done, p) p.on_save = types.MethodType(on_save, p) with self.assertRaises(SystemExit): main.__main__(test_input_json, p)
def test_proxy_basic_functionality(self): req = proxy.Req() req.method = "GET" req.path_query = "" req.headers = {"Accept": "application/json"} def on_save(self, fh, res): res.headers["X-Origin-Content-Type"] = res.headers["Content-Type"] res.headers["Content-Type"] = "application/json" res.body = json.dumps({"filename": self.fn}) p = proxy.Proxy(self.conf_path, req) # Patching on_save for test p.on_save = types.MethodType(on_save, p) p.fn = str(uuid.uuid4()) p.proxy() self.assertEqual(p.res.status, 200) self.assertEqual(p.res.body, json.dumps({"filename": p.fn})) self.assertEqual(p.res.headers["Content-Type"], "application/json")
def test_input_missing_keys(self): test_input_json = """{ "foo": "bar", "baz": "bliff" }""" def on_save(self, fh, res): pass def on_done(self): res = self.res.__dict__ assert res["status"] == 400 assert res["body"] == '{"error": "Missing keys in request"}', res sys.exit(1) p = proxy.Proxy(self.conf_path, proxy.Req()) # patching on_save and on_done for tests p.on_done = types.MethodType(on_done, p) p.on_save = types.MethodType(on_save, p) with self.assertRaises(SystemExit): main.__main__(test_input_json, p)
def test_json_response_with_timeout(self): test_input_json = """{ "method": "GET", "path_query": "/posts?userId=1", "timeout": 40.0 }""" req = proxy.Req() req.method = "GET" req.path_query = "" req.headers = {"Accept": "application/json"} # Use custom callbacks def on_save(self, fh, res): pass def on_done(self): assert self.res.status == http.HTTPStatus.OK print(json.dumps(self.res.__dict__)) self.p = proxy.Proxy(self.conf_path, req) # Patching on_save and on_done self.p.on_done = types.MethodType(on_done, self.p) self.p.on_save = types.MethodType(on_save, self.p) saved_stdout = sys.stdout try: out = StringIO() sys.stdout = out main.__main__(test_input_json, self.p) output = out.getvalue().strip() finally: sys.stdout = saved_stdout # Test that the right timeout was set in proxy object assert self.p.timeout == 40.0 response = json.loads(output) for item in json.loads(response["body"]): self.assertEqual(item["userId"], 1)
def test_non_json_response(self): test_input_json = """{ "method": "GET", "path_query": "" }""" def on_save(self, fh, res): subprocess.run(["cp", fh.name, "/tmp/{}".format(self.fn)]) res.headers["X-Origin-Content-Type"] = res.headers["Content-Type"] res.headers["Content-Type"] = "application/json" res.body = json.dumps({"filename": self.fn}) self.p = proxy.Proxy(self.conf_path, proxy.Req()) # Patching on_save to tests self.p.on_save = types.MethodType(on_save, self.p) self.p.fn = str(uuid.uuid4()) saved_stdout = sys.stdout try: out = StringIO() sys.stdout = out main.__main__(test_input_json, self.p) output = out.getvalue().strip() finally: sys.stdout = saved_stdout response = json.loads(output) self.assertEqual(response["status"], 200) # The proxy should have created a filename in the response body self.assertIn("filename", response["body"]) # The file should not be empty with open("/tmp/{}".format(self.p.fn)) as f: saved_file = f.read() # We expect HTML content in the file from the test data self.assertIn("<!DOCTYPE html>", saved_file)
def test_non_json_response(self): test_input_json = """{ "method": "GET", "path_query": "" }""" def on_save(fh, res, conf): self.fn = str(uuid.uuid4()) subprocess.run(["cp", fh.name, "/tmp/{}".format(self.fn)]) res.headers['X-Origin-Content-Type'] = res.headers['Content-Type'] res.headers['Content-Type'] = 'application/json' res.body = json.dumps({'filename': self.fn}) self.p = proxy.Proxy(self.conf, proxy.Req(), on_save) self.p.proxy() saved_stdout = sys.stdout try: out = StringIO() sys.stdout = out main.__main__(test_input_json, self.p) output = out.getvalue().strip() finally: sys.stdout = saved_stdout response = json.loads(output) self.assertEqual(response['status'], 200) # The proxy should have created a filename in the response body self.assertIn('filename', response['body']) # The file should not be empty with open("/tmp/{}".format(self.fn)) as f: saved_file = f.read() # We expect HTML content in the file from the test data self.assertIn("<html>", saved_file)
def __main__(incoming: str, p: Proxy) -> None: """ Deserialize incoming request in order to build and send a proxy request. """ logging.debug("Creating request to be sent by proxy") client_req: Dict[str, Any] = {} try: client_req = json.loads(incoming) except json.decoder.JSONDecodeError as e: logging.error(e) p.simple_error(400, "Invalid JSON in request") p.on_done() return req = proxy.Req() try: req.method = client_req["method"] req.path_query = client_req["path_query"] except KeyError as e: logging.error(e) p.simple_error(400, "Missing keys in request") p.on_done() if "headers" in client_req: req.headers = client_req["headers"] if "body" in client_req: req.body = client_req["body"] p.req = req if "timeout" in client_req: p.timeout = client_req["timeout"] p.proxy()
def make_request(self, method="GET", path_query="/", headers=None): req = proxy.Req() req.method = method if method else "GET" req.path_query = path_query if path_query else "/" req.headers = headers if headers else {"Accept": "application/json"} return req