troelskn-handsoap 0.4.1 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. data/VERSION.yml +1 -1
  2. data/lib/handsoap/service.rb +130 -5
  3. metadata +4 -4
data/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :minor: 4
3
- :patch: 1
3
+ :patch: 2
4
4
  :major: 0
@@ -189,12 +189,28 @@ module Handsoap
189
189
  on_after_create_http_client(http_client)
190
190
  http_client.headers = headers
191
191
  http_client.http_post post_body
192
- return { :status => http_client.response_code, :body => http_client.body_str, :content_type => http_client.content_type }
192
+ if %r|\Amultipart.*boundary=\"?([^\";,]+)\"?|n.match(http_client.content_type)
193
+ boundary = $1.dup
194
+ parts = Handsoap.parse_multipart(boundary, http_client.body_str)
195
+ is_multipart = true
196
+ else
197
+ parts = [{:head => http_client.header_str, :body => http_client.body_str}]
198
+ is_multipart = false
199
+ end
200
+ return { :status => http_client.response_code, :body => http_client.body_str, :content_type => http_client.content_type, :parts => parts, :multipart => is_multipart }
193
201
  elsif Handsoap.http_driver == :httpclient
194
202
  http_client = HTTPClient.new
195
203
  on_after_create_http_client(http_client)
196
204
  response = http_client.post(uri, post_body, headers)
197
- return { :status => response.status, :body => response.content, :content_type => response.contenttype }
205
+ if %r|\Amultipart.*boundary=\"?([^\";,]+)\"?|n.match(response.contenttype)
206
+ boundary = $1.dup
207
+ parts = Handsoap.parse_multipart(boundary, response.content)
208
+ is_multipart = true
209
+ else
210
+ parts = [{:head => response.all.join("\r\n"), :body => response.content}]
211
+ is_multipart = false
212
+ end
213
+ return { :status => response.status, :body => response.content, :content_type => response.contenttype, :parts => parts, :multipart => is_multipart }
198
214
  else
199
215
  raise "Unknown http driver #{Handsoap.http_driver}"
200
216
  end
@@ -220,12 +236,23 @@ module Handsoap
220
236
  logger.puts "--- Response ---"
221
237
  logger.puts "HTTP Status: %s" % [response[:status]]
222
238
  logger.puts "Content-Type: %s" % [response[:content_type]]
223
- logger.puts "---"
224
- logger.puts Handsoap.pretty_format_envelope(response[:body])
239
+ if response[:multipart]
240
+ num = 0
241
+ response[:parts].each do |part|
242
+ num += 1
243
+ logger.puts "--- Part ##{num} ---"
244
+ logger.puts part[:head].gsub(/\r\n/, "\n")
245
+ logger.puts "---"
246
+ logger.puts Handsoap.pretty_format_envelope(part[:body])
247
+ end
248
+ else
249
+ logger.puts "---"
250
+ logger.puts Handsoap.pretty_format_envelope(response[:body])
251
+ end
225
252
  end
226
253
  # Start the parsing pipe-line.
227
254
  # There are various stages and hooks for each, so that you can override those in your service classes.
228
- xml_document = parse_soap_response_document(response[:body])
255
+ xml_document = parse_soap_response_document(response[:parts].first[:body]) # Strictly speaking, the main part doesn't need to be first, but until proven otherwise, we'll just assume that.
229
256
  soap_fault = parse_soap_fault(xml_document)
230
257
  # Is the response a soap-fault?
231
258
  unless soap_fault.nil?
@@ -245,6 +272,10 @@ module Handsoap
245
272
  def xml_document.document
246
273
  self
247
274
  end
275
+ # I should probably use a class for this response object instead ...
276
+ def xml_document.parts
277
+ response[:parts]
278
+ end
248
279
  return xml_document
249
280
  end
250
281
  # Creates a standard SOAP envelope and yields the +Body+ element.
@@ -293,6 +324,100 @@ module Handsoap
293
324
  return xml_string
294
325
  end
295
326
 
