PageRenderTime 52ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/actionpack/test/dispatch/request_test.rb

http://github.com/rails/rails
Ruby | 1295 lines | 1129 code | 163 blank | 3 comment | 7 complexity | 67b5357bf39c972290e12d0ea1be9dab MD5 | raw file
  1. # frozen_string_literal: true
  2. require "abstract_unit"
  3. class BaseRequestTest < ActiveSupport::TestCase
  4. def setup
  5. @env = {
  6. :ip_spoofing_check => true,
  7. "rack.input" => "foo"
  8. }
  9. @original_tld_length = ActionDispatch::Http::URL.tld_length
  10. end
  11. def teardown
  12. ActionDispatch::Http::URL.tld_length = @original_tld_length
  13. end
  14. def url_for(options = {})
  15. options = { host: "www.example.com" }.merge!(options)
  16. ActionDispatch::Http::URL.url_for(options)
  17. end
  18. private
  19. def stub_request(env = {})
  20. ip_spoofing_check = env.key?(:ip_spoofing_check) ? env.delete(:ip_spoofing_check) : true
  21. @trusted_proxies ||= nil
  22. ip_app = ActionDispatch::RemoteIp.new(Proc.new { }, ip_spoofing_check, @trusted_proxies)
  23. ActionDispatch::Http::URL.tld_length = env.delete(:tld_length) if env.key?(:tld_length)
  24. ip_app.call(env)
  25. env = @env.merge(env)
  26. ActionDispatch::Request.new(env)
  27. end
  28. end
  29. class RequestUrlFor < BaseRequestTest
  30. test "url_for class method" do
  31. e = assert_raise(ArgumentError) { url_for(host: nil) }
  32. assert_match(/Please provide the :host parameter/, e.message)
  33. assert_equal "/books", url_for(only_path: true, path: "/books")
  34. assert_equal "http://www.example.com/books/?q=code", url_for(trailing_slash: true, path: "/books?q=code")
  35. assert_equal "http://www.example.com/books/?spareslashes=////", url_for(trailing_slash: true, path: "/books?spareslashes=////")
  36. assert_equal "http://www.example.com", url_for
  37. assert_equal "http://api.example.com", url_for(subdomain: "api")
  38. assert_equal "http://example.com", url_for(subdomain: false)
  39. assert_equal "http://www.ror.com", url_for(domain: "ror.com")
  40. assert_equal "http://api.ror.co.uk", url_for(host: "www.ror.co.uk", subdomain: "api", tld_length: 2)
  41. assert_equal "http://www.example.com:8080", url_for(port: 8080)
  42. assert_equal "https://www.example.com", url_for(protocol: "https")
  43. assert_equal "http://www.example.com/docs", url_for(path: "/docs")
  44. assert_equal "http://www.example.com#signup", url_for(anchor: "signup")
  45. assert_equal "http://www.example.com/", url_for(trailing_slash: true)
  46. assert_equal "http://dhh:supersecret@www.example.com", url_for(user: "dhh", password: "supersecret")
  47. assert_equal "http://www.example.com?search=books", url_for(params: { search: "books" })
  48. assert_equal "http://www.example.com?params=", url_for(params: "")
  49. assert_equal "http://www.example.com?params=1", url_for(params: 1)
  50. end
  51. end
  52. class RequestIP < BaseRequestTest
  53. test "remote ip" do
  54. request = stub_request "REMOTE_ADDR" => "1.2.3.4"
  55. assert_equal "1.2.3.4", request.remote_ip
  56. request = stub_request "REMOTE_ADDR" => "1.2.3.4,3.4.5.6"
  57. assert_equal "3.4.5.6", request.remote_ip
  58. request = stub_request "REMOTE_ADDR" => "1.2.3.4",
  59. "HTTP_X_FORWARDED_FOR" => "3.4.5.6"
  60. assert_equal "3.4.5.6", request.remote_ip
  61. request = stub_request "REMOTE_ADDR" => "127.0.0.1",
  62. "HTTP_X_FORWARDED_FOR" => "3.4.5.6"
  63. assert_equal "3.4.5.6", request.remote_ip
  64. request = stub_request "REMOTE_ADDR" => "127.0.0.1",
  65. "HTTP_X_FORWARDED_FOR" => "172.31.4.4, 10.0.0.1"
  66. assert_equal "172.31.4.4", request.remote_ip
  67. request = stub_request "HTTP_X_FORWARDED_FOR" => "3.4.5.6,unknown"
  68. assert_equal "3.4.5.6", request.remote_ip
  69. request = stub_request "HTTP_X_FORWARDED_FOR" => "3.4.5.6,172.16.0.1"
  70. assert_equal "3.4.5.6", request.remote_ip
  71. request = stub_request "HTTP_X_FORWARDED_FOR" => "3.4.5.6,192.168.0.1"
  72. assert_equal "3.4.5.6", request.remote_ip
  73. request = stub_request "HTTP_X_FORWARDED_FOR" => "3.4.5.6,10.0.0.1"
  74. assert_equal "3.4.5.6", request.remote_ip
  75. request = stub_request "HTTP_X_FORWARDED_FOR" => "172.31.4.4, 10.0.0.1"
  76. assert_equal "172.31.4.4", request.remote_ip
  77. request = stub_request "HTTP_X_FORWARDED_FOR" => "3.4.5.6, 10.0.0.1, 10.0.0.1"
  78. assert_equal "3.4.5.6", request.remote_ip
  79. request = stub_request "HTTP_X_FORWARDED_FOR" => "3.4.5.6,127.0.0.1"
  80. assert_equal "3.4.5.6", request.remote_ip
  81. request = stub_request "HTTP_X_FORWARDED_FOR" => "3.4.5.6:1234,127.0.0.1"
  82. assert_equal "3.4.5.6", request.remote_ip
  83. request = stub_request "HTTP_X_FORWARDED_FOR" => "unknown,192.168.0.1"
  84. assert_equal "192.168.0.1", request.remote_ip
  85. request = stub_request "HTTP_X_FORWARDED_FOR" => "9.9.9.9, 3.4.5.6, 172.31.4.4, 10.0.0.1"
  86. assert_equal "3.4.5.6", request.remote_ip
  87. request = stub_request "HTTP_X_FORWARDED_FOR" => "not_ip_address"
  88. assert_nil request.remote_ip
  89. request = stub_request "REMOTE_ADDR" => "1.2.3.4"
  90. assert_equal "1.2.3.4", request.remote_ip
  91. request.remote_ip = "2.3.4.5"
  92. assert_equal "2.3.4.5", request.remote_ip
  93. end
  94. test "remote ip spoof detection" do
  95. request = stub_request "HTTP_X_FORWARDED_FOR" => "1.1.1.1",
  96. "HTTP_CLIENT_IP" => "2.2.2.2"
  97. e = assert_raise(ActionDispatch::RemoteIp::IpSpoofAttackError) {
  98. request.remote_ip
  99. }
  100. assert_match(/IP spoofing attack/, e.message)
  101. assert_match(/HTTP_X_FORWARDED_FOR="1\.1\.1\.1"/, e.message)
  102. assert_match(/HTTP_CLIENT_IP="2\.2\.2\.2"/, e.message)
  103. end
  104. test "remote ip with spoof detection disabled" do
  105. request = stub_request "HTTP_X_FORWARDED_FOR" => "1.1.1.1",
  106. "HTTP_CLIENT_IP" => "2.2.2.2",
  107. :ip_spoofing_check => false
  108. assert_equal "1.1.1.1", request.remote_ip
  109. end
  110. test "remote ip spoof protection ignores private addresses" do
  111. request = stub_request "HTTP_X_FORWARDED_FOR" => "172.17.19.51",
  112. "HTTP_CLIENT_IP" => "172.17.19.51",
  113. "REMOTE_ADDR" => "1.1.1.1",
  114. "HTTP_X_BLUECOAT_VIA" => "de462e07a2db325e"
  115. assert_equal "1.1.1.1", request.remote_ip
  116. end
  117. test "remote ip v6" do
  118. request = stub_request "REMOTE_ADDR" => "2001:0db8:85a3:0000:0000:8a2e:0370:7334"
  119. assert_equal "2001:0db8:85a3:0000:0000:8a2e:0370:7334", request.remote_ip
  120. request = stub_request "REMOTE_ADDR" => "fe80:0000:0000:0000:0202:b3ff:fe1e:8329,2001:0db8:85a3:0000:0000:8a2e:0370:7334"
  121. assert_equal "2001:0db8:85a3:0000:0000:8a2e:0370:7334", request.remote_ip
  122. request = stub_request "REMOTE_ADDR" => "2001:0db8:85a3:0000:0000:8a2e:0370:7334",
  123. "HTTP_X_FORWARDED_FOR" => "fe80:0000:0000:0000:0202:b3ff:fe1e:8329"
  124. assert_equal "fe80:0000:0000:0000:0202:b3ff:fe1e:8329", request.remote_ip
  125. request = stub_request "REMOTE_ADDR" => "::1",
  126. "HTTP_X_FORWARDED_FOR" => "fe80:0000:0000:0000:0202:b3ff:fe1e:8329"
  127. assert_equal "fe80:0000:0000:0000:0202:b3ff:fe1e:8329", request.remote_ip
  128. request = stub_request "HTTP_X_FORWARDED_FOR" => "fe80:0000:0000:0000:0202:b3ff:fe1e:8329,unknown"
  129. assert_equal "fe80:0000:0000:0000:0202:b3ff:fe1e:8329", request.remote_ip
  130. request = stub_request "HTTP_X_FORWARDED_FOR" => "fe80:0000:0000:0000:0202:b3ff:fe1e:8329,::1"
  131. assert_equal "fe80:0000:0000:0000:0202:b3ff:fe1e:8329", request.remote_ip
  132. request = stub_request "HTTP_X_FORWARDED_FOR" => "fe80:0000:0000:0000:0202:b3ff:fe1e:8329, ::1, ::1"
  133. assert_equal "fe80:0000:0000:0000:0202:b3ff:fe1e:8329", request.remote_ip
  134. request = stub_request "HTTP_X_FORWARDED_FOR" => "unknown,::1"
  135. assert_equal "::1", request.remote_ip
  136. request = stub_request "HTTP_X_FORWARDED_FOR" => "2001:0db8:85a3:0000:0000:8a2e:0370:7334, fe80:0000:0000:0000:0202:b3ff:fe1e:8329, ::1, fc00::, fc01::, fdff"
  137. assert_equal "fe80:0000:0000:0000:0202:b3ff:fe1e:8329", request.remote_ip
  138. request = stub_request "HTTP_X_FORWARDED_FOR" => "FE00::, FDFF::"
  139. assert_equal "FE00::", request.remote_ip
  140. request = stub_request "HTTP_X_FORWARDED_FOR" => "not_ip_address"
  141. assert_nil request.remote_ip
  142. end
  143. test "remote ip v6 spoof detection" do
  144. request = stub_request "HTTP_X_FORWARDED_FOR" => "fe80:0000:0000:0000:0202:b3ff:fe1e:8329",
  145. "HTTP_CLIENT_IP" => "2001:0db8:85a3:0000:0000:8a2e:0370:7334"
  146. e = assert_raise(ActionDispatch::RemoteIp::IpSpoofAttackError) {
  147. request.remote_ip
  148. }
  149. assert_match(/IP spoofing attack/, e.message)
  150. assert_match(/HTTP_X_FORWARDED_FOR="fe80:0000:0000:0000:0202:b3ff:fe1e:8329"/, e.message)
  151. assert_match(/HTTP_CLIENT_IP="2001:0db8:85a3:0000:0000:8a2e:0370:7334"/, e.message)
  152. end
  153. test "remote ip v6 spoof detection disabled" do
  154. request = stub_request "HTTP_X_FORWARDED_FOR" => "fe80:0000:0000:0000:0202:b3ff:fe1e:8329",
  155. "HTTP_CLIENT_IP" => "2001:0db8:85a3:0000:0000:8a2e:0370:7334",
  156. :ip_spoofing_check => false
  157. assert_equal "fe80:0000:0000:0000:0202:b3ff:fe1e:8329", request.remote_ip
  158. end
  159. test "remote ip with user specified trusted proxies String" do
  160. @trusted_proxies = "67.205.106.73"
  161. request = stub_request "REMOTE_ADDR" => "3.4.5.6",
  162. "HTTP_X_FORWARDED_FOR" => "67.205.106.73"
  163. assert_equal "3.4.5.6", request.remote_ip
  164. request = stub_request "REMOTE_ADDR" => "172.16.0.1,67.205.106.73",
  165. "HTTP_X_FORWARDED_FOR" => "67.205.106.73"
  166. assert_equal "67.205.106.73", request.remote_ip
  167. request = stub_request "REMOTE_ADDR" => "67.205.106.73,3.4.5.6",
  168. "HTTP_X_FORWARDED_FOR" => "67.205.106.73"
  169. assert_equal "3.4.5.6", request.remote_ip
  170. request = stub_request "HTTP_X_FORWARDED_FOR" => "67.205.106.73,unknown"
  171. assert_equal "67.205.106.73", request.remote_ip # change
  172. request = stub_request "HTTP_X_FORWARDED_FOR" => "9.9.9.9, 3.4.5.6, 10.0.0.1, 67.205.106.73"
  173. assert_equal "3.4.5.6", request.remote_ip
  174. end
  175. test "remote ip v6 with user specified trusted proxies String" do
  176. @trusted_proxies = "fe80:0000:0000:0000:0202:b3ff:fe1e:8329"
  177. request = stub_request "REMOTE_ADDR" => "2001:0db8:85a3:0000:0000:8a2e:0370:7334",
  178. "HTTP_X_FORWARDED_FOR" => "fe80:0000:0000:0000:0202:b3ff:fe1e:8329"
  179. assert_equal "2001:0db8:85a3:0000:0000:8a2e:0370:7334", request.remote_ip
  180. request = stub_request "REMOTE_ADDR" => "fe80:0000:0000:0000:0202:b3ff:fe1e:8329,2001:0db8:85a3:0000:0000:8a2e:0370:7334",
  181. "HTTP_X_FORWARDED_FOR" => "fe80:0000:0000:0000:0202:b3ff:fe1e:8329"
  182. assert_equal "2001:0db8:85a3:0000:0000:8a2e:0370:7334", request.remote_ip
  183. request = stub_request "REMOTE_ADDR" => "fe80:0000:0000:0000:0202:b3ff:fe1e:8329,::1",
  184. "HTTP_X_FORWARDED_FOR" => "fe80:0000:0000:0000:0202:b3ff:fe1e:8329"
  185. assert_equal "fe80:0000:0000:0000:0202:b3ff:fe1e:8329", request.remote_ip
  186. request = stub_request "HTTP_X_FORWARDED_FOR" => "unknown,fe80:0000:0000:0000:0202:b3ff:fe1e:8329"
  187. assert_equal "fe80:0000:0000:0000:0202:b3ff:fe1e:8329", request.remote_ip
  188. request = stub_request "HTTP_X_FORWARDED_FOR" => "fe80:0000:0000:0000:0202:b3ff:fe1e:8329,2001:0db8:85a3:0000:0000:8a2e:0370:7334"
  189. assert_equal "2001:0db8:85a3:0000:0000:8a2e:0370:7334", request.remote_ip
  190. end
  191. test "remote ip with user specified trusted proxies Regexp" do
  192. @trusted_proxies = /^67\.205\.106\.73$/i
  193. request = stub_request "REMOTE_ADDR" => "67.205.106.73",
  194. "HTTP_X_FORWARDED_FOR" => "3.4.5.6"
  195. assert_equal "3.4.5.6", request.remote_ip
  196. request = stub_request "HTTP_X_FORWARDED_FOR" => "10.0.0.1, 9.9.9.9, 3.4.5.6, 67.205.106.73"
  197. assert_equal "3.4.5.6", request.remote_ip
  198. end
  199. test "remote ip v6 with user specified trusted proxies Regexp" do
  200. @trusted_proxies = /^fe80:0000:0000:0000:0202:b3ff:fe1e:8329$/i
  201. request = stub_request "REMOTE_ADDR" => "2001:0db8:85a3:0000:0000:8a2e:0370:7334",
  202. "HTTP_X_FORWARDED_FOR" => "fe80:0000:0000:0000:0202:b3ff:fe1e:8329"
  203. assert_equal "2001:0db8:85a3:0000:0000:8a2e:0370:7334", request.remote_ip
  204. request = stub_request "HTTP_X_FORWARDED_FOR" => "2001:0db8:85a3:0000:0000:8a2e:0370:7334, fe80:0000:0000:0000:0202:b3ff:fe1e:8329"
  205. assert_equal "2001:0db8:85a3:0000:0000:8a2e:0370:7334", request.remote_ip
  206. end
  207. test "remote ip middleware not present still returns an IP" do
  208. request = stub_request("REMOTE_ADDR" => "127.0.0.1")
  209. assert_equal "127.0.0.1", request.remote_ip
  210. end
  211. end
  212. class RequestDomain < BaseRequestTest
  213. test "domains" do
  214. request = stub_request "HTTP_HOST" => "192.168.1.200"
  215. assert_nil request.domain
  216. request = stub_request "HTTP_HOST" => "foo.192.168.1.200"
  217. assert_nil request.domain
  218. request = stub_request "HTTP_HOST" => "192.168.1.200.com"
  219. assert_equal "200.com", request.domain
  220. request = stub_request "HTTP_HOST" => "www.rubyonrails.org"
  221. assert_equal "rubyonrails.org", request.domain
  222. request = stub_request "HTTP_HOST" => "www.rubyonrails.co.uk"
  223. assert_equal "rubyonrails.co.uk", request.domain(2)
  224. request = stub_request "HTTP_HOST" => "www.rubyonrails.co.uk", :tld_length => 2
  225. assert_equal "rubyonrails.co.uk", request.domain
  226. end
  227. test "subdomains" do
  228. request = stub_request "HTTP_HOST" => "foobar.foobar.com"
  229. assert_equal %w( foobar ), request.subdomains
  230. assert_equal "foobar", request.subdomain
  231. request = stub_request "HTTP_HOST" => "192.168.1.200"
  232. assert_equal [], request.subdomains
  233. assert_equal "", request.subdomain
  234. request = stub_request "HTTP_HOST" => "foo.192.168.1.200"
  235. assert_equal [], request.subdomains
  236. assert_equal "", request.subdomain
  237. request = stub_request "HTTP_HOST" => "192.168.1.200.com"
  238. assert_equal %w( 192 168 1 ), request.subdomains
  239. assert_equal "192.168.1", request.subdomain
  240. request = stub_request "HTTP_HOST" => nil
  241. assert_equal [], request.subdomains
  242. assert_equal "", request.subdomain
  243. request = stub_request "HTTP_HOST" => "www.rubyonrails.org"
  244. assert_equal %w( www ), request.subdomains
  245. assert_equal "www", request.subdomain
  246. request = stub_request "HTTP_HOST" => "www.rubyonrails.co.uk"
  247. assert_equal %w( www ), request.subdomains(2)
  248. assert_equal "www", request.subdomain(2)
  249. request = stub_request "HTTP_HOST" => "dev.www.rubyonrails.co.uk"
  250. assert_equal %w( dev www ), request.subdomains(2)
  251. assert_equal "dev.www", request.subdomain(2)
  252. request = stub_request "HTTP_HOST" => "dev.www.rubyonrails.co.uk", :tld_length => 2
  253. assert_equal %w( dev www ), request.subdomains
  254. assert_equal "dev.www", request.subdomain
  255. end
  256. end
  257. class RequestPort < BaseRequestTest
  258. test "standard_port" do
  259. request = stub_request
  260. assert_equal 80, request.standard_port
  261. request = stub_request "HTTPS" => "on"
  262. assert_equal 443, request.standard_port
  263. end
  264. test "standard_port?" do
  265. request = stub_request
  266. assert_not_predicate request, :ssl?
  267. assert_predicate request, :standard_port?
  268. request = stub_request "HTTPS" => "on"
  269. assert_predicate request, :ssl?
  270. assert_predicate request, :standard_port?
  271. request = stub_request "HTTP_HOST" => "www.example.org:8080"
  272. assert_not_predicate request, :ssl?
  273. assert_not_predicate request, :standard_port?
  274. request = stub_request "HTTP_HOST" => "www.example.org:8443", "HTTPS" => "on"
  275. assert_predicate request, :ssl?
  276. assert_not_predicate request, :standard_port?
  277. end
  278. test "optional port" do
  279. request = stub_request "HTTP_HOST" => "www.example.org:80"
  280. assert_nil request.optional_port
  281. request = stub_request "HTTP_HOST" => "www.example.org:8080"
  282. assert_equal 8080, request.optional_port
  283. end
  284. test "port string" do
  285. request = stub_request "HTTP_HOST" => "www.example.org:80"
  286. assert_equal "", request.port_string
  287. request = stub_request "HTTP_HOST" => "www.example.org:8080"
  288. assert_equal ":8080", request.port_string
  289. end
  290. test "server port" do
  291. request = stub_request "SERVER_PORT" => "8080"
  292. assert_equal 8080, request.server_port
  293. request = stub_request "SERVER_PORT" => "80"
  294. assert_equal 80, request.server_port
  295. request = stub_request "SERVER_PORT" => ""
  296. assert_equal 0, request.server_port
  297. end
  298. end
  299. class RequestPath < BaseRequestTest
  300. test "full path" do
  301. request = stub_request "SCRIPT_NAME" => "", "PATH_INFO" => "/path/of/some/uri", "QUERY_STRING" => "mapped=1"
  302. assert_equal "/path/of/some/uri?mapped=1", request.fullpath
  303. assert_equal "/path/of/some/uri", request.path_info
  304. request = stub_request "SCRIPT_NAME" => "", "PATH_INFO" => "/path/of/some/uri"
  305. assert_equal "/path/of/some/uri", request.fullpath
  306. assert_equal "/path/of/some/uri", request.path_info
  307. request = stub_request "SCRIPT_NAME" => "", "PATH_INFO" => "/"
  308. assert_equal "/", request.fullpath
  309. assert_equal "/", request.path_info
  310. request = stub_request "SCRIPT_NAME" => "", "PATH_INFO" => "/", "QUERY_STRING" => "m=b"
  311. assert_equal "/?m=b", request.fullpath
  312. assert_equal "/", request.path_info
  313. request = stub_request "SCRIPT_NAME" => "/hieraki", "PATH_INFO" => "/"
  314. assert_equal "/hieraki/", request.fullpath
  315. assert_equal "/", request.path_info
  316. request = stub_request "SCRIPT_NAME" => "/collaboration/hieraki", "PATH_INFO" => "/books/edit/2"
  317. assert_equal "/collaboration/hieraki/books/edit/2", request.fullpath
  318. assert_equal "/books/edit/2", request.path_info
  319. request = stub_request "SCRIPT_NAME" => "/path", "PATH_INFO" => "/of/some/uri", "QUERY_STRING" => "mapped=1"
  320. assert_equal "/path/of/some/uri?mapped=1", request.fullpath
  321. assert_equal "/of/some/uri", request.path_info
  322. end
  323. test "original_fullpath returns ORIGINAL_FULLPATH" do
  324. request = stub_request("ORIGINAL_FULLPATH" => "/foo?bar")
  325. path = request.original_fullpath
  326. assert_equal "/foo?bar", path
  327. end
  328. test "original_url returns URL built using ORIGINAL_FULLPATH" do
  329. request = stub_request("ORIGINAL_FULLPATH" => "/foo?bar",
  330. "HTTP_HOST" => "example.org",
  331. "rack.url_scheme" => "http")
  332. url = request.original_url
  333. assert_equal "http://example.org/foo?bar", url
  334. end
  335. test "original_fullpath returns fullpath if ORIGINAL_FULLPATH is not present" do
  336. request = stub_request("PATH_INFO" => "/foo",
  337. "QUERY_STRING" => "bar")
  338. path = request.original_fullpath
  339. assert_equal "/foo?bar", path
  340. end
  341. end
  342. class RequestHost < BaseRequestTest
  343. test "host without specifying port" do
  344. request = stub_request "HTTP_HOST" => "rubyonrails.org"
  345. assert_equal "rubyonrails.org", request.host_with_port
  346. end
  347. test "host with default port" do
  348. request = stub_request "HTTP_HOST" => "rubyonrails.org:80"
  349. assert_equal "rubyonrails.org", request.host_with_port
  350. end
  351. test "host with non default port" do
  352. request = stub_request "HTTP_HOST" => "rubyonrails.org:81"
  353. assert_equal "rubyonrails.org:81", request.host_with_port
  354. end
  355. test "raw without specifying port" do
  356. request = stub_request "HTTP_HOST" => "rubyonrails.org"
  357. assert_equal "rubyonrails.org", request.raw_host_with_port
  358. end
  359. test "raw host with default port" do
  360. request = stub_request "HTTP_HOST" => "rubyonrails.org:80"
  361. assert_equal "rubyonrails.org:80", request.raw_host_with_port
  362. end
  363. test "raw host with non default port" do
  364. request = stub_request "HTTP_HOST" => "rubyonrails.org:81"
  365. assert_equal "rubyonrails.org:81", request.raw_host_with_port
  366. end
  367. test "proxy request" do
  368. request = stub_request "HTTP_HOST" => "glu.ttono.us:80"
  369. assert_equal "glu.ttono.us", request.host_with_port
  370. end
  371. test "http host" do
  372. request = stub_request "HTTP_HOST" => "rubyonrails.org:8080"
  373. assert_equal "rubyonrails.org", request.host
  374. assert_equal "rubyonrails.org:8080", request.host_with_port
  375. request = stub_request "HTTP_X_FORWARDED_HOST" => "www.firsthost.org, www.secondhost.org"
  376. assert_equal "www.secondhost.org", request.host
  377. request = stub_request "HTTP_X_FORWARDED_HOST" => "", "HTTP_HOST" => "rubyonrails.org"
  378. assert_equal "rubyonrails.org", request.host
  379. end
  380. test "http host with default port overrides server port" do
  381. request = stub_request "HTTP_HOST" => "rubyonrails.org"
  382. assert_equal "rubyonrails.org", request.host_with_port
  383. end
  384. test "host with port if http standard port is specified" do
  385. request = stub_request "HTTP_X_FORWARDED_HOST" => "glu.ttono.us:80"
  386. assert_equal "glu.ttono.us", request.host_with_port
  387. end
  388. test "host with port if https standard port is specified" do
  389. request = stub_request(
  390. "HTTP_X_FORWARDED_PROTO" => "https",
  391. "HTTP_X_FORWARDED_HOST" => "glu.ttono.us:443"
  392. )
  393. assert_equal "glu.ttono.us", request.host_with_port
  394. end
  395. test "host if ipv6 reference" do
  396. request = stub_request "HTTP_HOST" => "[2001:1234:5678:9abc:def0::dead:beef]"
  397. assert_equal "[2001:1234:5678:9abc:def0::dead:beef]", request.host
  398. end
  399. test "host if ipv6 reference with port" do
  400. request = stub_request "HTTP_HOST" => "[2001:1234:5678:9abc:def0::dead:beef]:8008"
  401. assert_equal "[2001:1234:5678:9abc:def0::dead:beef]", request.host
  402. end
  403. end
  404. class RequestCGI < BaseRequestTest
  405. test "CGI environment variables" do
  406. request = stub_request(
  407. "AUTH_TYPE" => "Basic",
  408. "GATEWAY_INTERFACE" => "CGI/1.1",
  409. "HTTP_ACCEPT" => "*/*",
  410. "HTTP_ACCEPT_CHARSET" => "UTF-8",
  411. "HTTP_ACCEPT_ENCODING" => "gzip, deflate",
  412. "HTTP_ACCEPT_LANGUAGE" => "en",
  413. "HTTP_CACHE_CONTROL" => "no-cache, max-age=0",
  414. "HTTP_FROM" => "googlebot",
  415. "HTTP_HOST" => "glu.ttono.us:8007",
  416. "HTTP_NEGOTIATE" => "trans",
  417. "HTTP_PRAGMA" => "no-cache",
  418. "HTTP_REFERER" => "http://www.google.com/search?q=glu.ttono.us",
  419. "HTTP_USER_AGENT" => "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en)",
  420. "PATH_INFO" => "/homepage/",
  421. "PATH_TRANSLATED" => "/home/kevinc/sites/typo/public/homepage/",
  422. "QUERY_STRING" => "",
  423. "REMOTE_ADDR" => "207.7.108.53",
  424. "REMOTE_HOST" => "google.com",
  425. "REMOTE_IDENT" => "kevin",
  426. "REMOTE_USER" => "kevin",
  427. "REQUEST_METHOD" => "GET",
  428. "SCRIPT_NAME" => "/dispatch.fcgi",
  429. "SERVER_NAME" => "glu.ttono.us",
  430. "SERVER_PORT" => "8007",
  431. "SERVER_PROTOCOL" => "HTTP/1.1",
  432. "SERVER_SOFTWARE" => "lighttpd/1.4.5",
  433. )
  434. assert_equal "Basic", request.auth_type
  435. assert_equal 0, request.content_length
  436. assert_nil request.content_mime_type
  437. assert_equal "CGI/1.1", request.gateway_interface
  438. assert_equal "*/*", request.accept
  439. assert_equal "UTF-8", request.accept_charset
  440. assert_equal "gzip, deflate", request.accept_encoding
  441. assert_equal "en", request.accept_language
  442. assert_equal "no-cache, max-age=0", request.cache_control
  443. assert_equal "googlebot", request.from
  444. assert_equal "glu.ttono.us", request.host
  445. assert_equal "trans", request.negotiate
  446. assert_equal "no-cache", request.pragma
  447. assert_equal "http://www.google.com/search?q=glu.ttono.us", request.referer
  448. assert_equal "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en)", request.user_agent
  449. assert_equal "/homepage/", request.path_info
  450. assert_equal "/home/kevinc/sites/typo/public/homepage/", request.path_translated
  451. assert_equal "", request.query_string
  452. assert_equal "207.7.108.53", request.remote_addr
  453. assert_equal "google.com", request.remote_host
  454. assert_equal "kevin", request.remote_ident
  455. assert_equal "kevin", request.remote_user
  456. assert_equal "GET", request.request_method
  457. assert_equal "/dispatch.fcgi", request.script_name
  458. assert_equal "glu.ttono.us", request.server_name
  459. assert_equal 8007, request.server_port
  460. assert_equal "HTTP/1.1", request.server_protocol
  461. assert_equal "lighttpd", request.server_software
  462. end
  463. end
  464. class LocalhostTest < BaseRequestTest
  465. test "IPs that match localhost" do
  466. request = stub_request("REMOTE_IP" => "127.1.1.1", "REMOTE_ADDR" => "127.1.1.1")
  467. assert_predicate request, :local?
  468. end
  469. end
  470. class RequestCookie < BaseRequestTest
  471. test "cookie syntax resilience" do
  472. request = stub_request("HTTP_COOKIE" => "_session_id=c84ace84796670c052c6ceb2451fb0f2; is_admin=yes")
  473. assert_equal "c84ace84796670c052c6ceb2451fb0f2", request.cookies["_session_id"], request.cookies.inspect
  474. assert_equal "yes", request.cookies["is_admin"], request.cookies.inspect
  475. end
  476. end
  477. class RequestParamsParsing < BaseRequestTest
  478. test "doesnt break when content type has charset" do
  479. request = stub_request(
  480. "REQUEST_METHOD" => "POST",
  481. "CONTENT_LENGTH" => "flamenco=love".length,
  482. "CONTENT_TYPE" => "application/x-www-form-urlencoded; charset=utf-8",
  483. "rack.input" => StringIO.new("flamenco=love")
  484. )
  485. assert_equal({ "flamenco" => "love" }, request.request_parameters)
  486. end
  487. test "doesnt interpret request uri as query string when missing" do
  488. request = stub_request("REQUEST_URI" => "foo")
  489. assert_equal({}, request.query_parameters)
  490. end
  491. end
  492. class RequestRewind < BaseRequestTest
  493. test "body should be rewound" do
  494. data = "rewind"
  495. env = {
  496. "rack.input" => StringIO.new(data),
  497. "CONTENT_LENGTH" => data.length,
  498. "CONTENT_TYPE" => "application/x-www-form-urlencoded; charset=utf-8"
  499. }
  500. # Read the request body by parsing params.
  501. request = stub_request(env)
  502. request.request_parameters
  503. # Should have rewound the body.
  504. assert_equal 0, request.body.pos
  505. end
  506. test "raw_post rewinds rack.input if RAW_POST_DATA is nil" do
  507. request = stub_request(
  508. "rack.input" => StringIO.new("raw"),
  509. "CONTENT_LENGTH" => 3
  510. )
  511. assert_equal "raw", request.raw_post
  512. assert_equal "raw", request.env["rack.input"].read
  513. end
  514. end
  515. class RequestProtocol < BaseRequestTest
  516. test "server software" do
  517. assert_equal "lighttpd", stub_request("SERVER_SOFTWARE" => "lighttpd/1.4.5").server_software
  518. assert_equal "apache", stub_request("SERVER_SOFTWARE" => "Apache3.422").server_software
  519. end
  520. test "xml http request" do
  521. request = stub_request
  522. assert_not_predicate request, :xml_http_request?
  523. assert_not_predicate request, :xhr?
  524. request = stub_request "HTTP_X_REQUESTED_WITH" => "DefinitelyNotAjax1.0"
  525. assert_not_predicate request, :xml_http_request?
  526. assert_not_predicate request, :xhr?
  527. request = stub_request "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest"
  528. assert_predicate request, :xml_http_request?
  529. assert_predicate request, :xhr?
  530. end
  531. test "reports ssl" do
  532. assert_not_predicate stub_request, :ssl?
  533. assert_predicate stub_request("HTTPS" => "on"), :ssl?
  534. end
  535. test "reports ssl when proxied via lighttpd" do
  536. assert_predicate stub_request("HTTP_X_FORWARDED_PROTO" => "https"), :ssl?
  537. end
  538. test "scheme returns https when proxied" do
  539. request = stub_request "rack.url_scheme" => "http"
  540. assert_not_predicate request, :ssl?
  541. assert_equal "http", request.scheme
  542. request = stub_request(
  543. "rack.url_scheme" => "http",
  544. "HTTP_X_FORWARDED_PROTO" => "https"
  545. )
  546. assert_predicate request, :ssl?
  547. assert_equal "https", request.scheme
  548. end
  549. end
  550. class RequestMethod < BaseRequestTest
  551. test "method returns environment's request method when it has not been
  552. overridden by middleware".squish do
  553. ActionDispatch::Request::HTTP_METHODS.each do |method|
  554. request = stub_request("REQUEST_METHOD" => method)
  555. assert_equal method, request.method
  556. assert_equal method.underscore.to_sym, request.method_symbol
  557. end
  558. end
  559. test "allow request method hacking" do
  560. request = stub_request("REQUEST_METHOD" => "POST")
  561. assert_equal "POST", request.request_method
  562. assert_equal "POST", request.env["REQUEST_METHOD"]
  563. request.request_method = "GET"
  564. assert_equal "GET", request.request_method
  565. assert_equal "GET", request.env["REQUEST_METHOD"]
  566. assert_predicate request, :get?
  567. end
  568. test "invalid http method raises exception" do
  569. assert_raise(ActionController::UnknownHttpMethod) do
  570. stub_request("REQUEST_METHOD" => "RANDOM_METHOD").request_method
  571. end
  572. end
  573. test "method returns original value of environment request method on POST" do
  574. request = stub_request("rack.methodoverride.original_method" => "POST")
  575. assert_equal "POST", request.method
  576. end
  577. test "method raises exception on invalid HTTP method" do
  578. assert_raise(ActionController::UnknownHttpMethod) do
  579. stub_request("rack.methodoverride.original_method" => "_RANDOM_METHOD").method
  580. end
  581. assert_raise(ActionController::UnknownHttpMethod) do
  582. stub_request("REQUEST_METHOD" => "_RANDOM_METHOD").method
  583. end
  584. end
  585. test "exception on invalid HTTP method unaffected by I18n settings" do
  586. old_locales = I18n.available_locales
  587. old_enforce = I18n.config.enforce_available_locales
  588. begin
  589. I18n.available_locales = [:nl]
  590. I18n.config.enforce_available_locales = true
  591. assert_raise(ActionController::UnknownHttpMethod) do
  592. stub_request("REQUEST_METHOD" => "_RANDOM_METHOD").method
  593. end
  594. ensure
  595. I18n.available_locales = old_locales
  596. I18n.config.enforce_available_locales = old_enforce
  597. end
  598. end
  599. test "post masquerading as patch" do
  600. request = stub_request(
  601. "REQUEST_METHOD" => "PATCH",
  602. "rack.methodoverride.original_method" => "POST"
  603. )
  604. assert_equal "POST", request.method
  605. assert_equal "PATCH", request.request_method
  606. assert_predicate request, :patch?
  607. end
  608. test "post masquerading as put" do
  609. request = stub_request(
  610. "REQUEST_METHOD" => "PUT",
  611. "rack.methodoverride.original_method" => "POST"
  612. )
  613. assert_equal "POST", request.method
  614. assert_equal "PUT", request.request_method
  615. assert_predicate request, :put?
  616. end
  617. test "post uneffected by local inflections" do
  618. existing_acronyms = ActiveSupport::Inflector.inflections.acronyms.dup
  619. begin
  620. ActiveSupport::Inflector.inflections do |inflect|
  621. inflect.acronym "POS"
  622. end
  623. assert_equal "pos_t", "POST".underscore
  624. request = stub_request "REQUEST_METHOD" => "POST"
  625. assert_equal :post, ActionDispatch::Request::HTTP_METHOD_LOOKUP["POST"]
  626. assert_equal :post, request.method_symbol
  627. assert_predicate request, :post?
  628. ensure
  629. # Reset original acronym set
  630. ActiveSupport::Inflector.inflections do |inflect|
  631. inflect.send(:instance_variable_set, "@acronyms", existing_acronyms)
  632. inflect.send(:define_acronym_regex_patterns)
  633. end
  634. end
  635. end
  636. end
  637. class RequestFormat < BaseRequestTest
  638. test "xml format" do
  639. request = stub_request "QUERY_STRING" => "format=xml"
  640. assert_equal Mime[:xml], request.format
  641. end
  642. test "xhtml format" do
  643. request = stub_request "QUERY_STRING" => "format=xhtml"
  644. assert_equal Mime[:html], request.format
  645. end
  646. test "txt format" do
  647. request = stub_request "QUERY_STRING" => "format=txt"
  648. assert_equal Mime[:text], request.format
  649. end
  650. test "XMLHttpRequest" do
  651. request = stub_request(
  652. "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest",
  653. "HTTP_ACCEPT" => [Mime[:js], Mime[:html], Mime[:xml], "text/xml", "*/*"].join(","),
  654. "QUERY_STRING" => ""
  655. )
  656. assert_predicate request, :xhr?
  657. assert_equal Mime[:js], request.format
  658. end
  659. test "can override format with parameter negative" do
  660. request = stub_request("QUERY_STRING" => "format=txt")
  661. assert_not_predicate request.format, :xml?
  662. end
  663. test "can override format with parameter positive" do
  664. request = stub_request("QUERY_STRING" => "format=xml")
  665. assert_predicate request.format, :xml?
  666. end
  667. test "formats text/html with accept header" do
  668. request = stub_request "HTTP_ACCEPT" => "text/html"
  669. assert_equal [Mime[:html]], request.formats
  670. end
  671. test "formats blank with accept header" do
  672. request = stub_request "HTTP_ACCEPT" => ""
  673. assert_equal [Mime[:html]], request.formats
  674. end
  675. test "formats XMLHttpRequest with accept header" do
  676. request = stub_request "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest"
  677. assert_equal [Mime[:js]], request.formats
  678. end
  679. test "formats application/xml with accept header" do
  680. request = stub_request("CONTENT_TYPE" => "application/xml; charset=UTF-8",
  681. "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest")
  682. assert_equal [Mime[:xml]], request.formats
  683. end
  684. test "formats format:text with accept header" do
  685. request = stub_request("QUERY_STRING" => "format=txt")
  686. assert_equal [Mime[:text]], request.formats
  687. end
  688. test "formats format:unknown with accept header" do
  689. request = stub_request("QUERY_STRING" => "format=unknown")
  690. assert_instance_of Mime::NullType, request.format
  691. end
  692. test "format is not nil with unknown format" do
  693. request = stub_request("QUERY_STRING" => "format=hello")
  694. assert_nil request.format
  695. assert_not_predicate request.format, :html?
  696. assert_not_predicate request.format, :xml?
  697. assert_not_predicate request.format, :json?
  698. end
  699. test "format does not throw exceptions when malformed GET parameters" do
  700. request = stub_request("QUERY_STRING" => "x[y]=1&x[y][][w]=2")
  701. assert request.formats
  702. assert_predicate request.format, :html?
  703. end
  704. test "format does not throw exceptions when invalid POST parameters" do
  705. body = "{record:{content:127.0.0.1}}"
  706. request = stub_request(
  707. "REQUEST_METHOD" => "POST",
  708. "CONTENT_LENGTH" => body.length,
  709. "CONTENT_TYPE" => "application/json",
  710. "rack.input" => StringIO.new(body),
  711. "action_dispatch.logger" => Logger.new(output = StringIO.new)
  712. )
  713. assert request.formats
  714. assert request.format.html?
  715. output.rewind && (err = output.read)
  716. assert_match(/Error occurred while parsing request parameters/, err)
  717. end
  718. test "formats with xhr request" do
  719. request = stub_request "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest",
  720. "QUERY_STRING" => ""
  721. assert_equal [Mime[:js]], request.formats
  722. end
  723. test "ignore_accept_header" do
  724. old_ignore_accept_header = ActionDispatch::Request.ignore_accept_header
  725. ActionDispatch::Request.ignore_accept_header = true
  726. begin
  727. request = stub_request "HTTP_ACCEPT" => "application/xml",
  728. "QUERY_STRING" => ""
  729. assert_equal [ Mime[:html] ], request.formats
  730. request = stub_request "HTTP_ACCEPT" => "koz-asked/something-crazy",
  731. "QUERY_STRING" => ""
  732. assert_equal [ Mime[:html] ], request.formats
  733. request = stub_request "HTTP_ACCEPT" => "*/*;q=0.1",
  734. "QUERY_STRING" => ""
  735. assert_equal [ Mime[:html] ], request.formats
  736. request = stub_request "HTTP_ACCEPT" => "application/jxw",
  737. "QUERY_STRING" => ""
  738. assert_equal [ Mime[:html] ], request.formats
  739. request = stub_request "HTTP_ACCEPT" => "application/xml",
  740. "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest",
  741. "QUERY_STRING" => ""
  742. assert_equal [ Mime[:js] ], request.formats
  743. request = stub_request "HTTP_ACCEPT" => "application/xml",
  744. "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest",
  745. "QUERY_STRING" => "format=json"
  746. assert_equal [ Mime[:json] ], request.formats
  747. ensure
  748. ActionDispatch::Request.ignore_accept_header = old_ignore_accept_header
  749. end
  750. end
  751. test "format taken from the path extension" do
  752. request = stub_request "PATH_INFO" => "/foo.xml", "QUERY_STRING" => ""
  753. assert_equal [Mime[:xml]], request.formats
  754. request = stub_request "PATH_INFO" => "/foo.123", "QUERY_STRING" => ""
  755. assert_equal [Mime[:html]], request.formats
  756. end
  757. test "formats from accept headers have higher precedence than path extension" do
  758. request = stub_request "HTTP_ACCEPT" => "application/json",
  759. "PATH_INFO" => "/foo.xml",
  760. "QUERY_STRING" => ""
  761. assert_equal [Mime[:json]], request.formats
  762. end
  763. end
  764. class RequestMimeType < BaseRequestTest
  765. test "content type" do
  766. assert_equal Mime[:html], stub_request("CONTENT_TYPE" => "text/html").content_mime_type
  767. end
  768. test "no content type" do
  769. assert_nil stub_request.content_mime_type
  770. end
  771. test "content type is XML" do
  772. assert_equal Mime[:xml], stub_request("CONTENT_TYPE" => "application/xml").content_mime_type
  773. end
  774. test "content type with charset" do
  775. assert_equal Mime[:xml], stub_request("CONTENT_TYPE" => "application/xml; charset=UTF-8").content_mime_type
  776. end
  777. test "user agent" do
  778. assert_equal "TestAgent", stub_request("HTTP_USER_AGENT" => "TestAgent").user_agent
  779. end
  780. test "negotiate_mime" do
  781. request = stub_request(
  782. "HTTP_ACCEPT" => "text/html",
  783. "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest"
  784. )
  785. assert_nil request.negotiate_mime([Mime[:xml], Mime[:json]])
  786. assert_equal Mime[:html], request.negotiate_mime([Mime[:xml], Mime[:html]])
  787. assert_equal Mime[:html], request.negotiate_mime([Mime[:xml], Mime::ALL])
  788. end
  789. test "negotiate_mime with content_type" do
  790. request = stub_request(
  791. "CONTENT_TYPE" => "application/xml; charset=UTF-8",
  792. "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest"
  793. )
  794. assert_equal Mime[:xml], request.negotiate_mime([Mime[:xml], Mime[:csv]])
  795. end
  796. end
  797. class RequestParameters < BaseRequestTest
  798. test "parameters" do
  799. request = stub_request "CONTENT_TYPE" => "application/json",
  800. "CONTENT_LENGTH" => 9,
  801. "RAW_POST_DATA" => '{"foo":1}',
  802. "QUERY_STRING" => "bar=2"
  803. assert_equal({ "foo" => 1, "bar" => "2" }, request.parameters)
  804. assert_equal({ "foo" => 1 }, request.request_parameters)
  805. assert_equal({ "bar" => "2" }, request.query_parameters)
  806. end
  807. test "parameters not accessible after rack parse error" do
  808. request = stub_request("QUERY_STRING" => "x[y]=1&x[y][][w]=2")
  809. 2.times do
  810. assert_raises(ActionController::BadRequest) do
  811. # rack will raise a Rack::Utils::ParameterTypeError when parsing this query string
  812. request.parameters
  813. end
  814. end
  815. end
  816. test "path parameters with invalid UTF8 encoding" do
  817. request = stub_request
  818. err = assert_raises(ActionController::BadRequest) do
  819. request.path_parameters = { foo: "\xBE" }
  820. end
  821. assert_predicate err.message, :valid_encoding?
  822. assert_equal "Invalid path parameters: Invalid encoding for parameter: �", err.message
  823. end
  824. test "parameters not accessible after rack parse error of invalid UTF8 character" do
  825. request = stub_request("QUERY_STRING" => "foo%81E=1")
  826. assert_raises(ActionController::BadRequest) { request.parameters }
  827. end
  828. test "parameters containing an invalid UTF8 character" do
  829. request = stub_request("QUERY_STRING" => "foo=%81E")
  830. assert_raises(ActionController::BadRequest) { request.parameters }
  831. end
  832. test "parameters containing a deeply nested invalid UTF8 character" do
  833. request = stub_request("QUERY_STRING" => "foo[bar]=%81E")
  834. assert_raises(ActionController::BadRequest) { request.parameters }
  835. end
  836. test "parameters not accessible after rack parse error 1" do
  837. request = stub_request(
  838. "REQUEST_METHOD" => "POST",
  839. "CONTENT_LENGTH" => "a%=".length,
  840. "CONTENT_TYPE" => "application/x-www-form-urlencoded; charset=utf-8",
  841. "rack.input" => StringIO.new("a%=")
  842. )
  843. assert_raises(ActionController::BadRequest) do
  844. # rack will raise a Rack::Utils::ParameterTypeError when parsing this query string
  845. request.parameters
  846. end
  847. end
  848. test "we have access to the original exception" do
  849. request = stub_request("QUERY_STRING" => "x[y]=1&x[y][][w]=2")
  850. e = assert_raises(ActionController::BadRequest) do
  851. # rack will raise a Rack::Utils::ParameterTypeError when parsing this query string
  852. request.parameters
  853. end
  854. assert_not_nil e.cause
  855. assert_equal e.cause.backtrace, e.backtrace
  856. end
  857. end
  858. class RequestParameterFilter < BaseRequestTest
  859. test "parameter filter is deprecated" do
  860. assert_deprecated do
  861. ActionDispatch::Http::ParameterFilter.new(["blah"])
  862. end
  863. end
  864. test "filtered_parameters returns params filtered" do
  865. request = stub_request(
  866. "action_dispatch.request.parameters" => {
  867. "lifo" => "Pratik",
  868. "amount" => "420",
  869. "step" => "1"
  870. },
  871. "action_dispatch.parameter_filter" => [:lifo, :amount]
  872. )
  873. params = request.filtered_parameters
  874. assert_equal "[FILTERED]", params["lifo"]
  875. assert_equal "[FILTERED]", params["amount"]
  876. assert_equal "1", params["step"]
  877. end
  878. test "filtered_env filters env as a whole" do
  879. request = stub_request(
  880. "action_dispatch.request.parameters" => {
  881. "amount" => "420",
  882. "step" => "1"
  883. },
  884. "RAW_POST_DATA" => "yada yada",
  885. "action_dispatch.parameter_filter" => [:lifo, :amount]
  886. )
  887. request = stub_request(request.filtered_env)
  888. assert_equal "[FILTERED]", request.raw_post
  889. assert_equal "[FILTERED]", request.params["amount"]
  890. assert_equal "1", request.params["step"]
  891. end
  892. test "filtered_path returns path with filtered query string" do
  893. %w(; &).each do |sep|
  894. request = stub_request(
  895. "QUERY_STRING" => %w(username=sikachu secret=bd4f21f api_key=b1bc3b3cd352f68d79d7).join(sep),
  896. "PATH_INFO" => "/authenticate",
  897. "action_dispatch.parameter_filter" => [:secret, :api_key]
  898. )
  899. path = request.filtered_path
  900. assert_equal %w(/authenticate?username=sikachu secret=[FILTERED] api_key=[FILTERED]).join(sep), path
  901. end
  902. end
  903. test "filtered_path should not unescape a genuine '[FILTERED]' value" do
  904. request = stub_request(
  905. "QUERY_STRING" => "secret=bd4f21f&genuine=%5BFILTERED%5D",
  906. "PATH_INFO" => "/authenticate",
  907. "action_dispatch.parameter_filter" => [:secret]
  908. )
  909. path = request.filtered_path
  910. assert_equal request.script_name + "/authenticate?secret=[FILTERED]&genuine=%5BFILTERED%5D", path
  911. end
  912. test "filtered_path should preserve duplication of keys in query string" do
  913. request = stub_request(
  914. "QUERY_STRING" => "username=sikachu&secret=bd4f21f&username=fxn",
  915. "PATH_INFO" => "/authenticate",
  916. "action_dispatch.parameter_filter" => [:secret]
  917. )
  918. path = request.filtered_path
  919. assert_equal request.script_name + "/authenticate?username=sikachu&secret=[FILTERED]&username=fxn", path
  920. end
  921. test "filtered_path should ignore searchparts" do
  922. request = stub_request(
  923. "QUERY_STRING" => "secret",
  924. "PATH_INFO" => "/authenticate",
  925. "action_dispatch.parameter_filter" => [:secret]
  926. )
  927. path = request.filtered_path
  928. assert_equal request.script_name + "/authenticate?secret", path
  929. end
  930. end
  931. class RequestEtag < BaseRequestTest
  932. test "always matches *" do
  933. request = stub_request("HTTP_IF_NONE_MATCH" => "*")
  934. assert_equal "*", request.if_none_match
  935. assert_equal ["*"], request.if_none_match_etags
  936. assert request.etag_matches?('"strong"')
  937. assert request.etag_matches?('W/"weak"')
  938. assert_not request.etag_matches?(nil)
  939. end
  940. test "doesn't match absent If-None-Match" do
  941. request = stub_request
  942. assert_nil request.if_none_match
  943. assert_equal [], request.if_none_match_etags
  944. assert_not request.etag_matches?("foo")
  945. assert_not request.etag_matches?(nil)
  946. end
  947. test "matches opaque ETag validators without unquoting" do
  948. header = '"the-etag"'
  949. request = stub_request("HTTP_IF_NONE_MATCH" => header)
  950. assert_equal header, request.if_none_match
  951. assert_equal ['"the-etag"'], request.if_none_match_etags
  952. assert request.etag_matches?('"the-etag"')
  953. assert_not request.etag_matches?("the-etag")
  954. end
  955. test "if_none_match_etags multiple" do
  956. header = 'etag1, etag2, "third etag", "etag4"'
  957. expected = ["etag1", "etag2", '"third etag"', '"etag4"']
  958. request = stub_request("HTTP_IF_NONE_MATCH" => header)
  959. assert_equal header, request.if_none_match
  960. assert_equal expected, request.if_none_match_etags
  961. expected.each do |etag|
  962. assert request.etag_matches?(etag), etag
  963. end
  964. end
  965. end
  966. class RequestVariant < BaseRequestTest
  967. def setup
  968. super
  969. @request = stub_request
  970. end
  971. test "setting variant to a symbol" do
  972. @request.variant = :phone
  973. assert_predicate @request.variant, :phone?
  974. assert_not_predicate @request.variant, :tablet?
  975. assert @request.variant.any?(:phone, :tablet)
  976. assert_not @request.variant.any?(:tablet, :desktop)
  977. end
  978. test "setting variant to an array of symbols" do
  979. @request.variant = [:phone, :tablet]
  980. assert_predicate @request.variant, :phone?
  981. assert_predicate @request.variant, :tablet?
  982. assert_not_predicate @request.variant, :desktop?
  983. assert @request.variant.any?(:tablet, :desktop)
  984. assert_not @request.variant.any?(:desktop, :watch)
  985. end
  986. test "clearing variant" do
  987. @request.variant = nil
  988. assert_empty @request.variant
  989. assert_not_predicate @request.variant, :phone?
  990. assert_not @request.variant.any?(:phone, :tablet)
  991. end
  992. test "setting variant to a non-symbol value" do
  993. assert_raise ArgumentError do
  994. @request.variant = "phone"
  995. end
  996. end
  997. test "setting variant to an array containing a non-symbol value" do
  998. assert_raise ArgumentError do
  999. @request.variant = [:phone, "tablet"]
  1000. end
  1001. end
  1002. end
  1003. class RequestFormData < BaseRequestTest
  1004. test "media_type is from the FORM_DATA_MEDIA_TYPES array" do
  1005. assert_predicate stub_request("CONTENT_TYPE" => "application/x-www-form-urlencoded"), :form_data?
  1006. assert_predicate stub_request("CONTENT_TYPE" => "multipart/form-data"), :form_data?
  1007. end
  1008. test "media_type is not from the FORM_DATA_MEDIA_TYPES array" do
  1009. assert_not_predicate stub_request("CONTENT_TYPE" => "application/xml"), :form_data?
  1010. assert_not_predicate stub_request("CONTENT_TYPE" => "multipart/related"), :form_data?
  1011. end
  1012. test "no Content-Type header is provided and the request_method is POST" do
  1013. request = stub_request("REQUEST_METHOD" => "POST")
  1014. assert_equal "", request.media_type
  1015. assert_equal "POST", request.request_method
  1016. assert_not_predicate request, :form_data?
  1017. end
  1018. end
  1019. class EarlyHintsRequestTest < BaseRequestTest
  1020. def setup
  1021. super
  1022. @env["rack.early_hints"] = lambda { |links| links }
  1023. @request = stub_request
  1024. end
  1025. test "when early hints is set in the env link headers are sent" do
  1026. early_hints = @request.send_early_hints("Link" => "</style.css>; rel=preload; as=style\n</script.js>; rel=preload")
  1027. expected_hints = { "Link" => "</style.css>; rel=preload; as=style\n</script.js>; rel=preload" }
  1028. assert_equal expected_hints, early_hints
  1029. end
  1030. end