sumo-search 2.0.3 → 2.1.0

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: 27b7af6b07a96c23c0583a4dea06fcfb5bf118d2
4
- data.tar.gz: 9e5b066988e0bd14f73fb82b261ca7930a92a2e8
3
+ metadata.gz: 34911b9efb6c328c089cda2f45d3b6ddbe941c98
4
+ data.tar.gz: 9ff1594f807e696be3b703609f322289cff41c52
5
5
  SHA512:
6
- metadata.gz: 16a15d1e68e1ac6601bc7bd8471092bee2c744c9ffcb32c63b17e942162cad3cd6828d665d10b69ffa0b991153e9b43319b4bdd1f8a7307d23b714291c3156f2
7
- data.tar.gz: 05fb4b9cd0ffcf642160fcdcbef91c55d88ebd7714a8b260d80c9f01b044e9e21da449fc1addb27053474798872fe7c0ef33ab0a992803170078042da91e64b6
6
+ metadata.gz: 367766f8515371162e4be5bdffffc4d2f805e363fae0265640e0e7f655ce96531e1e4312d46d3944e0683cf6f6cd90484474faa20a29d5913294f544695621d9
7
+ data.tar.gz: 6c812fc6cc43eb95156b825a51e4ea9a1f54c609a98ffa66c684d4c9e86af289973b2da77da52ddef3ac08366193dc1ee8973db912b3441e066ca55c12bf5d61
@@ -4,6 +4,8 @@ class Sumo::Client
4
4
 
5
5
  attr_reader :email, :password, :cookie
6
6
 
7
+ REDIRECT_STATUSES = [301, 302, 303, 307, 308]
8
+
7
9
  # The error message raised when the result can be parsed from Sumo.
8
10
  DEFAULT_ERROR_MESSAGE = 'Error sending API request'
9
11
 
@@ -13,13 +15,25 @@ class Sumo::Client
13
15
  @password = credentials['password'].freeze
14
16
  end
15
17
 
16
- # Send a HTTP request to the server, handling any errors that may occur.
18
+ # Send a request to the API and retrieve processed data.
17
19
  def request(hash, &block)
18
- response = connection.request(add_defaults(hash), &block)
20
+ handle_request(hash, &block).body
21
+ end
22
+
23
+ # Send a HTTP request to the server, handling any errors that may occur.
24
+ def handle_request(hash, endpoint = nil, depth = 0, &block)
25
+ response = connection(endpoint).request(add_defaults(hash), &block)
26
+
27
+ if REDIRECT_STATUSES.include?(response.status) &&
28
+ response.headers['Location']
29
+ response = handle_redirect(response, hash, depth, &block)
30
+ end
31
+
19
32
  handle_errors!(response)
20
33
  set_cookie!(response)
21
- response.body
34
+ response
22
35
  end
36
+ private :handle_request
23
37
 
24
38
  # Define methods for the HTTP methods used by the API (#get, #post, and
25
39
  # #delete).
@@ -32,13 +46,27 @@ class Sumo::Client
32
46
  # Private functions that operate on the request and response.
33
47
 
34
48
  def add_defaults(hash)
35
- hash.merge(
36
- :headers => default_headers.merge(hash[:headers] || {}),
37
- :path => "/api/v#{Sumo::API_VERSION}#{hash[:path]}"
38
- )
49
+ hash[:headers] = default_headers.merge(hash[:headers] || {})
50
+ hash[:path] = "/api/v#{Sumo::API_VERSION}#{hash[:path]}" unless
51
+ hash[:path].index("/api/v#{Sumo::API_VERSION}") == 0
52
+ hash
39
53
  end
40
54
  private :add_defaults
41
55
 