327
+ # Parses a multipart http-response body into parts.
328
+ # +boundary+ is a string of the boundary token.
329
+ # +content_io+ is either a string or an IO. If it's an IO, then content_length must be specified.
330
+ # +content_length+ (optional) is an integer, specifying the length of +content_io+
331
+ #
332
+ # This code is lifted from cgi.rb
333
+ #
334
+ def self.parse_multipart(boundary, content_io, content_length = nil)
335
+ if content_io.kind_of? String
336
+ content_length = content_io.length
337
+ content_io = StringIO.new(content_io, 'r')
338
+ elsif !(content_io.kind_of? IO) || content_length.nil?
339
+ raise "Second argument must be String or IO with content_length"
340
+ end
341
+
342
+ boundary = "--" + boundary
343
+ quoted_boundary = Regexp.quote(boundary, "n")
344
+ buf = ""
345
+ bufsize = 10 * 1024
346
+ boundary_end = ""
347
+
348
+ # start multipart/form-data
349
+ content_io.binmode if defined? content_io.binmode
350
+ boundary_size = boundary.size + "\r\n".size
351
+ content_length -= boundary_size
352
+ status = content_io.read(boundary_size)
353
+ if nil == status
354
+ raise EOFError, "no content body"
355
+ elsif boundary + "\r\n" != status
356
+ raise EOFError, "bad content body"
357
+ end
358
+
359
+ parts = []
360
+
361
+ loop do
362
+ head = nil
363
+ if 10240 < content_length
364
+ require "tempfile"
365
+ body = Tempfile.new("CGI")
366
+ else
367
+ begin
368
+ require "stringio"
369
+ body = StringIO.new
370
+ rescue LoadError
371
+ require "tempfile"
372
+ body = Tempfile.new("CGI")
373
+ end
374
+ end
375
+ body.binmode if defined? body.binmode
376
+
377
+ until head and /#{quoted_boundary}(?:\r\n|--)/n.match(buf)
378
+
379
+ if (not head) and /\r\n\r\n/n.match(buf)
380
+ buf = buf.sub(/\A((?:.|\n)*?\r\n)\r\n/n) do
381
+ head = $1.dup
382
+ ""
383
+ end
384
+ next
385
+ end
386
+
387
+ if head and ( ("\r\n" + boundary + "\r\n").size < buf.size )
388
+ body.print buf[0 ... (buf.size - ("\r\n" + boundary + "\r\n").size)]
389
+ buf[0 ... (buf.size - ("\r\n" + boundary + "\r\n").size)] = ""
390
+ end
391
+
392
+ c = if bufsize < content_length
393
+ content_io.read(bufsize)
394
+ else
395
+ content_io.read(content_length)
396
+ end
397
+ if c.nil? || c.empty?
398
+ raise EOFError, "bad content body"
399
+ end
400
+ buf.concat(c)
401
+ content_length -= c.size
402
+ end
403
+
404
+ buf = buf.sub(/\A((?:.|\n)*?)(?:[\r\n]{1,2})?#{quoted_boundary}([\r\n]{1,2}|--)/n) do
405
+ body.print $1
406
+ if "--" == $2
407
+ content_length = -1
408
+ end
409
+ boundary_end = $2.dup
410
+ ""
411
+ end
412
+
413
+ parts << {:head => head, :body => body.string}
414
+ break if buf.size == 0
415
+ break if content_length == -1
416
+ end
417
+ raise EOFError, "bad boundary end of body part" unless boundary_end =~ /--/
418
+ parts
419
+ end
420
+
296
421
  end
297
422
 
298
423
  # Legacy/BC code here. This shouldn't be used in new applications.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: troelskn-handsoap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Troels Knak-Nielsen
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-07-31 00:00:00 -07:00
12
+ date: 2009-08-03 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -33,7 +33,7 @@ files:
33
33
  - lib/handsoap/service.rb
34
34
  - lib/handsoap/xml_mason.rb
35
35
  - lib/handsoap/xml_query_front.rb
36
- has_rdoc: false
36
+ has_rdoc: true
37
37
  homepage: http://github.com/troelskn/handsoap
38
38
  licenses:
39
39
  post_install_message:
@@ -62,7 +62,7 @@ requirements:
62
62
  rubyforge_project:
63
63
  rubygems_version: 1.3.5
64
64
  signing_key:
65
- specification_version: 3
65
+ specification_version: 2
66
66
  summary: Handsoap is a library for creating SOAP clients in Ruby
67
67
  test_files: []
68
68