wrest 0.0.9 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (154) hide show
  1. data/CHANGELOG +34 -0
  2. data/README.rdoc +16 -10
  3. data/Rakefile +361 -123
  4. data/VERSION.yml +2 -2
  5. data/examples/delicious.rb +17 -7
  6. data/examples/facebook.rb +101 -0
  7. data/examples/keep_alive.rb +37 -0
  8. data/examples/twitter.rb +3 -3
  9. data/examples/twitter_public_timeline.rb +11 -4
  10. data/examples/wow_realm_status.rb +8 -2
  11. data/{spec/functional/sample_rails_app/public/favicon.ico → init.rb} +0 -0
  12. data/lib/wrest/components/{attributes_container → container}/alias_accessors.rb +4 -4
  13. data/lib/wrest/components/{attributes_container → container}/typecaster.rb +1 -1
  14. data/lib/wrest/components/{attributes_container.rb → container.rb} +46 -16
  15. data/lib/wrest/components/mutators.rb +4 -4
  16. data/lib/wrest/components/translators/json.rb +2 -2
  17. data/lib/wrest/components/translators/xml.rb +3 -2
  18. data/lib/wrest/components/translators.rb +3 -3
  19. data/lib/wrest/components.rb +3 -3
  20. data/lib/wrest/core_ext/hash.rb +1 -1
  21. data/lib/wrest/core_ext/string.rb +1 -1
  22. data/lib/wrest/curl/delete.rb +23 -0
  23. data/lib/wrest/curl/get.rb +23 -0
  24. data/lib/wrest/curl/options.rb +16 -0
  25. data/lib/wrest/curl/post.rb +23 -0
  26. data/lib/wrest/curl/put.rb +23 -0
  27. data/lib/wrest/curl/request.rb +95 -0
  28. data/lib/wrest/curl/response.rb +63 -0
  29. data/lib/wrest/curl/session.rb +57 -0
  30. data/lib/wrest/curl.rb +49 -0
  31. data/lib/wrest/exceptions.rb +16 -1
  32. data/lib/wrest/http_shared/headers.rb +350 -0
  33. data/lib/wrest/http_shared/standard_headers.rb +21 -0
  34. data/lib/wrest/http_shared/standard_tokens.rb +18 -0
  35. data/lib/wrest/http_shared.rb +24 -0
  36. data/lib/wrest/native/connection_factory.rb +23 -0
  37. data/lib/wrest/{http → native}/delete.rb +1 -1
  38. data/lib/wrest/{http → native}/get.rb +1 -1
  39. data/lib/wrest/{http → native}/options.rb +1 -1
  40. data/lib/wrest/{http → native}/post.rb +1 -1
  41. data/lib/wrest/{http → native}/put.rb +1 -1
  42. data/lib/wrest/{http → native}/redirection.rb +4 -1
  43. data/lib/wrest/{http → native}/request.rb +32 -20
  44. data/lib/wrest/{http → native}/response.rb +12 -4
  45. data/lib/wrest/native/session.rb +57 -0
  46. data/lib/wrest/native.rb +32 -0
  47. data/lib/wrest/resource/base.rb +1 -1
  48. data/lib/wrest/resource.rb +1 -1
  49. data/lib/wrest/test/request_patches.rb +5 -0
  50. data/lib/wrest/test.rb +1 -0
  51. data/lib/wrest/uri.rb +31 -3
  52. data/lib/wrest/version.rb +2 -2
  53. data/lib/wrest.rb +52 -16
  54. data/spec/unit/spec_helper.rb +12 -3
  55. data/spec/unit/wrest/components/attributes_container/alias_accessors_spec.rb +2 -2
  56. data/spec/unit/wrest/components/attributes_container/typecaster_spec.rb +6 -6
  57. data/spec/unit/wrest/components/attributes_container_spec.rb +44 -12
  58. data/spec/unit/wrest/components/translators/xml_spec.rb +7 -3
  59. data/spec/unit/wrest/curl/request_spec.rb +19 -0
  60. data/spec/unit/wrest/curl/response_spec.rb +16 -0
  61. data/spec/unit/wrest/http/response_spec.rb +17 -38
  62. data/spec/unit/wrest/{http → native}/redirection_spec.rb +5 -5
  63. data/spec/unit/wrest/{http → native}/request_spec.rb +15 -14
  64. data/spec/unit/wrest/native/response_spec.rb +72 -0
  65. data/spec/unit/wrest/native/session_spec.rb +74 -0
  66. data/spec/unit/wrest/resource/base_spec.rb +2 -2
  67. data/spec/unit/wrest/uri_spec.rb +51 -11
  68. data/wrest.gemspec +164 -0
  69. metadata +51 -165
  70. data/lib/wrest/http.rb +0 -25
  71. data/spec/functional/sample_rails_app/README +0 -3
  72. data/spec/functional/sample_rails_app/Rakefile +0 -10
  73. data/spec/functional/sample_rails_app/app/controllers/application_controller.rb +0 -10
  74. data/spec/functional/sample_rails_app/app/controllers/lead_bottles_controller.rb +0 -7
  75. data/spec/functional/sample_rails_app/app/helpers/application_helper.rb +0 -3
  76. data/spec/functional/sample_rails_app/app/models/bottle.rb +0 -3
  77. data/spec/functional/sample_rails_app/app/models/glass_bottle.rb +0 -3
  78. data/spec/functional/sample_rails_app/app/models/lead_bottle.rb +0 -3
  79. data/spec/functional/sample_rails_app/config/boot.rb +0 -110
  80. data/spec/functional/sample_rails_app/config/database.yml +0 -16
  81. data/spec/functional/sample_rails_app/config/environment.rb +0 -42
  82. data/spec/functional/sample_rails_app/config/environments/development.rb +0 -17
  83. data/spec/functional/sample_rails_app/config/environments/production.rb +0 -28
  84. data/spec/functional/sample_rails_app/config/environments/test.rb +0 -28
  85. data/spec/functional/sample_rails_app/config/initializers/backtrace_silencers.rb +0 -7
  86. data/spec/functional/sample_rails_app/config/initializers/inflections.rb +0 -10
  87. data/spec/functional/sample_rails_app/config/initializers/mime_types.rb +0 -5
  88. data/spec/functional/sample_rails_app/config/initializers/new_rails_defaults.rb +0 -19
  89. data/spec/functional/sample_rails_app/config/initializers/session_store.rb +0 -15
  90. data/spec/functional/sample_rails_app/config/locales/en.yml +0 -5
  91. data/spec/functional/sample_rails_app/config/routes.rb +0 -3
  92. data/spec/functional/sample_rails_app/db/development.sqlite3 +0 -0
  93. data/spec/functional/sample_rails_app/db/migrate/20090319115628_create_bottle.rb +0 -13
  94. data/spec/functional/sample_rails_app/db/schema.rb +0 -20
  95. data/spec/functional/sample_rails_app/db/test.sqlite3 +0 -0
  96. data/spec/functional/sample_rails_app/log/development.log +0 -1
  97. data/spec/functional/sample_rails_app/public/404.html +0 -30
  98. data/spec/functional/sample_rails_app/public/422.html +0 -30
  99. data/spec/functional/sample_rails_app/public/500.html +0 -30
  100. data/spec/functional/sample_rails_app/public/images/rails.png +0 -0
  101. data/spec/functional/sample_rails_app/public/index.html +0 -275
  102. data/spec/functional/sample_rails_app/public/robots.txt +0 -5
  103. data/spec/functional/sample_rails_app/script/about +0 -4
  104. data/spec/functional/sample_rails_app/script/autospec +0 -6
  105. data/spec/functional/sample_rails_app/script/console +0 -3
  106. data/spec/functional/sample_rails_app/script/dbconsole +0 -3
  107. data/spec/functional/sample_rails_app/script/destroy +0 -3
  108. data/spec/functional/sample_rails_app/script/generate +0 -3
  109. data/spec/functional/sample_rails_app/script/performance/benchmarker +0 -3
  110. data/spec/functional/sample_rails_app/script/performance/profiler +0 -3
  111. data/spec/functional/sample_rails_app/script/plugin +0 -3
  112. data/spec/functional/sample_rails_app/script/runner +0 -3
  113. data/spec/functional/sample_rails_app/script/server +0 -3
  114. data/spec/functional/sample_rails_app/script/spec +0 -10
  115. data/spec/functional/sample_rails_app/script/spec_server +0 -9
  116. data/spec/functional/sample_rails_app/test/performance/browsing_test.rb +0 -9
  117. data/spec/functional/sample_rails_app/test/test_helper.rb +0 -38
  118. data/spec/functional/sample_rails_app/tmtags +0 -2559
  119. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/MIT-LICENSE +0 -20
  120. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/README.rdoc +0 -100
  121. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/Rakefile +0 -18
  122. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/init.rb +0 -5
  123. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/install.rb +0 -1
  124. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/base.rb +0 -140
  125. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/controllers/resources.rb +0 -16
  126. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/controllers/resources_controller.rb +0 -26
  127. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/controllers/routes_controller.rb +0 -16
  128. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/core_extensions/api.rb +0 -26
  129. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/core_extensions/exception.rb +0 -23
  130. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/core_extensions/from_json.rb +0 -15
  131. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/dispatch.rb +0 -235
  132. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/models/resourced_route.rb +0 -84
  133. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/query.rb +0 -337
  134. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/render/html.rb +0 -50
  135. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/render/json.rb +0 -75
  136. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/render/xml.rb +0 -65
  137. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/render.rb +0 -63
  138. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/retrieve.rb +0 -74
  139. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full/version.rb +0 -9
  140. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/lib/resource_full.rb +0 -14
  141. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/spec/resource_full/base_spec.rb +0 -88
  142. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/spec/resource_full/controllers/resources_spec.rb +0 -29
  143. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/spec/resource_full/dispatch_spec.rb +0 -262
  144. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/spec/resource_full/models/resourced_route_spec.rb +0 -62
  145. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/spec/resource_full/query/parameter_spec.rb +0 -57
  146. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/spec/resource_full/query_spec.rb +0 -462
  147. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/spec/resource_full/render/html_spec.rb +0 -4
  148. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/spec/resource_full/render/json_spec.rb +0 -107
  149. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/spec/resource_full/render/xml_spec.rb +0 -98
  150. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/spec/resource_full/render_spec.rb +0 -5
  151. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/spec/resource_full/retrieve_spec.rb +0 -173
  152. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/spec/spec_helper.rb +0 -98
  153. data/spec/functional/sample_rails_app/vendor/plugins/resource_full/uninstall.rb +0 -1
  154. data/spec/functional/spec_helper.rb +0 -0
