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
|
$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 => e
STDERR.puts e
next
end
plum = Plum::HTTPConnection.new(sock)
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 = ""
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 = "Hello World! <a href=/abc.html>ABC</a> <a href=/fgsd>Not found</a>"
body << <<-EOF
<form action=post.page method=post>
<input type=text name=key value=default_value>
<input type=submit>
</form>
EOF
stream.respond({
":status": "200",
"server": "plum",
"content-type": "text/html",
"content-length": body.size
}, body)
when ["POST", "/post.page"]
body = "Posted value is: #{CGI.unescape(data).gsub("<", "<").gsub(">", ">")}<br> <a href=/>Back to top page</a>"
stream.respond({
":status": "200",
"server": "plum",
"content-type": "text/html",
"content-length": body.size
}, body)
else
body = "Page not found! <a href=/>Back to top page</a>"
stream.respond({
":status": "404",
"server": "plum",
"content-type": "text/html",
"content-length": body.size
}, body)
end
end
end
Thread.new {
begin
plum.run
rescue Plum::LegacyHTTPError
data = "Use modern web browser with HTTP/2 support."
resp = ""
resp << "HTTP/1.1 505 HTTP Version Not Supported\r\n"
resp << "Content-Type: text/plain\r\n"
resp << "Content-Length: #{data.bytesize}\r\n"
resp << "Server: plum/#{Plum::VERSION}\r\n"
resp << "\r\n"
resp << data
sock.write(resp)
rescue
puts $!
puts $!.backtrace
ensure
sock.close
end
}
end
|