LoginSignup
2
3

More than 1 year has passed since last update.

【Python】HTTP通信でGETを直接書く

Last updated at Posted at 2021-10-08

はじめに

HTTP 1.1 の通信でGETするのをsocket 通信として実装したいと思いました。
で「どんなメッセージを送ればよいのか」を調べたのですが、意外と良く分かりませんでした。
なのですが、それが簡単にわかる方法を見つけたので、ここにメモリます。

行ったこと:

  • HTTP GETリクエストを送られるデータを確認した
  • HTTPサーバにpython でGET を送ってみた

実験

GET request とその response を見る

ローカルにHTTPサーバを立てます。
まず、何か書いたテキストファイルを用意します。

.
└── hello.txt

このディレクトリでHTTP サーバを立てます。http.server については、こちらに使い方の説明がありますが、bind するアドレス、listen するport、ディレクトリなど指定できます。

$ python3 -m http.server

これに対して、curl を -v オプションを付けて実行します。

$ curl -v localhost:8000/hello.txt
*   Trying 127.0.0.1:8000...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8000 (#0)
> GET /hello.txt HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.68.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Server: SimpleHTTP/0.6 Python/3.8.10
< Date: Thu, 07 Oct 2021 15:46:15 GMT
< Content-type: text/plain
< Content-Length: 10
< Last-Modified: Thu, 07 Oct 2021 15:45:10 GMT
<
hello!!


* Closing connection 0

これで、送受信されるメッセージが見れました。

Python でGET request

TCP client でこのメッセージを送ってみます。

python で書くTCP client は以下の通りです。socket でsend/recv するのは binary array です。文字列との間の変換には decode, encode が必要なので注意。

import socket

hostname, port = "127.0.0.1", 8000
server_request = \
    "GET /hello.txt HTTP/1.1\r\n" \
    + "Host: localhost:8000\r\n" \
    + "User-Agent: curl/7.68.0\r\n" \
    + "Accept: */*\r\n\r\n"
print(f"request:\n{server_request}")
try:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(5.0)
    s.connect_ex( (hostname, port) )
    #s.settimeout(None)
    ret = s.sendall(bytes(server_request, 'utf-8'))
except Exception as e:
    print(f"{e}")
    raise e

try:
    data = s.recv(8192*16)
    print( f"response({len(data)}):")
    print(data.decode('unicode-escape'))
except Exception as e:
    raise e

さて、動かしてみると、、、

$ python3 python_get_client.py
request:
GET /hello.txt HTTP/1.1
Host: localhost:8000
User-Agent: curl/7.68.0
Accept: */*


response(186):
HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/3.8.10
Date: Thu, 07 Oct 2021 23:02:17 GMT
Content-type: text/plain
Content-Length: 10
Last-Modified: Thu, 07 Oct 2021 15:45:10 GMT


想定通り、同じレスポンス(当然だ^^;)を得られました。ばんざい。

まとめ

HTTP GETのリクエストとレスポンスを見ることができた。
次のステップとして、ここにあるように CONNECT でproxy tunnel を実装してみたいです。
(2021/10/08)

  • 続編を書きました。(2021/10/08)

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3