Class: MIME::Media::Parser

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

Overview

Parser for MIME::Media

Constant Summary collapse

HMD_RGX =
/^([\w-]+)\s*:\s*(.*)/.freeze
MPS =
'multipart/'
MP_RGX1 =
%r{^(digest|mixed);\s*boundary="(.*)"}.freeze
MP_RGX2 =
%r{^(digest|mixed);\s*boundary=(.*)}.freeze
APP_HTTP =
'application/http'

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeParser

Returns a new instance of Parser.



23
24
25
26
27
28
29
# File 'lib/safrano/multipart.rb', line 23

def initialize
  @state = :h
  @lines = []
  @target_hd = {}
  @target_ct = nil
  @sep = CRLF
end

Instance Attribute Details

#linesObject

Returns the value of attribute lines.



20
21
22
# File 'lib/safrano/multipart.rb', line 20

def lines
  @lines
end

#targetObject

Returns the value of attribute target.



21
22
23
# File 'lib/safrano/multipart.rb', line 21

def target
  @target
end

Instance Method Details

#addline(line) ⇒ Object



31
32
33
# File 'lib/safrano/multipart.rb', line 31

def addline(line)
  @lines << line
end

#hook_multipart(content_type, boundary) ⇒ Object



105
106
107
108
109
110
111
112
# File 'lib/safrano/multipart.rb', line 105

def hook_multipart(content_type, boundary)
  @target_hd[CTT_TYPE_LC] = content_type
  @target_ct = @target_hd[CTT_TYPE_LC]
  @target = multipart_content(boundary)
  @target.hd = @target_hd
  @target.ct = @target_ct
  @state = :bmp
end

#multipart_content(boundary) ⇒ Object



101
102
103
# File 'lib/safrano/multipart.rb', line 101

def multipart_content(boundary)
  MIME::Content::Multipart::Base.new(boundary)
end

#new_contentObject



118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/safrano/multipart.rb', line 118

def new_content
  @target =
    if @target_ct.start_with?(MPS) &&
       (md = (MP_RGX1.match(@target_ct[10..-1]) || MP_RGX2.match(@target_ct[10..-1])))
      multipart_content(md[2].strip)
    elsif @target_ct.start_with?(APP_HTTP)
      MIME::Content::Application::Http.new
    else
      MIME::Content::Text::Plain.new
    end
  @target.hd.merge! @target_hd
  @target.ct = @target_ct
  @target.level = @level
  @state = @target.is_a?(MIME::Content::Multipart::Base) ? :bmp : :b
end

#parse(level: 0) ⇒ Object



87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/safrano/multipart.rb', line 87

def parse(level: 0)
  @level = level
  return unless @lines

  @lines.each do |line|
    parse_line(line)
  end
  # Warning: recursive here
  @target.parser.parse(level: level)
  @target.parser = nil
  @lines = nil
  @target
end

#parse_first_part(line) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
# File 'lib/safrano/multipart.rb', line 35

def parse_first_part(line)
  if @target.parser.next_part(line)
    @state = :next_part
  # this is for when there is only one part
  # (first part is the last one)
  elsif @target.parser.last_part(line)
    @state = :end
  else
    @target.parser.addline(line)
  end
end

#parse_head(line) ⇒ Object



57
58
59
60
61
62
63
64
65
66
# File 'lib/safrano/multipart.rb', line 57

def parse_head(line)
  if (hmd = HMD_RGX.match(line))
    @target_hd[hmd[1].downcase] = hmd[2].strip

  elsif CRLF == line
    @target_ct = @target_hd[CTT_TYPE_LC] || TEXT_PLAIN
    @state = new_content

  end
end

#parse_line(line) ⇒ Object



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/safrano/multipart.rb', line 68

def parse_line(line)
  case @state
  when :h
    parse_head(line)

  when :b
    @target.parser.addline(line)

  when :bmp
    @state = :first_part if @target.parser.first_part(line)

  when :first_part
    parse_first_part(line)

  when :next_part
    parse_next_part(line)
  end
end

#parse_lines(inp, level: 0) ⇒ Object



134
135
136
137
# File 'lib/safrano/multipart.rb', line 134

def parse_lines(inp, level: 0)
  @lines = inp
  parse(level: level)
end

#parse_next_part(line) ⇒ Object



47
48
49
50
51
52
53
54
55
# File 'lib/safrano/multipart.rb', line 47

def parse_next_part(line)
  return if @target.parser.next_part(line)

  if @target.parser.last_part(line)
    @state = :end
  else
    @target.parser.addline(line)
  end
end

#parse_str(inpstr, level: 0) ⇒ Object



139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/safrano/multipart.rb', line 139

def parse_str(inpstr, level: 0)
  # we need to keep the line separators --> use io.readlines
  @lines = if inpstr.respond_to?(:readlines)
             inpstr.readlines(@sep)
           else
             # rack input wrapper only has gets but not readlines
             # BUT the rack SPEC says it only supports gets without argument!
             # --> finally we end up using read and split into lines...
             # normally should be ok for $batch POST payloads

             # inpstr.read should be a String
             inpstr.read.lines(@sep)
           end
  # tmp hack for test-tools that convert CRLF in payload to LF :-(
  if @lines.size == 1
    @sep = LF
    @lines = @lines.first.split(LF).map { |xline| "#{xline}#{CRLF}" }
  end
  parse(level: level)
end

#parse_string(inpstr, level: 0) ⇒ Object



160
161
162
163
164
165
166
167
168
169
# File 'lib/safrano/multipart.rb', line 160

def parse_string(inpstr, level: 0)
  @lines = inpstr.split(@sep)
  if @lines.size == 1
    @sep = LF
    @lines = @lines.first.split(LF)
  end
  # split is not keeping the separator, we re-add it
  @lines = @lines.map { |line| "#{line}#{CRLF}" }
  parse(level: level)
end