329 lines
7.9 KiB
Plaintext
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
|
|
}
|