#はじめに
HTTPサーバの仕組みを理解するために,HTTP用のサーバアプリやライブラリを使わずにTCPレベルのSocketを使ってHTTPサーバもどきを作ってみた
勉強用なので簡単な機能しかとりあえずつけてません
※以下のソースコードは脆弱性満載なので使用の際のトラブル等は全て自己責任でお願いします
#ソースコード
httpserver.rb
require "socket"
plane_ext = ["html","htm","txt"]
binary_ext = ["ico","jpg","png","gif"]
permited_ext = plane_ext + binary_ext
s = TCPServer.open(8080)
while true
puts "Server Ready..."
client = s.accept
puts "Accept HTTP Message"
msg=[]
msg_hash=Hash.new
request_msg = client.gets
request_msg = request_msg.chomp.split(" ") if request_msg!=nil
redo if request_msg==nil
while str=client.gets
if str!=nil
break if (str.chomp) == ""
str.chomp!
msg << str
buf=str.split(": ")
msg_hash[buf[0]] = buf[1]
end
end
puts "======== message ========="
puts request_msg.join(" ") if request_msg != nil
puts "======== message ========="
puts msg if msg != nil
puts "=========================="
sleep(1)
begin
filename= request_msg[1]
filename+="index.html" if filename[-1]=="/" # add "index.html"
while filename.sub!(/(\/\w*)(\/\.\.)/,"") do end # remove .. from filename
filename[0]="" # remove "/" on the first word
ext = filename.match(/\.([\w\.]*)/)[1] # get extemsion name from the filename
puts "filename = #{filename}"
puts "extension = [#{ext}]"
if filename[0,2] != ".." && permited_ext.include?(ext)
if plane_ext.include?(ext)
html = IO.read(filename)
elsif binary_ext.include?(ext)
html = IO.binread(filename)
end
client.puts "HTTP/1.1 200 OK"
client.puts ""
client.puts html
else
client.puts "HTTP/1.1 403 Forbidden"
client.puts ""
end
rescue Errno::ENOENT => e
client.puts "HTTP/1.1 404 Not Found"
client.puts ""
end
client.close
end
##ソースコード解説
- ソケットが繋がったらrequest_msgに最初の[リクエスト,パス,バージョン]が入ります
- その他のヘッダ部分はmsgとmsg_hashに入れます
- 改行のみのデータが来たら読み込みを停止します
- request_msgのパスを"/"で終われば"index.html"を付加して,最初の"/"を消して相対パスにします
- 対応するデータを探し,開けなければ「404」,開ければ「200」と「改行」,「データ」を送ります