aboutsummaryrefslogblamecommitdiffstats
path: root/actionpack/test/dispatch/request/multipart_params_parsing_test.rb
blob: da8233c074cf7c17fb5390326b470110bba9e356 (plain) (tree)
1
2
3
4
5
6
7
8

                             
                       
 
                                                                  

                                               
                                                              


             




                                                
                                                     



              
                                                          


       
                                                                      


                                                


                                   
                                                                         


                                       
                                                                                     

     
                                       
                                                                                               
                                                                                    
                 

                                                                                               


                                          
                                                          
                                                                                           
                                                                            
                 
                                                                                           
                                                                                               

     
                            
                                         
                                               
                                     
 

                                                   
                                                
                                      

     
                                                       
                                             
                                               
                                     
 

                                                               
                                                
                                      

     
                                        
                                                     

                                               

                         
 
                                                   

                                                
                           


                                  
                                               
                                               
                                     
 
                         
 
                                                   
                                                
                                          


                              
                                           
                                                       
                                     
 

                                                   
                                
                                      
 

                                                      




                                                
                                           
                                                
                                     

                                                 
                           
                                      

     
                                                                 
                                    
                                                  
                                               
                              


                                    
                                     
                                                        


                                               

     
                                         
                        
                                                   
                                                                           
                                  




                                  
                                                                                                             



                                               



                                                                                      
                                             
                                                                         
           

                                                                            
                                    



                         

                     
                                                              








                                                                   
                                                                             






                                              
                   
                                               
                                                                            
             




             
# frozen_string_literal: true

require "abstract_unit"

class MultipartParamsParsingTest < ActionDispatch::IntegrationTest
  class TestController < ActionController::Base
    class << self
      attr_accessor :last_request_parameters, :last_parameters
    end

    def parse
      self.class.last_request_parameters = begin
        request.request_parameters
      rescue EOFError
        {}
      end
      self.class.last_parameters = request.parameters
      head :ok
    end

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

  FIXTURE_PATH = File.expand_path("../../fixtures/multipart", __dir__)

  def teardown
    TestController.last_request_parameters = nil
  end

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

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

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

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

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

    file = params["file"]
    assert_equal "file.txt", file.original_filename
    assert_equal "text/plain", file.content_type
    assert_equal "contents", file.read
  end

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

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

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

    file = params["file"]
    foo  = params["foo"]

    assert_equal "file.txt", file.original_filename
    assert_equal "text/plain", file.content_type

    assert_equal "bar", foo
  end

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

    file = params["file"]

    assert_equal "file.txt", file.original_filename
    assert_equal "text/plain", file.content_type
    assert_equal(("a" * 20480), file.read)
  end

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

    file = params["file"]
    assert_equal "file.csv", file.original_filename
    assert_nil file.content_type
    assert_equal "contents", file.read

    file = params["flowers"]
    assert_equal "flowers.jpg", file.original_filename
    assert_equal "image/jpeg", file.content_type
    assert_equal 19512, file.size
  end

  test "parses mixed files" do
    params = parse_multipart("mixed_files")
    assert_equal %w(files foo), params.keys.sort
    assert_equal "bar", params["foo"]

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

  test "does not create tempfile if no file has been selected" do
    params = parse_multipart("none")
    assert_equal %w(submit-name), params.keys.sort
    assert_equal "Larry", params["submit-name"]
    assert_nil params["files"]
  end

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

  test "uploads and reads binary file" do
    with_test_routing do
      fixture = FIXTURE_PATH + "/ruby_on_rails.jpg"
      params = { uploaded_data: fixture_file_upload(fixture, "image/jpg") }
      post "/read", params: params
    end
  end

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

  # 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
        ActiveSupport::Deprecation.silence do
          get ":action", controller: "multipart_params_parsing_test/test"
        end
      end
      headers = { "CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x" }
      get "/parse", headers: headers
      assert_response :ok
    end
  end

  private
    def fixture(name)
      File.open(File.join(FIXTURE_PATH, name), "rb") do |file|
        { "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)
        post "/parse", params: headers.delete("rack.input"), headers: headers
        assert_response :ok
        TestController.last_request_parameters
      end
    end

    def with_test_routing
      with_routing do |set|
        set.draw do
          ActiveSupport::Deprecation.silence do
            post ":action", controller: "multipart_params_parsing_test/test"
          end
        end
        yield
      end
    end
end