multipart_params_parsing_test.rb 6.1 KB
Newer Older
K
Kir Shatrov 已提交
1
# frozen_string_literal: true
2
require "abstract_unit"
3

4
class MultipartParamsParsingTest < ActionDispatch::IntegrationTest
5 6
  class TestController < ActionController::Base
    class << self
7
      attr_accessor :last_request_parameters, :last_parameters
8 9 10
    end

    def parse
J
Jarmo Isotalo 已提交
11 12 13 14 15
      self.class.last_request_parameters = begin
        request.request_parameters
      rescue EOFError
        {}
      end
16
      self.class.last_parameters = request.parameters
17 18 19 20
      head :ok
    end

    def read
21
      render plain: "File: #{params[:uploaded_data].read}"
22 23 24
    end
  end

B
bogdanvlviv 已提交
25
  FIXTURE_PATH = File.expand_path("../../fixtures/multipart", __dir__)
26 27 28 29 30 31

  def teardown
    TestController.last_request_parameters = nil
  end

  test "parses single parameter" do
32
    assert_equal({ "foo" => "bar" }, parse_multipart("single_parameter"))
33 34 35
  end

  test "parses bracketed parameters" do
36
    assert_equal({ "foo" => { "baz" => "bar" } }, parse_multipart("bracketed_param"))
37 38
  end

39
  test "parse single utf8 parameter" do
40
    assert_equal({ "Iñtërnâtiônàlizætiøn_name" => "Iñtërnâtiônàlizætiøn_value" },
41
                 parse_multipart("single_utf8_param"), "request.request_parameters")
42
    assert_equal(
43 44
      "Iñtërnâtiônàlizætiøn_value",
      TestController.last_parameters["Iñtërnâtiônàlizætiøn_name"], "request.parameters")
45 46 47
  end

  test "parse bracketed utf8 parameter" do
48
    assert_equal({ "Iñtërnâtiônàlizætiøn_name" => {
49
      "Iñtërnâtiônàlizætiøn_nested_name" => "Iñtërnâtiônàlizætiøn_value" } },
50
      parse_multipart("bracketed_utf8_param"), "request.request_parameters")
51
    assert_equal(
52
      { "Iñtërnâtiônàlizætiøn_nested_name" => "Iñtërnâtiônàlizætiøn_value" },
53
      TestController.last_parameters["Iñtërnâtiônàlizætiøn_name"], "request.parameters")
54 55
  end

56
  test "parses text file" do
57
    params = parse_multipart("text_file")
58
    assert_equal %w(file foo), params.keys.sort
59
    assert_equal "bar", params["foo"]
60

61 62
    file = params["file"]
    assert_equal "file.txt", file.original_filename
63
    assert_equal "text/plain", file.content_type
64
    assert_equal "contents", file.read
65 66
  end

67
  test "parses utf8 filename with percent character" do
68
    params = parse_multipart("utf8_filename")
69
    assert_equal %w(file foo), params.keys.sort
70
    assert_equal "bar", params["foo"]
71

72 73
    file = params["file"]
    assert_equal "ファイル%名.txt", file.original_filename
74
    assert_equal "text/plain", file.content_type
75
    assert_equal "contents", file.read
76 77
  end

78
  test "parses boundary problem file" do
79
    params = parse_multipart("boundary_problem_file")
80 81
    assert_equal %w(file foo), params.keys.sort

82 83
    file = params["file"]
    foo  = params["foo"]
84

85
    assert_equal "file.txt", file.original_filename
86 87
    assert_equal "text/plain", file.content_type

88
    assert_equal "bar", foo
89 90 91
  end

  test "parses large text file" do
92
    params = parse_multipart("large_text_file")
93
    assert_equal %w(file foo), params.keys.sort
94
    assert_equal "bar", params["foo"]
95

96
    file = params["file"]
97

98
    assert_equal "file.txt", file.original_filename
99
    assert_equal "text/plain", file.content_type
100
    assert_equal(("a" * 20480), file.read)
101 102 103
  end

  test "parses binary file" do
104
    params = parse_multipart("binary_file")
105
    assert_equal %w(file flowers foo), params.keys.sort
106
    assert_equal "bar", params["foo"]
107

108 109
    file = params["file"]
    assert_equal "file.csv", file.original_filename
110
    assert_nil file.content_type
111
    assert_equal "contents", file.read
112

113 114
    file = params["flowers"]
    assert_equal "flowers.jpg", file.original_filename
115 116 117 118 119
    assert_equal "image/jpeg", file.content_type
    assert_equal 19512, file.size
  end

  test "parses mixed files" do
120
    params = parse_multipart("mixed_files")
J
José Valim 已提交
121
    assert_equal %w(files foo), params.keys.sort
122
    assert_equal "bar", params["foo"]
J
José Valim 已提交
123 124

    # Rack doesn't handle multipart/mixed for us.
125
    files = params["files"]
126
    assert_equal 19756, files.bytesize
127 128
  end

J
Joshua Peek 已提交
129
  test "does not create tempfile if no file has been selected" do
130
    params = parse_multipart("none")
131
    assert_equal %w(submit-name), params.keys.sort
132
    assert_equal "Larry", params["submit-name"]
133
    assert_nil params["files"]
J
Joshua Peek 已提交
134 135 136
  end

  test "parses empty upload file" do
137
    params = parse_multipart("empty")
138
    assert_equal %w(files submit-name), params.keys.sort
139 140 141
    assert_equal "Larry", params["submit-name"]
    assert params["files"]
    assert_equal "", params["files"].read
142 143
  end

144
  test "uploads and reads binary file" do
145
    with_test_routing do
146
      fixture = FIXTURE_PATH + "/ruby_on_rails.jpg"
147
      params = { uploaded_data: fixture_file_upload(fixture, "image/jpg") }
148
      post "/read", params: params
149 150 151 152 153
    end
  end

  test "uploads and reads file" do
    with_test_routing do
154
      post "/read", params: { uploaded_data: fixture_file_upload(FIXTURE_PATH + "/hello.txt", "text/plain") }
155 156 157 158
      assert_equal "File: Hello", response.body
    end
  end

159 160 161 162
  # This can happen in Internet Explorer when redirecting after multipart form submit.
  test "does not raise EOFError on GET request with multipart content-type" do
    with_routing do |set|
      set.draw do
163
        ActiveSupport::Deprecation.silence do
164
          get ":action", controller: "multipart_params_parsing_test/test"
165
        end
166 167
      end
      headers = { "CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x" }
168
      get "/parse", headers: headers
169 170 171 172
      assert_response :ok
    end
  end

173 174
  private
    def fixture(name)
175
      File.open(File.join(FIXTURE_PATH, name), "rb") do |file|
176 177 178 179 180 181 182 183 184
        { "rack.input" => file.read,
          "CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x",
          "CONTENT_LENGTH" => file.stat.size.to_s }
      end
    end

    def parse_multipart(name)
      with_test_routing do
        headers = fixture(name)
185
        post "/parse", params: headers.delete("rack.input"), headers: headers
186 187 188 189 190 191 192
        assert_response :ok
        TestController.last_request_parameters
      end
    end

    def with_test_routing
      with_routing do |set|
193
        set.draw do
194
          ActiveSupport::Deprecation.silence do
195
            post ":action", controller: "multipart_params_parsing_test/test"
196
          end
197 198 199 200 201
        end
        yield
      end
    end
end