httpi 1.1.1 → 2.0.0.rc1

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.
data/lib/httpi/dime.rb CHANGED
@@ -1,8 +1,12 @@
1
1
  module HTTPI
2
- class DimeRecord < Struct.new('DimeRecord', :version, :first, :last, :chunked, :type_format, :options, :id, :type, :data)
3
- end
2
+
3
+ DimeRecord = Struct.new(
4
+ 'DimeRecord', :version, :first, :last, :chunked,
5
+ :type_format, :options, :id, :type, :data
6
+ )
4
7
 
5
8
  class Dime < Array
9
+
6
10
  BINARY = 1
7
11
  XML = 2
8
12
 
@@ -11,40 +15,51 @@ module HTTPI
11
15
 
12
16
  while bytes.length > 0
13
17
  record = DimeRecord.new
18
+ configure_record(record, bytes)
14
19
 
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
20
+ big_endian_lengths(bytes).each do |attribute_set|
21
+ read_data(record, bytes, attribute_set)
42
22
  end
43
23
 
44
24
  self << record
45
25
  end
46
26
  end
47
27
 
28
+ # Shift out bitfields for the first fields.
29
+ def configure_record(record, bytes)
30
+ byte = bytes.shift
31
+
32
+ record.version = (byte >> 3) & 31 # 5 bits DIME format version (always 1)
33
+ record.first = (byte >> 2) & 1 # 1 bit Set if this is the first part in the message
34
+ record.last = (byte >> 1) & 1 # 1 bit Set if this is the last part in the message
35
+ record.chunked = byte & 1 # 1 bit This file is broken into chunked parts
36
+ record.type_format = (bytes.shift >> 4) & 15 # 4 bits Type of file in the part (1 for binary data, 2 for XML)
37
+ # 4 bits Reserved (skipped in the above command)
38
+ end
39
+
40
+ # Fetch big-endian lengths.
41
+ def big_endian_lengths(bytes)
42
+ lengths = [] # we can't use a hash since the order will be screwed in Ruby 1.8
43
+ lengths << [:options, (bytes.shift << 8) | bytes.shift] # 2 bytes Length of the "options" field
44
+ lengths << [:id, (bytes.shift << 8) | bytes.shift] # 2 bytes Length of the "ID" or "name" field
45
+ lengths << [:type, (bytes.shift << 8) | bytes.shift] # 2 bytes Length of the "type" field
46
+ lengths << [:data, (bytes.shift << 24) | (bytes.shift << 16) | (bytes.shift << 8) | bytes.shift] # 4 bytes Size of the included file
47
+ lengths
48
+ end
49
+
50
+ # Read in padded data.
51
+ def read_data(record, bytes, attribute_set)
52
+ attribute, length = attribute_set
53
+ content = bytes.slice!(0, length).pack('C*')
54
+
55
+ if attribute == :data && record.type_format == BINARY
56
+ content = StringIO.new(content)
57
+ end
58
+
59
+ record.send "#{attribute.to_s}=", content
60
+ bytes.slice!(0, 4 - (length & 3)) if (length & 3) != 0
61
+ end
62
+
48
63
  def xml_records
49
64
  select { |r| r.type_format == XML }
50
65
  end
@@ -52,5 +67,6 @@ module HTTPI
52
67
  def binary_records
53
68
  select { |r| r.type_format == BINARY }
54
69
  end
70
+
55
71
  end
56
72
  end
data/lib/httpi/request.rb CHANGED
@@ -93,7 +93,7 @@ module HTTPI
93
93
  ATTRIBUTES.each { |key| send("#{key}=", args[key]) if args[key] }
94
94
  end
95
95
 
96
- private
96
+ private
97
97
 
98
98
  # Stores the cookies from past requests.
99
99
  def cookie_store
@@ -1,8 +1,9 @@
1
1
  require "zlib"
2
2
  require "stringio"
3
+ require "rack/utils"
4
+
3
5
  require "httpi/dime"
