aboutsummaryrefslogtreecommitdiffstats
path: root/examples/non_tls_server.rb
blob: e481b05e02f860a5fcb41138841c1fb7e6c9a046 (plain)
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("<", "&lt;").gsub(">", "&gt;")}<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