Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Typhoeus #175

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .rubocop_todo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ Naming/AccessorMethodName:
- 'lib/api_auth/request_drivers/net_http.rb'
- 'lib/api_auth/request_drivers/rack.rb'
- 'lib/api_auth/request_drivers/rest_client.rb'
- 'lib/api_auth/request_drivers/typhoeus_request.rb'

# Offense count: 3
# Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames.
Expand Down
1 change: 1 addition & 0 deletions api_auth.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Gem::Specification.new do |s|
s.add_development_dependency 'pry'
s.add_development_dependency 'rake'
s.add_development_dependency 'rest-client', '~> 2.0'
s.add_development_dependency 'typhoeus'
s.add_development_dependency 'grape', '~> 1.1.0'
s.add_development_dependency 'rspec', '~> 3.4'

Expand Down
1 change: 1 addition & 0 deletions lib/api_auth.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
require 'api_auth/request_drivers/httpi'
require 'api_auth/request_drivers/faraday'
require 'api_auth/request_drivers/http'
require 'api_auth/request_drivers/typhoeus_request'

require 'api_auth/headers'
require 'api_auth/base'
Expand Down
2 changes: 2 additions & 0 deletions lib/api_auth/headers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ def initialize_request_driver(request)
HttpiRequest.new(request)
when /Faraday::Request/
FaradayRequest.new(request)
when /Typhoeus::Request/
TyphoeusRequest.new(request)
when /HTTP::Request/
HttpRequest.new(request)
end
Expand Down
81 changes: 81 additions & 0 deletions lib/api_auth/request_drivers/typhoeus_request.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
module ApiAuth
module RequestDrivers # :nodoc:
class TyphoeusRequest # :nodoc:
include ApiAuth::Helpers

def initialize(request)
@request = request
fetch_headers
end

def set_auth_header(header)
@request.options[:headers]['Authorization'] = header
fetch_headers
@request
end

def calculated_md5
body = @request.options[:body] || ''
md5_base64digest(body.to_s)
end

def populate_content_md5
return unless %w[POST PUT].include?(http_method.to_s.upcase)

@request.options[:headers]['Content-MD5'] = calculated_md5
fetch_headers
end

def md5_mismatch?
if %w[POST PUT].include?(http_method.to_s.upcase)
calculated_md5 != content_md5
else
false
end
end

def fetch_headers
@headers = capitalize_keys(@request.options[:headers])
end

def http_method
@request.options[:method].to_s.upcase
end

def content_type
find_header(%w[CONTENT-TYPE CONTENT_TYPE HTTP_CONTENT_TYPE])
end

def content_md5
find_header(%w[CONTENT-MD5 CONTENT_MD5 HTTP-CONTENT-MD5 HTTP_CONTENT_MD5])
end

def original_uri
find_header(%w[X-ORIGINAL-URI X_ORIGINAL_URI HTTP_X_ORIGINAL_URI])
end

def request_uri
URI.parse(@request.url).request_uri
end

def set_date
@request.options[:headers]['Date'] = Time.now.utc.httpdate
fetch_headers
end

def timestamp
find_header(%w[DATE HTTP_DATE])
end

def authorization_header
find_header %w[Authorization AUTHORIZATION HTTP_AUTHORIZATION]
end

private

def find_header(keys)
keys.map { |key| @headers[key] }.compact.first
end
end
end
end
196 changes: 196 additions & 0 deletions spec/request_drivers/typhoeus_request_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
require 'spec_helper'

describe ApiAuth::RequestDrivers::TyphoeusRequest do
let(:timestamp) { Time.now.utc.httpdate }

let(:request_url) { 'https://example.com/resource.xml?foo=bar&bar=foo' }
let(:upload_file) { File.open('spec/fixtures/upload.png', 'r') }

let(:request_headers) do
{
'Authorization' => 'APIAuth 1044:12345',
'content-md5' => '1B2M2Y8AsgTpgAmY7PhCfg==',
'content-type' => 'text/plain',
'date' => timestamp
}
end

let(:upload_request) do
Typhoeus::Request.new(request_url, method: :put, headers: request_headers, body: { file: upload_file })
end

let(:request) do
Typhoeus::Request.new(request_url, method: :put, headers: request_headers, body: "hello\nworld")
end

subject(:driven_request) { ApiAuth::RequestDrivers::TyphoeusRequest.new(request) }

describe 'getting headers correctly' do
describe '#content_type' do
it 'gets the content_type' do
expect(driven_request.content_type).to eq('text/plain')
end
end

