rets 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md CHANGED
@@ -1,4 +1,8 @@
1
- ### 0.3.0.rc.1
1
+ ### 0.4.0 / 2012-08-29
2
+
3
+ * fix: update authentication header to uri matches path
4
+
5
+ ### 0.3.0 / 2012-07-31
2
6
 
3
7
  * correctly handle digest authentication
4
8
 
data/lib/rets.rb CHANGED
@@ -8,7 +8,7 @@ require 'net/http/persistent'
8
8
  require 'nokogiri'
9
9
 
10
10
  module Rets
11
- VERSION = '0.3.0'
11
+ VERSION = '0.4.0'
12
12
 
13
13
  AuthorizationFailure = Class.new(ArgumentError)
14
14
  InvalidRequest = Class.new(ArgumentError)
data/lib/rets/client.rb CHANGED
@@ -1,12 +1,12 @@
1
1
  module Rets
2
- Session = Struct.new(:authorization, :capabilities, :cookies)
2
+ Session = Struct.new(:auth_digest, :capabilities, :cookies)
3
3
 
4
4
  class Client
5
5
  DEFAULT_OPTIONS = { :persistent => true }
6
6
 
7
7
  include Authentication
8
8
 
9
- attr_accessor :uri, :options, :authorization, :logger
9
+ attr_accessor :login_uri, :options, :logger, :auth_digest
10
10
  attr_writer :capabilities, :metadata
11
11
 
12
12
  def initialize(options)
@@ -16,26 +16,26 @@ module Rets
16
16
 
17
17
  def clean_setup
18
18
 
19
+ @auth_digest = nil
20
+ @cached_metadata = nil
19
21
  @capabilities = nil
22
+ @connection = nil
20
23
  @cookies = nil
21
24
  @metadata = nil
22
- @cached_metadata = nil
23
25
  @tries = nil
24
- @connection = nil
25
- self.authorization = nil
26
26
  self.capabilities = nil
27
27
 
28
- uri = URI.parse(@options[:login_url])
28
+ uri = URI.parse(@options[:login_url])
29
29
 
30
- uri.user = @options.key?(:username) ? CGI.escape(@options[:username]) : nil
31
- uri.password = @options.key?(:password) ? CGI.escape(@options[:password]) : nil
30
+ uri.user = @options.key?(:username) ? CGI.escape(@options[:username]) : nil
31
+ uri.password = @options.key?(:password) ? CGI.escape(@options[:password]) : nil
32
32
 
33
- self.options = DEFAULT_OPTIONS.merge(@options)
34
- self.uri = uri
33
+ self.options = DEFAULT_OPTIONS.merge(@options)
34
+ self.login_uri = uri
35
35
 
36
- self.logger = @options[:logger] || FakeLogger.new
36
+ self.logger = @options[:logger] || FakeLogger.new
37
37
 
38
- self.session = @options.delete(:session) if @options[:session]
38
+ self.session = @options.delete(:session) if @options[:session]
39
39
  @cached_metadata = @options[:metadata] || nil
40
40
  end
41
41
 
@@ -44,7 +44,7 @@ module Rets
44
44
  # provided in initialize. Returns the capabilities that the
45
45
  # RETS server provides, per http://retsdoc.onconfluence.com/display/rets172/4.10+Capability+URL+List.
46
46
  def login
47
- response = request(uri.path)
47
+ response = request(login_uri.path)
48
48
  self.capabilities = extract_capabilities(Nokogiri.parse(response.body))
49
49
  raise UnknownResponse, "Cannot read rets server capabilities." unless @capabilities
50
50
  @capabilities
@@ -267,7 +267,7 @@ module Rets
267
267
  end
268
268
 
269
269
  def raw_request(path, body = nil, extra_headers = {}, &reader)
270
- headers = build_headers.merge(extra_headers)
270
+ headers = build_headers(path).merge(extra_headers)
271
271
 
272
272
  post = Net::HTTP::Post.new(path, headers)
273
273
  post.body = body.to_s
@@ -280,7 +280,7 @@ POST #{path}
280
280
  #{binary?(body.to_s) ? '<<< BINARY BODY >>>' : body.to_s}
281
281
  EOF
282
282
 