@@ -0,0 +1,95 @@
1
+ # Copyright 2009 Sidu Ponnappa
2
+
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ # Unless required by applicable law or agreed to in writing, software distributed under the License
7
+ # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8
+ # See the License for the specific language governing permissions and limitations under the License.
9
+
10
+ module Wrest::Curl
11
+ # This represents a HTTP request. Typically you will never need to instantiate
12
+ # one of these yourself - you can use one of the more conveient APIs via Wrest::Uri
13
+ # or Wrest::Http::Get etc. instead.
14
+ class Request
15
+ attr_reader :http_request, :uri, :body, :headers, :username, :password, :follow_redirects,
16
+ :follow_redirects_limit, :timeout, :connection, :parameters, :auth_type
17
+ # Valid tuples for the options are:
18
+ # :username => String, defaults to nil
19
+ # :password => String, defaults to nil
20
+ # :follow_redirects => Boolean, defaults to true for Get, false for anything else
21
+ # :follow_redirects_limit => Integer, defaults to 5. This is the number of redirects
22
+ # that Wrest will automatically follow before raising an
23
+ # Wrest::Exceptions::AutoRedirectLimitExceeded exception.
24
+ # For example, if you set this to 1, the very first redirect
25
+ # will raise the exception.
26
+ # :timeout => The period, in seconds, after which a Timeout::Error is raised
27
+ # in the event of a connection failing to open. Defaulted to 60 by Uri#create_connection.
28
+ # :connection => The HTTP Connection object to use. This is how a keep-alive connection can be
29
+ # used for multiple requests. Not yet fully implemented for Curl.
30
+ #
31
+ # Curl specific options:
32
+ # :auth_type => This is a curl specific option and can be one of :basic, :digest, or :any. The default is :basic.
33
+ def initialize(wrest_uri, http_verb, parameters = {}, body = nil, headers = {}, options = {})
34
+ @uri = wrest_uri
35
+ @headers = headers.stringify_keys
36
+ @parameters = parameters
37
+ @body = body
38
+
39
+ @options = options.clone
40
+ @auth_type = @options[:auth_type] || :basic
41
+ @username = @options[:username]
42
+ @password = @options[:password]
43
+ @follow_redirects = (@options[:follow_redirects] ||= false)
44
+
45
+ @follow_redirects_limit = (@options[:follow_redirects_limit] ||= 5)
46
+ @timeout = @options[:timeout] || 60
47
+ @connection = @options[:connection]
48
+
49
+ @http_request = Patron::Request.new
50
+ @http_request.action = http_verb
51
+ @http_request.upload_data = body
52
+ @http_request.headers = headers
53
+ @http_request.username = username
54
+ @http_request.password = password
55
+ @http_request.auth_type = auth_type
56
+ @http_request.url = parameters.empty? ? uri.to_s : "#{uri.to_s}?#{parameters.to_query}"
57
+ @http_request.max_redirects = follow_redirects_limit if follow_redirects
58
+ @http_request.timeout = @timeout
59
+ end
60
+
61
+ # Makes a request and returns a Wrest::Http::Response.
62
+ # Data about the request is and logged to Wrest.logger
63
+ # The log entry contains the following information:
64
+ #
65
+ # --> indicates a request
66
+ # <-- indicates a response
67
+ #
68
+ # The type of request is mentioned in caps, followed by a hash
69
+ # uniquely uniquely identifying a particular request/response pair.
70
+ # In a multi-process or multi-threaded scenario, this can be used
71
+ # to identify request-response pairs.
72
+ #
73
+ # The request hash is followed by a connection hash; requests using the
74
+ # same connection (effectively a keep-alive connection) will have the
75
+ # same connection hash.
76
+ #
77
+ # This is followed by the response code, the payload size and the time taken.
78
+ def invoke
79
+ response = nil
80
+
81
+ @connection ||= Patron::Session.new
82
+ raise ArgumentError, "Empty URL" if http_request.url.empty?
83
+
84
+ prefix = "#{http_request.action.to_s.upcase} #{http_request.hash} #{connection.hash}"
85
+
86
+ Wrest.logger.debug "--> (#{prefix}) #{http_request.url}"
87
+ time = Benchmark.realtime { response = Wrest::Curl::Response.new(connection.handle_request(http_request))}
88
+ Wrest.logger.debug "<-- (#{prefix}) %s (%d bytes %.2fs)" % [response.message, response.body ? response.body.length : 0, time]
89
+
90
+ response
91
+ rescue Patron::TimeoutError => e
92
+ raise Wrest::Exceptions::Timeout.new(e)
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,63 @@
1
+ # Copyright 2009 Sidu Ponnappa
2
+
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at Http://www.apache.org/licenses/LICENSE-2.0
6
+ # Unless required by applicable law or agreed to in writing, software distributed under the License
7
+ # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8
+ # See the License for the specific language governing permissions and limitations under the License.
9
+
10
+ module Wrest #:nodoc:
11
+ module Curl #:nodoc:
12
+ # Decorates a response providing support for deserialisation.
13
+ class Response
14
+ attr_reader :http_response
15
+ include HttpShared::Headers
16
+
17
+ extend Forwardable
18
+ def_delegators :@http_response, :body, :headers
19
+
20
+ def initialize(http_response)
21
+ @http_response = http_response
22
+ initialize_http_header
23
+ end
24
+
25
+ def deserialise
26
+ deserialise_using(Wrest::Components::Translators.lookup(content_type))
27
+ end
28
+
29
+ def deserialise_using(translator)
30
+ translator.deserialise(@http_response)
31
+ end
32
+
33
+ def code
34
+ @http_response.status
35
+ end
36
+
37
+ def message
38
+ @http_response.status_line
39
+ end
40
+
41
+ def content_length
42
+ self[H::ContentLength].try(:to_i)
43
+ end
44
+
45
+ def content_type
46
+ self[H::ContentType].split(';').first
47
+ end
48
+
49
+ # A null object implementation - invoking this method on
50
+ # a response simply returns the same response unless
51
+ # the response is a Redirection (code 3xx), in which case a
52
+ # get is invoked on the url stored in the response headers
53
+ # under the key 'location' and the new Response is returned.
54
+ def follow(redirect_request_options = {})
55
+ self
56
+ end
57
+
58
+ def connection_closed?
59
+ self[StandardHeaders::Connection].downcase == StandardTokens::Close.downcase
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,57 @@
1
+ # Copyright 2009 Sidu Ponnappa
2
+
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ # Unless required by applicable law or agreed to in writing, software distributed under the License
7
+ # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8
+ # See the License for the specific language governing permissions and limitations under the License.
9
+
10
+ module Wrest::Native
11
+ # This class is a wrapper for a keep-alive HTTP connection. It simply passes the
12
+ # same connection instance as an option to all Wrest::Http::Request instances created using it.
13
+ #
14
+ # If at any point the server closes an existing connection during a Session by returning a
15
+ # Connection: Close header the current connection is destroyed and a fresh one created for the next
16
+ # request.
17
+ #
18
+ # The Session constructor can accept either a String URI or a Wrest::Uri as a parameter. If you
19
+ # need HTTP authentication, you should use a Wrest::Uri.
20
+ class Session
21
+ attr_reader :uri
22
+ def initialize(uri)
23
+ @uri = uri.is_a?(String) ? uri.to_uri : uri
24
+ @default_headers = { StandardHeaders::Connection => StandardTokens::KeepAlive }
25
+
26
+ yield(self) if block_given?
27
+ end
28
+
29
+ def connection
30
+ @connection ||= @uri.create_connection
31
+ end
32
+
33
+ def get(path = '', parameters = {}, headers = {})
34
+ maybe_destroy_connection @uri[path, {:connection => self.connection}].get(parameters, headers.merge(@default_headers))
35
+ end
36
+
37
+ def post(path = '', body = '', headers = {}, params = {})
38
+ maybe_destroy_connection @uri[path, {:connection => self.connection}].post(body, headers.merge(@default_headers), params)
39
+ end
40
+
41
+ def put(path = '', body = '', headers = {}, params = {})
42
+ maybe_destroy_connection @uri[path, {:connection => self.connection}].put(body, headers.merge(@default_headers), params)
43
+ end
44
+
45
+ def delete(path = '', parameters = {}, headers = {})
46
+ maybe_destroy_connection @uri[path, {:connection => self.connection}].delete(parameters, headers.merge(@default_headers))
47
+ end
48
+
49
+ def maybe_destroy_connection(response)
50
+ if response.connection_closed?
51
+ Wrest.logger.warn "Connection #{@connection.hash} has been closed by the server"
52
+ @connection = nil
53
+ end
54
+ response
55
+ end
56
+ end
57
+ end
data/lib/wrest/curl.rb ADDED
@@ -0,0 +1,49 @@
1
+ # Copyright 2009 Sidu Ponnappa
2
+
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ # Unless required by applicable law or agreed to in writing, software distributed under the License
7
+ # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8
+ # See the License for the specific language governing permissions and limitations under the License.
9
+
10
+ begin
11
+ gem 'patron', '>=0.4.4'
12
+ rescue Gem::LoadError => e
13
+ Wrest.logger.debug "Patron >= 0.4.4 not found. Patron is necessary to use libcurl. To install Patron run `sudo gem install patron` (patron is not available on JRuby, but you shouldn't need it anyway)."
14
+ raise e
15
+ end
16
+ require 'patron'
17
+
18
+ module Wrest #:nodoc:
19
+
20
+ # Contains all HTTP protocol related classes such as
21
+ # Get, Post, Request, Response etc. and uses Curl for
22
+ # better performance, but works only on CRuby and only on a *nix OS.
23
+ #
24
+ # This functionality is under development and the Wrest API
25
+ # may not cover using it fully.
26
+ #
27
+ # Note:
28
+ # * The Curl based APIs do *not* support the HTTP 'options' verb.
29
+ # * Since auto-redirect is natively supported by Curl, auto-redirect may
30
+ # behave differently from the native implementation for now.
31
+ module Curl
32
+ include Wrest::HttpShared
33
+ end
34
+ end
35
+
36
+ module Patron
37
+ class Session
38
+ public :handle_request
39
+ end
40
+ end
41
+
42
+ require "#{Wrest::Root}/wrest/curl/response"
43
+ require "#{Wrest::Root}/wrest/curl/request"
44
+ require "#{Wrest::Root}/wrest/curl/get"
45
+ require "#{Wrest::Root}/wrest/curl/put"
46
+ require "#{Wrest::Root}/wrest/curl/post"
47
+ require "#{Wrest::Root}/wrest/curl/delete"
48
+ require "#{Wrest::Root}/wrest/curl/options"
49
+ # require "#{Wrest::Root}/wrest/curl/session"
@@ -9,10 +9,25 @@ module Wrest
9
9
  # is requested. See Translators.
