t/integration.t: switch PUT tests to MD5, reuse buffers
[unicorn.git] / t / integration.ru
blob086126ab1902cbede1c50c91820a5fc18cf89dcb
1 #!ruby
2 # Copyright (C) unicorn hackers <unicorn-public@80x24.org>
3 # License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
5 # this goes for t/integration.t  We'll try to put as many tests
6 # in here as possible to avoid startup overhead of Ruby.
8 def early_hints(env, val)
9   env['rack.early_hints'].call('link' => val) # val may be ary or string
10   [ 200, {}, [ val.class.to_s ] ]
11 end
13 $orig_rack_200 = nil
14 def tweak_status_code
15   $orig_rack_200 = Rack::Utils::HTTP_STATUS_CODES[200]
16   Rack::Utils::HTTP_STATUS_CODES[200] = "HI"
17   [ 200, {}, [] ]
18 end
20 def restore_status_code
21   $orig_rack_200 or return [ 500, {}, [] ]
22   Rack::Utils::HTTP_STATUS_CODES[200] = $orig_rack_200
23   [ 200, {}, [] ]
24 end
26 class WriteOnClose
27   def each(&block)
28     @callback = block
29   end
31   def close
32     @callback.call "7\r\nGoodbye\r\n0\r\n\r\n"
33   end
34 end
36 def write_on_close
37   [ 200, { 'transfer-encoding' => 'chunked' }, WriteOnClose.new ]
38 end
40 def env_dump(env)
41   require 'json'
42   h = {}
43   env.each do |k,v|
44     case v
45     when String, Integer, true, false; h[k] = v
46     else
47       case k
48       when 'rack.version', 'rack.after_reply'; h[k] = v
49       end
50     end
51   end
52   h.to_json
53 end
55 def rack_input_tests(env)
56   return [ 100, {}, [] ] if /\A100-continue\z/i =~ env['HTTP_EXPECT']
57   cap = 16384
58   require 'digest/md5'
59   dig = Digest::MD5.new
60   input = env['rack.input']
61   case env['PATH_INFO']
62   when '/rack_input/size_first'; input.size
63   when '/rack_input/rewind_first'; input.rewind
64   when '/rack_input'; # OK
65   else
66     abort "bad path: #{env['PATH_INFO']}"
67   end
68   if buf = input.read(rand(cap))
69     begin
70       raise "#{buf.size} > #{cap}" if buf.size > cap
71       dig.update(buf)
72     end while input.read(rand(cap), buf)
73     buf.clear # remove this call if Ruby ever gets escape analysis
74   end
75   h = { 'content-type' => 'text/plain' }
76   if env['HTTP_TRAILER'] =~ /\bContent-MD5\b/i
77     cmd5_b64 = env['HTTP_CONTENT_MD5'] or return [500, {}, ['No Content-MD5']]
78     cmd5_bin = cmd5_b64.unpack('m')[0]
79     if cmd5_bin != dig.digest
80       h['content-length'] = cmd5_b64.size.to_s
81       return [ 500, h, [ cmd5_b64 ] ]
82     end
83   end
84   h['content-length'] = '32'
85   [ 200, h, [ dig.hexdigest ] ]
86 end
88 run(lambda do |env|
89   case env['REQUEST_METHOD']
90   when 'GET'
91     case env['PATH_INFO']
92     when '/rack-2-newline-headers'; [ 200, { 'X-R2' => "a\nb\nc" }, [] ]
93     when '/rack-3-array-headers'; [ 200, { 'x-r3' => %w(a b c) }, [] ]
94     when '/nil-header-value'; [ 200, { 'X-Nil' => nil }, [] ]
95     when '/unknown-status-pass-through'; [ '666 I AM THE BEAST', {}, [] ]
96     when '/env_dump'; [ 200, {}, [ env_dump(env) ] ]
97     when '/write_on_close'; write_on_close
98     when '/pid'; [ 200, {}, [ "#$$\n" ] ]
99     when '/early_hints_rack2'; early_hints(env, "r\n2")
100     when '/early_hints_rack3'; early_hints(env, %w(r 3))
101     else '/'; [ 200, {}, [ env_dump(env) ] ]
102     end # case PATH_INFO (GET)
103   when 'POST'
104     case env['PATH_INFO']
105     when '/tweak-status-code'; tweak_status_code
106     when '/restore-status-code'; restore_status_code
107     end # case PATH_INFO (POST)
108     # ...
109   when 'PUT'
110     case env['PATH_INFO']
111     when %r{\A/rack_input}; rack_input_tests(env)
112     end
113   end # case REQUEST_METHOD
114 end) # run