it 'gets the content_md5' do
expect(driven_request.content_md5).to eq('1B2M2Y8AsgTpgAmY7PhCfg==')
end

it 'gets the request_uri' do
expect(driven_request.request_uri).to eq('/resource.xml?foo=bar&bar=foo')
end

it 'gets the timestamp' do
expect(driven_request.timestamp).to eq(timestamp)
end

it 'gets the authorization_header' do
expect(driven_request.authorization_header).to eq('APIAuth 1044:12345')
end

describe '#calculated_md5' do
it 'calculates md5 from the body' do
expect(driven_request.calculated_md5).to eq('kZXQvrKoieG+Be1rsZVINw==')
end

it 'treats no body as empty string' do
request.options[:body] = nil
expect(driven_request.calculated_md5).to eq('1B2M2Y8AsgTpgAmY7PhCfg==')
end

context 'file upload' do
let(:request) { upload_request }

it 'calculates correctly for multipart content' do
expect(driven_request.calculated_md5).to eq('3wNtEzQ9ZdXZnkyg/glH1g==')
end
end
end

describe 'http_method' do
context 'when put request' do
let(:request) { Typhoeus::Request.new(request_url, method: :put, headers: request_headers) }

it 'returns upcased put' do
expect(driven_request.http_method).to eq('PUT')
end
end

context 'when get request' do
let(:request) { Typhoeus::Request.new(request_url, method: :get, headers: request_headers) }

it 'returns upcased get' do
expect(driven_request.http_method).to eq('GET')
end
end
end
end

describe 'setting headers correctly' do
let(:request_headers) do
{
'content-type' => 'text/plain'
}
end

let(:request) do
Typhoeus::Request.new(request_url, method: :put, headers: request_headers)
end

describe '#populate_content_md5' do
context 'when request type has no body' do
let(:request) do
Typhoeus::Request.new(request_url, method: :get, headers: request_headers)
end

it "doesn't populate content-md5" do
driven_request.populate_content_md5
expect(request.options[:headers]['Content-MD5']).to be_nil
end
end

context 'when request type has a body' do
let(:request) do
Typhoeus::Request.new(request_url, method: :put, headers: request_headers, body: "hello\nworld")
end

it 'populates content-md5' do
driven_request.populate_content_md5
expect(request.options[:headers]['Content-MD5']).to eq('kZXQvrKoieG+Be1rsZVINw==')
end

it 'refreshes the cached headers' do
driven_request.populate_content_md5
expect(driven_request.content_md5).to eq('kZXQvrKoieG+Be1rsZVINw==')
end
end
end

describe '#set_date' do
before do
allow(Time).to receive_message_chain(:now, :utc, :httpdate).and_return(timestamp)
end

it 'sets the date header of the request' do
driven_request.set_date
expect(request.options[:headers]['Date']).to eq(timestamp)
end

it 'refreshes the cached headers' do
driven_request.set_date
expect(driven_request.timestamp).to eq(timestamp)
end
end

describe '#set_auth_header' do
it 'sets the auth header' do
driven_request.set_auth_header('APIAuth 1044:54321')
expect(request.options[:headers]['Authorization']).to eq('APIAuth 1044:54321')
end
end
end

describe 'md5_mismatch?' do
context 'when request type has no body' do
let(:request) do
Typhoeus::Request.new(request_url, method: :get, headers: request_headers)
end

it 'is false' do
expect(driven_request.md5_mismatch?).to be false
end
end

context 'when request type has a body' do
let(:request) do
Typhoeus::Request.new(request_url, method: :put, headers: request_headers, body: "hello\world")
end

context 'when calculated matches sent' do
before do
request.options[:headers]['Content-MD5'] = '/F4DjTilcDIIVEHn/nAQsA=='
end

it 'is false' do
expect(driven_request.md5_mismatch?).to be false
end
end

context "when calculated doesn't match sent" do
before do
request.options[:headers]['Content-MD5'] = '3'
end

it 'is true' do
expect(driven_request.md5_mismatch?).to be true
end
end
end
end

describe 'fetch_headers' do
it 'returns request headers' do
expect(driven_request.fetch_headers).to include('CONTENT-TYPE' => 'text/plain')
end
end
end
1 change: 1 addition & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
require 'httpi'
require 'faraday'
require 'grape'
require 'typhoeus'
require 'net/http/post/multipart'

# Requires supporting files with custom matchers and macros, etc,
Expand Down