Skip to content

Instantly share code, notes, and snippets.

@matugm
Created September 30, 2020 00:19
Embed
What would you like to do?
require 'socket'
class RequestParser
def parse(request)
method, path, version = request.lines[0].split
{
path: path,
method: method,
headers: parse_headers(request)
}
end
def parse_headers(request)
headers = {}
request.lines[1..-1].each do |line|
return headers if line == "\r\n"
header, value = line.split
header = normalize(header)
headers[header] = value
end
end
def normalize(header)
header.gsub(":", "").downcase.to_sym
end
end
class Response
attr_reader :code
def initialize(code:, data: "")
@response =
"HTTP/1.1 #{code}\r\n" +
"Content-Length: #{data.size}\r\n" +
"\r\n" +
"#{data}\r\n"
@code = code
end
def send(client)
client.write(@response)
end
end
class ResponseBuilder
SERVER_ROOT = "/tmp/web-server/"
def prepare(request)
if request.fetch(:path) == "/"
respond_with(SERVER_ROOT + "index.html")
else
respond_with(SERVER_ROOT + request.fetch(:path))
end
end
def respond_with(path)
if File.exists?(path)
send_ok_response(File.binread(path))
else
send_file_not_found
end
end
def send_ok_response(data)
Response.new(code: 200, data: data)
end
def send_file_not_found
Response.new(code: 404)
end
end
server = TCPServer.new('localhost', 8080)
loop {
client = server.accept
request = client.readpartial(2048)
request = RequestParser.new.parse(request)
response = ResponseBuilder.new.prepare(request)
puts "#{client.peeraddr[3]} #{request.fetch(:path)} - #{response.code}"
response.send(client)
client.close
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment