{ "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 }