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