283
- connection_args = [Net::HTTP::Persistent === connection ? uri : nil, post].compact
283
+ connection_args = [Net::HTTP::Persistent === connection ? login_uri : nil, post].compact
284
284
 
285
285
  response = connection.request(*connection_args) do |res|
286
286
  res.read_body(&reader)
@@ -301,13 +301,8 @@ EOF
301
301
  def digest_auth_request(path, body = nil, extra_headers = {}, &reader)
302
302
  response = raw_request(path, body, extra_headers, &reader)
303
303
  if Net::HTTPUnauthorized === response
304
- challenge = extract_digest_header(response)
305
- if challenge
306
- uri2 = URI.parse(uri.to_s)
307
- uri2.user = uri.user
308
- uri2.password = uri.password
309
- uri2.path = path
310
- self.authorization = build_auth(challenge, uri2, tries)
304
+ @auth_digest = extract_digest_header(response)
305
+ if @auth_digest
311
306
  response = raw_request(path, body, extra_headers, &reader)
312
307
  if Net::HTTPUnauthorized === response
313
308
  raise AuthorizationFailure, "Authorization failed, check credentials?"
@@ -317,6 +312,16 @@ EOF
317
312
  response
318
313
  end
319
314
 
315
+ def authorization(path)
316
+ return nil unless @auth_digest
317
+ uri2 = URI.parse(login_uri.to_s)
318
+ uri2.user = login_uri.user
319
+ uri2.password = login_uri.password
320
+ uri2.path = path
321
+ build_auth(@auth_digest, uri2, tries)
322
+ end
323
+
324
+
320
325
  def request(*args, &block)
321
326
  handle_response(digest_auth_request(*args, &block))
322
327
  end
@@ -383,13 +388,13 @@ EOF
383
388
  end
384
389
 
385
390
  def session=(session)
386
- self.authorization = session.authorization
387
- self.capabilities = session.capabilities
388
- self.cookies = session.cookies
391
+ self.auth_digest = session.auth_digest
392
+ self.capabilities = session.capabilities
393
+ self.cookies = session.cookies
389
394
  end
390
395
 
391
396
  def session
392
- Session.new(authorization, capabilities, cookies)
397
+ Session.new(auth_digest, capabilities, cookies)
393
398
  end
394
399
 
395
400
 
@@ -435,7 +440,7 @@ EOF
435
440
  def connection
436
441
  @connection ||= options[:persistent] ?
437
442
  persistent_connection :
438
- Net::HTTP.new(uri.host, uri.port)
443
+ Net::HTTP.new(login_uri.host, login_uri.port)
439
444
  end
440
445
 
441
446
  def persistent_connection
@@ -457,15 +462,16 @@ EOF
457
462
  options[:version] || "RETS/1.7.2"
458
463
  end
459
464
 
460
- def build_headers
465
+ def build_headers(path)
461
466
  headers = {
462
467
  "User-Agent" => user_agent,
463
- "Host" => "#{uri.host}:#{uri.port}",
468
+ "Host" => "#{login_uri.host}:#{login_uri.port}",
464
469
  "RETS-Version" => rets_version
465
470
  }
466
471
 
467
- headers.merge!("Authorization" => authorization) if authorization
468
- headers.merge!("Cookie" => cookies) if cookies
472
+ auth = authorization(path)
473
+ headers.merge!("Authorization" => auth) if auth
474
+ headers.merge!("Cookie" => cookies) if cookies
469
475
 
470
476
  if options[:ua_password]
471
477
  headers.merge!(
data/test/test_client.rb CHANGED
@@ -11,8 +11,8 @@ class TestClient < Test::Unit::TestCase
11
11
  :login_url => "http://example.com",
12
12
  :username => "bob@example.com")
13
13
 
14
- assert_equal CGI.escape("bob@example.com"), client.uri.user
15
- assert_nil client.uri.password
14
+ assert_equal CGI.escape("bob@example.com"), client.login_uri.user
15
+ assert_nil client.login_uri.password
16
16
  end
17
17
 
18
18
  def test_initialize_adds_escaped_password_to_uri
@@ -21,7 +21,7 @@ class TestClient < Test::Unit::TestCase
21
21
  :username => "bob",
22
22
  :password => "secret@2!")
23
23
 
24
- assert_equal CGI.escape("secret@2!"), client.uri.password
24
+ assert_equal CGI.escape("secret@2!"), client.login_uri.password
25
25
  end
