httpi 1.1.1 → 2.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
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