rets4r 0.8.2 → 0.8.3
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +11 -0
- data/lib/rets4r/client.rb +93 -3
- data/test/client/tc_client.rb +19 -1
- metadata +15 -15
data/CHANGELOG
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
0.8.3
|
2
|
+
Added example #set_pre_request_block. (Fran�ois Beausoleil)
|
3
|
+
Allow a pre request block to be set for RETS4R::Client.
|
4
|
+
This allows the caller to change the request in any meaningful way, such as adding a
|
5
|
+
RETS-UA-Authorization header when appropriate. (Fran�ois Beausoleil)
|
6
|
+
Better response handling of HTTP errors. Response codes > 300 other than 401 now raise an
|
7
|
+
HTTPError exception that encapsulates the HTTPResponse object.
|
8
|
+
401 errors raise a LoginError exception. (Scott Patterson)
|
9
|
+
Added in RETS specification error messages to reference. (Scott Patterson)
|
10
|
+
New Rakefile. Install the rake gem and do 'rake test' to run the tests. (Fran�ois Beausoleil)
|
11
|
+
|
1
12
|
0.8.2
|
2
13
|
Added missing result parameter to Client#search's yield (Scott Patterson)
|
3
14
|
Added 1.7 to supported list and default version (Fran�ois Beausoleil)
|
data/lib/rets4r/client.rb
CHANGED
@@ -39,7 +39,30 @@ module RETS4R
|
|
39
39
|
SUPPORTED_RETS_VERSIONS = ['1.5', '1.7']
|
40
40
|
CAPABILITY_LIST = ['Action', 'ChangePassword', 'GetObject', 'Login', 'LoginComplete', 'Logout', 'Search', 'GetMetadata', 'Update']
|
41
41
|
SUPPORTED_PARSERS = [] # This will be populated by parsers as they load
|
42
|
-
|
42
|
+
|
43
|
+
# These are the response messages as defined in the RETS 1.5e2 and 1.7d6 specifications.
|
44
|
+
# Provided for convenience and are used by the HTTPError class to provide more useful
|
45
|
+
# messages.
|
46
|
+
RETS_HTTP_MESSAGES = {
|
47
|
+
'200' => 'Operation successful.',
|
48
|
+
'400' => 'The request could not be understood by the server due to malformed syntax.',
|
49
|
+
'401' => 'Either the header did not contain an acceptable Authorization or the username/password was invalid. The server response MUST include a WWW-Authenticate header field.',
|
50
|
+
'402' => 'The requested transaction requires a payment which could not be authorized.',
|
51
|
+
'403' => 'The server understood the request, but is refusing to fulfill it.',
|
52
|
+
'404' => 'The server has not found anything matching the Request-URI.',
|
53
|
+
'405' => 'The method specified in the Request-Line is not allowed for the resource identified by the Request-URI.',
|
54
|
+
'406' => 'The resource identified by the request is only capable of generating response entities which have content characteristics not acceptable according to the accept headers sent in the request.',
|
55
|
+
'408' => 'The client did not produce a request within the time that the server was prepared to wait.',
|
56
|
+
'411' => 'The server refuses to accept the request without a defined Content-Length.',
|
57
|
+
'412' => 'Transaction not permitted at this point in the session.',
|
58
|
+
'413' => 'The server is refusing to process a request because the request entity is larger than the server is willing or able to process.',
|
59
|
+
'414' => 'The server is refusing to service the request because the Request-URI is longer than the server is willing to interpret. This error usually only occurs for a GET method.',
|
60
|
+
'500' => 'The server encountered an unexpected condition which prevented it from fulfilling the request.',
|
61
|
+
'501' => 'The server does not support the functionality required to fulfill the request.',
|
62
|
+
'503' => 'The server is currently unable to handle the request due to a temporary overloading or maintenance of the server.',
|
63
|
+
'505' => 'The server does not support, or refuses to support, the HTTP protocol version that was used in the request message.',
|
64
|
+
}
|
65
|
+
|
43
66
|
attr_accessor :mimemap, :logger
|
44
67
|
|
45
68
|
# We load our parsers here so that they can modify the client class appropriately. Because
|
@@ -82,6 +105,35 @@ module RETS4R
|
|
82
105
|
end
|
83
106
|
end
|
84
107
|
|
108
|
+
# Assigns a block that will be called just before the request is sent.
|
109
|
+
# This block must accept three parameters:
|
110
|
+
# * self
|
111
|
+
# * Net::HTTP instance
|
112
|
+
# * Hash of headers
|
113
|
+
#
|
114
|
+
# The block's return value will be ignored. If you want to prevent the request
|
115
|
+
# to go through, raise an exception.
|
116
|
+
#
|
117
|
+
# == Example
|
118
|
+
#
|
119
|
+
# client = RETS4R::Client.new(...)
|
120
|
+
# # Make a new pre_request_block that calculates the RETS-UA-Authorization header.
|
121
|
+
# client.set_pre_request_block do |rets, http, headers|
|
122
|
+
# a1 = Digest::MD5.hexdigest([headers["User-Agent"], @password].join(":"))
|
123
|
+
# if headers.has_key?("Cookie") then
|
124
|
+
# cookie = headers["Cookie"].split(";").map(&:strip).select {|c| c =~ /rets-session-id/i}
|
125
|
+
# cookie = cookie ? cookie.split("=").last : ""
|
126
|
+
# else
|
127
|
+
# cookie = ""
|
128
|
+
# end
|
129
|
+
#
|
130
|
+
# parts = [a1, "", cookie, headers["RETS-Version"]]
|
131
|
+
# headers["RETS-UA-Authorization"] = "Digest " + Digest::MD5.hexdigest(parts.join(":"))
|
132
|
+
# end
|
133
|
+
def set_pre_request_block(&block)
|
134
|
+
@pre_request_block = block
|
135
|
+
end
|
136
|
+
|
85
137
|
# We only allow external read access to URLs because they are internally set based on the
|
86
138
|
# results of various queries.
|
87
139
|
def urls
|
@@ -343,9 +395,8 @@ module RETS4R
|
|
343
395
|
'Content-ID' => response['Content-ID']
|
344
396
|
}
|
345
397
|
|
346
|
-
if response['Content-Length'].to_i > 100
|
398
|
+
if response['Transfer-Encoding'].to_s.downcase == "chunked" || response['Content-Length'].to_i > 100 then
|
347
399
|
data_object = DataObject.new(info, response.body)
|
348
|
-
|
349
400
|
if block_given?
|
350
401
|
yield data_object
|
351
402
|
results += 1
|
@@ -466,6 +517,8 @@ module RETS4R
|
|
466
517
|
headers = @headers
|
467
518
|
headers.merge(header) unless header.empty?
|
468
519
|
|
520
|
+
@pre_request_block.call(self, http, headers) if @pre_request_block
|
521
|
+
|
469
522
|
logger.debug(headers.inspect) if logger
|
470
523
|
|
471
524
|
@semaphore.unlock
|
@@ -477,6 +530,10 @@ module RETS4R
|
|
477
530
|
if response.code == '401'
|
478
531
|
# Authentication is required
|
479
532
|
raise AuthRequired
|
533
|
+
elsif response.code.to_i >= 300
|
534
|
+
# We have a non-successful response that we cannot handle
|
535
|
+
@semaphore.unlock if @semaphore.locked?
|
536
|
+
raise HTTPError.new(response)
|
480
537
|
else
|
481
538
|
cookies = []
|
482
539
|
if set_cookies = response.get_fields('set-cookie') then
|
@@ -494,6 +551,9 @@ module RETS4R
|
|
494
551
|
retry_auth -= 1
|
495
552
|
set_header('Authorization', Auth.authenticate(response, @username, @password, url.path, method, @headers['RETS-Request-ID'], get_user_agent, @nc))
|
496
553
|
retry
|
554
|
+
else
|
555
|
+
@semaphore.unlock if @semaphore.locked?
|
556
|
+
raise LoginError.new(response.message)
|
497
557
|
end
|
498
558
|
end
|
499
559
|
|
@@ -545,6 +605,36 @@ module RETS4R
|
|
545
605
|
class Unsupported < ClientException
|
546
606
|
end
|
547
607
|
|
608
|
+
# The HTTP response returned by the server indicates that there was an error processing
|
609
|
+
# the request and the client cannot continue on its own without intervention.
|
610
|
+
class HTTPError < ClientException
|
611
|
+
attr_accessor :http_response
|
612
|
+
|
613
|
+
# Takes a HTTPResponse object
|
614
|
+
def initialize(http_response)
|
615
|
+
self.http_response = http_response
|
616
|
+
end
|
617
|
+
|
618
|
+
# Shorthand for calling HTTPResponse#code
|
619
|
+
def code
|
620
|
+
http_response.code
|
621
|
+
end
|
622
|
+
|
623
|
+
# Shorthand for calling HTTPResponse#message
|
624
|
+
def message
|
625
|
+
http_response.message
|
626
|
+
end
|
627
|
+
|
628
|
+
# Returns the RETS specification message for the HTTP response code
|
629
|
+
def rets_message
|
630
|
+
Client::RETS_HTTP_MESSAGES[code]
|
631
|
+
end
|
632
|
+
|
633
|
+
def to_s
|
634
|
+
"#{code} #{message}: #{rets_message}"
|
635
|
+
end
|
636
|
+
end
|
637
|
+
|
548
638
|
# A general RETS level exception was encountered. This would include HTTP and RETS
|
549
639
|
# specification level errors as well as informative mishaps such as authentication being
|
550
640
|
# required for access.
|
data/test/client/tc_client.rb
CHANGED
@@ -94,13 +94,30 @@ module RETS4R
|
|
94
94
|
|
95
95
|
def test_returns_single_entity_object_in_a_single_element_array
|
96
96
|
@response.expects(:[]).with('content-type').at_least_once.returns("image/jpeg")
|
97
|
+
@response.expects(:[]).with('Transfer-Encoding').at_least_once.returns("")
|
97
98
|
@response.expects(:[]).with('Content-Length').at_least_once.returns(241)
|
98
99
|
@response.expects(:[]).with('Object-ID').at_least_once.returns("25478")
|
99
100
|
@response.expects(:[]).with('Content-ID').at_least_once.returns("5589")
|
100
101
|
@response.expects(:body).returns("\000"*241)
|
101
102
|
|
102
103
|
results = @rets.get_object("Property", "Photo", "392103:*")
|
103
|
-
assert_equal 1, results.size, "Client parsed
|
104
|
+
assert_equal 1, results.size, "Client parsed one object out of the request"
|
105
|
+
assert_kind_of RETS4R::Client::DataObject, results[0], "First result isn't a DataObject"
|
106
|
+
assert_equal "image/jpeg", results[0].type["Content-Type"], "Content-Type not copied"
|
107
|
+
assert_equal "5589", results[0].type["Content-ID"], "Content-ID not copied"
|
108
|
+
assert_equal "25478", results[0].type["Object-ID"], "Object-ID not copied"
|
109
|
+
assert_equal 241, results[0].data.size, "First object isn't 241 bytes in length"
|
110
|
+
end
|
111
|
+
|
112
|
+
def test_returns_single_entity_object_as_chunked_encoding_in_a_single_element_array
|
113
|
+
@response.expects(:[]).with('content-type').at_least_once.returns("image/jpeg")
|
114
|
+
@response.expects(:[]).with('Transfer-Encoding').at_least_once.returns("chunked")
|
115
|
+
@response.expects(:[]).with('Object-ID').at_least_once.returns("25478")
|
116
|
+
@response.expects(:[]).with('Content-ID').at_least_once.returns("5589")
|
117
|
+
@response.expects(:body).returns("\000"*241)
|
118
|
+
|
119
|
+
results = @rets.get_object("Property", "Photo", "392103:*")
|
120
|
+
assert_equal 1, results.size, "Client parsed one object out of the request"
|
104
121
|
assert_kind_of RETS4R::Client::DataObject, results[0], "First result isn't a DataObject"
|
105
122
|
assert_equal "image/jpeg", results[0].type["Content-Type"], "Content-Type not copied"
|
106
123
|
assert_equal "5589", results[0].type["Content-ID"], "Content-ID not copied"
|
@@ -110,6 +127,7 @@ module RETS4R
|
|
110
127
|
|
111
128
|
def test_yields_data_objects_to_block_and_returns_blocks_value
|
112
129
|
@response.expects(:[]).with('content-type').at_least_once.returns("image/jpeg")
|
130
|
+
@response.expects(:[]).with('Transfer-Encoding').at_least_once.returns("")
|
113
131
|
@response.expects(:[]).with('Content-Length').at_least_once.returns(241)
|
114
132
|
@response.expects(:[]).with('Object-ID').at_least_once.returns("25478")
|
115
133
|
@response.expects(:[]).with('Content-ID').at_least_once.returns("5589")
|
metadata
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.9.
|
2
|
+
rubygems_version: 0.9.4
|
3
3
|
specification_version: 1
|
4
4
|
name: rets4r
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.8.
|
7
|
-
date:
|
6
|
+
version: 0.8.3
|
7
|
+
date: 2008-01-03 00:00:00 -08:00
|
8
8
|
summary: A native Ruby implementation of RETS (Real Estate Transaction Standard).
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -34,29 +34,21 @@ files:
|
|
34
34
|
- examples/client_metadata.rb
|
35
35
|
- examples/client_search.rb
|
36
36
|
- lib/rets4r
|
37
|
-
- lib/rets4r.rb
|
38
37
|
- lib/rets4r/auth.rb
|
39
38
|
- lib/rets4r/client
|
40
|
-
- lib/rets4r/client.rb
|
41
39
|
- lib/rets4r/client/data.rb
|
42
40
|
- lib/rets4r/client/dataobject.rb
|
43
41
|
- lib/rets4r/client/metadata.rb
|
44
42
|
- lib/rets4r/client/metadataindex.rb
|
45
43
|
- lib/rets4r/client/parser
|
46
|
-
- lib/rets4r/client/parser.rb
|
47
|
-
- lib/rets4r/client/transaction.rb
|
48
44
|
- lib/rets4r/client/parser/rexml.rb
|
49
45
|
- lib/rets4r/client/parser/xmlparser.rb
|
46
|
+
- lib/rets4r/client/parser.rb
|
47
|
+
- lib/rets4r/client/transaction.rb
|
48
|
+
- lib/rets4r/client.rb
|
49
|
+
- lib/rets4r.rb
|
50
50
|
- test/client
|
51
|
-
- test/ts_all.rb
|
52
|
-
- test/ts_client.rb
|
53
51
|
- test/client/data
|
54
|
-
- test/client/parser
|
55
|
-
- test/client/tc_auth.rb
|
56
|
-
- test/client/tc_client.rb
|
57
|
-
- test/client/tc_metadataindex.rb
|
58
|
-
- test/client/test_parser.rb
|
59
|
-
- test/client/ts_all.rb
|
60
52
|
- test/client/data/1.5
|
61
53
|
- test/client/data/1.5/error.xml
|
62
54
|
- test/client/data/1.5/invalid_compact.xml
|
@@ -64,8 +56,16 @@ files:
|
|
64
56
|
- test/client/data/1.5/metadata.xml
|
65
57
|
- test/client/data/1.5/search_compact.xml
|
66
58
|
- test/client/data/1.5/search_unescaped_compact.xml
|
59
|
+
- test/client/parser
|
67
60
|
- test/client/parser/tc_rexml.rb
|
68
61
|
- test/client/parser/tc_xmlparser.rb
|
62
|
+
- test/client/tc_auth.rb
|
63
|
+
- test/client/tc_client.rb
|
64
|
+
- test/client/tc_metadataindex.rb
|
65
|
+
- test/client/test_parser.rb
|
66
|
+
- test/client/ts_all.rb
|
67
|
+
- test/ts_all.rb
|
68
|
+
- test/ts_client.rb
|
69
69
|
- CONTRIBUTORS
|
70
70
|
- README
|
71
71
|
- LICENSE
|