10
10
  class UnsupportedContentType < StandardError
11
11
  end
12
-
12
+
13
13
  # Raised when a request auto redirects more times than are allowed
14
14
  # by its follow_redirects_limit. See Wrest::Http::Redirection.
15
15
  class AutoRedirectLimitExceeded < StandardError
16
16
  end
17
+
18
+ # Raised when a request is made when either RAILS_ENV or
19
+ # ENV['RAILS_ENV'] is set to 'test', which is the case when
20
+ # running tests/specs in a Rails application.
21
+ #
22
+ # See wrest/test/request_patches.
23
+ class RealRequestMadeInTestEnvironmet < StandardError
24
+ end
25
+
26
+ # Raised when a request times out
27
+ class Timeout < StandardError
28
+ end
29
+
30
+ class UnsupportedHttpVerb < StandardError
31
+ end
17
32
  end
18
33
  end
@@ -0,0 +1,350 @@
1
+ #
2
+ # Header module.
3
+ #
4
+ # Provides access to headers in the mixed-into class as a hash-like
5
+ # object, except with case-insensitive keys. Also provides
6
+ # methods for accessing commonly-used header values in a more
7
+ # convenient format.
8
+ #
9
+ # Sourced from Net::HTTP and then modified to be generic
10
+ module Wrest
11
+ module HttpShared
12
+ module Headers
13
+
14
+ def initialize_http_header
15
+ headers.each do |key, value|
16
+ headers[key.downcase] = value.strip
17
+ end
18
+ end
19
+
20
+ # Returns the header field corresponding to the case-insensitive key.
21
+ # For example, a key of "Content-Type" might return "text/html"
22
+ def [](key)
23
+ headers[key] || headers[key.downcase]
24
+ end
25
+
26
+ # # Sets the header field corresponding to the case-insensitive key.
27
+ # def []=(key, val)
28
+ # unless val
29
+ # headers.delete key.downcase
30
+ # return val
31
+ # end
32
+ # headers[key.downcase] = [val]
33
+ # end
34
+ #
35
+ # # [Ruby 1.8.3]
36
+ # # Adds header field instead of replace.
37
+ # # Second argument +val+ must be a String.
38
+ # # See also #[]=, #[] and #get_fields.
39
+ # #
40
+ # # request.add_field 'X-My-Header', 'a'
41
+ # # p request['X-My-Header'] #=> "a"
42
+ # # p request.get_fields('X-My-Header') #=> ["a"]
43
+ # # request.add_field 'X-My-Header', 'b'
44
+ # # p request['X-My-Header'] #=> "a, b"
45
+ # # p request.get_fields('X-My-Header') #=> ["a", "b"]
46
+ # # request.add_field 'X-My-Header', 'c'
47
+ # # p request['X-My-Header'] #=> "a, b, c"
48
+ # # p request.get_fields('X-My-Header') #=> ["a", "b", "c"]
49
+ # #
50
+ # def add_field(key, val)
51
+ # if headers.key?(key.downcase)
52
+ # headers[key.downcase].push val
53
+ # else
54
+ # headers[key.downcase] = [val]
55
+ # end
56
+ # end
57
+ #
58
+ # # [Ruby 1.8.3]
59
+ # # Returns an array of header field strings corresponding to the
60
+ # # case-insensitive +key+. This method allows you to get duplicated
61
+ # # header fields without any processing. See also #[].
62
+ # #
63
+ # # p response.get_fields('Set-Cookie')
64
+ # # #=> ["session=al98axx; expires=Fri, 31-Dec-1999 23:58:23",
65
+ # # "query=rubyscript; expires=Fri, 31-Dec-1999 23:58:23"]
66
+ # # p response['Set-Cookie']
67
+ # # #=> "session=al98axx; expires=Fri, 31-Dec-1999 23:58:23, query=rubyscript; expires=Fri, 31-Dec-1999 23:58:23"
68
+ # #
69
+ # def get_fields(key)
70
+ # return nil unless headers[key.downcase]
71
+ # headers[key.downcase].dup
72
+ # end
73
+ #
74
+ # # Returns the header field corresponding to the case-insensitive key.
75
+ # # Returns the default value +args+, or the result of the block, or nil,
76
+ # # if there's no header field named key. See Hash#fetch
77
+ # def fetch(key, *args, &block) #:yield: +key+
78
+ # a = headers.fetch(key.downcase, *args, &block)
79
+ # a.join(', ')
80
+ # end
81
+ #
82
+ # # Iterates for each header names and values.
83
+ # def each_header #:yield: +key+, +value+
84
+ # headers.each do |k,va|
85
+ # yield k, va.join(', ')
86
+ # end
87
+ # end
88
+ #
89
+ # alias each each_header
90
+ #
91
+ # # Iterates for each header names.
92
+ # def each_name(&block) #:yield: +key+
93
+ # headers.each_key(&block)
94
+ # end
95
+ #
96
+ # alias each_key each_name
97
+ #
98
+ # # Iterates for each capitalized header names.
99
+ # def each_capitalized_name(&block) #:yield: +key+
100
+ # headers.each_key do |k|
101
+ # yield capitalize(k)
102
+ # end
103
+ # end
104
+ #
105
+ # # Iterates for each header values.
106
+ # def each_value #:yield: +value+
107
+ # headers.each_value do |va|
108
+ # yield va.join(', ')
109
+ # end
110
+ # end
111
+ #
112
+ # # Removes a header field.
113
+ # def delete(key)
114
+ # headers.delete(key.downcase)
115
+ # end
116
+ #
117
+ # # true if +key+ header exists.
118
+ # def key?(key)
119
+ # headers.key?(key.downcase)
120
+ # end
121
+ #
122
+ # # Returns a Hash consist of header names and values.
123
+ # def to_hash
124
+ # headers.dup
125
+ # end
126
+ #
127
+ # # As for #each_header, except the keys are provided in capitalized form.
128
+ # def each_capitalized
129
+ # headers.each do |k,v|
130
+ # yield capitalize(k), v.join(', ')
131
+ # end
132
+ # end
133
+ #
134
+ # alias canonical_each each_capitalized
135
+ #
136
+ # def capitalize(name)
137
+ # name.split(/-/).map {|s| s.capitalize }.join('-')
138
+ # end
139
+ # private :capitalize
140
+ #
141
+ # # Returns an Array of Range objects which represents Range: header field,
142
+ # # or +nil+ if there is no such header.
143
+ # def range
144
+ # return nil unless headers['range']
145
+ # self['Range'].split(/,/).map {|spec|
146
+ # m = /bytes\s*=\s*(\d+)?\s*-\s*(\d+)?/i.match(spec) or
147
+ # raise HTTPHeaderSyntaxError, "wrong Range: #{spec}"
148
+ # d1 = m[1].to_i
149
+ # d2 = m[2].to_i
150
+ # if m[1] and m[2] then d1..d2
151
+ # elsif m[1] then d1..-1
152
+ # elsif m[2] then -d2..-1
153
+ # else
154
+ # raise HTTPHeaderSyntaxError, 'range is not specified'
155
+ # end
156
+ # }
157
+ # end
158
+ #
159
+ # # Set Range: header from Range (arg r) or beginning index and
160
+ # # length from it (arg idx&len).
161
+ # #
162
+ # # req.range = (0..1023)
163
+ # # req.set_range 0, 1023
164
+ # #
165
+ # def set_range(r, e = nil)
166
+ # unless r
167
+ # headers.delete 'range'
168
+ # return r
169
+ # end
170
+ # r = (r...r+e) if e
171
+ # case r
172
+ # when Numeric
173
+ # n = r.to_i
174
+ # rangestr = (n > 0 ? "0-#{n-1}" : "-#{-n}")
175
+ # when Range
176
+ # first = r.first
177
+ # last = r.last
178
+ # last -= 1 if r.exclude_end?
179
+ # if last == -1
180
+ # rangestr = (first > 0 ? "#{first}-" : "-#{-first}")
181
+ # else
182
+ # raise HTTPHeaderSyntaxError, 'range.first is negative' if first < 0
183
+ # raise HTTPHeaderSyntaxError, 'range.last is negative' if last < 0
184
+ # raise HTTPHeaderSyntaxError, 'must be .first < .last' if first > last
185
+ # rangestr = "#{first}-#{last}"
186
+ # end
187
+ # else
188
+ # raise TypeError, 'Range/Integer is required'
189
+ # end
190
+ # headers['range'] = ["bytes=#{rangestr}"]
191
+ # r
192
+ # end
193
+ #
194
+ # alias range= set_range
195
+ #
196
+ # # Returns an Integer object which represents the Content-Length: header field
197
+ # # or +nil+ if that field is not provided.
198
+ # def content_length
199
+ # return nil unless key?('Content-Length')
200
+ # len = self['Content-Length'].slice(/\d+/) or
201
+ # raise HTTPHeaderSyntaxError, 'wrong Content-Length format'
202
+ # len.to_i
203
+ # end
204
+ #
205
+ # def content_length=(len)
206
+ # unless len
207
+ # headers.delete 'content-length'
208
+ # return nil
209
+ # end
210
+ # headers['content-length'] = [len.to_i.to_s]
211
+ # end
212
+ #
213
+ # # Returns "true" if the "transfer-encoding" header is present and
214
+ # # set to "chunked". This is an HTTP/1.1 feature, allowing the
215
+ # # the content to be sent in "chunks" without at the outset
216
+ # # stating the entire content length.
217
+ # def chunked?
218
+ # return false unless headers['transfer-encoding']
219
+ # field = self['Transfer-Encoding']
220
+ # (/(?:\A|[^\-\w])chunked(?![\-\w])/i =~ field) ? true : false
221
+ # end
222
+ #
223
+ # # Returns a Range object which represents Content-Range: header field.
224
+ # # This indicates, for a partial entity body, where this fragment
225
+ # # fits inside the full entity body, as range of byte offsets.
226
+ # def content_range
227
+ # return nil unless headers['content-range']
228
+ # m = %r<bytes\s+(\d+)-(\d+)/(\d+|\*)>i.match(self['Content-Range']) or
229
+ # raise HTTPHeaderSyntaxError, 'wrong Content-Range format'
230
+ # m[1].to_i .. m[2].to_i + 1
231
+ # end
232
+ #
233
+ # # The length of the range represented in Content-Range: header.
234
+ # def range_length
235
+ # r = content_range() or return nil
236
+ # r.end - r.begin
237
+ # end
238
+ #
239
+ # # Returns a content type string such as "text/html".
240
+ # # This method returns nil if Content-Type: header field does not exist.
241
+ # def content_type
242
+ # return nil unless main_type()
243
+ # if sub_type()
244
+ # "#{main_type()}/#{sub_type()}"
245
+ # else
246
+ # main_type()
247
+ # end
248
+ # end
249
+ #
250
+ # # Returns a content type string such as "text".
251
+ # # This method returns nil if Content-Type: header field does not exist.
252
+ # def main_type
253
+ # return nil unless headers['content-type']
254
+ # self['Content-Type'].split(';').first.to_s.split('/')[0].to_s.strip
255
+ # end
256
+ #
257
+ # # Returns a content type string such as "html".
258
+ # # This method returns nil if Content-Type: header field does not exist
259
+ # # or sub-type is not given (e.g. "Content-Type: text").
260
+ # def sub_type
261
+ # return nil unless headers['content-type']
262
+ # main, sub = *self['Content-Type'].split(';').first.to_s.split('/')
263
+ # return nil unless sub
264
+ # sub.strip
265
+ # end
266
+ #
267
+ # # Returns content type parameters as a Hash as like
268
+ # # {"charset" => "iso-2022-jp"}.
269
+ # def type_params
270
+ # result = {}
271
+ # list = self['Content-Type'].to_s.split(';')
272
+ # list.shift
273
+ # list.each do |param|
274
+ # k, v = *param.split('=', 2)
275
+ # result[k.strip] = v.strip
276
+ # end
277
+ # result
278
+ # end
279
+ #
280
+ # # Set Content-Type: header field by +type+ and +params+.
281
+ # # +type+ must be a String, +params+ must be a Hash.
282
+ # def set_content_type(type, params = {})
283
+ # headers['content-type'] = [type + params.map{|k,v|"; #{k}=#{v}"}.join('')]
284
+ # end
285
+ #
286
+ # alias content_type= set_content_type
287
+ #
288
+ # # Set header fields and a body from HTML form data.
289
+ # # +params+ should be a Hash containing HTML form data.
290
+ # # Optional argument +sep+ means data record separator.
291
+ # #
292
+ # # This method also set Content-Type: header field to
293
+ # # application/x-www-form-urlencoded.
294
+ # #
295
+ # # Example:
296
+ # # http.form_data = {"q" => "ruby", "lang" => "en"}
297
+ # # http.form_data = {"q" => ["ruby", "perl"], "lang" => "en"}
298
+ # # http.set_form_data({"q" => "ruby", "lang" => "en"}, ';')
299
+ # #
300
+ # def set_form_data(params, sep = '&')
301
+ # self.body = params.map {|k, v| encode_kvpair(k, v) }.flatten.join(sep)
302
+ # self.content_type = 'application/x-www-form-urlencoded'
303
+ # end
304
+ #
305
+ # alias form_data= set_form_data
306
+ #
307
+ # def encode_kvpair(k, vs)
308
+ # Array(vs).map {|v| "#{urlencode(k)}=#{urlencode(v.to_s)}" }
309
+ # end
310
+ # private :encode_kvpair
311
+ #
312
+ # def urlencode(str)
313
+ # str.dup.force_encoding('ASCII-8BIT').gsub(/[^a-zA-Z0-9_\.\-]/){'%%%02x' % $&.ord}
314
+ # end
315
+ # private :urlencode
316
+ #
317
+ # # Set the Authorization: header for "Basic" authorization.
318
+ # def basic_auth(account, password)
319
+ # headers['authorization'] = [basic_encode(account, password)]
320
+ # end
321
+ #
322
+ # # Set Proxy-Authorization: header for "Basic" authorization.
323
+ # def proxy_basic_auth(account, password)
324
+ # headers['proxy-authorization'] = [basic_encode(account, password)]
325
+ # end
326
+ #
327
+ # def basic_encode(account, password)
328
+ # 'Basic ' + ["#{account}:#{password}"].pack('m').delete("\r\n")
329
+ # end
330
+ # private :basic_encode
331
+ #
332
+ # def connection_close?
333
+ # tokens(headers['connection']).include?('close') or
334
+ # tokens(headers['proxy-connection']).include?('close')
335
+ # end
336
+ #
337
+ # def connection_keep_alive?
338
+ # tokens(headers['connection']).include?('keep-alive') or
339
+ # tokens(headers['proxy-connection']).include?('keep-alive')
340
+ # end
341
+ #
342
+ # def tokens(vals)
343
+ # return [] unless vals
344
+ # vals.map {|v| v.split(',') }.flatten\
345
+ # .reject {|str| str.strip.empty? }\
346
+ # .map {|tok| tok.strip.downcase }
347
+ # end
348
+ end
349
+ end
350
+ end
@@ -0,0 +1,21 @@
1
+ # Copyright 2009 Sidu Ponnappa
2
+
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at Http://www.apache.org/licenses/LICENSE-2.0
6
+ # Unless required by applicable law or agreed to in writing, software distributed under the License
7
+ # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8
+ # See the License for the specific language governing permissions and limitations under the License.
9
+
10
+ module Wrest #:nodoc:
11
+ module HttpShared #:nodoc:
12
+ module StandardHeaders
13
+ Connection = 'connection'
14
+ ContentType = 'content-type'
15
+ ContentLength = 'content-length'
16
+ IfNoneMatch = 'if-none-match'
17
+ end
18
+ end
19
+ end
20
+
21
+
@@ -0,0 +1,18 @@
1
+ # Copyright 2009 Sidu Ponnappa
2
+
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at Http://www.apache.org/licenses/LICENSE-2.0
6
+ # Unless required by applicable law or agreed to in writing, software distributed under the License
7
+ # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8
+ # See the License for the specific language governing permissions and limitations under the License.
9
+
10
+ module Wrest #:nodoc:
11
+ module HttpShared #:nodoc:
12
+ module StandardTokens
13
+ Close = 'close'
14
+ KeepAlive = 'keep-alive'
15
+ FormEncoded = 'application/x-www-form-urlencoded'
16
+ end
17
+ end
18
+ end