PageRenderTime 44ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/actionpack/test/controller/request_test.rb

https://github.com/cardmagic/rails
Ruby | 891 lines | 781 code | 108 blank | 2 comment | 3 complexity | b26015d9fdcd02034d24b74aa4f1496e MD5 | raw file
  1. require 'abstract_unit'
  2. require 'action_controller/integration'
  3. class RequestTest < Test::Unit::TestCase
  4. def setup
  5. ActionController::Base.relative_url_root = nil
  6. @request = ActionController::TestRequest.new
  7. end
  8. def teardown
  9. ActionController::Base.relative_url_root = nil
  10. end
  11. def test_remote_ip
  12. assert_equal '0.0.0.0', @request.remote_ip
  13. @request.remote_addr = '1.2.3.4'
  14. assert_equal '1.2.3.4', @request.remote_ip(true)
  15. @request.remote_addr = '1.2.3.4,3.4.5.6'
  16. assert_equal '1.2.3.4', @request.remote_ip(true)
  17. @request.env['HTTP_CLIENT_IP'] = '2.3.4.5'
  18. assert_equal '1.2.3.4', @request.remote_ip(true)
  19. @request.remote_addr = '192.168.0.1'
  20. assert_equal '2.3.4.5', @request.remote_ip(true)
  21. @request.env.delete 'HTTP_CLIENT_IP'
  22. @request.remote_addr = '1.2.3.4'
  23. @request.env['HTTP_X_FORWARDED_FOR'] = '3.4.5.6'
  24. assert_equal '1.2.3.4', @request.remote_ip(true)
  25. @request.remote_addr = '127.0.0.1'
  26. @request.env['HTTP_X_FORWARDED_FOR'] = '3.4.5.6'
  27. assert_equal '3.4.5.6', @request.remote_ip(true)
  28. @request.env['HTTP_X_FORWARDED_FOR'] = 'unknown,3.4.5.6'
  29. assert_equal '3.4.5.6', @request.remote_ip(true)
  30. @request.env['HTTP_X_FORWARDED_FOR'] = '172.16.0.1,3.4.5.6'
  31. assert_equal '3.4.5.6', @request.remote_ip(true)
  32. @request.env['HTTP_X_FORWARDED_FOR'] = '192.168.0.1,3.4.5.6'
  33. assert_equal '3.4.5.6', @request.remote_ip(true)
  34. @request.env['HTTP_X_FORWARDED_FOR'] = '10.0.0.1,3.4.5.6'
  35. assert_equal '3.4.5.6', @request.remote_ip(true)
  36. @request.env['HTTP_X_FORWARDED_FOR'] = '10.0.0.1, 10.0.0.1, 3.4.5.6'
  37. assert_equal '3.4.5.6', @request.remote_ip(true)
  38. @request.env['HTTP_X_FORWARDED_FOR'] = '127.0.0.1,3.4.5.6'
  39. assert_equal '3.4.5.6', @request.remote_ip(true)
  40. @request.env['HTTP_X_FORWARDED_FOR'] = 'unknown,192.168.0.1'
  41. assert_equal 'unknown', @request.remote_ip(true)
  42. @request.env['HTTP_X_FORWARDED_FOR'] = '9.9.9.9, 3.4.5.6, 10.0.0.1, 172.31.4.4'
  43. assert_equal '3.4.5.6', @request.remote_ip(true)
  44. @request.env['HTTP_CLIENT_IP'] = '8.8.8.8'
  45. e = assert_raises(ActionController::ActionControllerError) {
  46. @request.remote_ip(true)
  47. }
  48. assert_match /IP spoofing attack/, e.message
  49. assert_match /HTTP_X_FORWARDED_FOR="9.9.9.9, 3.4.5.6, 10.0.0.1, 172.31.4.4"/, e.message
  50. assert_match /HTTP_CLIENT_IP="8.8.8.8"/, e.message
  51. @request.env['HTTP_X_FORWARDED_FOR'] = '8.8.8.8, 9.9.9.9'
  52. assert_equal '8.8.8.8', @request.remote_ip(true)
  53. @request.env.delete 'HTTP_CLIENT_IP'
  54. @request.env.delete 'HTTP_X_FORWARDED_FOR'
  55. end
  56. def test_domains
  57. @request.host = "www.rubyonrails.org"
  58. assert_equal "rubyonrails.org", @request.domain
  59. @request.host = "www.rubyonrails.co.uk"
  60. assert_equal "rubyonrails.co.uk", @request.domain(2)
  61. @request.host = "192.168.1.200"
  62. assert_nil @request.domain
  63. @request.host = "foo.192.168.1.200"
  64. assert_nil @request.domain
  65. @request.host = "192.168.1.200.com"
  66. assert_equal "200.com", @request.domain
  67. @request.host = nil
  68. assert_nil @request.domain
  69. end
  70. def test_subdomains
  71. @request.host = "www.rubyonrails.org"
  72. assert_equal %w( www ), @request.subdomains
  73. @request.host = "www.rubyonrails.co.uk"
  74. assert_equal %w( www ), @request.subdomains(2)
  75. @request.host = "dev.www.rubyonrails.co.uk"
  76. assert_equal %w( dev www ), @request.subdomains(2)
  77. @request.host = "foobar.foobar.com"
  78. assert_equal %w( foobar ), @request.subdomains
  79. @request.host = "192.168.1.200"
  80. assert_equal [], @request.subdomains
  81. @request.host = "foo.192.168.1.200"
  82. assert_equal [], @request.subdomains
  83. @request.host = "192.168.1.200.com"
  84. assert_equal %w( 192 168 1 ), @request.subdomains
  85. @request.host = nil
  86. assert_equal [], @request.subdomains
  87. end
  88. def test_port_string
  89. @request.port = 80
  90. assert_equal "", @request.port_string
  91. @request.port = 8080
  92. assert_equal ":8080", @request.port_string
  93. end
  94. def test_request_uri
  95. @request.env['SERVER_SOFTWARE'] = 'Apache 42.342.3432'
  96. @request.set_REQUEST_URI "http://www.rubyonrails.org/path/of/some/uri?mapped=1"
  97. assert_equal "/path/of/some/uri?mapped=1", @request.request_uri
  98. assert_equal "/path/of/some/uri", @request.path
  99. @request.set_REQUEST_URI "http://www.rubyonrails.org/path/of/some/uri"
  100. assert_equal "/path/of/some/uri", @request.request_uri
  101. assert_equal "/path/of/some/uri", @request.path
  102. @request.set_REQUEST_URI "/path/of/some/uri"
  103. assert_equal "/path/of/some/uri", @request.request_uri
  104. assert_equal "/path/of/some/uri", @request.path
  105. @request.set_REQUEST_URI "/"
  106. assert_equal "/", @request.request_uri
  107. assert_equal "/", @request.path
  108. @request.set_REQUEST_URI "/?m=b"
  109. assert_equal "/?m=b", @request.request_uri
  110. assert_equal "/", @request.path
  111. @request.set_REQUEST_URI "/"
  112. @request.env['SCRIPT_NAME'] = "/dispatch.cgi"
  113. assert_equal "/", @request.request_uri
  114. assert_equal "/", @request.path
  115. ActionController::Base.relative_url_root = "/hieraki"
  116. @request.set_REQUEST_URI "/hieraki/"
  117. @request.env['SCRIPT_NAME'] = "/hieraki/dispatch.cgi"
  118. assert_equal "/hieraki/", @request.request_uri
  119. assert_equal "/", @request.path
  120. ActionController::Base.relative_url_root = nil
  121. ActionController::Base.relative_url_root = "/collaboration/hieraki"
  122. @request.set_REQUEST_URI "/collaboration/hieraki/books/edit/2"
  123. @request.env['SCRIPT_NAME'] = "/collaboration/hieraki/dispatch.cgi"
  124. assert_equal "/collaboration/hieraki/books/edit/2", @request.request_uri
  125. assert_equal "/books/edit/2", @request.path
  126. ActionController::Base.relative_url_root = nil
  127. # The following tests are for when REQUEST_URI is not supplied (as in IIS)
  128. @request.env['PATH_INFO'] = "/path/of/some/uri?mapped=1"
  129. @request.env['SCRIPT_NAME'] = nil #"/path/dispatch.rb"
  130. @request.set_REQUEST_URI nil
  131. assert_equal "/path/of/some/uri?mapped=1", @request.request_uri
  132. assert_equal "/path/of/some/uri", @request.path
  133. ActionController::Base.relative_url_root = '/path'
  134. @request.env['PATH_INFO'] = "/path/of/some/uri?mapped=1"
  135. @request.env['SCRIPT_NAME'] = "/path/dispatch.rb"
  136. @request.set_REQUEST_URI nil
  137. assert_equal "/path/of/some/uri?mapped=1", @request.request_uri(true)
  138. assert_equal "/of/some/uri", @request.path(true)
  139. ActionController::Base.relative_url_root = nil
  140. @request.env['PATH_INFO'] = "/path/of/some/uri"
  141. @request.env['SCRIPT_NAME'] = nil
  142. @request.set_REQUEST_URI nil
  143. assert_equal "/path/of/some/uri", @request.request_uri
  144. assert_equal "/path/of/some/uri", @request.path
  145. @request.env['PATH_INFO'] = "/"
  146. @request.set_REQUEST_URI nil
  147. assert_equal "/", @request.request_uri
  148. assert_equal "/", @request.path
  149. @request.env['PATH_INFO'] = "/?m=b"
  150. @request.set_REQUEST_URI nil
  151. assert_equal "/?m=b", @request.request_uri
  152. assert_equal "/", @request.path
  153. @request.env['PATH_INFO'] = "/"
  154. @request.env['SCRIPT_NAME'] = "/dispatch.cgi"
  155. @request.set_REQUEST_URI nil
  156. assert_equal "/", @request.request_uri
  157. assert_equal "/", @request.path
  158. ActionController::Base.relative_url_root = '/hieraki'
  159. @request.env['PATH_INFO'] = "/hieraki/"
  160. @request.env['SCRIPT_NAME'] = "/hieraki/dispatch.cgi"
  161. @request.set_REQUEST_URI nil
  162. assert_equal "/hieraki/", @request.request_uri
  163. assert_equal "/", @request.path
  164. ActionController::Base.relative_url_root = nil
  165. @request.set_REQUEST_URI '/hieraki/dispatch.cgi'
  166. ActionController::Base.relative_url_root = '/hieraki'
  167. assert_equal "/dispatch.cgi", @request.path(true)
  168. ActionController::Base.relative_url_root = nil
  169. @request.set_REQUEST_URI '/hieraki/dispatch.cgi'
  170. ActionController::Base.relative_url_root = '/foo'
  171. assert_equal "/hieraki/dispatch.cgi", @request.path(true)
  172. ActionController::Base.relative_url_root = nil
  173. # This test ensures that Rails uses REQUEST_URI over PATH_INFO
  174. ActionController::Base.relative_url_root = nil
  175. @request.env['REQUEST_URI'] = "/some/path"
  176. @request.env['PATH_INFO'] = "/another/path"
  177. @request.env['SCRIPT_NAME'] = "/dispatch.cgi"
  178. assert_equal "/some/path", @request.request_uri(true)
  179. assert_equal "/some/path", @request.path(true)
  180. end
  181. def test_host_with_default_port
  182. @request.host = "rubyonrails.org"
  183. @request.port = 80
  184. assert_equal "rubyonrails.org", @request.host_with_port
  185. end
  186. def test_host_with_non_default_port
  187. @request.host = "rubyonrails.org"
  188. @request.port = 81
  189. assert_equal "rubyonrails.org:81", @request.host_with_port
  190. end
  191. def test_server_software
  192. assert_equal nil, @request.server_software(true)
  193. @request.env['SERVER_SOFTWARE'] = 'Apache3.422'
  194. assert_equal 'apache', @request.server_software(true)
  195. @request.env['SERVER_SOFTWARE'] = 'lighttpd(1.1.4)'
  196. assert_equal 'lighttpd', @request.server_software(true)
  197. end
  198. def test_xml_http_request
  199. assert !@request.xml_http_request?
  200. assert !@request.xhr?
  201. @request.env['HTTP_X_REQUESTED_WITH'] = "DefinitelyNotAjax1.0"
  202. assert !@request.xml_http_request?
  203. assert !@request.xhr?
  204. @request.env['HTTP_X_REQUESTED_WITH'] = "XMLHttpRequest"
  205. assert @request.xml_http_request?
  206. assert @request.xhr?
  207. end
  208. def test_reports_ssl
  209. assert !@request.ssl?
  210. @request.env['HTTPS'] = 'on'
  211. assert @request.ssl?
  212. end
  213. def test_reports_ssl_when_proxied_via_lighttpd
  214. assert !@request.ssl?
  215. @request.env['HTTP_X_FORWARDED_PROTO'] = 'https'
  216. assert @request.ssl?
  217. end
  218. def test_symbolized_request_methods
  219. [:get, :post, :put, :delete].each do |method|
  220. self.request_method = method
  221. assert_equal method, @request.method
  222. end
  223. end
  224. def test_invalid_http_method_raises_exception
  225. assert_raises(ActionController::UnknownHttpMethod) do
  226. self.request_method = :random_method
  227. end
  228. end
  229. def test_allow_method_hacking_on_post
  230. self.request_method = :post
  231. [:get, :head, :options, :put, :post, :delete].each do |method|
  232. @request.instance_eval { @parameters = { :_method => method.to_s } ; @request_method = nil }
  233. @request.request_method(true)
  234. assert_equal(method == :head ? :get : method, @request.method)
  235. end
  236. end
  237. def test_invalid_method_hacking_on_post_raises_exception
  238. self.request_method = :post
  239. @request.instance_eval { @parameters = { :_method => :random_method } ; @request_method = nil }
  240. assert_raises(ActionController::UnknownHttpMethod) do
  241. @request.request_method(true)
  242. end
  243. end
  244. def test_restrict_method_hacking
  245. @request.instance_eval { @parameters = { :_method => 'put' } }
  246. [:get, :put, :delete].each do |method|
  247. self.request_method = method
  248. assert_equal method, @request.method
  249. end
  250. end
  251. def test_head_masquerading_as_get
  252. self.request_method = :head
  253. assert_equal :get, @request.method
  254. assert @request.get?
  255. assert @request.head?
  256. end
  257. def test_xml_format
  258. @request.instance_eval { @parameters = { :format => 'xml' } }
  259. assert_equal Mime::XML, @request.format
  260. end
  261. def test_xhtml_format
  262. @request.instance_eval { @parameters = { :format => 'xhtml' } }
  263. assert_equal Mime::HTML, @request.format
  264. end
  265. def test_txt_format
  266. @request.instance_eval { @parameters = { :format => 'txt' } }
  267. assert_equal Mime::TEXT, @request.format
  268. end
  269. def test_nil_format
  270. ActionController::Base.use_accept_header, old =
  271. false, ActionController::Base.use_accept_header
  272. @request.instance_eval { @parameters = {} }
  273. @request.env["HTTP_X_REQUESTED_WITH"] = "XMLHttpRequest"
  274. assert @request.xhr?
  275. assert_equal Mime::JS, @request.format
  276. ensure
  277. ActionController::Base.use_accept_header = old
  278. end
  279. def test_content_type
  280. @request.env["CONTENT_TYPE"] = "text/html"
  281. assert_equal Mime::HTML, @request.content_type
  282. end
  283. def test_format_assignment_should_set_format
  284. @request.instance_eval { self.format = :txt }
  285. assert !@request.format.xml?
  286. @request.instance_eval { self.format = :xml }
  287. assert @request.format.xml?
  288. end
  289. def test_content_no_type
  290. assert_equal nil, @request.content_type
  291. end
  292. def test_content_type_xml
  293. @request.env["CONTENT_TYPE"] = "application/xml"
  294. assert_equal Mime::XML, @request.content_type
  295. end
  296. def test_content_type_with_charset
  297. @request.env["CONTENT_TYPE"] = "application/xml; charset=UTF-8"
  298. assert_equal Mime::XML, @request.content_type
  299. end
  300. def test_user_agent
  301. assert_not_nil @request.user_agent
  302. end
  303. def test_parameters
  304. @request.instance_eval { @request_parameters = { "foo" => 1 } }
  305. @request.instance_eval { @query_parameters = { "bar" => 2 } }
  306. assert_equal({"foo" => 1, "bar" => 2}, @request.parameters)
  307. assert_equal({"foo" => 1}, @request.request_parameters)
  308. assert_equal({"bar" => 2}, @request.query_parameters)
  309. end
  310. protected
  311. def request_method=(method)
  312. @request.env['REQUEST_METHOD'] = method.to_s.upcase
  313. @request.request_method(true)
  314. end
  315. end
  316. class UrlEncodedRequestParameterParsingTest < Test::Unit::TestCase
  317. def setup
  318. @query_string = "action=create_customer&full_name=David%20Heinemeier%20Hansson&customerId=1"
  319. @query_string_with_empty = "action=create_customer&full_name="
  320. @query_string_with_array = "action=create_customer&selected[]=1&selected[]=2&selected[]=3"
  321. @query_string_with_amps = "action=create_customer&name=Don%27t+%26+Does"
  322. @query_string_with_multiple_of_same_name =
  323. "action=update_order&full_name=Lau%20Taarnskov&products=4&products=2&products=3"
  324. @query_string_with_many_equal = "action=create_customer&full_name=abc=def=ghi"
  325. @query_string_without_equal = "action"
  326. @query_string_with_many_ampersands =
  327. "&action=create_customer&&&full_name=David%20Heinemeier%20Hansson"
  328. @query_string_with_empty_key = "action=create_customer&full_name=David%20Heinemeier%20Hansson&=Save"
  329. end
  330. def test_query_string
  331. assert_equal(
  332. { "action" => "create_customer", "full_name" => "David Heinemeier Hansson", "customerId" => "1"},
  333. ActionController::AbstractRequest.parse_query_parameters(@query_string)
  334. )
  335. end
  336. def test_deep_query_string
  337. expected = {'x' => {'y' => {'z' => '10'}}}
  338. assert_equal(expected, ActionController::AbstractRequest.parse_query_parameters('x[y][z]=10'))
  339. end
  340. def test_deep_query_string_with_array
  341. assert_equal({'x' => {'y' => {'z' => ['10']}}}, ActionController::AbstractRequest.parse_query_parameters('x[y][z][]=10'))
  342. assert_equal({'x' => {'y' => {'z' => ['10', '5']}}}, ActionController::AbstractRequest.parse_query_parameters('x[y][z][]=10&x[y][z][]=5'))
  343. end
  344. def test_deep_query_string_with_array_of_hash
  345. assert_equal({'x' => {'y' => [{'z' => '10'}]}}, ActionController::AbstractRequest.parse_query_parameters('x[y][][z]=10'))
  346. assert_equal({'x' => {'y' => [{'z' => '10', 'w' => '10'}]}}, ActionController::AbstractRequest.parse_query_parameters('x[y][][z]=10&x[y][][w]=10'))
  347. end
  348. def test_deep_query_string_with_array_of_hashes_with_one_pair
  349. assert_equal({'x' => {'y' => [{'z' => '10'}, {'z' => '20'}]}}, ActionController::AbstractRequest.parse_query_parameters('x[y][][z]=10&x[y][][z]=20'))
  350. assert_equal("10", ActionController::AbstractRequest.parse_query_parameters('x[y][][z]=10&x[y][][z]=20')["x"]["y"].first["z"])
  351. assert_equal("10", ActionController::AbstractRequest.parse_query_parameters('x[y][][z]=10&x[y][][z]=20').with_indifferent_access[:x][:y].first[:z])
  352. end
  353. def test_deep_query_string_with_array_of_hashes_with_multiple_pairs
  354. assert_equal(
  355. {'x' => {'y' => [{'z' => '10', 'w' => 'a'}, {'z' => '20', 'w' => 'b'}]}},
  356. ActionController::AbstractRequest.parse_query_parameters('x[y][][z]=10&x[y][][w]=a&x[y][][z]=20&x[y][][w]=b')
  357. )
  358. end
  359. def test_query_string_with_nil
  360. assert_equal(
  361. { "action" => "create_customer", "full_name" => ''},
  362. ActionController::AbstractRequest.parse_query_parameters(@query_string_with_empty)
  363. )
  364. end
  365. def test_query_string_with_array
  366. assert_equal(
  367. { "action" => "create_customer", "selected" => ["1", "2", "3"]},
  368. ActionController::AbstractRequest.parse_query_parameters(@query_string_with_array)
  369. )
  370. end
  371. def test_query_string_with_amps
  372. assert_equal(
  373. { "action" => "create_customer", "name" => "Don't & Does"},
  374. ActionController::AbstractRequest.parse_query_parameters(@query_string_with_amps)
  375. )
  376. end
  377. def test_query_string_with_many_equal
  378. assert_equal(
  379. { "action" => "create_customer", "full_name" => "abc=def=ghi"},
  380. ActionController::AbstractRequest.parse_query_parameters(@query_string_with_many_equal)
  381. )
  382. end
  383. def test_query_string_without_equal
  384. assert_equal(
  385. { "action" => nil },
  386. ActionController::AbstractRequest.parse_query_parameters(@query_string_without_equal)
  387. )
  388. end
  389. def test_query_string_with_empty_key
  390. assert_equal(
  391. { "action" => "create_customer", "full_name" => "David Heinemeier Hansson" },
  392. ActionController::AbstractRequest.parse_query_parameters(@query_string_with_empty_key)
  393. )
  394. end
  395. def test_query_string_with_many_ampersands
  396. assert_equal(
  397. { "action" => "create_customer", "full_name" => "David Heinemeier Hansson"},
  398. ActionController::AbstractRequest.parse_query_parameters(@query_string_with_many_ampersands)
  399. )
  400. end
  401. def test_unbalanced_query_string_with_array
  402. assert_equal(
  403. {'location' => ["1", "2"], 'age_group' => ["2"]},
  404. ActionController::AbstractRequest.parse_query_parameters("location[]=1&location[]=2&age_group[]=2")
  405. )
  406. assert_equal(
  407. {'location' => ["1", "2"], 'age_group' => ["2"]},
  408. ActionController::AbstractRequest.parse_request_parameters({'location[]' => ["1", "2"],
  409. 'age_group[]' => ["2"]})
  410. )
  411. end
  412. def test_request_hash_parsing
  413. query = {
  414. "note[viewers][viewer][][type]" => ["User", "Group"],
  415. "note[viewers][viewer][][id]" => ["1", "2"]
  416. }
  417. expected = { "note" => { "viewers"=>{"viewer"=>[{ "id"=>"1", "type"=>"User"}, {"type"=>"Group", "id"=>"2"} ]} } }
  418. assert_equal(expected, ActionController::AbstractRequest.parse_request_parameters(query))
  419. end
  420. def test_parse_params
  421. input = {
  422. "customers[boston][first][name]" => [ "David" ],
  423. "customers[boston][first][url]" => [ "http://David" ],
  424. "customers[boston][second][name]" => [ "Allan" ],
  425. "customers[boston][second][url]" => [ "http://Allan" ],
  426. "something_else" => [ "blah" ],
  427. "something_nil" => [ nil ],
  428. "something_empty" => [ "" ],
  429. "products[first]" => [ "Apple Computer" ],
  430. "products[second]" => [ "Pc" ],
  431. "" => [ 'Save' ]
  432. }
  433. expected_output = {
  434. "customers" => {
  435. "boston" => {
  436. "first" => {
  437. "name" => "David",
  438. "url" => "http://David"
  439. },
  440. "second" => {
  441. "name" => "Allan",
  442. "url" => "http://Allan"
  443. }
  444. }
  445. },
  446. "something_else" => "blah",
  447. "something_empty" => "",
  448. "something_nil" => "",
  449. "products" => {
  450. "first" => "Apple Computer",
  451. "second" => "Pc"
  452. }
  453. }
  454. assert_equal expected_output, ActionController::AbstractRequest.parse_request_parameters(input)
  455. end
  456. UploadedStringIO = ActionController::UploadedStringIO
  457. class MockUpload < UploadedStringIO
  458. def initialize(content_type, original_path, *args)
  459. self.content_type = content_type
  460. self.original_path = original_path
  461. super *args
  462. end
  463. end
  464. def test_parse_params_from_multipart_upload
  465. file = MockUpload.new('img/jpeg', 'foo.jpg')
  466. ie_file = MockUpload.new('img/jpeg', 'c:\\Documents and Settings\\foo\\Desktop\\bar.jpg')
  467. non_file_text_part = MockUpload.new('text/plain', '', 'abc')
  468. input = {
  469. "something" => [ UploadedStringIO.new("") ],
  470. "array_of_stringios" => [[ UploadedStringIO.new("One"), UploadedStringIO.new("Two") ]],
  471. "mixed_types_array" => [[ UploadedStringIO.new("Three"), "NotStringIO" ]],
  472. "mixed_types_as_checkboxes[strings][nested]" => [[ file, "String", UploadedStringIO.new("StringIO")]],
  473. "ie_mixed_types_as_checkboxes[strings][nested]" => [[ ie_file, "String", UploadedStringIO.new("StringIO")]],
  474. "products[string]" => [ UploadedStringIO.new("Apple Computer") ],
  475. "products[file]" => [ file ],
  476. "ie_products[string]" => [ UploadedStringIO.new("Microsoft") ],
  477. "ie_products[file]" => [ ie_file ],
  478. "text_part" => [non_file_text_part]
  479. }
  480. expected_output = {
  481. "something" => "",
  482. "array_of_stringios" => ["One", "Two"],
  483. "mixed_types_array" => [ "Three", "NotStringIO" ],
  484. "mixed_types_as_checkboxes" => {
  485. "strings" => {
  486. "nested" => [ file, "String", "StringIO" ]
  487. },
  488. },
  489. "ie_mixed_types_as_checkboxes" => {
  490. "strings" => {
  491. "nested" => [ ie_file, "String", "StringIO" ]
  492. },
  493. },
  494. "products" => {
  495. "string" => "Apple Computer",
  496. "file" => file
  497. },
  498. "ie_products" => {
  499. "string" => "Microsoft",
  500. "file" => ie_file
  501. },
  502. "text_part" => "abc"
  503. }
  504. params = ActionController::AbstractRequest.parse_request_parameters(input)
  505. assert_equal expected_output, params
  506. # Lone filenames are preserved.
  507. assert_equal 'foo.jpg', params['mixed_types_as_checkboxes']['strings']['nested'].first.original_filename
  508. assert_equal 'foo.jpg', params['products']['file'].original_filename
  509. # But full Windows paths are reduced to their basename.
  510. assert_equal 'bar.jpg', params['ie_mixed_types_as_checkboxes']['strings']['nested'].first.original_filename
  511. assert_equal 'bar.jpg', params['ie_products']['file'].original_filename
  512. end
  513. def test_parse_params_with_file
  514. input = {
  515. "customers[boston][first][name]" => [ "David" ],
  516. "something_else" => [ "blah" ],
  517. "logo" => [ File.new(File.dirname(__FILE__) + "/cgi_test.rb").path ]
  518. }
  519. expected_output = {
  520. "customers" => {
  521. "boston" => {
  522. "first" => {
  523. "name" => "David"
  524. }
  525. }
  526. },
  527. "something_else" => "blah",
  528. "logo" => File.new(File.dirname(__FILE__) + "/cgi_test.rb").path,
  529. }
  530. assert_equal expected_output, ActionController::AbstractRequest.parse_request_parameters(input)
  531. end
  532. def test_parse_params_with_array
  533. input = { "selected[]" => [ "1", "2", "3" ] }
  534. expected_output = { "selected" => [ "1", "2", "3" ] }
  535. assert_equal expected_output, ActionController::AbstractRequest.parse_request_parameters(input)
  536. end
  537. def test_parse_params_with_non_alphanumeric_name
  538. input = { "a/b[c]" => %w(d) }
  539. expected = { "a/b" => { "c" => "d" }}
  540. assert_equal expected, ActionController::AbstractRequest.parse_request_parameters(input)
  541. end
  542. def test_parse_params_with_single_brackets_in_middle
  543. input = { "a/b[c]d" => %w(e) }
  544. expected = { "a/b" => {} }
  545. assert_equal expected, ActionController::AbstractRequest.parse_request_parameters(input)
  546. end
  547. def test_parse_params_with_separated_brackets
  548. input = { "a/b@[c]d[e]" => %w(f) }
  549. expected = { "a/b@" => { }}
  550. assert_equal expected, ActionController::AbstractRequest.parse_request_parameters(input)
  551. end
  552. def test_parse_params_with_separated_brackets_and_array
  553. input = { "a/b@[c]d[e][]" => %w(f) }
  554. expected = { "a/b@" => { }}
  555. assert_equal expected , ActionController::AbstractRequest.parse_request_parameters(input)
  556. end
  557. def test_parse_params_with_unmatched_brackets_and_array
  558. input = { "a/b@[c][d[e][]" => %w(f) }
  559. expected = { "a/b@" => { "c" => { }}}
  560. assert_equal expected, ActionController::AbstractRequest.parse_request_parameters(input)
  561. end
  562. def test_parse_params_with_nil_key
  563. input = { nil => nil, "test2" => %w(value1) }
  564. expected = { "test2" => "value1" }
  565. assert_equal expected, ActionController::AbstractRequest.parse_request_parameters(input)
  566. end
  567. def test_parse_params_with_array_prefix_and_hashes
  568. input = { "a[][b][c]" => %w(d) }
  569. expected = {"a" => [{"b" => {"c" => "d"}}]}
  570. assert_equal expected, ActionController::AbstractRequest.parse_request_parameters(input)
  571. end
  572. def test_parse_params_with_complex_nesting
  573. input = { "a[][b][c][][d][]" => %w(e) }
  574. expected = {"a" => [{"b" => {"c" => [{"d" => ["e"]}]}}]}
  575. assert_equal expected, ActionController::AbstractRequest.parse_request_parameters(input)
  576. end
  577. end
  578. class MultipartRequestParameterParsingTest < Test::Unit::TestCase
  579. FIXTURE_PATH = File.dirname(__FILE__) + '/../fixtures/multipart'
  580. def test_single_parameter
  581. params = process('single_parameter')
  582. assert_equal({ 'foo' => 'bar' }, params)
  583. end
  584. def test_bracketed_param
  585. assert_equal({ 'foo' => { 'baz' => 'bar'}}, process('bracketed_param'))
  586. end
  587. def test_text_file
  588. params = process('text_file')
  589. assert_equal %w(file foo), params.keys.sort
  590. assert_equal 'bar', params['foo']
  591. file = params['file']
  592. assert_kind_of StringIO, file
  593. assert_equal 'file.txt', file.original_filename
  594. assert_equal "text/plain", file.content_type
  595. assert_equal 'contents', file.read
  596. end
  597. def test_boundary_problem_file
  598. params = process('boundary_problem_file')
  599. assert_equal %w(file foo), params.keys.sort
  600. file = params['file']
  601. foo = params['foo']
  602. if RUBY_VERSION > '1.9'
  603. assert_kind_of File, file
  604. else
  605. assert_kind_of Tempfile, file
  606. end
  607. assert_equal 'file.txt', file.original_filename
  608. assert_equal "text/plain", file.content_type
  609. assert_equal 'bar', foo
  610. end
  611. def test_large_text_file
  612. params = process('large_text_file')
  613. assert_equal %w(file foo), params.keys.sort
  614. assert_equal 'bar', params['foo']
  615. file = params['file']
  616. if RUBY_VERSION > '1.9'
  617. assert_kind_of File, file
  618. else
  619. assert_kind_of Tempfile, file
  620. end
  621. assert_equal 'file.txt', file.original_filename
  622. assert_equal "text/plain", file.content_type
  623. assert ('a' * 20480) == file.read
  624. end
  625. uses_mocha "test_no_rewind_stream" do
  626. def test_no_rewind_stream
  627. # Ensures that parse_multipart_form_parameters works with streams that cannot be rewound
  628. file = File.open(File.join(FIXTURE_PATH, 'large_text_file'), 'rb')
  629. file.expects(:rewind).raises(Errno::ESPIPE)
  630. params = ActionController::AbstractRequest.parse_multipart_form_parameters(file, 'AaB03x', file.stat.size, {})
  631. assert_not_equal 0, file.pos # file was not rewound after reading
  632. end
  633. end
  634. def test_binary_file
  635. params = process('binary_file')
  636. assert_equal %w(file flowers foo), params.keys.sort
  637. assert_equal 'bar', params['foo']
  638. file = params['file']
  639. assert_kind_of StringIO, file
  640. assert_equal 'file.csv', file.original_filename
  641. assert_nil file.content_type
  642. assert_equal 'contents', file.read
  643. file = params['flowers']
  644. assert_kind_of StringIO, file
  645. assert_equal 'flowers.jpg', file.original_filename
  646. assert_equal "image/jpeg", file.content_type
  647. assert_equal 19512, file.size
  648. #assert_equal File.read(File.dirname(__FILE__) + '/../../../activerecord/test/fixtures/flowers.jpg'), file.read
  649. end
  650. def test_mixed_files
  651. params = process('mixed_files')
  652. assert_equal %w(files foo), params.keys.sort
  653. assert_equal 'bar', params['foo']
  654. # Ruby CGI doesn't handle multipart/mixed for us.
  655. files = params['files']
  656. assert_kind_of String, files
  657. files.force_encoding('ASCII-8BIT') if files.respond_to?(:force_encoding)
  658. assert_equal 19756, files.size
  659. end
  660. private
  661. def process(name)
  662. File.open(File.join(FIXTURE_PATH, name), 'rb') do |file|
  663. params = ActionController::AbstractRequest.parse_multipart_form_parameters(file, 'AaB03x', file.stat.size, {})
  664. assert_equal 0, file.pos # file was rewound after reading
  665. params
  666. end
  667. end
  668. end
  669. class XmlParamsParsingTest < Test::Unit::TestCase
  670. def test_hash_params
  671. person = parse_body("<person><name>David</name></person>")[:person]
  672. assert_kind_of Hash, person
  673. assert_equal 'David', person['name']
  674. end
  675. def test_single_file
  676. person = parse_body("<person><name>David</name><avatar type='file' name='me.jpg' content_type='image/jpg'>#{ActiveSupport::Base64.encode64('ABC')}</avatar></person>")
  677. assert_equal "image/jpg", person['person']['avatar'].content_type
  678. assert_equal "me.jpg", person['person']['avatar'].original_filename
  679. assert_equal "ABC", person['person']['avatar'].read
  680. end
  681. def test_multiple_files
  682. person = parse_body(<<-end_body)
  683. <person>
  684. <name>David</name>
  685. <avatars>
  686. <avatar type='file' name='me.jpg' content_type='image/jpg'>#{ActiveSupport::Base64.encode64('ABC')}</avatar>
  687. <avatar type='file' name='you.gif' content_type='image/gif'>#{ActiveSupport::Base64.encode64('DEF')}</avatar>
  688. </avatars>
  689. </person>
  690. end_body
  691. assert_equal "image/jpg", person['person']['avatars']['avatar'].first.content_type
  692. assert_equal "me.jpg", person['person']['avatars']['avatar'].first.original_filename
  693. assert_equal "ABC", person['person']['avatars']['avatar'].first.read
  694. assert_equal "image/gif", person['person']['avatars']['avatar'].last.content_type
  695. assert_equal "you.gif", person['person']['avatars']['avatar'].last.original_filename
  696. assert_equal "DEF", person['person']['avatars']['avatar'].last.read
  697. end
  698. private
  699. def parse_body(body)
  700. env = { 'rack.input' => StringIO.new(body),
  701. 'CONTENT_TYPE' => 'application/xml',
  702. 'CONTENT_LENGTH' => body.size.to_s }
  703. ActionController::RackRequest.new(env).request_parameters
  704. end
  705. end
  706. class LegacyXmlParamsParsingTest < XmlParamsParsingTest
  707. private
  708. def parse_body(body)
  709. env = { 'rack.input' => StringIO.new(body),
  710. 'HTTP_X_POST_DATA_FORMAT' => 'xml',
  711. 'CONTENT_LENGTH' => body.size.to_s }
  712. ActionController::RackRequest.new(env).request_parameters
  713. end
  714. end
  715. class JsonParamsParsingTest < Test::Unit::TestCase
  716. def test_hash_params_for_application_json
  717. person = parse_body({:person => {:name => "David"}}.to_json,'application/json')[:person]
  718. assert_kind_of Hash, person
  719. assert_equal 'David', person['name']
  720. end
  721. def test_hash_params_for_application_jsonrequest
  722. person = parse_body({:person => {:name => "David"}}.to_json,'application/jsonrequest')[:person]
  723. assert_kind_of Hash, person
  724. assert_equal 'David', person['name']
  725. end
  726. private
  727. def parse_body(body,content_type)
  728. env = { 'rack.input' => StringIO.new(body),
  729. 'CONTENT_TYPE' => content_type,
  730. 'CONTENT_LENGTH' => body.size.to_s }
  731. ActionController::RackRequest.new(env).request_parameters
  732. end
  733. end