はじめに
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)