26
26
 
27
27
  def test_initialize_merges_default_options
@@ -58,11 +58,11 @@ class TestClient < Test::Unit::TestCase
58
58
  post = mock()
59
59
  post.expects(:body=).with("fake body")
60
60
 
61
- headers = @client.build_headers
61
+ headers = @client.build_headers('path')
62
62
 
63
63
  Net::HTTP::Post.expects(:new).with("/foo", headers).returns(post)
64
64
 
65
- @client.connection.expects(:request).with(@client.uri, post).returns(stub_everything)
65
+ @client.connection.expects(:request).with(@client.login_uri, post).returns(stub_everything)
66
66
 
67
67
  @client.expects(:handle_cookies)
68
68
  @client.expects(:handle_response)
@@ -77,7 +77,7 @@ class TestClient < Test::Unit::TestCase
77
77
  end
78
78
 
79
79
  def test_request_passes_correct_arguments_to_persistent_connection
80
- @client.connection.expects(:request).with(@client.uri, instance_of(Net::HTTP::Post)).returns(stub_everything)
80
+ @client.connection.expects(:request).with(@client.login_uri, instance_of(Net::HTTP::Post)).returns(stub_everything)
81
81
 
82
82
  @client.stubs(:handle_cookies)
83
83
  @client.stubs(:handle_response)
@@ -213,18 +213,18 @@ class TestClient < Test::Unit::TestCase
213
213
  "User-Agent" => "Client/1.0",
214
214
  "Host" => "example.com:80",
215
215
  "RETS-Version" => "RETS/1.7.2"},
216
- @client.build_headers)
216
+ @client.build_headers('path'))
217
217
  end
218
218
 
219
219
  def test_build_headers_provides_authorization
220
- @client.authorization = "Just trust me"
220
+ @client.expects(:authorization).returns("Just trust me")
221
221
 
222
222
  assert_equal({
223
223
  "Authorization" => "Just trust me",
224
224
  "User-Agent" => "Client/1.0",
225
225
  "Host" => "example.com:80",
226
226
  "RETS-Version" => "RETS/1.7.2"},
227
- @client.build_headers)
227
+ @client.build_headers('path'))
228
228
  end
229
229
 
230
230
  def test_build_headers_provides_cookies
@@ -235,7 +235,7 @@ class TestClient < Test::Unit::TestCase
235
235
  "User-Agent" => "Client/1.0",
236
236
  "Host" => "example.com:80",
237
237
  "RETS-Version" => "RETS/1.7.2"},
238
- @client.build_headers)
238
+ @client.build_headers('path'))
239
239
  end
240
240
 
241
241
 
@@ -289,33 +289,33 @@ DIGEST
289
289
 
290
290
 
291
291
  def test_session_restores_state
292
- session = Rets::Session.new("Digest auth", {"Foo" => "/foo"}, "sessionid=123")
292
+ session = Rets::Session.new({:digest => 'true'}, {"Foo" => "/foo"}, "sessionid=123")
293
293
 
294
294
  @client.session = session
295
295
 
296
- assert_equal("Digest auth", @client.authorization)
296
+ assert_equal({:digest => 'true'}, @client.auth_digest)
297
297
  assert_equal({"Foo" => "/foo"}, @client.capabilities)
298
298
  assert_equal("sessionid=123", @client.cookies)
299
299
  end
300
300
 
301
301
  def test_session_dumps_state
302
- @client.authorization = "Digest auth"
302
+ @client.auth_digest = {:digest => 'true'}
303
303
  @client.capabilities = {"Foo" => "/foo"}
304
304
  @client.cookies = "session-id=123"
305
305
 
306
306
  session = @client.session
307
307
 
308
- assert_equal("Digest auth", session.authorization)
308
+ assert_equal({:digest => 'true'}, session.auth_digest)
309
309
  assert_equal({"Foo" => "/foo"}, session.capabilities)
310
310
  assert_equal("session-id=123", session.cookies)
311
311
  end
312
312
 
313
313
  def test_initialize_with_session_restores_state
314
- session = Rets::Session.new("Digest auth", {"Foo" => "/foo"}, "sessionid=123")
314
+ session = Rets::Session.new({:digest => true}, {"Foo" => "/foo"}, "sessionid=123")
315
315
 
