はじめに
前の投稿に続いて、今回はproxy を通すところを試してみました。これがやりたかった。
内容
まず、適当なサーバに対してGET を送り、レスポンス(短いのがいいな)が返ってくるの確認します。
$ curl http://google.com
<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>301 Moved</TITLE></HEAD><BODY>
<H1>301 Moved</H1>
The document has moved
<A HREF="http://www.google.com/">here</A>.
</BODY></HTML>
これをproxy経由にしてみます。
無料のproxy server
Google 先生に free proxy サーバと問い合わせてみると、いろいろなサイトを教えてくれます。
私は、以下から日本国内にあるものを見つけ、利用させていただくことにしました。
curl でproxy経由させたときの送受信
前回と同様にcURLを使って調べます。proxy server を指定するには、-x を使います。
$ curl -v google.com:80 -x http://116.80.45.7:80
* Trying 116.80.45.7:80...
* TCP_NODELAY set
* Connected to 116.80.45.7 (116.80.45.7) port 80 (#0)
> GET http://google.com:80/ HTTP/1.1
> Host: google.com
> User-Agent: curl/7.68.0
> Accept: */*
> Proxy-Connection: Keep-Alive
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 301 Moved Permanently
< Location: http://www.google.com/
< Content-Type: text/html; charset=UTF-8
< Date: Fri, 08 Oct 2021 13:32:22 GMT
< Expires: Sun, 07 Nov 2021 13:32:22 GMT
< Cache-Control: public, max-age=2592000
< Server: gws
< Content-Length: 219
< X-XSS-Protection: 0
< X-Frame-Options: SAMEORIGIN
<
<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>301 Moved</TITLE></HEAD><BODY>
<H1>301 Moved</H1>
The document has moved
<A HREF="http://www.google.com/">here</A>.
</BODY></HTML>
* Connection #0 to host 116.80.45.7 left intact
リクエストの部分で、目的とするhost を書いています。このリクエストをproxy server に送っています。
python code で通信してみる
なので、同じことをしてみます。コードは前回のを少し変えてこんな感じです。
import socket
proxy_hostname, proxy_port = "116.80.45.7", 80
hostname, port = "google.com", 80
server_request = \
f"GET http://{hostname}:{port}/ HTTP/1.1\r\n" \
+ f"Host: {hostname}:{port}\r\n" \
+ "User-Agent: MyPython\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( (proxy_hostname, proxy_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_proxy_get.py
request:
GET http://google.com:80/ HTTP/1.1
Host: google.com:80
User-Agent: MyPhthon
Accept: */*
response(528):
HTTP/1.1 301 Moved Permanently
Location: http://www.google.com/
Content-Type: text/html; charset=UTF-8
Date: Fri, 08 Oct 2021 13:28:44 GMT
Expires: Sun, 07 Nov 2021 13:28:44 GMT
Cache-Control: public, max-age=2592000
Server: gws
Content-Length: 219
X-XSS-Protection: 0
X-Frame-Options: SAMEORIGIN
<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>301 Moved</TITLE></HEAD><BODY>
<H1>301 Moved</H1>
The document has moved
<A HREF="http://www.google.com/">here</A>.
</BODY></HTML>
無事に動いてます。やったー、今日は調子がいいぞ。
Proxy tunnel を通す(CONNECT メソドの登場)
ここで、curl のオプションに --proxytunnel
を付けてみます。
$ curl -v google.com -x http://116.80.45.7:80 --proxytunnel
* Trying 116.80.45.7:80...
* TCP_NODELAY set
* Connected to 116.80.45.7 (116.80.45.7) port 80 (#0)
* allocate connect buffer!
* Establish HTTP proxy tunnel to google.com:80
> CONNECT google.com:80 HTTP/1.1
> Host: google.com:80
> User-Agent: curl/7.68.0
> Proxy-Connection: Keep-Alive
>
< HTTP/1.1 405 Method Not Allowed
< Content-Type: text/html; charset=UTF-8
< Referrer-Policy: no-referrer
< Content-Length: 1592
< Date: Fri, 08 Oct 2021 13:17:05 GMT
< Connection: close
<
* Received HTTP code 405 from proxy after CONNECT
* CONNECT phase completed!
* Closing connection 0
curl: (56) Received HTTP code 405 from proxy after CONNECT
先程のpython script でリクエストヘッダを書き換えます。
server_request = \
f"CONNECT {hostname}:{port}/ HTTP/1.1\r\n" \
+ f"Host: {hostname}:{port}\r\n" \
+ "User-Agent: MyPython\r\n" \
+ "Accept: */*\r\n\r\n"
とりあえず同じものを送れるようにはなり、同じ結果が返ってきました。
まとめ
HTTP Proxy を理解するために、curl で送受信されるデータを見て、同じ内容をpython で送ってみた。
とりあえず、これでproxy を通すベタな実装はできる気がした。
本当は、おじさんは便利なモジュールを使いたいのだ。そうなのだが誰も教えてくれないので、自分で実装しているのです。
(2021/10/08)