Skip to content

Commit

Permalink
Refactor uri normalizer feature a bit
Browse files Browse the repository at this point in the history
I'm still pretty unhappy with how the end result looks, but I think that
in order to make it suck less - lots of things should be refactored thus
it shuold be done later.

My vision here is that `HTTP::Options` shold be passed to
`HTTP::Request`. Most likele `build_request` should be moved away from
Client as well.
  • Loading branch information
ixti committed Mar 11, 2019
1 parent 7fd1356 commit c7e5de7
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 38 deletions.
4 changes: 2 additions & 2 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ Metrics/ClassLength:

# TODO: Lower to 6
Metrics/CyclomaticComplexity:
Max: 9
Max: 8

Metrics/PerceivedComplexity:
Max: 9
Max: 8

# TODO: Lower to 80
Metrics/LineLength:
Expand Down
14 changes: 6 additions & 8 deletions lib/http/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,14 @@ def build_request(verb, uri, opts = {}) # rubocop:disable Style/OptionHash
uri = make_request_uri(uri, opts)
headers = make_request_headers(opts)
body = make_request_body(opts, headers)
proxy = opts.proxy
normalize_uri = opts.features[:normalize_uri]&.method(:normalize_uri)

req = HTTP::Request.new(
:verb => verb,
:uri => uri,
:headers => headers,
:proxy => proxy,
:body => body,
:normalize_uri => normalize_uri
:verb => verb,
:uri => uri,
:uri_normalizer => opts.feature(:normalize_uri)&.normalizer,
:proxy => opts.proxy,
:headers => headers,
:body => body
)

opts.features.inject(req) do |request, (_name, feature)|
Expand Down
2 changes: 1 addition & 1 deletion lib/http/features/auto_deflate.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def wrap_request(request)
:headers => request.headers,
:proxy => request.proxy,
:body => deflated_body(request.body),
:normalize_uri => request.normalize_uri
:uri_normalizer => request.uri_normalizer
)
end

Expand Down
14 changes: 3 additions & 11 deletions lib/http/features/normalize_uri.rb
Original file line number Diff line number Diff line change
@@ -1,24 +1,16 @@
# frozen_string_literal: true

require "http/uri"

module HTTP
module Features
class NormalizeUri < Feature
attr_reader :normalizer

def initialize(normalizer: Normalizer)
def initialize(normalizer: HTTP::URI::NORMALIZER)
@normalizer = normalizer
end

def normalize_uri(uri)
normalizer.call(uri)
end

module Normalizer
def self.call(uri)
HTTP::URI::NORMALIZER.call(uri)
end
end

HTTP::Options.register_feature(:normalize_uri, self)
end
end
Expand Down
44 changes: 28 additions & 16 deletions lib/http/request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class UnsupportedSchemeError < RequestError; end
# Scheme is normalized to be a lowercase symbol e.g. :http, :https
attr_reader :scheme

attr_reader :normalize_uri
attr_reader :uri_normalizer

# "Request URI" as per RFC 2616
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html
Expand All @@ -75,27 +75,25 @@ class UnsupportedSchemeError < RequestError; end

# @option opts [String] :version
# @option opts [#to_s] :verb HTTP request method
# @option opts [#to_s] :normalize_uri
# @option opts [#call] :uri_normalizer (HTTP::URI::NORMALIZER)
# @option opts [HTTP::URI, #to_s] :uri
# @option opts [Hash] :headers
# @option opts [Hash] :proxy
# @option opts [String, Enumerable, IO, nil] :body
def initialize(opts)
@verb = opts.fetch(:verb).to_s.downcase.to_sym
normalizer = opts.fetch(:normalize_uri, nil) || HTTP::URI::NORMALIZER
@uri = normalizer.call(opts.fetch(:uri))
@verb = opts.fetch(:verb).to_s.downcase.to_sym
@uri_normalizer = opts[:uri_normalizer] || HTTP::URI::NORMALIZER

@uri = @uri_normalizer.call(opts.fetch(:uri))
@scheme = @uri.scheme.to_s.downcase.to_sym if @uri.scheme

raise(UnsupportedMethodError, "unknown method: #{verb}") unless METHODS.include?(@verb)
raise(UnsupportedSchemeError, "unknown scheme: #{scheme}") unless SCHEMES.include?(@scheme)

@proxy = opts[:proxy] || {}
@body = (body = opts[:body]).is_a?(Request::Body) ? body : Request::Body.new(body)
@version = opts[:version] || "1.1"
@headers = HTTP::Headers.coerce(opts[:headers] || {})

@headers[Headers::HOST] ||= default_host_header_value
@headers[Headers::USER_AGENT] ||= USER_AGENT
@headers = prepare_headers(opts[:headers])
@body = prepare_body(opts[:body])
end

# Returns new Request with updated uri
Expand All @@ -104,12 +102,13 @@ def redirect(uri, verb = @verb)
headers.delete(Headers::HOST)

self.class.new(
:verb => verb,
:uri => @uri.join(uri),
:headers => headers,
:proxy => proxy,
:body => body.source,
:version => version
:verb => verb,
:uri => @uri.join(uri),
:headers => headers,
:proxy => proxy,
:body => body.source,
:version => version,
:uri_normalizer => uri_normalizer
)
end

Expand Down Expand Up @@ -216,5 +215,18 @@ def port
def default_host_header_value
PORTS[@scheme] != port ? "#{host}:#{port}" : host
end

def prepare_body(body)
body.is_a?(Request::Body) ? body : Request::Body.new(body)
end

def prepare_headers(headers)
headers = HTTP::Headers.coerce(headers || {})

headers[Headers::HOST] ||= default_host_header_value
headers[Headers::USER_AGENT] ||= USER_AGENT

headers
end
end
end
2 changes: 2 additions & 0 deletions lib/http/uri.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ class URI
# @private
HTTPS_SCHEME = "https"

# @private
NORMALIZER = lambda do |uri|
uri = HTTP::URI.parse uri

HTTP::URI.new(
:scheme => uri.normalized_scheme,
:authority => uri.normalized_authority,
Expand Down

0 comments on commit c7e5de7

Please sign in to comment.