multipart 0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (2) hide show
  1. data/multipart.rb +216 -0
  2. metadata +53 -0
@@ -0,0 +1,216 @@
1
+ # Multipart POST file upload for Net::HTTP::Post.
2
+ #
3
+ # By Leonardo Boiko <leoboiko@gmail.com>, public domain.
4
+ #
5
+ # Usage: see documentation for Net::HTTP::FileForPost and
6
+ # Net::HTTP::Post#set_multipart_data.
7
+
8
+ require 'net/http'
9
+ require 'stringio'
10
+
11
+ module Net
12
+ class HTTP
13
+
14
+ # When sending files via POST (rfc1867), the HTTP message has a
15
+ # special content-type: multipart/form-data. Its body includes
16
+ # zero or more key/value parameters like in other POST messages,
17
+ # plus one or more file upload parameters. File upload parameters
18
+ # are special:
19
+ #
20
+ # - A single parameter may carry more than one file. This
21
+ # technique is called multipart/mixed.
22
+ #
23
+ # - Each _file_ (not parameter!) can include extra metadata: its
24
+ # filename and mimetype.
25
+ #
26
+ # This class models the file arguments used in
27
+ # multipart/form-data. See Net::HTTP::Post#set_multipart_data for
28
+ # examples.
29
+ #
30
+ class FileForPost
31
+ attr_accessor :filename, :mimetype, :shouldclose
32
+ attr_reader :input
33
+
34
+ # Arguments:
35
+ #
36
+ # filepath_or_io:: The file to upload; either the pathname to
37
+ # open, or an IO object. If it's a pathname,
38
+ # it will be opened now and closed
39
+ # automatically later.
40
+ #
41
+ # mimetype:: The content-type. Per RFC defaults to
42
+ # 'application/octet-stream', but I recommend setting
43
+ # it explicitly.
44
+ #
45
+ # filename:: The file name to send to the remote server. If not
46
+ # supplied, will guess one based on the file's path.
47
+ # You can set it later with filename=.
48
+ #
49
+ def initialize(filepath_or_io,
50
+ mimetype='application/octet-stream',
51
+ filename=nil)
52
+ @mimetype = mimetype
53
+ @filename = nil
54
+
55
+ if filepath_or_io.respond_to? :read
56
+ @input = filepath_or_io
57
+ @shouldclose = false # came opened
58
+
59
+ if filepath_or_io.respond_to? :path
60
+ @filename = File.basename(filepath_or_io.path)
61
+ end
62
+
63
+ else
64
+ @input = File.open(filepath_or_io, 'rb')
65
+ @shouldclose = true # I opened it
66
+ @filename = File.basename(filepath_or_io)
67
+ end
68
+
69
+ end
70
+
71
+ def read(*args)
72
+ @input.read(*args)
73
+ end
74
+
75
+ def maybeclose
76
+ @input.close if @shouldclose
77
+ end
78
+ end
79
+
80
+ class Post
81
+
82
+ # Similar to Net::HTTP::Post#set_form_data (in Ruby's stardard
83
+ # library), but set up file upload parameters using the
84
+ # appropriate HTTP/HTML Forms multipart format.
85
+ #
86
+ # *Arguments*
87
+ #
88
+ # files_params:: A hash of file upload parameters. The keys are
89
+ # parameter names, and the values are
90
+ # Net::HTTP::FileForPost instances. See that
91
+ # class documentation for more info about how
92
+ # POST file upload works.
93
+ #
94
+ # other_params:: A hash of {key => value} pairs for the regular
95
+ # POST parameters, just like in set_form_data.
96
+ # Don't mix set_form_data and set_multipart_data;
97
+ # they'll overwrite each other's work.
98
+ #
99
+ # boundary1, boundary2:: A couple of strings which doesn't occur
100
+ # in your files. Boundary2 is only
101
+ # needed if you're using the
102
+ # multipart/mixed technique. The
103
+ # defaults should be OK for most cases.
104
+ #
105
+ # *Examples*
106
+ #
107
+ # Simplest case (single-parameter single-file), complete:
108
+ #
109
+ # require 'net/http'
110
+ # require 'rubygems'
111
+ # require 'multipart'
112
+ #
113
+ # req = Net::HTTP::Post.new('/scripts/upload.rb')
114
+ # req.basic_auth('jack', 'inflamed sense of rejection')
115
+ #
116
+ # file = Net::HTTP::FileForPost.new('/tmp/yourlife.txt', 'text/plain')
117
+ # req.set_multipart_data({:poem => file},
118
+ #
119
+ # {:author => 'jack',
120
+ # :user_agent => 'soapfactory'})
121
+ #
122
+ # res = Net::HTTP.new(url.host, url.port).start do |http|
123
+ # http.request(req)
124
+ # end
125
+ #
126
+ # Convoluted example:
127
+ #
128
+ # pic1 = Net::HTTP::FileForPost.new('pic1.jpeg', 'image/jpeg')
129
+ # pic2 = Net::HTTP::FileForPost.new(pic2_io, 'image/jpeg')
130
+ # pic3 = Net::HTTP::FileForPost.new('pic3.png', 'image/png')
131
+ # pic1_t = Net::HTTP::FileForPost.new('pic1_thumb.jpeg', 'image/jpeg')
132
+ # pic2_t = Net::HTTP::FileForPost.new(pic2_t_io, 'image/jpeg')
133
+ # desc = Net::HTTP::FileForPost.new('desc.html', 'text/html',
134
+ # 'index.html') # remote fname
135
+ #
136
+ # req.set_multipart_data({:gallery_description => des,
137
+ # :pictures => [pic1, pic2, pic3],
138
+ # :thumbnails => [pic1_t, pic2_t]},
139
+ #
140
+ # {:gallery_name => 'mygallery',
141
+ # :encoding => 'utf-8'})
142
+ #
143
+ def set_multipart_data(files_params,
144
+ other_params={},
145
+ boundary1="paranguaricutirimirruaru0xdeadbeef",
146
+ boundary2="paranguaricutirimirruaru0x20132")
147
+
148
+ self.content_type = "multipart/form-data, boundary=\"#{boundary1}\""
149
+
150
+ tmp = StringIO.new('r+b')
151
+
152
+ # let's do the easy ones first
153
+ other_params.each do |key,val|
154
+ tmp.write "\n--#{boundary1}\n"
155
+ tmp.write "content-disposition: form-data; name=\"#{key}\"\n"
156
+ tmp.write "\n"
157
+ tmp.write "#{val}"
158
+ end
159
+
160
+ # now handle the files...
161
+ files_params.each do |name, file|
162
+ tmp.write "\n--#{boundary1}\n"
163
+
164
+ # no \n
165
+ tmp.write "content-disposition: form-data; name=\"#{name}\""
166
+
167
+ if not file.is_a? Enumerable
168
+ # single-file multipart is different
169
+
170
+ if file.filename
171
+ # right in content-dispo line
172
+ tmp.write "; filename=\"#{file.filename}\"\n"
173
+ else
174
+ tmp.write "\n"
175
+ end
176
+
177
+ tmp.write "Content-Type: #{file.mimetype}\n"
178
+ tmp.write "Content-Transfer-Encoding: binary\n"
179
+ tmp.write "\n"
180
+ tmp.write(file.read())
181
+ file.maybeclose
182
+ else
183
+ # multiple-file parameter (multipart/mixed)
184
+ tmp.write "\n"
185
+ tmp.write "Content-Type: multipart/mixed,"
186
+ tmp.write " boundary=\"#{boundary2}\"\n"
187
+
188
+ file.each do |f|
189
+ tmp.write "\n--#{boundary2}\n"
190
+
191
+ tmp.write "Content-disposition: attachment"
192
+ if f.filename
193
+ tmp.write "; filename=\"#{f.filename}\"\n"
194
+ else
195
+ tmp.write "\n"
196
+ end
197
+
198
+ tmp.write "Content-Type: #{f.mimetype}\n"
199
+ tmp.write "Content-Transfer-Encoding: binary\n"
200
+ tmp.write "\n"
201
+ tmp.write(f.read())
202
+ f.maybeclose
203
+ end
204
+ tmp.write "\n--#{boundary2}\n"
205
+ end
206
+ end
207
+ tmp.write "\n--#{boundary1}\n"
208
+
209
+ tmp.flush.seek(0)
210
+
211
+ self.body_stream = tmp
212
+ nil
213
+ end
214
+ end
215
+ end
216
+ end
metadata ADDED
@@ -0,0 +1,53 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: multipart
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.2"
5
+ platform: ruby
6
+ authors:
7
+ - Leonardo Boiko
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-08-05 00:00:00 -03:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Multipart is a gem that adds support to multipart/form-encoded and multipart/mixed (file upload) to Net::HTTP::Post. Nothing more, nothing less. Currently it supports a file param with multiple files, but not multiple file params.
17
+ email: leoboiko@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - multipart.rb
26
+ has_rdoc: true
27
+ homepage: http://rubyforge.org/projects/multipart
28
+ post_install_message:
29
+ rdoc_options: []
30
+
31
+ require_paths:
32
+ - .
33
+ required_ruby_version: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: 1.8.3
38
+ version:
39
+ required_rubygems_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: "0"
44
+ version:
45
+ requirements: []
46
+
47
+ rubyforge_project: multipart
48
+ rubygems_version: 1.1.1
49
+ signing_key:
50
+ specification_version: 2
51
+ summary: add multipart (file upload) support to Net::HTTP::Post
52
+ test_files: []
53
+