Class: Praxis::MultipartParser

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

Constant Summary collapse

EOL =
"\r\n".freeze
MULTIPART_BOUNDARY =
"AaB03x".freeze
MULTIPART =
%r|\Amultipart/.*boundary=\"?([^\";,]+)\"?|n.freeze
TOKEN =
/[^\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
BUFSIZE =
16384

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(headers, body) ⇒ MultipartParser

Returns a new instance of MultipartParser.



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

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

Class Method Details

.parse(headers, body) ⇒ Object



27
28
29
# File 'lib/praxis/multipart/parser.rb', line 27

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

Instance Method Details

#parseObject



41
42
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
# File 'lib/praxis/multipart/parser.rb', line 41

def parse
  return nil unless setup_parse

  @preamble = fast_forward_to_first_boundary

  loop do
    head, filename, content_type, name, body =
      get_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 $1 == "--"
    end

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

    parsed_headers = head.split(EOL).each_with_object(Hash.new) 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? && $1 != EOL) || @content_length == -1
  end

  @io.rewind

  [@preamble, @parts]
end