56
+ # Recursively handle redirection up to 10 level depth
57
+ def handle_redirect(response, hash, depth, &block)
58
+ fail 'Too many redirections.' if depth > 9
59
+
60
+ endpoint = response.headers['Location']
61
+ .match(%r{^(https://.+\.[a-z]+)/}).to_a[1]
62
+
63
+ depth += 1
64
+ # I tried to blindly follow redirection path, but it omits the job ID.
65
+ # hash[:path] = path
66
+ handle_request(hash, endpoint, depth, &block)
67
+ end
68
+ private :handle_redirect
69
+
42
70
  def handle_errors!(response)
43
71
  case response.status
44
72
  when 400..499 then raise ClientError, extract_error_message(response.body)
@@ -79,8 +107,13 @@ class Sumo::Client
79
107
  end
80
108
  private :creds
81
109
 
82
- def connection
83
- @connection ||= Excon.new('https://api.sumologic.com')
110
+ def connection(endpoint = nil)
111
+ @connections ||= {}
112
+ endpoint ||= 'https://api.sumologic.com'
113
+
114
+ fail 'Base url out of allowed domain.' unless
115
+ endpoint.match(%r{^https://.+\.sumologic\.com$})
116
+ @connections[endpoint] ||= Excon.new(endpoint)
84
117
  end
85
118
  private :connection
86
119
  end
@@ -1,8 +1,8 @@
1
1
  # This module holds versioning information for the gem.
2
2
  module Sumo
3
3
  MAJOR = 2
4
- MINOR = 0
5
- PATCH = 3
4
+ MINOR = 1
5
+ PATCH = 0
6
6
  RELEASE = nil
7
7
 
8
8
  VERSION = [MAJOR, MINOR, PATCH, RELEASE].compact.join('.')
@@ -46,6 +46,7 @@ describe Sumo::Client do
46
46
  subject.stub(:handle_errors!)
47
47
  response.stub(:body)
48
48
  response.stub(:headers).and_return({})
49
+ response.stub(:status).and_return(200)
49
50
  connection.should_receive(:request)
50
51
  .with(
51
52
  :method => :get,
@@ -134,6 +135,118 @@ describe Sumo::Client do
134
135
  end
135
136
  end
136
137
  end
138
+
139
+ context 'when a 3xx-level status code is returned by the API' do
140
+ let(:cookie) { 'oreo' }
141
+ let(:headers) { {'Set-Cookie' => cookie } }
142
+ let(:default_connection) { double(:default_connection) }
143
+ let(:redirect_connection) { double(:redirect_connection) }
144
+
145
+ before do
146
+ # Do not stub full connection method but only Excon.
147
+ subject.stub(:connection).and_call_original
148
+ default_connection.stub(:request).and_return(response)
149
+ allow(Excon).to receive(:new)
150
+ .with('https://api.sumologic.com').and_return default_connection
151
+ allow(Excon).to receive(:new)
152
+ .with('https://api.us2.sumologic.com').and_return redirect_connection
153
+ end
154
+
155
+ context 'and the redirection url is within sumologic domain' do
156
+ let(:response) do
157
+ double(:response, :status => 301, :body => '', :headers => {
158
+ 'Location' => 'https://api.us2.sumologic.com/api/v1/jobs'
159
+ })
160
+ end
161
+ let(:final_response) do
162
+ double(:response, :status => 200, :body => '', :headers => {})
163
+ end
164
+
165
+ it 'should follow it' do
166
+ expect(default_connection).to receive(:request)
167
+ .with(
168
+ :method => :get,
169
+ :path => '/api/v1/',
170
+ :headers => {
171
+ 'Content-Type' => 'application/json',
172
+ 'Accept' => 'application/json',
173
+ 'Authorization' => "Basic #{encoded}" })
174
+ .and_return(response)
175
+
176
+ expect(redirect_connection).to receive(:request)
177
+ .with(
178
+ :method => :get,
179
+ :path => '/api/v1/',
180
+ :headers => {
181
+ 'Content-Type' => 'application/json',
182
+ 'Accept' => 'application/json',
183
+ 'Authorization' => "Basic #{encoded}" })
184
+ .and_return(final_response)
185
+ subject.request(:method => :get, :path => '/')
186
+ end
187
+ end
188
+
189
+ context 'and the redirection url is outside of sumologic' do
190
+ let(:response) do
191
+ double(:response, :status => 301, :body => '', :headers => {
192
+ 'Location' => 'https://donotfollow.me/api/v1/jobs'
193
+ })
194
+ end
195
+
196
+ it 'should not follow it' do
197
+ expect(default_connection).to receive(:request)
198
+ .with(
199
+ :method => :get,
200
+ :path => '/api/v1/',
201
+ :headers => {
202
+ 'Content-Type' => 'application/json',
203
+ 'Accept' => 'application/json',
204
+ 'Authorization' => "Basic #{encoded}" })
205
+ .once
206
+ .and_return(response)
207
+ expect(Excon).not_to receive(:new)
208
+ .with('https://donotfollow.me')
209
+ expect do
210
+ subject.request(:method => :get, :path => '/')
211
+ end.to raise_error 'Base url out of allowed domain.'
212
+ end
213
+ end
214
+
215
+ context 'and there is a redirection loop' do
216
+ let(:response) do
217
+ double(:response, :status => 301, :body => '', :headers => {
218
+ 'Location' => 'https://api.us2.sumologic.com/api/v1/jobs'
219
+ })
220
+ end
221
+
222
+ it 'should throw a too many redirections error' do
223
+ expect(default_connection).to receive(:request)
224
+ .with(
225
+ :method => :get,
226
+ :path => '/api/v1/',
227
+ :headers => {
228
+ 'Content-Type' => 'application/json',
229
+ 'Accept' => 'application/json',
230
+ 'Authorization' => "Basic #{encoded}" })
231
+ .and_return(response)
232
+
233
+ expect(redirect_connection).to receive(:request)
234
+ .with(
235
+ :method => :get,
236
+ :path => '/api/v1/',
237
+ :headers => {
238
+ 'Content-Type' => 'application/json',
239
+ 'Accept' => 'application/json',
240
+ 'Authorization' => "Basic #{encoded}" })
241
+ .exactly(10).times
242
+ .and_return(response)
243
+
244
+ expect do
245
+ subject.request(:method => :get, :path => '/')
246
+ end.to raise_error 'Too many redirections.'
247
+ end
248
+ end
249
+ end
137
250
  end
138
251
 
139
252
  [:get, :post, :delete].each do |http_method|
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sumo-search
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.3
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Swipely, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-10 00:00:00.000000000 Z
11
+ date: 2015-09-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: excon