$ make server&
[1] 27748
python server.py --port 5000
$ make proxy&
[2] 27754
python proxy.py --port 5001
$ make client
http :5001/api/foo
127.0.0.1 - - [14/Aug/2018 00:12:29] "GET / HTTP/1.1" 200 28
127.0.0.1 - - [14/Aug/2018 00:12:29] "GET /api/foo HTTP/1.1" 200 36
HTTP/1.0 200 OK
Content-Length: 36
Content-type: application/json; charset=utf-8
Date: Mon, 13 Aug 2018 15:12:29 GMT
Server: WSGIServer/0.2 CPython/3.7.0
{
"age": "**20**",
"name": "**foo**"
}
Last active
August 13, 2018 15:40
-
-
Save podhmo/14aa242415ec2592eeebb71c9f821f43 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
server: | |
python server.py --port 5000 | |
proxy: | |
python proxy.py --port 5001 | |
client: | |
http :5001/api/foo | |
client2: | |
echo '{"foo": "boo"}' | http --json POST :5001 headerX:headerV qsK==qsV | |
client3: | |
http --form POST :5001 headerX:headerV qsK==qsV foo=boo |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import typing as t | |
import typing_extensions as tx | |
import json | |
from wsgiref.simple_server import make_server | |
import requests | |
class Request: | |
def __init__(self, environ): | |
self.environ = environ | |
@property | |
def wsgi_input(self): | |
return self.environ["wsgi.input"] | |
@property | |
def path(self): | |
return self.environ["PATH_INFO"] | |
@property | |
def method(self): | |
return self.environ["REQUEST_METHOD"] | |
@property | |
def query_string(self): | |
return self.environ.get("QUERY_STRING") | |
@property | |
def headers(self): | |
environ = self.environ | |
return {k[5:].replace("_", "-"): environ[k] for k in environ if k.startswith("HTTP_")} | |
@property | |
def content_type(self): | |
return self.environ.get("CONTENT_TYPE") | |
@property | |
def content_length(self): | |
v = self.environ.get("CONTENT_LENGTH") or None | |
if v is None: | |
return None | |
return int(v) | |
@property | |
def data(self): | |
if not self.content_length: | |
return None | |
return self.wsgi_input.read(self.content_length) | |
class Response(tx.Protocol): | |
status_code: int | |
reason: str | |
headers: t.Dict[str, str] | |
@property | |
def content(self) -> bytes: | |
... | |
def json(self) -> dict: | |
... | |
class Proxy: | |
def __init__( | |
self, | |
request: t.Callable[[Request], Response], | |
response: t.Callable[[Response], bytes], | |
): | |
self.request = request | |
self.response = response | |
def __call__( | |
self, | |
environ: dict, | |
start_response: t.Callable[[str, t.List[t.Tuple[str, str]]], None], | |
) -> None: | |
response = self.request(Request(environ)) | |
if response.status_code == 200: | |
content = self.response(response) | |
else: | |
content = response.content | |
start_response(f'{response.status_code} {response.reason}', list(response.headers.items())) | |
return [content] | |
def main(port=4444): | |
def request(req: Request) -> Response: | |
url = f"http://localhost:5000{req.path}" | |
if req.query_string: | |
url = f"{url}?{req.query_string}" | |
return requests.request(req.method, url, data=req.data, headers=req.headers) | |
def response(res: Response) -> bytes: | |
if not res.headers.get("Content-Type", "").lstrip().startswith("application/json"): | |
return res.content | |
res.headers.pop("Content-Length", None) | |
body = res.json() | |
for k in list(body.keys()): | |
body[k] = f"**{body[k]}**" | |
return json.dumps(body).encode("utf-8") | |
proxy = Proxy(request, response) | |
with make_server('', port, proxy) as httpd: | |
httpd.serve_forever() | |
if __name__ == "__main__": | |
import argparse | |
parser = argparse.ArgumentParser() | |
parser.add_argument("--port", type=int, default=4444) | |
args = parser.parse_args() | |
main(port=args.port) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
requests | |
typing-extensions |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import json | |
from wsgiref.simple_server import make_server | |
def app(environ, start_response): | |
status = '200 OK' | |
headers = [('Content-type', 'application/json; charset=utf-8')] | |
start_response(status, headers) | |
data = { | |
"name": "foo", | |
"age": "20", | |
} | |
return [json.dumps(data).encode("utf-8")] | |
def main(port=4445): | |
with make_server('', port, app) as httpd: | |
httpd.serve_forever() | |
if __name__ == "__main__": | |
import argparse | |
parser = argparse.ArgumentParser() | |
parser.add_argument("--port", type=int, default=4444) | |
args = parser.parse_args() | |
main(port=args.port) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment