tickethub 0.3.51 → 0.3.52

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c3b1862803f43e2f70410a2eb6108b1d13ed51a4
4
- data.tar.gz: 7a630302ee8cd1745aae8107d4635818494daf27
3
+ metadata.gz: 0c3d2fbee50f8b1649c00ce062145feba07d6ad1
4
+ data.tar.gz: e5ab1ddb6e9503d8d3a7b77c834f04223765f96b
5
5
  SHA512:
6
- metadata.gz: 7aed3e243ea8f61ecdb5729b916ef64837051eee842b182617cd4e4e24e93332b8fa1c103d9af2d6fe3ad153ae2f781f126a701600253bac42b7efc8e723a390
7
- data.tar.gz: d8c8e3ea78ac78453813dbadb3a51f0c76274f1bc75cc44dee55301bfeb64a4f8ecaa2e53e0d77e087a0af0321824aa95399cc662b7a0db6e5cba1a5f753e0fa
6
+ metadata.gz: e148ff6eede8074c3b76be0f36f69f79c5143fcf20bba3f6ef79d2784c7c5a90dceebacc38543ff7b8bab5b141be45877f2d0d243fa197442606d5fda4ed639f
7
+ data.tar.gz: 67e18750bd49ba334f9092d31caa2642e412b9a8d67f0d654a27698608fcbd42deb867d6f7bf4f8b356d09ffa8545b1b5eb96ba258280f58f6e01ce5b5a0c455
@@ -40,6 +40,10 @@ module Tickethub
40
40
  request(:head, path, headers, &block)
41
41
  end
42
42
 
43
+ def put(path, body = '', headers = {}, &block)
44
+ request(:put, path, body, headers, &block)
45
+ end
46
+
43
47
  def patch(path, body = '', headers = {}, &block)
44
48
  request(:patch, path, body, headers, &block)
45
49
  end
@@ -50,48 +54,72 @@ module Tickethub
50
54
 
51
55
  protected
52
56
 
57
+ def request=(request)
58
+ @request = request
59
+ end
60
+
53
61
  # Makes a request to the remote service.
54
62
  def request(method, path, *arguments)
55
63
  response = http.send(method, path, *arguments)
64
+ response.uri = URI.join(endpoint, path)
65
+
56
66
  handle_response(response)
57
67
 
58
- rescue Timeout::Error => e
59
- raise TimeoutError.new(e.message)
68
+ rescue Timeout::Error, Net::OpenTimeout => e
69
+ raise TimeoutError.new(@request, e.message)
60
70
  rescue OpenSSL::SSL::SSLError => e
61
- raise SSLError.new(e.message)
71
+ raise SSLError.new(@request, e.message)
72
+ rescue SocketError,
73
+ EOFError,
74
+ Net::HTTPBadResponse,
75
+ Net::HTTPHeaderSyntaxError,
76
+ Net::HTTPServerException,
77
+ Net::ProtocolError,
78
+ Errno::ECONNABORTED,
79
+ Errno::ECONNREFUSED,
80
+ Errno::ECONNRESET,
81
+ Errno::ETIMEDOUT,
82
+ Errno::ENETUNREACH,
83
+ Errno::EHOSTUNREACH,
84
+ Errno::EINVAL,
85
+ Errno::ENOPROTOOPT => e
86
+ raise ErrnoError.new(@request, e.message)
87
+ rescue Zlib::DataError,
88
+ Zlib::BufError => e
89
+ raise ZlibError.new(@request, e.message)
62
90
  end
63
91
 
64
92
  # Handles response and error codes from the remote service.
65
93
  def handle_response(response)
66
94
  case response.code.to_i
67
- when 301,302
68
- raise Redirection.new(response)
69
- when 200...400
70
- response
71
- when 400
72
- raise BadRequest.new(response)
73
- when 401
74
- raise UnauthorizedAccess.new(response)
75
- when 403
76
- raise ForbiddenAccess.new(response)
77
- when 404
78
- raise ResourceNotFound.new(response)
79
- when 405
80
- raise MethodNotAllowed.new(response)
81
- when 409
82
- raise ResourceConflict.new(response)
83
- when 410
84
- raise ResourceGone.new(response)
85
- when 422
86
- raise ResourceInvalid.new(response)
87
- when 401...500
88
- raise ClientError.new(response)
89
- when 500...600
90
- raise ServerError.new(response)
91
- else
92
- raise ConnectionError.new(
93
- response, "Unknown response code: #{response.code}"
94
- )
95
+ when 200...299
96
+ response
97
+ when 300..399
98
+ raise Redirection.new(@request, response)
99
+ when 400
100
+ raise BadRequest.new(@request, response)
101
+ when 401
102
+ raise UnauthorizedAccess.new(@request, response)
103
+ when 403
104
+ raise ForbiddenAccess.new(@request, response)
105
+ when 404
106
+ raise ResourceNotFound.new(@request, response)
107
+ when 405
108
+ raise MethodNotAllowed.new(@request, response)
109
+ when 409
110
+ raise ResourceConflict.new(@request, response)
111
+ when 410
112
+ raise ResourceGone.new(@request, response)
113
+ when 422
114
+ raise ResourceInvalid.new(@request, response)
115
+ when 401...500
116
+ raise ClientError.new(@request, response)
117
+ when 500...600
118
+ raise ServerError.new(@request, response)
119
+ else
120
+ raise ResponseError.new(
121
+ @request, response, "Unknown response code: #{response.code}"
122
+ )
95
123
  end
96
124
  end
97
125
 
@@ -113,7 +141,13 @@ module Tickethub
113
141
 
114
142
  def configure_http(http)
115
143
  http = apply_ssl_options(http)
116
- http.read_timeout = timeout if timeout
144
+
145
+ # Net::HTTP timeouts default to 60 seconds.
146
+ if timeout
147
+ http.open_timeout = timeout
148
+ http.read_timeout = timeout
149
+ end
150
+
117
151
  http
118
152
  end
119
153
 
@@ -1,44 +1,65 @@
1
1
  module Tickethub
2
- class ConnectionError < StandardError # :nodoc:
2
+ class Error < StandardError
3
+ attr_reader :request
4
+
5
+ def initialize(request = nil, message = nil)
6
+ super(message)
7
+ @request = request
8
+ end
9
+ end
10
+
11
+ ConnectionError = Error
12
+ RequestError = Error
13
+
14
+ class ResponseError < Error
3
15
  attr_reader :response
4
16
 
5
- def initialize(response, message = nil)
17
+ def initialize(request, response, message = nil)
18
+ super(request, message)
6
19
  @response = response
7
- @message = message
8
20
  end
9
21
 
10
22
  def to_s
11
23
  message = "Failed."
12
24
  message << " Response code = #{response.code}." if response.respond_to?(:code)
13
25
  message << " Response message = #{response.message}." if response.respond_to?(:message)
14
- message << " Response Body = #{response.body}." if response.respond_to?(:body)
26
+
27
+ if response.respond_to?(:body)
28
+ # Error messages need to be in UTF-8
29
+ body = response.body.dup.to_s
30
+ body = body.encode('UTF-8', :invalid => :replace, :undef => :replace, :replace => '?')
31
+ message << " Response Body = #{body}."
32
+ end
33
+
15
34
  message
16
35
  end
17
36
  end
18
37
 
19
38
  # Raised when a Timeout::Error occurs.
20
- class TimeoutError < ConnectionError
21
- def initialize(message)
22
- @message = message
23
- end
24
- def to_s; @message ;end
39
+ class TimeoutError < RequestError
25
40
  end
26
41
 
27
42
  # Raised when a OpenSSL::SSL::SSLError occurs.
28
- class SSLError < ConnectionError
29
- def initialize(message)
30
- @message = message
31
- end
32
- def to_s; @message ;end
43
+ class SSLError < RequestError
44
+ end
45
+
46
+ class ErrnoError < RequestError
47
+ end
48
+
49
+ class ZlibError < RequestError
33
50
  end
34
51
 
35
52
  # 3xx Redirection
36
- class Redirection < ConnectionError # :nodoc:
53
+ class Redirection < ResponseError # :nodoc:
54
+ def to_s; response['Location'] ? "#{super} => #{response['Location']}" : super; end
55
+ end
56
+
57
+ class RedirectionLoop < ResponseError # :nodoc:
37
58
  def to_s; response['Location'] ? "#{super} => #{response['Location']}" : super; end
38
59
  end
39
60
 
40
61
  # 4xx Client Error
41
- class ClientError < ConnectionError; end # :nodoc:
62
+ class ClientError < ResponseError; end # :nodoc:
42
63
 
43
64
  # 400 Bad Request
44
65
  class BadRequest < ClientError; end # :nodoc
@@ -52,11 +73,17 @@ module Tickethub
52
73
  # 404 Not Found
53
74
  class ResourceNotFound < ClientError; end # :nodoc:
54
75
 
76
+ # 409 Conflict
77
+ class ResourceConflict < ClientError; end # :nodoc:
78
+
79
+ # 410 Gone
80
+ class ResourceGone < ClientError; end # :nodoc:
81
+
55
82
  # 422 Invalid
56
83
  class ResourceInvalid < ClientError; end # :nodoc:
57
84
 
58
85
  # 5xx Server Error
59
- class ServerError < ConnectionError; end # :nodoc:
86
+ class ServerError < ResponseError; end # :nodoc:
60
87
 
61
88
  # 405 Method Not Allowed
62
89
  class MethodNotAllowed < ClientError # :nodoc:
@@ -10,6 +10,14 @@ module Tickethub
10
10
  value.to_s.split('_').map {|w| w.capitalize }.join
11
11
  end
12
12
 
13
+ def deep_merge(hash, other_hash)
14
+ hash.merge(other_hash) do |key, oldval, newval|
15
+ oldval = oldval.to_hash if oldval.respond_to?(:to_hash)
16
+ newval = newval.to_hash if newval.respond_to?(:to_hash)
17
+ oldval.class.to_s == 'Hash' && newval.class.to_s == 'Hash' ? deep_merge(oldval, newval) : newval
18
+ end
19
+ end
20
+
13
21
  # Stolen from Rack:
14
22
 
15
23
  DEFAULT_SEP = /[&;] */n
@@ -30,6 +38,22 @@ module Tickethub
30
38
  end
31
39
  end
32
40
 
41
+ def to_url_param(value, prefix = nil)
42
+ case value
43
+ when Array
44
+ value.map { |v|
45
+ to_url_param(v, "#{prefix}[]")
46
+ }.join("&")
47
+ when Hash
48
+ value.map { |k, v|
49
+ to_url_param(v, prefix ? "#{prefix}[#{uri_escape(k)}]" : uri_escape(k))
50
+ }.join("&")
51
+ else
52
+ raise ArgumentError, "value must be a Hash" if prefix.nil?
53
+ "#{prefix}=#{uri_escape(value)}"
54
+ end
55
+ end
56
+
33
57
  def from_param(param)
34
58
  Rack::Utils.parse_nested_query(param)
35
59
  (value || '').split('&').each do |res|
@@ -51,7 +75,15 @@ module Tickethub
51
75
  end
52
76
 
53
77
  def escape(s)
54
- URI.encode_www_form_component(s)
78
+ URI.encode_www_form_component(s.to_s)
79
+ end
80
+
81
+ ESCAPE_RE = /[^a-zA-Z0-9 .~_-]/
82
+
83
+ def uri_escape(s)
84
+ s.to_s.gsub(ESCAPE_RE) {|match|
85
+ '%' + match.unpack('H2' * match.bytesize).join('%').upcase
86
+ }.tr(' ', '+')
55
87
  end
56
88
 
57
89
  if defined?(::Encoding)
@@ -2,12 +2,12 @@ require 'securerandom'
2
2
 
3
3
  module Tickethub
4
4
  class Request
5
-
6
5
  attr_reader :options, :format, :url
7
- attr_accessor :params, :body, :method, :headers
8
6
 
9
- # Connection options
10
- attr_accessor :proxy, :user, :password, :auth_type, :timeout, :retries, :ssl_options
7
+ attr_accessor :params, :body, :method, :headers,
8
+ :proxy, :user, :password, :retries,
9
+ :auth_type, :timeout, :ssl_options,
10
+ :max_attempts, :follow_redirection
11
11
 
12
12
  def initialize(url, options = {})
13
13
  @url = url.to_s
@@ -15,16 +15,19 @@ module Tickethub
15
15
  @retries = 3
16
16
  @timeout = 10
17
17
 
18
- @options = options
18
+ @options = {
19
+ :method => :get,
20
+ :params => {},
21
+ :headers => {},
22
+ :format => :form,
23
+ :max_attempts => 5,
24
+ :follow_redirection => true
25
+ }.merge(options)
26
+
19
27
  @options.each do |key, val|
