proxy.py/tutorial/responses.ipynb

329 lines
7.9 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Http Response\n",
"\n",
"## Usage\n",
"\n",
"To construct a response packet you have a variety of facilities available.\n",
"\n",
"Previously we saw how to parse HTTP responses using `HttpParser`. Of-course, we can also construct a response packet using `HttpParser` class."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"b'HTTP/1.1 200 OK\\r\\nContent-Length: 0\\r\\n\\r\\n'\n"
]
}
],
"source": [
"from proxy.http.parser import HttpParser, httpParserTypes\n",
"from proxy.common.constants import HTTP_1_1\n",
"\n",
"response = HttpParser(httpParserTypes.RESPONSE_PARSER)\n",
"response.code = b'200'\n",
"response.reason = b'OK'\n",
"response.version = HTTP_1_1\n",
"\n",
"print(response.build_response())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"But, this is a painful way to construct responses. Hence, other high level abstractions are available.\n",
"\n",
"Example, following one liner will give us the same response packet."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"b'HTTP/1.1 200 OK\\r\\nContent-Length: 0\\r\\n\\r\\n'\n"
]
}
],
"source": [
"from proxy.http.responses import okResponse\n",
"\n",
"print(okResponse().tobytes())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Notice how `okResponse` will always add a `Content-Length` header for you.\n",
"\n",
"You can also customize other headers"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"b'HTTP/1.1 200 OK\\r\\nX-Custom-Header: my value\\r\\nContent-Length: 0\\r\\n\\r\\n'\n"
]
}
],
"source": [
"response = okResponse(\n",
" headers={\n",
" b'X-Custom-Header': b'my value',\n",
" },\n",
")\n",
"\n",
"print(response.tobytes())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's add some content to our response packet"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"b'HTTP/1.1 200 OK\\r\\nX-Custom-Header: my value\\r\\nContent-Length: 11\\r\\n\\r\\nHello World'\n"
]
}
],
"source": [
"response = okResponse(\n",
" content=b'Hello World',\n",
" headers={\n",
" b'X-Custom-Header': b'my value',\n",
" },\n",
")\n",
"\n",
"print(response.tobytes())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Note, how `okResponse` automatically added a `Content-Length` header for us.\n",
"\n",
"Depending upon `--min-compression-length` flag, `okResponse` will also perform compression for content.\n",
"\n",
"Example, default value for min compression length is 20."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"b\"HTTP/1.1 200 OK\\r\\nX-Custom-Header: my value\\r\\nContent-Encoding: gzip\\r\\nContent-Length: 23\\r\\n\\r\\n\\x1f\\x8b\\x08\\x00\\x80'\\xf4a\\x02\\xff\\xf3\\xf0\\xc0\\x02\\x00h\\x81?s\\x15\\x00\\x00\\x00\"\n"
]
}
],
"source": [
"response = okResponse(\n",
" content=b'H' * 21,\n",
" headers={\n",
" b'X-Custom-Header': b'my value',\n",
" },\n",
")\n",
"\n",
"print(response.tobytes())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You can pass a custom value for `min_compression_length` kwarg to `okResponse`."
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"b'HTTP/1.1 200 OK\\r\\nHost: jaxl.com\\r\\nContent-Length: 21\\r\\n\\r\\nHHHHHHHHHHHHHHHHHHHHH'\n"
]
}
],
"source": [
"response = okResponse(\n",
" content=b'H' * 21,\n",
" headers={\n",
" b'Host': b'jaxl.com',\n",
" },\n",
" min_compression_length=21,\n",
")\n",
"\n",
"print(response.tobytes())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Internally, `okResponse` uses `build_http_response` and hence you can also pass any argument also accepted by `build_http_response`. Example, it supports a `conn_close` argument which will add a `Connection: close` header. Simply, pass `conn_close=True`."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"b'HTTP/1.1 200 OK\\r\\nHost: jaxl.com\\r\\nContent-Length: 11\\r\\nConnection: close\\r\\n\\r\\nHello World'\n"
]
}
],
"source": [
"response = okResponse(\n",
" content=b'Hello World',\n",
" headers={\n",
" b'Host': b'jaxl.com',\n",
" },\n",
" conn_close=True,\n",
")\n",
"\n",
"print(response.tobytes())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Chunked Encoding\n",
"\n",
"You can also send chunked encoded responses."
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"b'HTTP/1.1 200 OK\\r\\nTransfer-Encoding: chunked\\r\\n\\r\\n5\\r\\nHello\\r\\n5\\r\\n Worl\\r\\n1\\r\\nd\\r\\n0\\r\\n\\r\\n'\n"
]
}
],
"source": [
"from proxy.http.parser import ChunkParser\n",
"\n",
"chunks = ChunkParser.to_chunks(b'Hello World', chunk_size=5)\n",
"response = okResponse(\n",
" content=chunks,\n",
" headers={\n",
" b'Transfer-Encoding': b'chunked',\n",
" },\n",
" # Avoid compressing chunks for demo purposes here\n",
" # Ideally you should omit this flag and send\n",
" # compressed chunks.\n",
" min_compression_length=len(chunks),\n",
")\n",
"\n",
"print(response.tobytes())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If we omit the `min_compression_length` flag"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"b'HTTP/1.1 200 OK\\r\\nTransfer-Encoding: chunked\\r\\nContent-Encoding: gzip\\r\\n\\r\\n\\x1f\\x8b\\x08\\x00\\xd3\\n\\xf1a\\x02\\xff3\\xe5\\xe5\\xf2H\\xcd\\xc9\\xc9\\xe7\\xe52\\xe5\\xe5R\\x08\\xcf/\\xca\\xe1\\xe52\\xe4\\xe5J\\xe1\\xe52\\xe0\\xe5\\xe2\\xe5\\x02\\x00\\x90S\\xbb/\\x1f\\x00\\x00\\x00'\n"
]
}
],
"source": [
"response = okResponse(\n",
" content=chunks,\n",
" headers={\n",
" b'Transfer-Encoding': b'chunked',\n",
" },\n",
")\n",
"\n",
"print(response.tobytes())"
]
}
],
"metadata": {
"interpreter": {
"hash": "da9d6927d62b2b95bde149eedfbd5367cb7f465aad65a736f49c99ee3db39df7"
},
"kernelspec": {
"display_name": "Python 3.10.0 64-bit ('venv310': venv)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.0"
},
"orig_nbformat": 4
},
"nbformat": 4,
"nbformat_minor": 2
}