Class: Praxis::MultipartParser

Inherits:
Object
  • Object
show all
Defined in:
lib/praxis/multipart/parser.rb

Constant Summary collapse

EOL =
"\r\n"
MULTIPART_BOUNDARY =
'AaB03x'
MULTIPART =
%r{\Amultipart/.*boundary="?([^";,]+)"?}n.freeze
TOKEN =
%r{[^\s()<>,;:\\"/\[\]?=]+}.freeze
CONDISP =
/Content-Disposition:\s*#{TOKEN}\s*/i.freeze
DISPPARM =
/;\s*(#{TOKEN})=("(?:\\"|[^"])*"|#{TOKEN})/.freeze
RFC2183 =
/^#{CONDISP}(#{DISPPARM})+$/i.freeze
BROKEN_QUOTED =
/^#{CONDISP}.*;\sfilename="(.*?)"(?:\s*$|\s*;\s*#{TOKEN}=)/i.freeze
BROKEN_UNQUOTED =
/^#{CONDISP}.*;\sfilename=(#{TOKEN})/i.freeze
MULTIPART_CONTENT_TYPE =
/Content-Type: (.*)#{EOL}/ni.freeze
MULTIPART_CONTENT_DISPOSITION =
/Content-Disposition:.*\s+name="?([^";]*)"?/ni.freeze
MULTIPART_CONTENT_ID =
/Content-ID:\s*([^#{EOL}]*)/ni.freeze
HEADER_KV =
/(?<k>[^:]+): (?<v>.*)/.freeze
UNTIL_NEWLINE =
/\A([^\n]*\n)/.freeze
TERMINAL_CRLF =
/\r\n$/.freeze
PARAMS_BUF_SIZE =

Same as implicitly in rack 1.x

65_536
BUFSIZE =
16_384

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(headers, body) ⇒ MultipartParser

Returns a new instance of MultipartParser.



33
34
35
36
37
38
39
40
41
# File 'lib/praxis/multipart/parser.rb', line 33

def initialize(headers, body)
  @headers = headers
  @io = StringIO.new
  Array(body).each do |chunk|
    @io << chunk
  end
  @io.rewind
  @parts = []
end

Class Method Details

.parse(headers, body) ⇒ Object



29
30
31
# File 'lib/praxis/multipart/parser.rb', line 29

def self.parse(headers, body)
  new(headers, body).parse
end

Instance Method Details

#parseObject



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/praxis/multipart/parser.rb', line 43

def parse
  return nil unless setup_parse

  @preamble = fast_forward_to_first_boundary

  loop do
    head, filename, content_type, name, body =
      current_head_and_filename_and_content_type_and_name_and_body

    # Save the rest.
    if (i = @buf.index(rx))
      body << @buf.slice!(0, i)
      @buf.slice!(0, @boundary_size + 2)

      @content_length = -1 if Regexp.last_match(1) == '--'
    end

    filename, data = get_data(filename, body, content_type, name, head)

    parsed_headers = head.split(EOL).each_with_object({}) do |line, hash|
      match = HEADER_KV.match(line)
      k = match[:k]
      v = match[:v]
      hash[k] = v
    end

    part = MultipartPart.new(data, parsed_headers, name: name, filename: filename)

    @parts << part

    # break if we're at the end of a buffer, but not if it is the end of a field
    break if (@buf.empty? && Regexp.last_match(1) != EOL) || @content_length == -1
  end

  @io.rewind

  [@preamble, @parts]
end