Class: Landline::Util::MultipartParser

Inherits:
Object
  • Object
show all
Includes:
ParserSorting
Defined in:
lib/landline/util/multipart.rb

Overview

A very naive implementation of a Multipart form parser.

Instance Method Summary collapse

Constructor Details

#initialize(io, boundary) ⇒ MultipartParser



46
47
48
49
50
51
# File 'lib/landline/util/multipart.rb', line 46

def initialize(io, boundary)
  @input = io.is_a?(String) ? StringIO.new(io) : io
  @boundary = boundary
  @state = :idle
  @data = []
end

Instance Method Details

#parseArray<FormPart, FormFile>

Parse multipart formdata



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/landline/util/multipart.rb', line 59

def parse
  return @data unless @data.empty?

  while (line = @input.gets)
    case @state
    when :idle # waiting for valid boundary
      if line == "--#{@boundary}\r\n"
        # transition to :headers on valid boundary
        @state = :headers
        @data.append(FormPart.new(*([nil] * 5), {}))
      end
    when :headers # after valid boundary - checking for headers
      if line == "\r\n"
        # prepare form field and transition to :data or :file
        @state = file?(@data[-1].headers) ? :file : :data
        if @state == :data
          setup_data_meta(@data[-1])
        else
          setup_file_meta(@data[-1])
        end
        next
      end
      push_header(line, @data[-1].headers)
    when :data, :file # after headers - processing form data
      if @data[-1].headers.empty?
        # transition to :idle on empty headers
        @state = :idle
        next
      end
      if ["--#{@boundary}\r\n", "--#{@boundary}--\r\n"].include? line
        # finalize and transition to either :headers or :idle
        if @state == :file
          @data[-1].tempfile.truncate(@data[-1].tempfile.size - 2)
          @data[-1].tempfile.close
        else
          @data[-1].data.delete_suffix! "\r\n"
        end
        @state = line == "--#{@boundary}\r\n" ? :headers : :idle
        @data.append(FormPart.new(*([nil] * 5), {}))
        next
      end
      if @state == :data
        @data[-1].data ||= ""
        @data[-1].data << line
      else
        @data[-1].tempfile << line
      end
    end
  end
  @state = :idle
  @data.pop
  @data.freeze
end

#to_hHash

Return a hash of current form. (equivalent to Query.parse but for multipart/form-data)



117
118
119
# File 'lib/landline/util/multipart.rb', line 117

def to_h
  flatten(sort(gen_hash(parse)))
end