4
6
  require "httpi/cookie"
5
- require "rack/utils"
6
7
 
7
8
  module HTTPI
8
9
 
@@ -52,7 +53,7 @@ module HTTPI
52
53
 
53
54
  attr_writer :body
54
55
 
55
- private
56
+ private
56
57
 
57
58
  def decode_body
58
59
  return @body = "" if !raw_body || raw_body.empty?
@@ -73,8 +74,9 @@ module HTTPI
73
74
 
74
75
  # Returns the gzip decoded response body.
75
76
  def decoded_gzip_body
76
- gzip = Zlib::GzipReader.new StringIO.new(raw_body)
77
- raise ArgumentError.new "couldn't create gzip reader" unless gzip
77
+ unless gzip = Zlib::GzipReader.new(StringIO.new(raw_body))
78
+ raise ArgumentError, "Unable to create Zlib::GzipReader"
79
+ end
78
80
  gzip.read
79
81
  ensure
80
82
  gzip.close if gzip
data/lib/httpi/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module HTTPI
2
2
 
3
- VERSION = "1.1.1"
3
+ VERSION = "2.0.0.rc1"
4
4
 
5
5
  end
@@ -0,0 +1,23 @@
1
+ require "spec_helper"
2
+ require "httpi/adapter/base"
3
+
4
+ describe HTTPI::Adapter::Base do
5
+
6
+ subject(:base) { HTTPI::Adapter::Base.new(request) }
7
+ let(:request) { HTTPI::Request.new }
8
+
9
+ describe "#client" do
10
+ it "returns the adapter's client instance" do
11
+ expect { base.client }.
12
+ to raise_error(HTTPI::NotImplementedError, "Adapters need to implement a #client method")
13
+ end
14
+ end
15
+
16
+ describe "#request" do
17
+ it "executes arbitrary HTTP requests" do
18
+ expect { base.request(:get) }.
19
+ to raise_error(HTTPI::NotImplementedError, "Adapters need to implement a #request method")
20
+ end
21
+ end
22
+
23
+ end
@@ -4,13 +4,15 @@ require "httpi/request"
4
4
 
5
5
  # curb does not run on jruby
6
6
  unless RUBY_PLATFORM =~ /java/
7
- require "curb"
7
+ HTTPI::Adapter.load_adapter(:curb)
8
8
 
9
9
  describe HTTPI::Adapter::Curb do
10
- let(:adapter) { HTTPI::Adapter::Curb.new }
11
- let(:curb) { Curl::Easy.any_instance }
12
10
 
13
- describe "#get" do
11
+ let(:adapter) { HTTPI::Adapter::Curb.new(request) }
12
+ let(:curb) { Curl::Easy.any_instance }
13
+ let(:request) { HTTPI::Request.new("http://example.com") }
14
+
15
+ describe "#request(:get)" do
14
16
  before do
15
17
  curb.expects(:http_get)
16
18
  curb.expects(:response_code).returns(200)
@@ -19,11 +21,11 @@ unless RUBY_PLATFORM =~ /java/
19
21
  end
20
22
 
21
23
  it "returns a valid HTTPI::Response" do
22
- adapter.get(basic_request).should match_response(:body => Fixture.xml)
24
+ adapter.request(:get).should match_response(:body => Fixture.xml)
23
25
  end
24
26
  end
25
27
 
26
- describe "#post" do
28
+ describe "#request(:post)" do
27
29
  before do
28
30
  curb.expects(:http_post)
29
31
  curb.expects(:response_code).returns(200)
@@ -32,18 +34,20 @@ unless RUBY_PLATFORM =~ /java/
32
34
  end
33
35
 
34
36
  it "returns a valid HTTPI::Response" do
35
- adapter.post(basic_request).should match_response(:body => Fixture.xml)
37
+ adapter.request(:post).should match_response(:body => Fixture.xml)
36
38
  end
