-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathhyperloop.rb
117 lines (96 loc) · 2.15 KB
/
hyperloop.rb
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
require 'socket'
require 'http/parser'
require 'stringio'
require 'thread'
class Hyperloop
def initialize port
@server = TCPServer.new port
end
def prefork
3.times do
fork do
start
end
end
waitall
end
def waitall
Process.waitall
rescue Interrupt
puts "\nKilled all. No zombies."
end
def start
loop do
socket = @server.accept
Thread.new { SocketHandler.new(socket).process }
end
rescue Interrupt
end
end
class Hyperloop
module AppLoader
def run app
app
end
def load_app
eval File.read('config.ru')
end
end
end
class Hyperloop
class SocketHandler
HTTP_DEFINITIONS = {
200 => 'OK',
404 => 'Not Found'
}
include Hyperloop::AppLoader
def initialize socket
@socket = socket
@parser = Http::Parser.new self
@app = load_app
end
def process
parse_data_from_socket
end
def parse_data_from_socket
until @socket.closed? || @socket.eof?
data = @socket.readpartial 1024
@parser << data
end
end
def on_message_complete
send_response
close_socket
write_to_screen
end
def send_response
status, headers, body = @app.call parsed_data_to_rack_env
@socket.write "HTTP/1.1 #{status} #{HTTP_DEFINITIONS[status]}\r\n"
headers.each_pair { |key, value| @socket.write "#{key}: #{value}\r\n" }
@socket.write "\r\n"
body.each { |chunk| @socket.write chunk }
body.close if body.respond_to? :close
end
def parsed_data_to_rack_env
Hash.new.tap do |env|
@parser.headers.each_pair do |key, value|
env["HTTP_#{key.upcase.gsub('-', '_')}"] = value
end
env['PATH_INFO'] = @parser.request_path
env["REQUEST_METHOD"] = @parser.http_method
env["rack.input"] = StringIO.new
end
end
def write_to_screen
puts "#{@parser.http_method} #{@parser.request_path}"
puts @parser.headers.inspect
puts
end
def close_socket
@socket.close
end
end
end
server = Hyperloop.new 3000
puts "Starting Hyperloop server on port 3000"
server.prefork