1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
|
require 'socket'
module NetHTTPSpecs
class NullWriter
def <<(s) end
def puts(*args) end
def print(*args) end
def printf(*args) end
end
class SmallHTTPServer
def initialize(bind_address)
@server = TCPServer.new(bind_address, 0)
@thread = Thread.new {
Thread.current.abort_on_exception = true
listen
}
end
def ip
@server.addr[3]
end
def port
@server.addr[1]
end
def listen
until @server.closed?
client = @server.accept
handle_client(client)
end
end
def handle_client(client)
begin
until client.closed?
request = client.gets("\r\n\r\n")
break unless request
if request == "CLOSE"
@server.close
break
end
handle_request(client, request)
end
ensure
client.close
end
end
def parse_request(request)
request, *headers = request.chomp.lines.map { |line| line.chomp }
request_method, request_uri, _http_version = request.split
headers = headers.map { |line| line.split(': ', 2) }.to_h
[request_method, request_uri, headers]
end
def handle_request(client, request)
request_method, request_uri, headers = parse_request(request)
if headers.include? 'Content-Length'
request_body_size = Integer(headers['Content-Length'])
request_body = client.read(request_body_size)
end
case request_uri
when '/'
raise request_method unless request_method == 'GET'
reply(client, "This is the index page.", request_method)
when '/request'
reply(client, "Request type: #{request_method}", request_method)
when '/request/body'
reply(client, request_body, request_method)
when '/request/header'
reply(client, headers.inspect, request_method)
when '/request/basic_auth'
reply(client, "username: \npassword: ", request_method)
else
raise request_uri
end
end
def reply(client, body, request_method)
client.print "HTTP/1.1 200 OK\r\n"
if request_method == 'HEAD'
client.close
else
client.print "Content-Type: text/plain\r\n"
client.print "Content-Length: #{body.bytesize}\r\n"
client.print "\r\n"
client.print body
end
end
def close
TCPSocket.open(ip, port) do |socket|
socket.write "CLOSE"
end
@thread.join
end
end
@server = nil
class << self
def port
raise "server not started" unless @server
@server.port
end
def start_server
bind_address = platform_is(:windows) ? "localhost" : "127.0.0.1"
@server = SmallHTTPServer.new(bind_address)
end
def stop_server
if @server
@server.close
@server = nil
end
end
end
end
|