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 +3 -0
- data/lib/httpi/auth/ssl.rb +4 -1
- data/lib/httpi/dime.rb +56 -0
- data/lib/httpi/response.rb +27 -3
- data/lib/httpi/version.rb +1 -1
- data/spec/fixtures/attachment.gif +0 -0
- data/spec/fixtures/xml_dime.dime +0 -0
- data/spec/fixtures/xml_dime.xml +1 -0
- data/spec/httpi/response_spec.rb +35 -1
- data/spec/support/fixture.rb +8 -0
- metadata +9 -5
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
|
data/lib/httpi/auth/ssl.rb
CHANGED
@@ -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
|
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
|
data/lib/httpi/response.rb
CHANGED
@@ -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
|
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
|
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
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>
|
data/spec/httpi/response_spec.rb
CHANGED
@@ -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.
|
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
|
data/spec/support/fixture.rb
CHANGED
@@ -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:
|
4
|
+
hash: 3
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
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-
|
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
|