Class: Hayabusa::Http_session::Post_multipart

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

Overview

This class parses and handels post-multipart requests.

Defined Under Namespace

Classes: File_upload

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(args) ⇒ Post_multipart

Returns a new instance of Post_multipart.



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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
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
# File 'lib/hayabusa_http_session_post_multipart.rb', line 8

def initialize(args)
  @args = args
  crlf = args[:crlf]
  crlf_len = crlf.length
  
  boundary_regexp = /\A--#{Regexp.escape(@args[:boundary])}(--)?(\r\n|\n|$)\z/
  @return = {}
  @data = nil
  @mode = nil
  @clength = 0
  @headers = {}
  @counts = {}
  @files_arr = args[:files_arr]
  str_crlf = nil
  
  @args[:io].each do |line|
    begin
      boundary_match = line.match(boundary_regexp)
    rescue ArgumentError
      #Happens when "invalid byte sequence in UTF-8" - the boundary-line will be UTF-8-valid and match the 'boundary_regexp'.
      boundary_match = false
    end
    
    if boundary_match
      #Finish the data we were writing.
      self.finish_data if @data
      
      @data_written = 0
      @clength = nil
      @name = nil
      @mode = "headers"
      str_crlf = nil
    elsif @mode == "headers"
      if match = line.match(/^(.+?):\s+(.+)#{crlf}$/)
        key = match[1].to_s.downcase
        val = match[2]
        
        @headers[key] = val
        
        if key == "content-length"
          @clength = val.to_i
        elsif key == "content-disposition"
          #Figure out value-name in post-hash.
          match_name = val.match(/name=\"(.+?)\"/)
          raise "Could not match name." if !match_name
          @name = match_name[1]
          
          #Fix count with name if given as increamental [].
          if match = @name.match(/^(.+)\[\]$/)
            if !@counts.key?(match[1])
              @counts[match[1]] = 0
            else
              @counts[match[1]] += 1
            end
            
            @name = "#{match[1]}[#{@counts[match[1]]}]"
          end
          
          #Figure out actual filename.
          if match_fname = val.match(/filename=\"(.+?)\"/)
            @fname = match_fname[1]
            @data = Tempfile.new("hayabusa_http_session_post_multipart")
          else
            @data = ""
          end
        end
      elsif line == crlf
        @mode = "body"
      else
        raise "Could not match header from: '#{line}'."
      end
    elsif @mode == "body"
      if line[-crlf_len, crlf_len] == crlf
        str = "#{str_crlf}#{line[0, line.length - crlf_len]}"
        str_crlf = crlf
      else
        str = "#{str_crlf}#{line}"
        str_crlf = nil
      end
      
      @data_written += str.bytesize
      @data << str
      
      self.finish_data if @clength and @data_written >= @clength
    elsif !@mode and (line == crlf or line == "\n" or line == "\r\n")
      #ignore.
    else
      raise "Invalid mode: '#{@mode}' (#{@mode.class.name}) for line: '#{line}' for total post-string:\n#{@args[:io].string}"
    end
  end
  
  self.finish_data if @data
  
  @data = nil
  @headers = nil
  @mode = nil
  @args = nil
end

Instance Attribute Details

#returnObject (readonly)

This hash contains all the data read from the post-request.



6
7
8
# File 'lib/hayabusa_http_session_post_multipart.rb', line 6

def return
  @return
end

Instance Method Details

#finish_dataObject

Add the current treated data to the return-hash.



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/hayabusa_http_session_post_multipart.rb', line 108

def finish_data
  if @headers.empty? and @data_written == 0
    @data.close(true) if @data.is_a?(Tempfile)
    
    self.reset_data
    return nil
  end
  
  if @data.is_a?(Tempfile)
    @data.close(false)
    @files_arr << @data.path if @data.respond_to?(:path)
  end
  
  raise "No 'content-disposition' was given (#{@headers}) (#{@data})." if !@name
  
  if @fname
    obj = Hayabusa::Http_session::Post_multipart::File_upload.new(
      :fname => @fname,
      :headers => @headers,
      :data => @data
    )
    @return[@name] = obj
  else
    @return[@name] = @data
  end
  
  self.reset_data
end

#reset_dataObject



137
138
139
140
141
142
143
144
# File 'lib/hayabusa_http_session_post_multipart.rb', line 137

def reset_data
  @data = nil
  @name = nil
  @fname = nil
  @headers = {}
  @mode = nil
  @clength = 0
end