37
39
  end
38
40
 
39
- describe "#post" do
41
+ describe "#request(:post)" do
40
42
  it "sends the body in the request" do
41
- curb.expects(:http_post).with('xml=hi&name=123')
42
- adapter.post(basic_request { |request| request.body = 'xml=hi&name=123' } )
43
+ curb.expects(:http_post).with("xml=hi&name=123")
44
+
45
+ request.body = "xml=hi&name=123"
46
+ adapter.request(:post)
43
47
  end
44
48
  end
45
49
 
46
- describe "#head" do
50
+ describe "#request(:head)" do
47
51
  before do
48
52
  curb.expects(:http_head)
49
53
  curb.expects(:response_code).returns(200)
@@ -52,11 +56,11 @@ unless RUBY_PLATFORM =~ /java/
52
56
  end
53
57
 
54
58
  it "returns a valid HTTPI::Response" do
55
- adapter.head(basic_request).should match_response(:body => Fixture.xml)
59
+ adapter.request(:head).should match_response(:body => Fixture.xml)
56
60
  end
57
61
  end
58
62
 
59
- describe "#put" do
63
+ describe "#request(:put)" do
60
64
  before do
61
65
  curb.expects(:http_put)
62
66
  curb.expects(:response_code).returns(200)
@@ -65,18 +69,20 @@ unless RUBY_PLATFORM =~ /java/
65
69
  end
66
70
 
67
71
  it "returns a valid HTTPI::Response" do
68
- adapter.put(basic_request).should match_response(:body => Fixture.xml)
72
+ adapter.request(:put).should match_response(:body => Fixture.xml)
69
73
  end
70
74
  end
71
75
 
72
- describe "#put" do
76
+ describe "#request(:put)" do
73
77
  it "sends the body in the request" do
74
78
  curb.expects(:http_put).with('xml=hi&name=123')
75
- adapter.put(basic_request { |request| request.body = 'xml=hi&name=123' } )
79
+
80
+ request.body = 'xml=hi&name=123'
81
+ adapter.request(:put)
76
82
  end
77
83
  end
78
84
 
79
- describe "#delete" do
85
+ describe "#request(:delete)" do
80
86
  before do
81
87
  curb.expects(:http_delete)
82
88
  curb.expects(:response_code).returns(200)
@@ -85,7 +91,14 @@ unless RUBY_PLATFORM =~ /java/
85
91
  end
86
92
 
87
93
  it "returns a valid HTTPI::Response" do
88
- adapter.delete(basic_request).should match_response(:body => "")
94
+ adapter.request(:delete).should match_response(:body => "")
95
+ end
96
+ end
97
+
98
+ describe "#request(:custom)" do
99
+ it "raises a NotSupportedError" do
100
+ expect { adapter.request(:custom) }.
101
+ to raise_error(HTTPI::NotSupportedError, "Curb does not support custom HTTP methods")
89
102
  end
90
103
  end
91
104
 
@@ -94,145 +107,172 @@ unless RUBY_PLATFORM =~ /java/
94
107
 
95
108
  describe "url" do
96
109
  it "always sets the request url" do
97
- curb.expects(:url=).with(basic_request.url.to_s)
98
- adapter.get(basic_request)
110
+ curb.expects(:url=).with(request.url.to_s)
111
+ adapter.request(:get)
99
112
  end
100
113
  end
101
114
 
102
115
  describe "proxy_url" do
103
116
  it "is not set unless it's specified" do
104
117
  curb.expects(:proxy_url=).never
105
- adapter.get(basic_request)
118
+ adapter.request(:get)
106
119
  end
107
120
 
108
121
  it "is set if specified" do
109
- request = basic_request { |request| request.proxy = "http://proxy.example.com" }
110
-
122
+ request.proxy = "http://proxy.example.com"
111
123
  curb.expects(:proxy_url=).with(request.proxy.to_s)