20
28
  method = "#{key}="
21
29
  send(method, val) if respond_to?(method)
22
30
  end
23
-
24
- self.method ||= :get
25
- self.params ||= {}
26
- self.headers ||= {}
27
- self.format ||= :form
28
31
  end
29
32
 
30
33
  def format=(mime_or_format)
@@ -46,50 +49,86 @@ module Tickethub
46
49
  @uri = URI.parse(url)
47
50
  @uri.path = '/' if @uri.path.empty?
48
51
 
49
- if @uri.query
50
- @params.merge!(Helpers.from_param(@uri.query))
51
- @uri.query = nil
52
- end
53
-
54
52
  @uri
55
53
  end
56
54
 
55
+ def uri_params
56
+ uri.query ? Helpers.from_param(uri.query) : {}
57
+ end
58
+
57
59
  def path
58
60
  uri.path
59
61
  end
60
62
 
61
- def execute
62
- if encoded?
63
- result = connection.send(method, path, encoded, build_headers)
64
- else
65
- result = connection.send(method, query_path, build_headers)
63
+ def query_path
64
+ query_path = path.dup
65
+ query_params = uri_params.dup
66
+ query_params.merge!(params) unless encoded?
67
+
68
+ if query_params.any?
69
+ query_path += '?' + Helpers.to_url_param(query_params)
66
70
  end
67
71
 
68
- Response.new(result)
72
+ query_path
73
+ end
69
74
 
70
- rescue TimeoutError, ServerError, SSLError => err
71
- raise err if (@retries -= 1) == 0
72
- execute
73
- rescue Redirection => error
74
- raise error unless error.response['Location']
75
- location = URI.parse(error.response['Location'])
75
+ def encoded?
76
+ [:post, :put].include?(method)
77
+ end
76
78
 
77
- # Path is relative
78
- unless location.host
79
- location = URI.join(uri, location)
80
- end
79
+ def encoded
80
+ params.any? ? format.encode(params) : body
81
+ end
81
82
 
82
- self.url = location.to_s
83
+ def execute
84
+ with_redirection do
85
+ if encoded?
86
+ result = connection.send(method, query_path, encoded, build_headers)
87
+ else
88
+ result = connection.send(method, query_path, build_headers)
89
+ end
90
+
91
+ Response.new(result, uri)
92
+ end
93
+ rescue ServerError, RequestError => err
94
+ raise err if (@retries -= 1) == 0
83
95
  execute
84
96
  end
85
97
 
86
98
  protected
87
99
 
100
+ def with_redirection(&block)
101
+ attempts = 1
102
+
103
+ begin
104
+ yield
105
+ rescue Redirection => error
106
+ raise error unless follow_redirection
107
+
108
+ attempts += 1
109
+
110
+ raise error unless error.response['Location']
111
+ raise RedirectionLoop.new(self, error.response) if attempts > max_attempts
112
+
113
+ location = error.response['Location'].scrub
114
+ location = URI.parse(location)
115
+
116
+ # Path is relative
117
+ unless location.host
118
+ location = URI.join(uri, location)
119
+ end
120
+
121
+ self.url = location.to_s
122
+ retry
123
+ end
124
+ end
125
+
88
126
  def connection
89
127
  Connection.new(uri,
90
128
  :proxy => proxy,
91
129
  :timeout => timeout,
92
- :ssl_options => ssl_options
130
+ :ssl_options => ssl_options,
131
+ :request => self
93
132
  )
94
133
  end
95
134
 
@@ -117,23 +156,5 @@ module Tickethub
117
156
  .merge(headers)
118
157
  .merge('X-Request-ID' => @id)
119
158
  end
120
-
121
- def query_path
122
- query_path = path
123
-
124
- if params.any?
125
- query_path += '?' + Helpers.to_param(params)
126
- end
127
-
128
- query_path
129
- end
130
-
131
- def encoded?
132
- [:post, :patch].include?(method)
133
- end
134
-
135
- def encoded
136
- params.any? ? format.encode(params) : body
137
- end
138
159
  end
139
160
  end
@@ -1,3 +1,3 @@
1
1
  module Tickethub
2
- VERSION = '0.3.51'
2
+ VERSION = '0.3.52'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tickethub
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.51
4
+ version: 0.3.52
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oliver Morgan