t0012: fix race condition in reload
[unicorn.git] / test / unit / test_request.rb
blob67ac1b9aef04a02e4010acb15135aa0cfdd974eb
1 # -*- encoding: binary -*-
3 # Copyright (c) 2009 Eric Wong
4 # You can redistribute it and/or modify it under the same terms as Ruby.
6 require 'test/test_helper'
8 include Unicorn
10 class RequestTest < Test::Unit::TestCase
12   class MockRequest < StringIO
13     alias_method :readpartial, :sysread
14     alias_method :kgio_read!, :sysread
15     alias_method :read_nonblock, :sysread
16     def kgio_addr
17       '127.0.0.1'
18     end
19   end
21   def setup
22     @request = HttpRequest.new
23     @app = lambda do |env|
24       [ 200, { 'Content-Length' => '0', 'Content-Type' => 'text/plain' }, [] ]
25     end
26     @lint = Rack::Lint.new(@app)
27   end
29   def test_options
30     client = MockRequest.new("OPTIONS * HTTP/1.1\r\n" \
31                              "Host: foo\r\n\r\n")
32     res = env = nil
33     assert_nothing_raised { env = @request.read(client) }
34     assert_equal '', env['REQUEST_PATH']
35     assert_equal '', env['PATH_INFO']
36     assert_equal '*', env['REQUEST_URI']
37     assert_nothing_raised { res = @lint.call(env) }
38   end
40   def test_absolute_uri_with_query
41     client = MockRequest.new("GET http://e:3/x?y=z HTTP/1.1\r\n" \
42                              "Host: foo\r\n\r\n")
43     res = env = nil
44     assert_nothing_raised { env = @request.read(client) }
45     assert_equal '/x', env['REQUEST_PATH']
46     assert_equal '/x', env['PATH_INFO']
47     assert_equal 'y=z', env['QUERY_STRING']
48     assert_nothing_raised { res = @lint.call(env) }
49   end
51   def test_absolute_uri_with_fragment
52     client = MockRequest.new("GET http://e:3/x#frag HTTP/1.1\r\n" \
53                              "Host: foo\r\n\r\n")
54     res = env = nil
55     assert_nothing_raised { env = @request.read(client) }
56     assert_equal '/x', env['REQUEST_PATH']
57     assert_equal '/x', env['PATH_INFO']
58     assert_equal '', env['QUERY_STRING']
59     assert_equal 'frag', env['FRAGMENT']
60     assert_nothing_raised { res = @lint.call(env) }
61   end
63   def test_absolute_uri_with_query_and_fragment
64     client = MockRequest.new("GET http://e:3/x?a=b#frag HTTP/1.1\r\n" \
65                              "Host: foo\r\n\r\n")
66     res = env = nil
67     assert_nothing_raised { env = @request.read(client) }
68     assert_equal '/x', env['REQUEST_PATH']
69     assert_equal '/x', env['PATH_INFO']
70     assert_equal 'a=b', env['QUERY_STRING']
71     assert_equal 'frag', env['FRAGMENT']
72     assert_nothing_raised { res = @lint.call(env) }
73   end
75   def test_absolute_uri_unsupported_schemes
76     %w(ssh+http://e/ ftp://e/x http+ssh://e/x).each do |abs_uri|
77       client = MockRequest.new("GET #{abs_uri} HTTP/1.1\r\n" \
78                                "Host: foo\r\n\r\n")
79       assert_raises(HttpParserError) { @request.read(client) }
80     end
81   end
83   def test_x_forwarded_proto_https
84     res = env = nil
85     client = MockRequest.new("GET / HTTP/1.1\r\n" \
86                              "X-Forwarded-Proto: https\r\n" \
87                              "Host: foo\r\n\r\n")
88     assert_nothing_raised { env = @request.read(client) }
89     assert_equal "https", env['rack.url_scheme']
90     assert_nothing_raised { res = @lint.call(env) }
91   end
93   def test_x_forwarded_proto_http
94     res = env = nil
95     client = MockRequest.new("GET / HTTP/1.1\r\n" \
96                              "X-Forwarded-Proto: http\r\n" \
97                              "Host: foo\r\n\r\n")
98     assert_nothing_raised { env = @request.read(client) }
99     assert_equal "http", env['rack.url_scheme']
100     assert_nothing_raised { res = @lint.call(env) }
101   end
103   def test_x_forwarded_proto_invalid
104     res = env = nil
105     client = MockRequest.new("GET / HTTP/1.1\r\n" \
106                              "X-Forwarded-Proto: ftp\r\n" \
107                              "Host: foo\r\n\r\n")
108     assert_nothing_raised { env = @request.read(client) }
109     assert_equal "http", env['rack.url_scheme']
110     assert_nothing_raised { res = @lint.call(env) }
111   end
113   def test_rack_lint_get
114     client = MockRequest.new("GET / HTTP/1.1\r\nHost: foo\r\n\r\n")
115     res = env = nil
116     assert_nothing_raised { env = @request.read(client) }
117     assert_equal "http", env['rack.url_scheme']
118     assert_equal '127.0.0.1', env['REMOTE_ADDR']
119     assert_nothing_raised { res = @lint.call(env) }
120   end
122   def test_no_content_stringio
123     client = MockRequest.new("GET / HTTP/1.1\r\nHost: foo\r\n\r\n")
124     res = env = nil
125     assert_nothing_raised { env = @request.read(client) }
126     assert_equal StringIO, env['rack.input'].class
127   end
129   def test_zero_content_stringio
130     client = MockRequest.new("PUT / HTTP/1.1\r\n" \
131                              "Content-Length: 0\r\n" \
132                              "Host: foo\r\n\r\n")
133     res = env = nil
134     assert_nothing_raised { env = @request.read(client) }
135     assert_equal StringIO, env['rack.input'].class
136   end
138   def test_real_content_not_stringio
139     client = MockRequest.new("PUT / HTTP/1.1\r\n" \
140                              "Content-Length: 1\r\n" \
141                              "Host: foo\r\n\r\n")
142     res = env = nil
143     assert_nothing_raised { env = @request.read(client) }
144     assert_equal Unicorn::TeeInput, env['rack.input'].class
145   end
147   def test_rack_lint_put
148     client = MockRequest.new(
149       "PUT / HTTP/1.1\r\n" \
150       "Host: foo\r\n" \
151       "Content-Length: 5\r\n" \
152       "\r\n" \
153       "abcde")
154     res = env = nil
155     assert_nothing_raised { env = @request.read(client) }
156     assert ! env.include?(:http_body)
157     assert_nothing_raised { res = @lint.call(env) }
158   end
160   def test_rack_lint_big_put
161     count = 100
162     bs = 0x10000
163     buf = (' ' * bs).freeze
164     length = bs * count
165     client = Tempfile.new('big_put')
166     def client.kgio_addr; '127.0.0.1'; end
167     def client.kgio_read(*args)
168       readpartial(*args)
169     rescue EOFError
170     end
171     def client.kgio_read!(*args)
172       readpartial(*args)
173     end
174     client.syswrite(
175       "PUT / HTTP/1.1\r\n" \
176       "Host: foo\r\n" \
177       "Content-Length: #{length}\r\n" \
178       "\r\n")
179     count.times { assert_equal bs, client.syswrite(buf) }
180     assert_equal 0, client.sysseek(0)
181     res = env = nil
182     assert_nothing_raised { env = @request.read(client) }
183     assert ! env.include?(:http_body)
184     assert_equal length, env['rack.input'].size
185     count.times {
186       tmp = env['rack.input'].read(bs)
187       tmp << env['rack.input'].read(bs - tmp.size) if tmp.size != bs
188       assert_equal buf, tmp
189     }
190     assert_nil env['rack.input'].read(bs)
191     assert_nothing_raised { env['rack.input'].rewind }
192     assert_nothing_raised { res = @lint.call(env) }
193   end