httpi 0.6.1 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -139,6 +139,7 @@ HTTPI::Auth::SSL
139
139
 
140
140
  request = HTTPI::Request.new
141
141
  request.auth.ssl.cert_key_file = "client_key.pem"
142
+ request.auth.ssl.cert_key_password = "C3rtP@ssw0rd"
142
143
  request.auth.ssl.cert_file = "client_cert.pem"
143
144
  request.auth.ssl.verify_mode = :none
144
145
 
@@ -168,6 +169,8 @@ It contains the response code, headers and body.
168
169
  response.headers # => { "Content-Encoding" => "gzip" }
169
170
  response.body # => "<!DOCTYPE HTML PUBLIC ...>"
170
171
 
172
+ The `response.body` handles gzipped and [DIME](http://en.wikipedia.org/wiki/Direct_Internet_Message_Encapsulation) encoded responses.
173
+
171
174
  ### TODO
172
175
 
173
176
  * Return the original `HTTPI::Request` for debugging purposes
@@ -20,6 +20,9 @@ module HTTPI
20
20
  # Accessor for the cert key file to validate SSL certificates.
21
21
  attr_accessor :cert_key_file
22
22
 
23
+ # Accessor for the cert key password to validate SSL certificates.
24
+ attr_accessor :cert_key_password
25
+
23
26
  # Accessor for the cert file to validate SSL connections.
24
27
  attr_accessor :cert_file
25
28
 
@@ -55,7 +58,7 @@ module HTTPI
55
58
 
56
59
  # Returns an <tt>OpenSSL::PKey::RSA</tt> for the +cert_key_file+.
57
60
  def cert_key
58
- @cert_key ||= OpenSSL::PKey::RSA.new File.read(cert_key_file)
61
+ @cert_key ||= OpenSSL::PKey::RSA.new(File.read(cert_key_file), cert_key_password)
59
62
  end
60
63
 
61
64
  # Sets the +OpenSSL+ certificate key.
data/lib/httpi/dime.rb ADDED
@@ -0,0 +1,56 @@
1
+ module HTTPI
2
+ class DimeRecord < Struct.new('DimeRecord', :version, :first, :last, :chunked, :type_format, :options, :id, :type, :data)
3
+ end
4
+
5
+ class Dime < Array
6
+ BINARY = 1
7
+ XML = 2
8
+
9
+ def initialize(body)
10
+ bytes = body.unpack('C*')
11
+
12
+ while bytes.length > 0
13
+ record = DimeRecord.new
14
+
15
+ # Shift out bitfields for the first fields
16
+ byte = bytes.shift
17
+ record.version = (byte >> 3) & 31 # 5 bits DIME format version (always 1)
18
+ record.first = (byte >> 2) & 1 # 1 bit Set if this is the first part in the message
19
+ record.last = (byte >> 1) & 1 # 1 bit Set if this is the last part in the message
20
+ record.chunked = byte & 1 # 1 bit This file is broken into chunked parts
21
+ record.type_format = (bytes.shift >> 4) & 15 # 4 bits Type of file in the part (1 for binary data, 2 for XML)
22
+ # 4 bits Reserved (skipped in the above command)
23
+
24
+ # Fetch big-endian lengths
25
+ lengths = [] # we can't use a hash since the order will be screwed in Ruby 1.8
26
+ lengths << [:options, (bytes.shift << 8) | bytes.shift] # 2 bytes Length of the "options" field
27
+ lengths << [:id, (bytes.shift << 8) | bytes.shift] # 2 bytes Length of the "ID" or "name" field
28
+ lengths << [:type, (bytes.shift << 8) | bytes.shift] # 2 bytes Length of the "type" field
29
+ lengths << [:data, (bytes.shift << 24) | (bytes.shift << 16) | (bytes.shift << 8) | bytes.shift] # 4 bytes Size of the included file
30
+
31
+ # Read in padded data
32
+ lengths.each do |attribute_set|
33
+ attribute, length = attribute_set
34
+ content = bytes.slice!(0, length).pack('C*')
35
+ if attribute == :data && record.type_format == BINARY
36
+ content = StringIO.new(content)
37
+ end
38
+
39
+ record.send "#{attribute.to_s}=", content
40
+
41
+ bytes.slice!(0, 4 - (length & 3)) if (length & 3) != 0
42
+ end
43
+
44
+ self << record
45
+ end
46
+ end
47
+
48
+ def xml_records
49
+ select { |r| r.type_format == XML }
50
+ end
51
+
52
+ def binary_records
53
+ select { |r| r.type_format == BINARY }
54
+ end
55
+ end
56
+ end
@@ -1,5 +1,6 @@
1
1
  require "zlib"
2
2
  require "stringio"
3
+ require "httpi/dime"
3
4
 
4
5
  module HTTPI
5
6
 
@@ -18,34 +19,57 @@ module HTTPI
18
19
  self.raw_body = body
19
20
  end
20
21
 
21
- attr_accessor :code, :headers, :raw_body
22
+ attr_accessor :code, :headers, :raw_body, :attachments
22
23
 
23
24
  # Returns whether the HTTP response is considered successful.
24
25
  def error?
25
26
  !SuccessfulResponseCodes.include? code.to_i
26
27
  end
27
28
 
29
+ def attachments
30
+ decode_body unless @body
31
+ @attachments ||= []
32
+ end
33
+
28
34
  # Returns the HTTP response body.
29
35
  def body
30
- @body ||= gzipped_response? ? decoded_body : raw_body
36
+ decode_body unless @body
37
+ @body
31
38
  end
32
39
 
33
40
  attr_writer :body
34
41
 
35
42
  private
36
43
 
44
+ def decode_body
45
+ body = gzipped_response? ? decoded_gzip_body : raw_body
46
+ @body = dime_response? ? decoded_dime_body(body) : body
47
+ end
48
+
37
49
  # Returns whether the response is gzipped.
38
50
  def gzipped_response?
39
51
  headers["Content-Encoding"] == "gzip" || raw_body[0..1] == "\x1f\x8b"
40
52
  end
41
53
 
54
+ # Returns whether this is a DIME response.
55
+ def dime_response?
56
+ headers['Content-Type'] == 'application/dime'
57
+ end
58
+
42
59
  # Returns the gzip decoded response body.
43
- def decoded_body
60
+ def decoded_gzip_body
44
61
  gzip = Zlib::GzipReader.new StringIO.new(raw_body)
45
62
  gzip.read
46
63
  ensure
47
64
  gzip.close
48
65
  end
49
66
 
67
+ # Returns the DIME decoded response body.
68
+ def decoded_dime_body(body = nil)
69
+ dime = Dime.new(body || raw_body)
70
+ self.attachments = dime.binary_records
71
+ dime.xml_records.first.data
72
+ end
73
+
50
74
  end
51
75
  end
data/lib/httpi/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module HTTPI
2
2
 
3
- VERSION = "0.6.1"
3
+ VERSION = "0.7.0"
4
4
 
5
5
  end
Binary file
Binary file
@@ -0,0 +1 @@
1
+ <?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soapenv:Body><getFileResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><getFileReturn href="#id0"/></getFileResponse><multiRef id="id0" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="ns1:FileVW" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://ws"><created xsi:type="xsd:dateTime">2010-10-27T22:00:00.000Z</created><id xsi:type="xsd:int">2181136</id><lastUpdated xsi:type="xsd:dateTime">2010-10-27T22:00:00.000Z</lastUpdated><metadata href="#id1"/><name xsi:type="xsd:string">attachment.gif</name><size xsi:type="xsd:long">80</size><type xsi:type="xsd:string">gif</type><version xsi:type="xsd:long">1</version></multiRef><multiRef id="id1" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="ns2:MetadataVW" xmlns:ns2="http://ws" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"><CR_Latest xsi:type="xsd:boolean">true</CR_Latest><MD5 xsi:type="xsd:string">0xC11FE5DB260A89160FFF4EC26630EEB8</MD5><PSize xsi:type="xsd:string" xsi:nil="true"/><category xsi:type="xsd:string">1</category><completionRate xsi:type="xsd:int">1</completionRate><date xsi:type="xsd:string" xsi:nil="true"/><docNo xsi:type="xsd:string"></docNo><filesId xsi:type="xsd:int">2181136</filesId><init xsi:type="xsd:string"></init><locked xsi:type="xsd:boolean">false</locked><mdate xsi:type="xsd:dateTime">2010-10-28T20:27:00.000Z</mdate><meta1 xsi:type="xsd:string" xsi:nil="true"/><meta10 xsi:type="xsd:string" xsi:nil="true"/><meta11 xsi:type="xsd:string" xsi:nil="true"/><meta12 xsi:type="xsd:string" xsi:nil="true"/><meta13 xsi:type="xsd:string" xsi:nil="true"/><meta14 xsi:type="xsd:string" xsi:nil="true"/><meta15 xsi:type="xsd:string" xsi:nil="true"/><meta16 xsi:type="xsd:string" xsi:nil="true"/><meta17 xsi:type="xsd:string" xsi:nil="true"/><meta18 xsi:type="xsd:string" xsi:nil="true"/><meta19 xsi:type="xsd:string" xsi:nil="true"/><meta2 xsi:type="xsd:string" xsi:nil="true"/><meta20 xsi:type="xsd:string" xsi:nil="true"/><meta3 xsi:type="xsd:string" xsi:nil="true"/><meta4 xsi:type="xsd:string" xsi:nil="true"/><meta5 xsi:type="xsd:string" xsi:nil="true"/><meta6 xsi:type="xsd:string" xsi:nil="true"/><meta7 xsi:type="xsd:string" xsi:nil="true"/><meta8 xsi:type="xsd:string" xsi:nil="true"/><meta9 xsi:type="xsd:string" xsi:nil="true"/><note xsi:type="xsd:string" xsi:nil="true"/><ref xsi:type="xsd:string"></ref><ref2 xsi:type="xsd:string" xsi:nil="true"/><ref3 xsi:type="xsd:string" xsi:nil="true"/><ref4 xsi:type="xsd:string" xsi:nil="true"/><revDate xsi:type="xsd:string"></revDate><revName xsi:type="xsd:string"></revName><scale xsi:type="xsd:string" xsi:nil="true"/><scaleUnit xsi:type="xsd:string" xsi:nil="true"/><size xsi:type="xsd:int">80</size><type xsi:type="xsd:string">Document</type><version xsi:type="xsd:int">1</version></multiRef></soapenv:Body></soapenv:Envelope>
@@ -2,7 +2,7 @@ require "spec_helper"
2
2
  require "httpi/response"
3
3
 
4
4
  describe HTTPI::Response do
5
- let(:response) { HTTPI::Response.new 200, { "Content-Encoding" => "gzip" }, Fixture.gzip }
5
+ let(:response) { HTTPI::Response.new 200, { "Content-Encoding" => "gzip" }, Fixture.xml }
6
6
 
7
7
  describe "#code" do
8
8
  it "should return the HTTP response code" do
@@ -15,6 +15,11 @@ describe HTTPI::Response do
15
15
  end
16
16
  end
17
17
 
18
+ end
19
+
20
+ describe HTTPI::Response, "gzip" do
21
+ let(:response) { HTTPI::Response.new 200, { "Content-Encoding" => "gzip" }, Fixture.gzip }
22
+
18
23
  describe "#headers" do
19
24
  it "should return the HTTP response headers" do
20
25
  response.headers.should == { "Content-Encoding" => "gzip" }
@@ -34,3 +39,32 @@ describe HTTPI::Response do
34
39
  end
35
40
 
36
41
  end
42
+
43
+ describe HTTPI::Response, "DIME" do
44
+ let(:response) { HTTPI::Response.new 200, { "Content-Type" => "application/dime" }, Fixture.dime }
45
+
46
+ describe "#headers" do
47
+ it "should return the HTTP response headers" do
48
+ response.headers.should == { "Content-Type" => "application/dime" }
49
+ end
50
+ end
51
+
52
+ describe "#body" do
53
+ it "should return the (dime decoded) HTTP response body" do
54
+ response.body.should == Fixture.xml_dime
55
+ end
56
+ end
57
+
58
+ describe "#raw_body" do
59
+ it "should return the raw HTML response body" do
60
+ response.raw_body.should == Fixture.dime
61
+ end
62
+ end
63
+
64
+ describe "#attachments" do
65
+ it "should return proper attachment when given a dime response" do
66
+ response.attachments.first.data == File.read(File.expand_path("../../fixtures/attachment.gif", __FILE__))
67
+ end
68
+ end
69
+
70
+ end
@@ -5,10 +5,18 @@ class Fixture
5
5
  @xml ||= load :xml
6
6
  end
7
7
 
8
+ def xml_dime
9
+ @xml_dime ||= load :xml_dime
10
+ end
11
+
8
12
  def gzip
9
13
  @gzip ||= load :xml, :gz
10
14
  end
11
15
 
16
+ def dime
17
+ @dime ||= load :xml_dime, :dime
18
+ end
19
+
12
20
  private
13
21
 
14
22
  def load(fixture, type = :xml)
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: httpi
3
3
  version: !ruby/object:Gem::Version
4
- hash: 5
4
+ hash: 3
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 6
9
- - 1
10
- version: 0.6.1
8
+ - 7
9
+ - 0
10
+ version: 0.7.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Daniel Harrington
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2010-11-01 00:00:00 +01:00
19
+ date: 2010-11-10 00:00:00 +01:00
20
20
  default_executable:
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency
@@ -124,13 +124,17 @@ files:
124
124
  - lib/httpi/adapter/net_http.rb
125
125
  - lib/httpi/auth/config.rb
126
126
  - lib/httpi/auth/ssl.rb
127
+ - lib/httpi/dime.rb
127
128
  - lib/httpi/request.rb
128
129
  - lib/httpi/response.rb
129
130
  - lib/httpi/version.rb
131
+ - spec/fixtures/attachment.gif
130
132
  - spec/fixtures/client_cert.pem
131
133
  - spec/fixtures/client_key.pem
132
134
  - spec/fixtures/xml.gz
133
135
  - spec/fixtures/xml.xml
136
+ - spec/fixtures/xml_dime.dime
137
+ - spec/fixtures/xml_dime.xml
134
138
  - spec/httpi/adapter/curb_spec.rb
135
139
  - spec/httpi/adapter/httpclient_spec.rb
136
140
  - spec/httpi/adapter/net_http_spec.rb