ソースコード書いてみた。
require "socket"
require "time"
port = 8001
server = TCPServer.open(port)
while true
# TCPSocket オブジェクトを取得
socket = server.accept
req_headers = {}
# HTTPリクエストが来るのを待って1行ずつ取得
while line = socket.gets
# リクエストの終了
break if line == "\r\n"
# リクエストヘッダの取得
i = line.index(":")
if i == nil
# リクエスト行
if line.split(" ")[0] == "GET"
req_method = line.strip
end
else
# リクエストヘッダ
key = line[0, i].strip
val = line[i..-1].strip
req_headers[key] = val
end
end
# アクセス元の情報を出力
p socket.peeraddr
# リクエスト情報の出力
p req_method
p req_headers
# HTTPステータスを指定
res_status = "HTTP/1.1 200 OK"
# レスポンスヘッダの構築
res_headers = {
"Server" => "My Ruby Web Server",
"Date" => Time.now.httpdate, # RFC1123
"Content-Type" => "text/html; charset=UTF-8"
}
# レスポンスボディの構築
res_body = "<html><body>hello, world</body></html>"
# レスポンス出力
socket.puts res_status
res_headers.each{|key, val|
socket.puts "#{key}: #{val}"
}
socket.puts "Connection: close"
socket.puts "" # ヘッダとボディの間には空行が必要
socket.puts res_body
socket.close
end
server.close
webserver.rb というファイル名で保存して、 ruby コマンドで実行。
$ ruby webserver.rb
HTTPクライアントとして、他のターミナルなどから curl でアクセスしてみる。 --dump-header オプションを付けると、HTTPレスポンスヘッダも見ることができる。
$ curl --dump-header - http://localhost:8001/foo/bar/?a=b
HTTP/1.1 200 OK
Server: My Ruby Web Server
Date: Thu, 12 May 2016 00:42:36 GMT
Content-Type: text/html; charset=UTF-8
Connection: close
<html><body>hello, world</body></html>
Ruby 実行側では、リクエスト情報を出力できている。
$ ruby webserver.rb
["AF_INET", 49926, "127.0.0.1", "127.0.0.1"]
"GET /foo/bar/?a=b HTTP/1.1"
{"Host"=>": localhost:8001", "User-Agent"=>": curl/7.43.0", "Accept"=>": */*"}
今回の環境: Mac OS X El Capitan + Ruby 2.3.0
$ uname -mrsv
Darwin 15.4.0 Darwin Kernel Version 15.4.0: Fri Feb 26 22:08:05 PST 2016; root:xnu-3248.40.184~3/RELEASE_X86_64 x86_64
$ ruby -v
ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-darwin15]
この Web サーバの実装だとシングルスレッドで動作するので、できれば Thread クラスなどでマルチスレッド化したいところ。
tags: ruby
Posted by NI-Lab. (@nilab)