316
316
  client = Rets::Client.new(:login_url => "http://example.com", :session => session)
317
317
 
318
- assert_equal("Digest auth", client.authorization)
318
+ assert_equal({:digest => true}, client.auth_digest)
319
319
  assert_equal({"Foo" => "/foo"}, client.capabilities)
320
320
  assert_equal("sessionid=123", client.cookies)
321
321
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rets
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-08-22 00:00:00.000000000 Z
12
+ date: 2012-08-29 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: net-http-persistent
@@ -44,13 +44,13 @@ dependencies:
44
44
  - !ruby/object:Gem::Version
45
45
  version: 1.5.2
46
46
  - !ruby/object:Gem::Dependency
47
- name: mocha
47
+ name: rdoc
48
48
  requirement: !ruby/object:Gem::Requirement
49
49
  none: false
50
50
  requirements:
51
51
  - - ~>
52
52
  - !ruby/object:Gem::Version
53
- version: 0.11.0
53
+ version: '3.10'
54
54
  type: :development
55
55
  prerelease: false
56
56
  version_requirements: !ruby/object:Gem::Requirement
@@ -58,15 +58,15 @@ dependencies:
58
58
  requirements:
59
59
  - - ~>
60
60
  - !ruby/object:Gem::Version
61
- version: 0.11.0
61
+ version: '3.10'
62
62
  - !ruby/object:Gem::Dependency
63
- name: vcr
63
+ name: mocha
64
64
  requirement: !ruby/object:Gem::Requirement
65
65
  none: false
66
66
  requirements:
67
67
  - - ~>
68
68
  - !ruby/object:Gem::Version
69
- version: 2.2.2
69
+ version: 0.11.0
70
70
  type: :development
71
71
  prerelease: false
72
72
  version_requirements: !ruby/object:Gem::Requirement
@@ -74,15 +74,15 @@ dependencies:
74
74
  requirements:
75
75
  - - ~>
76
76
  - !ruby/object:Gem::Version
77
- version: 2.2.2
77
+ version: 0.11.0
78
78
  - !ruby/object:Gem::Dependency
79
- name: webmock
79
+ name: vcr
80
80
  requirement: !ruby/object:Gem::Requirement
81
81
  none: false
82
82
  requirements:
83
83
  - - ~>
84
84
  - !ruby/object:Gem::Version
85
- version: 1.8.0
85
+ version: 2.2.2
86
86
  type: :development
87
87
  prerelease: false
88
88
  version_requirements: !ruby/object:Gem::Requirement
@@ -90,15 +90,15 @@ dependencies:
90
90
  requirements:
91
91
  - - ~>
92
92
  - !ruby/object:Gem::Version
93
- version: 1.8.0
93
+ version: 2.2.2
94
94
  - !ruby/object:Gem::Dependency
95
- name: rdoc
95
+ name: webmock
96
96
  requirement: !ruby/object:Gem::Requirement
97
97
  none: false
98
98
  requirements:
99
99
  - - ~>
100
100
  - !ruby/object:Gem::Version
101
- version: '3.10'
101
+ version: 1.8.0
102
102
  type: :development
103
103
  prerelease: false
104
104
  version_requirements: !ruby/object:Gem::Requirement
@@ -106,7 +106,7 @@ dependencies:
106
106
  requirements:
107
107
  - - ~>
108
108
  - !ruby/object:Gem::Version
109
- version: '3.10'
109
+ version: 1.8.0
110
110
  - !ruby/object:Gem::Dependency
111
111
  name: hoe
112
112
  requirement: !ruby/object:Gem::Requirement
@@ -114,7 +114,7 @@ dependencies:
114
114
  requirements:
115
115
  - - ~>
116
116
  - !ruby/object:Gem::Version
117
- version: '2.13'
117
+ version: '3.0'
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
@@ -122,7 +122,7 @@ dependencies:
122
122
  requirements:
123
123
  - - ~>
124
124
  - !ruby/object:Gem::Version
125
- version: '2.13'
125
+ version: '3.0'
126
126
  description: ! '[![Build Status](https://secure.travis-ci.org/estately/rets.png?branch=master)](http://travis-ci.org/estately/rets)
127
127
 
128
128
  A pure-ruby library for fetching data from [RETS] servers.