112
- adapter.get(request)
124
+
125
+ adapter.request(:get)
113
126
  end
114
127
  end
115
128
 
116
129
  describe "timeout" do
117
130
  it "is not set unless it's specified" do
118
131
  curb.expects(:timeout=).never
119
- adapter.get(basic_request)
132
+ adapter.request(:get)
120
133
  end
121
134
 
122
135
  it "is set if specified" do
123
- request = basic_request { |request| request.read_timeout = 30 }
136
+ request.read_timeout = 30
137
+ curb.expects(:timeout=).with(request.read_timeout)
124
138
 
125
- curb.expects(:timeout=).with(30)
126
- adapter.get(request)
139
+ adapter.request(:get)
127
140
  end
128
141
  end
129
142
 
130
143
  describe "connect_timeout" do
131
144
  it "is not set unless it's specified" do
132
145
  curb.expects(:connect_timeout=).never
133
- adapter.get(basic_request)
146
+ adapter.request(:get)
134
147
  end
135
148
 
136
149
  it "is set if specified" do
137
- request = basic_request { |request| request.open_timeout = 30 }
138
-
150
+ request.open_timeout = 30
139
151
  curb.expects(:connect_timeout=).with(30)
140
- adapter.get(request)
152
+
153
+ adapter.request(:get)
141
154
  end
142
155
  end
143
156
 
144
157
  describe "headers" do
145
158
  it "is always set" do
146
159
  curb.expects(:headers=).with({})
147
- adapter.get(basic_request)
160
+ adapter.request(:get)
148
161
  end
149
162
  end
150
163
 
151
164
  describe "verbose" do
152
165
  it "is always set to false" do
153
166
  curb.expects(:verbose=).with(false)
154
- adapter.get(basic_request)
167
+ adapter.request(:get)
155
168
  end
156
169
  end
157
170
 
158
171
  describe "http_auth_types" do
159
172
  it "is set to :basic for HTTP basic auth" do
160
- request = basic_request { |request| request.auth.basic "username", "password" }
161
-
173
+ request.auth.basic "username", "password"
162
174
  curb.expects(:http_auth_types=).with(:basic)
163
- adapter.get(request)
175
+
176
+ adapter.request(:get)
164
177
  end
165
178
 
166
179
  it "is set to :digest for HTTP digest auth" do
167
- request = basic_request { |request| request.auth.digest "username", "password" }
168
-
180
+ request.auth.digest "username", "password"
169
181
  curb.expects(:http_auth_types=).with(:digest)
170
- adapter.get(request)
182
+
183
+ adapter.request(:get)
171
184
  end
172
185
 
173
186
  it "is set to :gssnegotiate for HTTP Negotiate auth" do
174
- request = basic_request { |request| request.auth.gssnegotiate }
175
-
187
+ request.auth.gssnegotiate
176
188
  curb.expects(:http_auth_types=).with(:gssnegotiate)
177
- adapter.get(request)
189
+
190
+ adapter.request(:get)
178
191
  end
179
192
  end
180
193
 
181
194
  describe "username and password" do
182
195
  it "is set for HTTP basic auth" do
183
- request = basic_request { |request| request.auth.basic "username", "password" }
196
+ request.auth.basic "username", "password"
184
197
 
185
198
  curb.expects(:username=).with("username")
186
199
  curb.expects(:password=).with("password")
187
- adapter.get(request)
200
+ adapter.request(:get)
188
201
  end
189
202
 
190
203
  it "is set for HTTP digest auth" do
191
- request = basic_request { |request| request.auth.digest "username", "password" }
204
+ request.auth.digest "username", "password"
192
205
 
193
206
  curb.expects(:username=).with("username")
194
207
  curb.expects(:password=).with("password")
195
- adapter.get(request)
208
+ adapter.request(:get)
196
209
  end
197
210
  end
198
211
 
199
212
  context "(for SSL client auth)" do
