Commit a41db2f

mo khan <mo.khan@gmail.com>
2020-01-13 23:42:02
Allow following redirects
1 parent 0a6eda8
lib/net/hippie/client.rb
@@ -11,6 +11,7 @@ module Net
       }.freeze
 
       attr_accessor :mapper, :read_timeout, :open_timeout, :logger
+      attr_accessor :follow_redirects
 
       def initialize(certificate: nil, headers: DEFAULT_HEADERS,
         key: nil, passphrase: nil, verify_mode: Net::Hippie.verify_mode)
@@ -22,43 +23,34 @@ module Net
         @read_timeout = 30
         @verify_mode = verify_mode
         @logger = Net::Hippie.logger
+        @follow_redirects = 0
       end
 
       def execute(uri, request)
-        response = http_for(normalize_uri(uri)).request(request)
-        if block_given?
-          yield request, response
-        else
-          response
+        response = follow(limit: follow_redirects) do
+          http_for(normalize_uri(uri)).request(request)
         end
+        block_given? ? yield(request, response) : response
       end
 
       def get(uri, headers: {}, body: {}, &block)
-        request = request_for(Net::HTTP::Get, uri, headers: headers, body: body)
-        execute(uri, request, &block)
+        run(uri, Net::HTTP::Get, headers, body, &block)
       end
 
       def patch(uri, headers: {}, body: {}, &block)
-        type = Net::HTTP::Patch
-        request = request_for(type, uri, headers: headers, body: body)
-        execute(uri, request, &block)
+        run(uri, Net::HTTP::Patch, headers, body, &block)
       end
 
       def post(uri, headers: {}, body: {}, &block)
-        type = Net::HTTP::Post
-        request = request_for(type, uri, headers: headers, body: body)
-        execute(uri, request, &block)
+        run(uri, Net::HTTP::Post, headers, body, &block)
       end
 
       def put(uri, headers: {}, body: {}, &block)
-        request = request_for(Net::HTTP::Put, uri, headers: headers, body: body)
-        execute(uri, request, &block)
+        run(uri, Net::HTTP::Put, headers, body, &block)
       end
 
       def delete(uri, headers: {}, body: {}, &block)
-        type = Net::HTTP::Delete
-        request = request_for(type, uri, headers: headers, body: body)
-        execute(uri, request, &block)
+        run(uri, Net::HTTP::Delete, headers, body, &block)
       end
 
       # attempt 1 -> delay 0.1 second
@@ -81,8 +73,7 @@ module Net
 
       private
 
-      attr_reader :default_headers
-      attr_reader :verify_mode
+      attr_reader :default_headers, :verify_mode
       attr_reader :certificate, :key, :passphrase
 
       def attempt(attempt, max)
@@ -131,6 +122,17 @@ module Net
       def warn(message)
         logger.warn(message)
       end
+
+      def follow(limit: 0, &block)
+        response = yield
+        redirected = limit.positive? && response.is_a?(Net::HTTPRedirection)
+        redirected ? follow(limit: limit - 1, &block) : response
+      end
+
+      def run(uri, http_method, headers, body, &block)
+        request = request_for(http_method, uri, headers: headers, body: body)
+        execute(uri, request, &block)
+      end
     end
   end
 end
lib/net/hippie/version.rb
@@ -2,6 +2,6 @@
 
 module Net
   module Hippie
-    VERSION = '0.2.7'
+    VERSION = '0.3.7'
   end
 end
test/net/client_test.rb
@@ -18,6 +18,23 @@ class ClientTest < Minitest::Test
     end
   end
 
+  def test_get_with_redirects
+    url = 'https://www.example.org/'
+    n = 10
+    WebMock
+      .stub_request(:get, url)
+      .to_return(status: 301, headers: { 'Location' => url })
+      .times(n)
+      .then
+      .to_return(status: 200, body: { success: true }.to_json)
+
+    subject.follow_redirects = n
+    response = subject.get(url)
+    refute_nil response
+    assert_equal Net::HTTPOK, response.class
+    assert JSON.parse(response.body)['success']
+  end
+
   def test_get_root_path
     VCR.use_cassette('get_root') do
       uri = URI.parse('https://www.mokhan.ca')
@@ -87,8 +104,8 @@ class ClientTest < Minitest::Test
   def test_get_with_headers
     headers = { 'Accept' => 'application/vnd.haveibeenpwned.v2+json' }
     WebMock.stub_request(:get, 'https://haveibeenpwned.com/api/breaches')
-           .with(headers: headers)
-           .to_return(status: 201, body: {}.to_json)
+      .with(headers: headers)
+      .to_return(status: 201, body: {}.to_json)
 
     uri = URI.parse('https://haveibeenpwned.com/api/breaches')
 
@@ -133,8 +150,8 @@ class ClientTest < Minitest::Test
     uri = URI.parse('https://haveibeenpwned.com/api/breaches')
     body = { 'hello' => 'world' }
     WebMock.stub_request(:get, uri.to_s)
-           .with(body: body.to_json)
-           .to_return(status: 201, body: {}.to_json)
+      .with(body: body.to_json)
+      .to_return(status: 201, body: {}.to_json)
 
     response = subject.get(uri, body: body)
 
.rubocop.yml
@@ -7,7 +7,7 @@ AllCops:
     - 'vendor/**/*'
   TargetRubyVersion: 2.4
 
-Layout/AlignParameters:
+Layout/ParameterAlignment:
   EnforcedStyle: with_fixed_indentation
 
 Naming/RescuedExceptionsVariableName:
CHANGELOG.md
@@ -7,7 +7,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
 ## [Unreleased]
-- nil
+### Added
+- Allow following HTTP redirects.
 
 ## [0.2.7] - 2019-10-04
 ### Added