4943dc090c0460c31766b2e40cec23f90159ab9e
[unicorn.git] / test / unit / test_request.rb
blob4943dc090c0460c31766b2e40cec23f90159ab9e
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 GPLv3
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     res = env = nil
34     assert_nothing_raised { env = @request.read(client) }
35     assert_equal '', env['REQUEST_PATH']
36     assert_equal '', env['PATH_INFO']
37     assert_equal '*', env['REQUEST_URI']
38     assert_nothing_raised { res = @lint.call(env) }
39   end
41   def test_absolute_uri_with_query
42     client = MockRequest.new("GET http://e:3/x?y=z HTTP/1.1\r\n" \
43                              "Host: foo\r\n\r\n")
44     res = env = nil
45     assert_nothing_raised { env = @request.read(client) }
46     assert_equal '/x', env['REQUEST_PATH']
47     assert_equal '/x', env['PATH_INFO']
48     assert_equal 'y=z', env['QUERY_STRING']
49     assert_nothing_raised { res = @lint.call(env) }
50   end
52   def test_absolute_uri_with_fragment
53     client = MockRequest.new("GET http://e:3/x#frag HTTP/1.1\r\n" \
54                              "Host: foo\r\n\r\n")
55     res = env = nil
56     assert_nothing_raised { env = @request.read(client) }
57     assert_equal '/x', env['REQUEST_PATH']
58     assert_equal '/x', env['PATH_INFO']
59     assert_equal '', env['QUERY_STRING']
60     assert_equal 'frag', env['FRAGMENT']
61     assert_nothing_raised { res = @lint.call(env) }
62   end
64   def test_absolute_uri_with_query_and_fragment
65     client = MockRequest.new("GET http://e:3/x?a=b#frag HTTP/1.1\r\n" \
66                              "Host: foo\r\n\r\n")
67     res = env = nil
68     assert_nothing_raised { env = @request.read(client) }
69     assert_equal '/x', env['REQUEST_PATH']
70     assert_equal '/x', env['PATH_INFO']
71     assert_equal 'a=b', env['QUERY_STRING']
72     assert_equal 'frag', env['FRAGMENT']
73     assert_nothing_raised { res = @lint.call(env) }
74   end
76   def test_absolute_uri_unsupported_schemes
77     %w(ssh+http://e/ ftp://e/x http+ssh://e/x).each do |abs_uri|
78       client = MockRequest.new("GET #{abs_uri} HTTP/1.1\r\n" \
79                                "Host: foo\r\n\r\n")
80       assert_raises(HttpParserError) { @request.read(client) }
81     end
82   end
84   def test_x_forwarded_proto_https
85     res = env = nil
86     client = MockRequest.new("GET / HTTP/1.1\r\n" \
87                              "X-Forwarded-Proto: https\r\n" \
88                              "Host: foo\r\n\r\n")
89     assert_nothing_raised { env = @request.read(client) }
90     assert_equal "https", env['rack.url_scheme']
91     assert_nothing_raised { res = @lint.call(env) }
92   end
94   def test_x_forwarded_proto_http
95     res = env = nil
96     client = MockRequest.new("GET / HTTP/1.1\r\n" \
97                              "X-Forwarded-Proto: http\r\n" \
98                              "Host: foo\r\n\r\n")
99     assert_nothing_raised { env = @request.read(client) }
100     assert_equal "http", env['rack.url_scheme']
101     assert_nothing_raised { res = @lint.call(env) }
102   end
104   def test_x_forwarded_proto_invalid
105     res = env = nil
106     client = MockRequest.new("GET / HTTP/1.1\r\n" \
107                              "X-Forwarded-Proto: ftp\r\n" \
108                              "Host: foo\r\n\r\n")
109     assert_nothing_raised { env = @request.read(client) }
110     assert_equal "http", env['rack.url_scheme']
111     assert_nothing_raised { res = @lint.call(env) }
112   end
114   def test_rack_lint_get
115     client = MockRequest.new("GET / HTTP/1.1\r\nHost: foo\r\n\r\n")
116     res = env = nil
117     assert_nothing_raised { env = @request.read(client) }
118     assert_equal "http", env['rack.url_scheme']
119     assert_equal '127.0.0.1', env['REMOTE_ADDR']
120     assert_nothing_raised { res = @lint.call(env) }
121   end
123   def test_no_content_stringio
124     client = MockRequest.new("GET / HTTP/1.1\r\nHost: foo\r\n\r\n")
125     env = nil
126     assert_nothing_raised { env = @request.read(client) }
127     assert_equal StringIO, env['rack.input'].class
128   end
130   def test_zero_content_stringio
131     client = MockRequest.new("PUT / HTTP/1.1\r\n" \
132                              "Content-Length: 0\r\n" \
133                              "Host: foo\r\n\r\n")
134     env = nil
135     assert_nothing_raised { env = @request.read(client) }
136     assert_equal StringIO, env['rack.input'].class
137   end
139   def test_real_content_not_stringio
140     client = MockRequest.new("PUT / HTTP/1.1\r\n" \
141                              "Content-Length: 1\r\n" \
142                              "Host: foo\r\n\r\n")
143     env = nil
144     assert_nothing_raised { env = @request.read(client) }
145     assert_equal Unicorn::TeeInput, env['rack.input'].class
146   end
148   def test_rack_lint_put
149     client = MockRequest.new(
150       "PUT / HTTP/1.1\r\n" \
151       "Host: foo\r\n" \
152       "Content-Length: 5\r\n" \
153       "\r\n" \
154       "abcde")
155     res = env = nil
156     assert_nothing_raised { env = @request.read(client) }
157     assert ! env.include?(:http_body)
158     assert_nothing_raised { res = @lint.call(env) }
159   end
161   def test_rack_lint_big_put
162     count = 100
163     bs = 0x10000
164     buf = (' ' * bs).freeze
165     length = bs * count
166     client = Tempfile.new('big_put')
167     def client.kgio_addr; '127.0.0.1'; end
168     def client.kgio_read(*args)
169       readpartial(*args)
170     rescue EOFError
171     end
172     def client.kgio_read!(*args)
173       readpartial(*args)
174     end
175     client.syswrite(
176       "PUT / HTTP/1.1\r\n" \
177       "Host: foo\r\n" \
178       "Content-Length: #{length}\r\n" \
179       "\r\n")
180     count.times { assert_equal bs, client.syswrite(buf) }
181     assert_equal 0, client.sysseek(0)
182     res = env = nil
183     assert_nothing_raised { env = @request.read(client) }
184     assert ! env.include?(:http_body)
185     assert_equal length, env['rack.input'].size
186     count.times {
187       tmp = env['rack.input'].read(bs)
188       tmp << env['rack.input'].read(bs - tmp.size) if tmp.size != bs
189       assert_equal buf, tmp
190     }
191     assert_nil env['rack.input'].read(bs)
192     assert_nothing_raised { env['rack.input'].rewind }
193     assert_nothing_raised { res = @lint.call(env) }
194   end