200
- let(:ssl_auth_request) do
201
- basic_request do |request|
202
- request.auth.ssl.cert_key_file = "spec/fixtures/client_key.pem"
203
- request.auth.ssl.cert_file = "spec/fixtures/client_cert.pem"
204
- end
213
+ let(:request) do
214
+ request = HTTPI::Request.new("http://example.com")
215
+ request.auth.ssl.cert_key_file = "spec/fixtures/client_key.pem"
216
+ request.auth.ssl.cert_file = "spec/fixtures/client_cert.pem"
217
+ request
205
218
  end
206
219
 
207
220
  it "cert_key, cert and ssl_verify_peer should be set" do
208
- curb.expects(:cert_key=).with(ssl_auth_request.auth.ssl.cert_key_file)
209
- curb.expects(:cert=).with(ssl_auth_request.auth.ssl.cert_file)
221
+ curb.expects(:cert_key=).with(request.auth.ssl.cert_key_file)
222
+ curb.expects(:cert=).with(request.auth.ssl.cert_file)
210
223
  curb.expects(:ssl_verify_peer=).with(true)
211
- curb.expects(:certtype=).with(ssl_auth_request.auth.ssl.cert_type.to_s.upcase)
224
+ curb.expects(:certtype=).with(request.auth.ssl.cert_type.to_s.upcase)
212
225
 
213
- adapter.get(ssl_auth_request)
226
+ adapter.request(:get)
214
227
  end
215
228
 
216
229
  it "sets the cert_type to DER if specified" do
217
- ssl_auth_request.auth.ssl.cert_type = :der
230
+ request.auth.ssl.cert_type = :der
218
231
  curb.expects(:certtype=).with(:der.to_s.upcase)
219
232
 
220
- adapter.get(ssl_auth_request)
233
+ adapter.request(:get)
234
+ end
235
+
236
+ it "raise if an invalid cert type was set" do
237
+ expect { request.auth.ssl.cert_type = :invalid }.
238
+ to raise_error(ArgumentError, "Invalid SSL cert type :invalid\nPlease specify one of [:pem, :der]")
221
239
  end
222
240
 
223
241
  it "sets the cacert if specified" do
224
- ssl_auth_request.auth.ssl.ca_cert_file = "spec/fixtures/client_cert.pem"
225
- curb.expects(:cacert=).with(ssl_auth_request.auth.ssl.ca_cert_file)
242
+ request.auth.ssl.ca_cert_file = "spec/fixtures/client_cert.pem"
243
+ curb.expects(:cacert=).with(request.auth.ssl.ca_cert_file)
226
244
 
227
- adapter.get(ssl_auth_request)
245
+ adapter.request(:get)
228
246
  end
229
- end
230
- end
231
247
 
232
- def basic_request
233
- request = HTTPI::Request.new :url => "http://example.com"
234
- yield request if block_given?
235
- request
248
+ context 'sets ssl_version' do
249
+ it 'defaults to nil when no ssl_version is specified' do
250
+ curb.expects(:ssl_version=).with(nil)
251
+ adapter.request(:get)
252
+ end
253
+
254
+ it 'to 1 when ssl_version is specified as TLSv1' do
255
+ request.auth.ssl.ssl_version = :TLSv1
256
+ curb.expects(:ssl_version=).with(1)
257
+
258
+ adapter.request(:get)
259
+ end
260
+
261
+ it 'to 2 when ssl_version is specified as SSLv2' do
262
+ request.auth.ssl.ssl_version = :SSLv2
263
+ curb.expects(:ssl_version=).with(2)
264
+
265
+ adapter.request(:get)
266
+ end
267
+
268
+ it 'to 3 when ssl_version is specified as SSLv3' do
269
+ request.auth.ssl.ssl_version = :SSLv3
270
+ curb.expects(:ssl_version=).with(3)
271
+
272
+ adapter.request(:get)
273
+ end
274
+ end
275
+ end
236
276
  end
237
277
 
238
278
  end