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
124
125
126
127
128
129
130
131
132
|
# frozen-string-literal: true
$LOAD_PATH << File.expand_path("../../lib", __FILE__)
require "plum"
require "socket"
require "cgi"
def log(con, stream, s)
prefix = "[%02x;%02x] " % [con, stream]
if s.is_a?(Enumerable)
puts s.map { |a| prefix + a.to_s }.join("\n")
else
puts prefix + s.to_s
end
end
tcp_server = TCPServer.new("0.0.0.0", 40080)
loop do
begin
sock = tcp_server.accept
id = sock.fileno
puts "#{id}: accept!"
rescue
STDERR.puts $!
next
end
plum = Plum::HTTPServerConnection.new(sock.method(:write))
plum.on(:frame) do |frame|
log(id, frame.stream_id, "recv: #{frame.inspect}")
end
plum.on(:send_frame) do |frame|
log(id, frame.stream_id, "send: #{frame.inspect}")
end
plum.on(:connection_error) do |exception|
puts exception
puts exception.backtrace
end
plum.on(:stream) do |stream|
stream.on(:stream_error) do |exception|
puts exception
puts exception.backtrace
end
stream.on(:send_deferred) do |frame|
log(id, frame.stream_id, "send (deferred): #{frame.inspect}")
end
headers = data = nil
stream.on(:open) do
headers = nil
data = String.new
end
stream.on(:headers) do |headers_|
log(id, stream.id, headers_.map { |name, value| "#{name}: #{value}" })
headers = headers_.to_h
end
stream.on(:data) do |data_|
log(id, stream.id, data_)
data << data_
end
stream.on(:end_stream) do
case [headers[":method"], headers[":path"]]
when ["GET", "/"]
body = <<-EOF
Hello World! <a href=/abc.html>ABC</a> <a href=/fgsd>Not found</a>
<form action=post.page method=post>
<input type=text name=key value=default_value>
<input type=submit>
</form>
EOF
stream.send_headers({
":status": "200",
"server": "plum",
"content-type": "text/html",
"content-length": body.bytesize
}, end_stream: false)
stream.send_data(body, end_stream: true)
when ["POST", "/post.page"]
body = "Posted value is: #{CGI.unescape(data).gsub("<", "<").gsub(">", ">")}<br> <a href=/>Back to top page</a>"
stream.send_headers({
":status": "200",
"server": "plum",
"content-type": "text/html",
"content-length": body.bytesize
}, end_stream: false)
stream.send_data(body, end_stream: true)
else
body = "Page not found! <a href=/>Back to top page</a>"
stream.send_headers({
":status": "404",
"server": "plum",
"content-type": "text/html",
"content-length": body.bytesize
}, end_stream: false)
stream.send_data(body, end_stream: true)
end
end
end
Thread.new {
begin
while !sock.closed? && !sock.eof?
plum << sock.readpartial(1024)
end
rescue Plum::LegacyHTTPError
data = "Use modern web browser with HTTP/2 support."
resp = "HTTP/1.1 505 HTTP Version Not Supported\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: #{data.bytesize}\r\n"
"Server: plum/#{Plum::VERSION}\r\n"
"\r\n"
"#{data}"
sock.write(resp)
rescue
puts $!
puts $!.backtrace
ensure
sock.close
end
}
end
|