mirror of
https://github.com/HoneyryderChuck/httpx.git
synced 2025-09-30 00:01:02 -04:00
rubocop auto-corrections according to some basic rules for now
This commit is contained in:
parent
53303b65bc
commit
2b1ab8b6b6
106
.rubocop.yml
Normal file
106
.rubocop.yml
Normal file
@ -0,0 +1,106 @@
|
||||
inherit_from: .rubocop_todo.yml
|
||||
|
||||
AllCops:
|
||||
TargetRubyVersion: 2.3
|
||||
DisplayCopNames: true
|
||||
Include:
|
||||
- Rakefile
|
||||
- palanca.gemspec
|
||||
Exclude:
|
||||
- '*.rb'
|
||||
- 'bugreports/*'
|
||||
- 'examples/**/*'
|
||||
- '.bundle/**/*'
|
||||
- 'vendor/**/*'
|
||||
|
||||
Metrics/LineLength:
|
||||
Max: 120
|
||||
|
||||
Metrics/MethodLength:
|
||||
Max: 200
|
||||
|
||||
Metrics/ParameterLists:
|
||||
CountKeywordArgs: false
|
||||
|
||||
Naming/FileName:
|
||||
Exclude:
|
||||
- Gemfile
|
||||
- Rakefile
|
||||
|
||||
Lint/EndAlignment:
|
||||
EnforcedStyleAlignWith: variable
|
||||
|
||||
Lint/HandleExceptions:
|
||||
Enabled: false
|
||||
|
||||
Lint/RescueException:
|
||||
Exclude:
|
||||
# starts the server in a new thread
|
||||
- lib/palanca/server.rb
|
||||
# safely close the ssl socket, copied from ruby-openssl
|
||||
- lib/palanca/server/ssl.rb
|
||||
# guards against Exceptions in a thread loop
|
||||
- lib/palanca/executor/threaded.rb
|
||||
#Style/CaseIndentation:
|
||||
# EnforcedStyle: end
|
||||
|
||||
#Style/IndentHash:
|
||||
# EnforcedStyle: consistent
|
||||
|
||||
Style/Alias:
|
||||
EnforcedStyle: prefer_alias_method
|
||||
|
||||
Style/TrailingCommaInLiteral:
|
||||
EnforcedStyleForMultiline: comma
|
||||
|
||||
Style/StringLiterals:
|
||||
EnforcedStyle: double_quotes
|
||||
|
||||
Style/StringLiteralsInInterpolation:
|
||||
EnforcedStyle: double_quotes
|
||||
|
||||
Style/GlobalVars:
|
||||
AllowedVariables: [$PALANCA_DEBUG]
|
||||
|
||||
#Style/SpaceAroundOperators:
|
||||
# Enabled: false
|
||||
|
||||
#Style/ExtraSpacing:
|
||||
# Enabled: false
|
||||
|
||||
Style/ClassVars:
|
||||
Exclude:
|
||||
# header field transformation caches
|
||||
- lib/palanca/http/headers.rb
|
||||
- lib/palanca/http1/headers.rb
|
||||
|
||||
Style/SignalException:
|
||||
Enabled: false
|
||||
|
||||
Style/FrozenStringLiteralComment:
|
||||
Enabled: false
|
||||
|
||||
Style/ParallelAssignment:
|
||||
Enabled: false
|
||||
|
||||
Style/ParenthesesAroundCondition:
|
||||
Enabled: false
|
||||
|
||||
Style/IfInsideElse:
|
||||
Enabled: false
|
||||
|
||||
Style/MultilineIfModifier:
|
||||
Enabled: false
|
||||
|
||||
Style/TrailingCommaInArguments:
|
||||
Enabled: false
|
||||
|
||||
Style/TrailingUnderscoreVariable:
|
||||
Enabled: false
|
||||
|
||||
Performance/TimesMap:
|
||||
Enabled: false
|
||||
|
||||
Performance/RedundantBlockCall:
|
||||
Enabled: false
|
||||
|
40
.rubocop_todo.yml
Normal file
40
.rubocop_todo.yml
Normal file
@ -0,0 +1,40 @@
|
||||
Metrics/AbcSize:
|
||||
Max: 185
|
||||
|
||||
Metrics/CyclomaticComplexity:
|
||||
Max: 60
|
||||
|
||||
Metrics/PerceivedComplexity:
|
||||
Max: 46
|
||||
|
||||
Metrics/ClassLength:
|
||||
Max: 325
|
||||
|
||||
Metrics/ModuleLength:
|
||||
Max: 325
|
||||
|
||||
Metrics/BlockLength:
|
||||
Max: 100
|
||||
|
||||
#Naming/MethodName:
|
||||
|
||||
# TODO: remove this if min supported version of ruby is 2.3
|
||||
Layout/IndentHeredoc:
|
||||
Enabled: false
|
||||
|
||||
Style/SafeNavigation:
|
||||
Enabled: false
|
||||
|
||||
Security/Eval:
|
||||
Enabled: false
|
||||
|
||||
Style/ClassAndModuleChildren:
|
||||
Enabled: false
|
||||
|
||||
# TODO: remove this if min supported version of ruby is 2.3
|
||||
Style/HashSyntax:
|
||||
Enabled: false
|
||||
|
||||
Style/NumericPredicate:
|
||||
Exclude:
|
||||
- lib/palanca/extensions/*.rb
|
7
Gemfile
7
Gemfile
@ -4,15 +4,16 @@ source "https://rubygems.org"
|
||||
gemspec
|
||||
|
||||
gem "rake", "~> 12.3"
|
||||
gem "rubocop", require: false
|
||||
gem "simplecov", require: false
|
||||
|
||||
platform :mri do
|
||||
gem "brotli", require: false
|
||||
gem "pry-byebug", require: false
|
||||
gem "pry-byebug", require: false
|
||||
end
|
||||
# gem "guard-rspec", :require => false
|
||||
# gem "nokogiri", :require => false
|
||||
gem "pry", :require => false
|
||||
gem "pry", :require => false
|
||||
|
||||
gem "certificate_authority", git: "https://github.com/cchandler/certificate_authority.git",
|
||||
branch: "master",
|
||||
@ -20,7 +21,7 @@ gem "certificate_authority", git: "https://github.com/cchandler/certificate_auth
|
||||
|
||||
gem "simplecov"
|
||||
|
||||
gem "oga", require: false
|
||||
gem "minitest", require: false
|
||||
gem "minitest-proveit", require: false
|
||||
gem "oga", require: false
|
||||
gem "rubocop", require: false
|
||||
|
@ -23,8 +23,8 @@ Gem::Specification.new do |gem|
|
||||
|
||||
gem.required_ruby_version = ">= 2.1"
|
||||
|
||||
gem.add_runtime_dependency "http_parser.rb", ">= 0.6.0"
|
||||
gem.add_runtime_dependency "http-2", ">= 0.8.4"
|
||||
gem.add_runtime_dependency "http-form_data", ">= 2.0.0", "< 3"
|
||||
gem.add_runtime_dependency "http_parser.rb", ">= 0.6.0"
|
||||
gem.add_development_dependency "http-cookie", "~> 1.0"
|
||||
end
|
||||
|
@ -9,13 +9,13 @@ module HTTPX
|
||||
def_delegator :@buffer, :<<
|
||||
|
||||
def_delegator :@buffer, :to_s
|
||||
|
||||
|
||||
def_delegator :@buffer, :to_str
|
||||
|
||||
|
||||
def_delegator :@buffer, :empty?
|
||||
|
||||
|
||||
def_delegator :@buffer, :slice!
|
||||
|
||||
|
||||
def_delegator :@buffer, :clear
|
||||
|
||||
def initialize(limit)
|
||||
|
@ -1,6 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module HTTPX
|
||||
module HTTPX
|
||||
module Callbacks
|
||||
def on(type, &action)
|
||||
callbacks(type) << action
|
||||
@ -23,7 +23,7 @@ module HTTPX
|
||||
@callbacks = callbackable.callbacks
|
||||
end
|
||||
|
||||
def callbacks(type=nil)
|
||||
def callbacks(type = nil)
|
||||
return @callbacks unless type
|
||||
@callbacks ||= Hash.new { |h, k| h[k] = [] }
|
||||
@callbacks[type]
|
||||
|
@ -21,13 +21,13 @@ module HTTPX
|
||||
end
|
||||
|
||||
def accept(type)
|
||||
headers("accept" => String(type))
|
||||
headers("accept" => String(type))
|
||||
end
|
||||
|
||||
def plugin(*plugins)
|
||||
Class.new(Client).plugins(plugins).new
|
||||
end
|
||||
alias :plugins :plugin
|
||||
alias_method :plugins, :plugin
|
||||
|
||||
def with(options)
|
||||
branch(default_options.merge(options))
|
||||
@ -41,9 +41,8 @@ module HTTPX
|
||||
|
||||
# :nodoc:
|
||||
def branch(options)
|
||||
return self.class.new(options) if self.is_a?(Client)
|
||||
return self.class.new(options) if is_a?(Client)
|
||||
Client.new(options)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -24,8 +24,8 @@ module HTTPX
|
||||
#
|
||||
# A channel may also route requests for a different host for which the +io+ was connected
|
||||
# to, provided that the IP is the same and the port and scheme as well. This will allow to
|
||||
# share the same socket to send HTTP/2 requests to different hosts.
|
||||
# TODO: For this to succeed, the certificates sent by the servers to the client must be
|
||||
# share the same socket to send HTTP/2 requests to different hosts.
|
||||
# TODO: For this to succeed, the certificates sent by the servers to the client must be
|
||||
# identical (or match both hosts).
|
||||
#
|
||||
class Channel
|
||||
@ -42,12 +42,12 @@ module HTTPX
|
||||
class << self
|
||||
def by(uri, options)
|
||||
io = case uri.scheme
|
||||
when "http"
|
||||
IO.registry("tcp").new(uri.host, uri.port, options)
|
||||
when "https"
|
||||
IO.registry("ssl").new(uri.host, uri.port, options)
|
||||
else
|
||||
raise Error, "#{uri.scheme}: unrecognized channel"
|
||||
when "http"
|
||||
IO.registry("tcp").new(uri.host, uri.port, options)
|
||||
when "https"
|
||||
IO.registry("ssl").new(uri.host, uri.port, options)
|
||||
else
|
||||
raise Error, "#{uri.scheme}: unrecognized channel"
|
||||
end
|
||||
new(io, options)
|
||||
end
|
||||
@ -71,8 +71,8 @@ module HTTPX
|
||||
ip = TCPSocket.getaddress(uri.host)
|
||||
|
||||
ip == @io.ip &&
|
||||
uri.port == @io.port &&
|
||||
uri.scheme == @io.scheme
|
||||
uri.port == @io.port &&
|
||||
uri.scheme == @io.scheme
|
||||
end
|
||||
|
||||
def to_io
|
||||
@ -84,7 +84,7 @@ module HTTPX
|
||||
@io.to_io
|
||||
end
|
||||
|
||||
def close(hard=false)
|
||||
def close(hard = false)
|
||||
pr = @parser
|
||||
transition(:closed)
|
||||
return true if hard
|
||||
@ -127,7 +127,7 @@ module HTTPX
|
||||
siz = @io.read(wsize, @read_buffer)
|
||||
throw(:close, self) unless siz
|
||||
return if siz.zero?
|
||||
log { "READ: #{siz} bytes..."}
|
||||
log { "READ: #{siz} bytes..." }
|
||||
parser << @read_buffer
|
||||
end
|
||||
end
|
||||
@ -137,23 +137,23 @@ module HTTPX
|
||||
return if @write_buffer.empty?
|
||||
siz = @io.write(@write_buffer)
|
||||
throw(:close, self) unless siz
|
||||
log { "WRITE: #{siz} bytes..."}
|
||||
log { "WRITE: #{siz} bytes..." }
|
||||
return if siz.zero?
|
||||
end
|
||||
end
|
||||
|
||||
def send_pending
|
||||
while !@write_buffer.full? && (req_args = @pending.shift)
|
||||
request, args = req_args
|
||||
request, args = req_args
|
||||
parser.send(request, **args)
|
||||
end
|
||||
end
|
||||
|
||||
def parser
|
||||
@parser ||= build_parser
|
||||
@parser ||= build_parser
|
||||
end
|
||||
|
||||
def build_parser(protocol=@io.protocol)
|
||||
def build_parser(protocol = @io.protocol)
|
||||
parser = registry(protocol).new(@write_buffer, @options)
|
||||
parser.inherit_callbacks(self)
|
||||
parser.on(:close) { throw(:close, self) }
|
||||
|
@ -16,15 +16,15 @@ module HTTPX
|
||||
@parser = HTTP::Parser.new(self)
|
||||
@parser.header_value_type = :arrays
|
||||
@buffer = buffer
|
||||
@version = [1,1]
|
||||
@pending = []
|
||||
@version = [1, 1]
|
||||
@pending = []
|
||||
@requests = []
|
||||
@has_response = false
|
||||
end
|
||||
|
||||
def close
|
||||
def close
|
||||
@parser.reset!
|
||||
@has_response = false
|
||||
@has_response = false
|
||||
end
|
||||
|
||||
def empty?
|
||||
@ -64,7 +64,7 @@ module HTTPX
|
||||
# HTTP Parser callbacks
|
||||
#
|
||||
# must be public methods, or else they won't be reachable
|
||||
|
||||
|
||||
def on_message_begin
|
||||
log(2) { "parsing begins" }
|
||||
end
|
||||
@ -81,9 +81,9 @@ module HTTPX
|
||||
@parser.status_code,
|
||||
@parser.http_version.join("."),
|
||||
headers, @options)
|
||||
log { "-> HEADLINE: #{response.status} HTTP/#{@parser.http_version.join(".")}" }
|
||||
log { "-> HEADLINE: #{response.status} HTTP/#{@parser.http_version.join(".")}" }
|
||||
log { response.headers.each.map { |f, v| "-> HEADER: #{f}: #{v}" }.join("\n") }
|
||||
|
||||
|
||||
request.response = response
|
||||
# parser can't say if it's parsing GET or HEAD,
|
||||
# call the completeness callback manually
|
||||
@ -111,7 +111,7 @@ module HTTPX
|
||||
emit(:response, request, response)
|
||||
|
||||
if @parser.upgrade?
|
||||
response << @parser.upgrade_data
|
||||
response << @parser.upgrade_data
|
||||
throw(:called)
|
||||
end
|
||||
close
|
||||
@ -121,7 +121,7 @@ module HTTPX
|
||||
@requests.map { |r| r.transition(:idle) }
|
||||
# server doesn't handle pipelining, and probably
|
||||
# doesn't support keep-alive. Fallback to send only
|
||||
# 1 keep alive request.
|
||||
# 1 keep alive request.
|
||||
@max_concurrent_requests = 1
|
||||
end
|
||||
log(2) { "connection: close" }
|
||||
@ -132,11 +132,11 @@ module HTTPX
|
||||
private
|
||||
|
||||
def set_request_headers(request)
|
||||
request.headers["host"] ||= request.authority
|
||||
request.headers["host"] ||= request.authority
|
||||
request.headers["connection"] ||= "keep-alive"
|
||||
if !request.headers.key?("content-length") &&
|
||||
request.body.bytesize == Float::INFINITY
|
||||
request.chunk!
|
||||
request.body.bytesize == Float::INFINITY
|
||||
request.chunk!
|
||||
end
|
||||
end
|
||||
|
||||
@ -163,7 +163,7 @@ module HTTPX
|
||||
@buffer << buffer
|
||||
buffer.clear
|
||||
request.headers.each do |field, value|
|
||||
buffer << "#{capitalized(field)}: #{value}" << CRLF
|
||||
buffer << "#{capitalized(field)}: #{value}" << CRLF
|
||||
log { "<- HEADER: #{buffer.chomp}" }
|
||||
@buffer << buffer
|
||||
buffer.clear
|
||||
@ -184,8 +184,8 @@ module HTTPX
|
||||
|
||||
UPCASED = {
|
||||
"www-authenticate" => "WWW-Authenticate",
|
||||
"http2-settings" => "HTTP2-Settings"
|
||||
}
|
||||
"http2-settings" => "HTTP2-Settings",
|
||||
}.freeze
|
||||
|
||||
def capitalized(field)
|
||||
UPCASED[field] || field.to_s.split("-").map(&:capitalize).join("-")
|
||||
@ -193,4 +193,3 @@ module HTTPX
|
||||
end
|
||||
Channel.register "http/1.1", Channel::HTTP1
|
||||
end
|
||||
|
||||
|
@ -39,7 +39,7 @@ module HTTPX
|
||||
end
|
||||
unless stream = @streams[request]
|
||||
stream = @connection.new_stream
|
||||
handle_stream(stream, request)
|
||||
handle_stream(stream, request)
|
||||
@streams[request] = stream
|
||||
end
|
||||
handle(request, stream)
|
||||
@ -66,9 +66,7 @@ module HTTPX
|
||||
request.path
|
||||
end
|
||||
|
||||
def set_request_headers(request)
|
||||
|
||||
end
|
||||
def set_request_headers(request); end
|
||||
|
||||
def handle(request, stream)
|
||||
catch(:buffer_full) do
|
||||
@ -107,7 +105,7 @@ module HTTPX
|
||||
headers[":scheme"] = request.scheme
|
||||
headers[":method"] = request.verb.to_s.upcase
|
||||
headers[":path"] = headline_uri(request)
|
||||
headers[":authority"] = request.authority
|
||||
headers[":authority"] = request.authority
|
||||
headers = headers.merge(request.headers)
|
||||
log(1, "#{stream.id}: ") do
|
||||
headers.map { |k, v| "-> HEADER: #{k}: #{v}" }.join("\n")
|
||||
@ -142,7 +140,7 @@ module HTTPX
|
||||
headers = @options.headers_class.new(h)
|
||||
response = @options.response_class.new(request, status, "2.0", headers, @options)
|
||||
request.response = response
|
||||
@streams[request] = stream
|
||||
@streams[request] = stream
|
||||
end
|
||||
|
||||
def on_stream_data(stream, request, data)
|
||||
@ -152,14 +150,11 @@ module HTTPX
|
||||
end
|
||||
|
||||
def on_stream_close(stream, request, error)
|
||||
if request.expects?
|
||||
return handle(request, stream)
|
||||
end
|
||||
return handle(request, stream) if request.expects?
|
||||
response = request.response || ErrorResponse.new(error, @retries)
|
||||
emit(:response, request, response)
|
||||
log(2, "#{stream.id}: ") { "closing stream" }
|
||||
|
||||
|
||||
@streams.delete(request)
|
||||
send(@pending.shift) unless @pending.empty?
|
||||
end
|
||||
@ -175,7 +170,7 @@ module HTTPX
|
||||
def on_close(*)
|
||||
return unless @connection.state == :closed && @connection.active_stream_count.zero?
|
||||
log { "connection closed" }
|
||||
emit(:close)
|
||||
emit(:close)
|
||||
end
|
||||
|
||||
def on_frame_sent(frame)
|
||||
|
@ -6,13 +6,13 @@ module HTTPX
|
||||
include Chainable
|
||||
|
||||
def initialize(options = {})
|
||||
@options = self.class.default_options.merge(options)
|
||||
@options = self.class.default_options.merge(options)
|
||||
@connection = Connection.new(@options)
|
||||
@responses = {}
|
||||
if block_given?
|
||||
begin
|
||||
@keep_open = true
|
||||
yield self
|
||||
yield self
|
||||
ensure
|
||||
@keep_open = false
|
||||
close
|
||||
@ -27,7 +27,7 @@ module HTTPX
|
||||
def request(*args, keep_open: @keep_open, **options)
|
||||
requests = __build_reqs(*args, **options)
|
||||
responses = __send_reqs(*requests)
|
||||
return responses.first if responses.size == 1
|
||||
return responses.first if responses.size == 1
|
||||
responses
|
||||
ensure
|
||||
close unless keep_open
|
||||
@ -48,10 +48,10 @@ module HTTPX
|
||||
def fetch_response(request)
|
||||
response = @responses.delete(request)
|
||||
if response.is_a?(ErrorResponse) && response.retryable?
|
||||
channel = find_channel(request)
|
||||
channel.send(request, retries: response.retries - 1)
|
||||
return
|
||||
end
|
||||
channel = find_channel(request)
|
||||
channel.send(request, retries: response.retries - 1)
|
||||
return
|
||||
end
|
||||
response
|
||||
end
|
||||
|
||||
@ -83,7 +83,7 @@ module HTTPX
|
||||
__build_req(verb, uri, options)
|
||||
end
|
||||
else
|
||||
[ __build_req(verb, uris, options) ]
|
||||
[__build_req(verb, uris, options)]
|
||||
end
|
||||
else
|
||||
raise ArgumentError, "unsupported number of arguments"
|
||||
@ -108,9 +108,7 @@ module HTTPX
|
||||
|
||||
break if requests.empty?
|
||||
rescue TimeoutError => e
|
||||
while requests.shift
|
||||
responses << ErrorResponse.new(e.message, 0)
|
||||
end
|
||||
responses << ErrorResponse.new(e.message, 0) while requests.shift
|
||||
break
|
||||
end
|
||||
end
|
||||
|
@ -34,7 +34,7 @@ module HTTPX
|
||||
while ch = @channels.shift
|
||||
ch.close(true)
|
||||
@selector.deregister(ch)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -49,7 +49,7 @@ module HTTPX
|
||||
# maximize pipelining by opening as few channels as possible.
|
||||
#
|
||||
def find_channel(uri)
|
||||
return @channels.find do |channel|
|
||||
@channels.find do |channel|
|
||||
channel.match?(uri)
|
||||
end
|
||||
end
|
||||
|
@ -139,7 +139,7 @@ module HTTPX
|
||||
def array_value(value)
|
||||
case value
|
||||
when Array
|
||||
value.map{ |val| String(val) }
|
||||
value.map { |val| String(val) }
|
||||
else
|
||||
[String(value)]
|
||||
end
|
||||
@ -150,4 +150,3 @@ module HTTPX
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -14,21 +14,21 @@ module HTTPX
|
||||
@state = :idle
|
||||
@options = Options.new(options)
|
||||
@fallback_protocol = @options.fallback_protocol
|
||||
@ip = TCPSocket.getaddress(hostname)
|
||||
@ip = TCPSocket.getaddress(hostname)
|
||||
@port = port
|
||||
if @options.io
|
||||
@io = case @options.io
|
||||
when Hash
|
||||
@options.io[@ip] || @options.io["#{@ip}:#{@port}"]
|
||||
else
|
||||
@options.io
|
||||
when Hash
|
||||
@options.io[@ip] || @options.io["#{@ip}:#{@port}"]
|
||||
else
|
||||
@options.io
|
||||
end
|
||||
unless @io.nil?
|
||||
@keep_open = true
|
||||
@keep_open = true
|
||||
@state = :connected
|
||||
end
|
||||
end
|
||||
@io ||= build_socket
|
||||
@io ||= build_socket
|
||||
end
|
||||
|
||||
def scheme
|
||||
@ -40,21 +40,20 @@ module HTTPX
|
||||
end
|
||||
|
||||
def protocol
|
||||
@fallback_protocol
|
||||
@fallback_protocol
|
||||
end
|
||||
|
||||
def connect
|
||||
return unless closed?
|
||||
begin
|
||||
if @io.closed?
|
||||
transition(:idle)
|
||||
transition(:idle)
|
||||
@io = build_socket
|
||||
end
|
||||
@io.connect_nonblock(Socket.sockaddr_in(@port, @ip))
|
||||
rescue Errno::EISCONN
|
||||
end
|
||||
transition(:connected)
|
||||
|
||||
rescue Errno::EINPROGRESS,
|
||||
Errno::EALREADY,
|
||||
::IO::WaitReadable
|
||||
@ -139,7 +138,7 @@ module HTTPX
|
||||
end
|
||||
|
||||
class SSL < TCP
|
||||
TLS_OPTIONS = OpenSSL::SSL::SSLContext.instance_methods.include?(:alpn_protocols) ?
|
||||
TLS_OPTIONS = OpenSSL::SSL::SSLContext.instance_methods.include?(:alpn_protocols) ?
|
||||
{ alpn_protocols: %w[h2 http/1.1] } : {}
|
||||
|
||||
def initialize(_, _, options)
|
||||
@ -155,7 +154,7 @@ module HTTPX
|
||||
|
||||
def protocol
|
||||
@io.alpn_protocol
|
||||
rescue
|
||||
rescue StandardError
|
||||
super
|
||||
end
|
||||
|
||||
@ -182,14 +181,13 @@ module HTTPX
|
||||
transition(:negotiated)
|
||||
end
|
||||
|
||||
|
||||
if RUBY_VERSION < "2.3"
|
||||
def read(*)
|
||||
super
|
||||
rescue ::IO::WaitWritable
|
||||
0
|
||||
end
|
||||
|
||||
|
||||
def write(*)
|
||||
super
|
||||
rescue ::IO::WaitReadable
|
||||
|
@ -1,9 +1,9 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Loggable
|
||||
def log(level=@options.debug_level, label="", &msg)
|
||||
def log(level = @options.debug_level, label = "", &msg)
|
||||
return unless @options.debug
|
||||
return unless @options.debug_level >= level
|
||||
return unless @options.debug_level >= level
|
||||
@options.debug << (+label << msg.call << "\n")
|
||||
end
|
||||
end
|
||||
|
@ -26,7 +26,7 @@ module HTTPX
|
||||
|
||||
def def_option(name, &interpreter)
|
||||
defined_options << name.to_sym
|
||||
interpreter ||= lambda { |v| v }
|
||||
interpreter ||= ->(v) { v }
|
||||
|
||||
attr_accessor name
|
||||
protected :"#{name}="
|
||||
@ -43,7 +43,7 @@ module HTTPX
|
||||
:debug_level => (ENV["HTTPX_DEBUG"] || 1).to_i,
|
||||
:ssl => {},
|
||||
:http2_settings => { settings_enable_push: 0 },
|
||||
:fallback_protocol => "http/1.1",
|
||||
:fallback_protocol => "http/1.1",
|
||||
:timeout => Timeout.new,
|
||||
:headers => {},
|
||||
:max_concurrent_requests => MAX_CONCURRENT_REQUESTS,
|
||||
@ -110,17 +110,17 @@ module HTTPX
|
||||
end
|
||||
|
||||
def to_hash
|
||||
hash_pairs = self.class.
|
||||
defined_options.
|
||||
flat_map { |opt_name| [opt_name, send(opt_name)] }
|
||||
hash_pairs = self.class
|
||||
.defined_options
|
||||
.flat_map { |opt_name| [opt_name, send(opt_name)] }
|
||||
Hash[*hash_pairs]
|
||||
end
|
||||
|
||||
def dup
|
||||
dupped = super
|
||||
dupped.headers = headers.dup
|
||||
dupped.ssl = ssl.dup
|
||||
dupped.request_class = request_class.dup
|
||||
dupped.headers = headers.dup
|
||||
dupped.ssl = ssl.dup
|
||||
dupped.request_class = request_class.dup
|
||||
dupped.response_class = response_class.dup
|
||||
dupped.headers_class = headers_class.dup
|
||||
dupped.request_body_class = request_body_class.dup
|
||||
|
@ -12,10 +12,9 @@ module HTTPX
|
||||
def basic_authentication(user, password)
|
||||
authentication("Basic #{Base64.strict_encode64("#{user}:#{password}")}")
|
||||
end
|
||||
alias :basic_auth :basic_authentication
|
||||
alias_method :basic_auth, :basic_authentication
|
||||
end
|
||||
end
|
||||
register_plugin :basic_authentication, BasicAuthentication
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -11,7 +11,7 @@ module HTTPX
|
||||
|
||||
module InstanceMethods
|
||||
def initialize(opts = {})
|
||||
super(opts.merge(headers: {"accept-encoding" => Compression.registry.keys}))
|
||||
super(opts.merge(headers: { "accept-encoding" => Compression.registry.keys }))
|
||||
end
|
||||
end
|
||||
|
||||
@ -58,14 +58,14 @@ module HTTPX
|
||||
buffer << decoder.finish if @_compressed_length <= 0
|
||||
end
|
||||
buffer
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
class Encoder
|
||||
def initialize(body, deflater)
|
||||
@body = body.respond_to?(:read) ? body : StringIO.new(body.to_s)
|
||||
@buffer = StringIO.new("".b, File::RDWR)
|
||||
@deflater = deflater
|
||||
@deflater = deflater
|
||||
end
|
||||
|
||||
def each(&blk)
|
||||
@ -106,11 +106,11 @@ module HTTPX
|
||||
extend Forwardable
|
||||
|
||||
def_delegator :@inflater, :finish
|
||||
|
||||
|
||||
def_delegator :@inflater, :close
|
||||
|
||||
def initialize(inflater)
|
||||
@inflater = inflater
|
||||
def initialize(inflater)
|
||||
@inflater = inflater
|
||||
end
|
||||
|
||||
def decode(chunk)
|
||||
|
@ -3,50 +3,49 @@
|
||||
module HTTPX
|
||||
module Plugins
|
||||
module Compression
|
||||
module Brotli
|
||||
|
||||
module Brotli
|
||||
def self.load_dependencies(klass, *)
|
||||
klass.plugin(:compression)
|
||||
require "brotli"
|
||||
end
|
||||
|
||||
def self.configure(*)
|
||||
Compression.register "br", self
|
||||
Compression.register "br", self
|
||||
end
|
||||
|
||||
module Encoder
|
||||
module_function
|
||||
|
||||
def deflate(raw, buffer, chunk_size: )
|
||||
begin
|
||||
while chunk = raw.read(chunk_size)
|
||||
compressed = ::Brotli.deflate(chunk)
|
||||
buffer << compressed
|
||||
yield compressed if block_given?
|
||||
end
|
||||
def deflate(raw, buffer, chunk_size:)
|
||||
while chunk = raw.read(chunk_size)
|
||||
compressed = ::Brotli.deflate(chunk)
|
||||
buffer << compressed
|
||||
yield compressed if block_given?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module BrotliWrapper
|
||||
module_function
|
||||
|
||||
def inflate(text)
|
||||
::Brotli.inflate(text)
|
||||
end
|
||||
def close
|
||||
end
|
||||
|
||||
def close; end
|
||||
|
||||
def finish
|
||||
""
|
||||
end
|
||||
end
|
||||
|
||||
module_function
|
||||
|
||||
|
||||
def encoder
|
||||
Encoder
|
||||
end
|
||||
|
||||
def decoder
|
||||
|
||||
def decoder
|
||||
Decoder.new(BrotliWrapper)
|
||||
end
|
||||
end
|
||||
|
@ -3,36 +3,34 @@
|
||||
module HTTPX
|
||||
module Plugins
|
||||
module Compression
|
||||
module Deflate
|
||||
module Deflate
|
||||
def self.load_dependencies(*)
|
||||
require "stringio"
|
||||
require "zlib"
|
||||
end
|
||||
|
||||
def self.configure(*)
|
||||
Compression.register "deflate", self
|
||||
Compression.register "deflate", self
|
||||
end
|
||||
|
||||
module Encoder
|
||||
module_function
|
||||
|
||||
def deflate(raw, buffer, chunk_size: )
|
||||
begin
|
||||
deflater = Zlib::Deflate.new(Zlib::BEST_COMPRESSION,
|
||||
Zlib::MAX_WBITS,
|
||||
Zlib::MAX_MEM_LEVEL,
|
||||
Zlib::HUFFMAN_ONLY)
|
||||
while chunk = raw.read(chunk_size)
|
||||
compressed = deflater.deflate(chunk)
|
||||
buffer << compressed
|
||||
yield compressed if block_given?
|
||||
end
|
||||
last = deflater.finish
|
||||
buffer << last
|
||||
yield last if block_given?
|
||||
ensure
|
||||
deflater.close
|
||||
def deflate(raw, buffer, chunk_size:)
|
||||
deflater = Zlib::Deflate.new(Zlib::BEST_COMPRESSION,
|
||||
Zlib::MAX_WBITS,
|
||||
Zlib::MAX_MEM_LEVEL,
|
||||
Zlib::HUFFMAN_ONLY)
|
||||
while chunk = raw.read(chunk_size)
|
||||
compressed = deflater.deflate(chunk)
|
||||
buffer << compressed
|
||||
yield compressed if block_given?
|
||||
end
|
||||
last = deflater.finish
|
||||
buffer << last
|
||||
yield last if block_given?
|
||||
ensure
|
||||
deflater.close
|
||||
end
|
||||
end
|
||||
|
||||
@ -50,4 +48,3 @@ module HTTPX
|
||||
register_plugin :"compression/deflate", Compression::Deflate
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -11,32 +11,30 @@ module HTTPX
|
||||
end
|
||||
|
||||
def self.configure(*)
|
||||
Compression.register "gzip", self
|
||||
Compression.register "gzip", self
|
||||
end
|
||||
|
||||
class Encoder
|
||||
def deflate(raw, buffer, chunk_size: )
|
||||
begin
|
||||
gzip = Zlib::GzipWriter.new(self)
|
||||
def deflate(raw, buffer, chunk_size:)
|
||||
gzip = Zlib::GzipWriter.new(self)
|
||||
|
||||
while chunk = raw.read(chunk_size)
|
||||
gzip.write(chunk)
|
||||
gzip.flush
|
||||
compressed = compressed_chunk
|
||||
buffer << compressed
|
||||
yield compressed if block_given?
|
||||
end
|
||||
ensure
|
||||
gzip.close
|
||||
while chunk = raw.read(chunk_size)
|
||||
gzip.write(chunk)
|
||||
gzip.flush
|
||||
compressed = compressed_chunk
|
||||
buffer << compressed
|
||||
yield compressed if block_given?
|
||||
end
|
||||
ensure
|
||||
gzip.close
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
def write(chunk)
|
||||
@compressed_chunk = chunk
|
||||
end
|
||||
|
||||
|
||||
def compressed_chunk
|
||||
compressed = @compressed_chunk
|
||||
compressed
|
||||
@ -45,18 +43,17 @@ module HTTPX
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
module_function
|
||||
|
||||
|
||||
def encoder
|
||||
Encoder.new
|
||||
end
|
||||
|
||||
|
||||
def decoder
|
||||
Decoder.new(Zlib::Inflate.new(32 + Zlib::MAX_WBITS))
|
||||
end
|
||||
end
|
||||
end
|
||||
register_plugin :"compression/gzip", Compression::GZIP
|
||||
register_plugin :"compression/gzip", Compression::GZIP
|
||||
end
|
||||
end
|
||||
|
@ -45,7 +45,7 @@ module HTTPX
|
||||
jar
|
||||
end
|
||||
end
|
||||
alias :cookies :cookie_jar
|
||||
alias_method :cookies, :cookie_jar
|
||||
end
|
||||
|
||||
module OptionsMethods
|
||||
@ -56,8 +56,8 @@ module HTTPX
|
||||
cookies
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
register_plugin :cookies, Cookies
|
||||
register_plugin :cookies, Cookies
|
||||
end
|
||||
end
|
||||
|
@ -15,7 +15,7 @@ module HTTPX
|
||||
@_digest = Digest.new(user, password)
|
||||
self
|
||||
end
|
||||
alias :digest_auth :digest_authentication
|
||||
alias_method :digest_auth, :digest_authentication
|
||||
|
||||
def request(*args, keep_open: @keep_open, **options)
|
||||
return super unless @_digest
|
||||
@ -32,13 +32,13 @@ module HTTPX
|
||||
responses = []
|
||||
|
||||
requests.each do |request|
|
||||
token = @_digest.generate_header(request, prev_response)
|
||||
token = @_digest.generate_header(request, prev_response)
|
||||
request.headers["authorization"] = "Digest #{token}"
|
||||
response = __send_reqs(*request).first
|
||||
responses << response
|
||||
prev_response = response
|
||||
end
|
||||
return responses.first if responses.size == 1
|
||||
return responses.first if responses.size == 1
|
||||
responses
|
||||
ensure
|
||||
close unless keep_open
|
||||
@ -53,7 +53,7 @@ module HTTPX
|
||||
@nonce = 0
|
||||
end
|
||||
|
||||
def generate_header(request, response, iis = false)
|
||||
def generate_header(request, response, _iis = false)
|
||||
method = request.verb.to_s.upcase
|
||||
www = response.headers["www-authenticate"]
|
||||
|
||||
@ -62,40 +62,39 @@ module HTTPX
|
||||
|
||||
uri = request.path
|
||||
|
||||
params = Hash[ auth_info.scan(/(\w+)="(.*?)"/) ]
|
||||
params = Hash[auth_info.scan(/(\w+)="(.*?)"/)]
|
||||
|
||||
nonce = params["nonce"]
|
||||
nc = next_nonce
|
||||
|
||||
|
||||
# verify qop
|
||||
qop = params["qop"]
|
||||
|
||||
if params["algorithm"] =~ /(.*?)(-sess)?$/
|
||||
algorithm = case $1
|
||||
when "MD5" then ::Digest::MD5
|
||||
when "SHA1" then ::Digest::SHA1
|
||||
when "SHA2" then ::Digest::SHA2
|
||||
when "SHA256" then ::Digest::SHA256
|
||||
when "SHA384" then ::Digest::SHA384
|
||||
when "SHA512" then ::Digest::SHA512
|
||||
when "RMD160" then ::Digest::RMD160
|
||||
else raise DigestError, "unknown algorithm \"#{$1}\""
|
||||
algorithm = case Regexp.last_match(1)
|
||||
when "MD5" then ::Digest::MD5
|
||||
when "SHA1" then ::Digest::SHA1
|
||||
when "SHA2" then ::Digest::SHA2
|
||||
when "SHA256" then ::Digest::SHA256
|
||||
when "SHA384" then ::Digest::SHA384
|
||||
when "SHA512" then ::Digest::SHA512
|
||||
when "RMD160" then ::Digest::RMD160
|
||||
else raise DigestError, "unknown algorithm \"#{Regexp.last_match(1)}\""
|
||||
end
|
||||
sess = $2
|
||||
sess = Regexp.last_match(2)
|
||||
else
|
||||
algorithm = ::Digest::MD5
|
||||
end
|
||||
|
||||
if qop or sess
|
||||
cnonce = make_cnonce
|
||||
nc = "%08x" % nc
|
||||
|
||||
if qop || sess
|
||||
cnonce = make_cnonce
|
||||
nc = format("%08x", nc)
|
||||
end
|
||||
|
||||
a1 = if sess then
|
||||
[ algorithm.hexdigest("#{@user}:#{params["realm"]}:#{@password}"),
|
||||
nonce,
|
||||
cnonce,
|
||||
].join ":"
|
||||
a1 = if sess
|
||||
[algorithm.hexdigest("#{@user}:#{params["realm"]}:#{@password}"),
|
||||
nonce,
|
||||
cnonce].join ":"
|
||||
else
|
||||
"#{@user}:#{params["realm"]}:#{@password}"
|
||||
end
|
||||
@ -108,17 +107,17 @@ module HTTPX
|
||||
request_digest = request_digest.join(":")
|
||||
|
||||
header = [
|
||||
%[username="#{@user}"],
|
||||
%[nonce="#{nonce}"],
|
||||
%[uri="#{uri}"],
|
||||
%[response="#{algorithm.hexdigest(request_digest)}"]
|
||||
%(username="#{@user}"),
|
||||
%(nonce="#{nonce}"),
|
||||
%(uri="#{uri}"),
|
||||
%(response="#{algorithm.hexdigest(request_digest)}"),
|
||||
]
|
||||
header << %[realm="#{params["realm"]}"] if params.key?("realm")
|
||||
header << %[algorithm=#{params["algorithm"]}"] if params.key?("algorithm")
|
||||
header << %[opaque="#{params["opaque"]}"] if params.key?("opaque")
|
||||
header << %[cnonce="#{cnonce}"] if cnonce
|
||||
header << %[nc=#{nc}]
|
||||
header << %[qop=#{qop}] if qop
|
||||
header << %(realm="#{params["realm"]}") if params.key?("realm")
|
||||
header << %(algorithm=#{params["algorithm"]}") if params.key?("algorithm")
|
||||
header << %(opaque="#{params["opaque"]}") if params.key?("opaque")
|
||||
header << %(cnonce="#{cnonce}") if cnonce
|
||||
header << %(nc=#{nc})
|
||||
header << %(qop=#{qop}) if qop
|
||||
header.join ", "
|
||||
end
|
||||
|
||||
@ -131,7 +130,7 @@ module HTTPX
|
||||
SecureRandom.random_number(2**32),
|
||||
].join ":"
|
||||
end
|
||||
|
||||
|
||||
def next_nonce
|
||||
@nonce += 1
|
||||
end
|
||||
@ -140,4 +139,3 @@ module HTTPX
|
||||
register_plugin :digest_authentication, DigestAuthentication
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -4,7 +4,6 @@ module HTTPX
|
||||
module Plugins
|
||||
module FollowRedirects
|
||||
module InstanceMethods
|
||||
|
||||
MAX_REDIRECTS = 3
|
||||
REDIRECT_STATUS = 300..399
|
||||
|
||||
@ -13,40 +12,38 @@ module HTTPX
|
||||
end
|
||||
|
||||
def request(*args, **options)
|
||||
begin
|
||||
# do not needlessly close channels
|
||||
keep_open = @keep_open
|
||||
@keep_open = true
|
||||
|
||||
max_redirects = @options.max_redirects || MAX_REDIRECTS
|
||||
requests = __build_reqs(*args, **options)
|
||||
responses = __send_reqs(*requests)
|
||||
# do not needlessly close channels
|
||||
keep_open = @keep_open
|
||||
@keep_open = true
|
||||
|
||||
loop do
|
||||
redirect_requests = []
|
||||
indexes = responses.each_with_index.map do |response, index|
|
||||
next unless REDIRECT_STATUS.include?(response.status)
|
||||
request = requests[index]
|
||||
retry_request = __build_redirect_req(request, response, options)
|
||||
redirect_requests << retry_request
|
||||
index
|
||||
end.compact
|
||||
break if redirect_requests.empty?
|
||||
break if max_redirects <= 0
|
||||
max_redirects -= 1
|
||||
max_redirects = @options.max_redirects || MAX_REDIRECTS
|
||||
requests = __build_reqs(*args, **options)
|
||||
responses = __send_reqs(*requests)
|
||||
|
||||
redirect_responses = __send_reqs(*redirect_requests)
|
||||
indexes.each_with_index do |index, i2|
|
||||
requests[index] = redirect_requests[i2]
|
||||
responses[index] = redirect_responses[i2]
|
||||
end
|
||||
loop do
|
||||
redirect_requests = []
|
||||
indexes = responses.each_with_index.map do |response, index|
|
||||
next unless REDIRECT_STATUS.include?(response.status)
|
||||
request = requests[index]
|
||||
retry_request = __build_redirect_req(request, response, options)
|
||||
redirect_requests << retry_request
|
||||
index
|
||||
end.compact
|
||||
break if redirect_requests.empty?
|
||||
break if max_redirects <= 0
|
||||
max_redirects -= 1
|
||||
|
||||
redirect_responses = __send_reqs(*redirect_requests)
|
||||
indexes.each_with_index do |index, i2|
|
||||
requests[index] = redirect_requests[i2]
|
||||
responses[index] = redirect_responses[i2]
|
||||
end
|
||||
|
||||
return responses.first if responses.size == 1
|
||||
responses
|
||||
ensure
|
||||
@keep_open = keep_open
|
||||
end
|
||||
|
||||
return responses.first if responses.size == 1
|
||||
responses
|
||||
ensure
|
||||
@keep_open = keep_open
|
||||
end
|
||||
|
||||
private
|
||||
@ -68,9 +65,8 @@ module HTTPX
|
||||
super
|
||||
klass.def_option(:max_redirects)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
register_plugin :follow_redirects, FollowRedirects
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -21,23 +21,23 @@ module HTTPX
|
||||
upgrade_request.headers["http2-settings"] = HTTP2::Client.settings_header(@options.http2_settings)
|
||||
# TODO: validate!
|
||||
upgrade_response = __send_reqs(*upgrade_request).first
|
||||
|
||||
|
||||
if upgrade_response.status == 101
|
||||
channel = find_channel(upgrade_request)
|
||||
parser = channel.upgrade_parser("h2")
|
||||
parser.extend(UpgradeExtensions)
|
||||
parser.upgrade(upgrade_request, upgrade_response, **options)
|
||||
data = upgrade_response.to_s
|
||||
parser << data
|
||||
parser << data
|
||||
responses = __send_reqs(*requests)
|
||||
else
|
||||
# proceed as usual
|
||||
responses = [upgrade_response] + __send_reqs(*requests[1..-1])
|
||||
end
|
||||
return responses.first if responses.size == 1
|
||||
responses
|
||||
responses
|
||||
ensure
|
||||
@_h2c_probed = true
|
||||
@_h2c_probed = true
|
||||
close unless keep_open
|
||||
end
|
||||
end
|
||||
@ -54,7 +54,7 @@ module HTTPX
|
||||
end
|
||||
|
||||
module UpgradeExtensions
|
||||
def upgrade(request, response, retries: @retries, **)
|
||||
def upgrade(request, _response, retries: @retries, **)
|
||||
@connection.send_connection_preface
|
||||
# skip checks, it is assumed that this is the first
|
||||
# request in the connection
|
||||
@ -66,8 +66,9 @@ module HTTPX
|
||||
|
||||
module FrameBuilder
|
||||
include HTTP2
|
||||
|
||||
module_function
|
||||
|
||||
|
||||
def settings_value(settings)
|
||||
frame = Framer.new.generate(type: :settings, stream: 0, payload: settings)
|
||||
Base64.urlsafe_encode64(frame[9..-1])
|
||||
|
@ -11,18 +11,18 @@ module HTTPX
|
||||
|
||||
attr_reader :uri, :username, :password
|
||||
|
||||
def initialize(uri: , username: nil, password: nil)
|
||||
def initialize(uri:, username: nil, password: nil)
|
||||
@uri = uri.is_a?(URI::Generic) ? uri : URI(uri)
|
||||
@username = username || @uri.user
|
||||
@password = password || @uri.password
|
||||
end
|
||||
|
||||
def authenticated?
|
||||
@username && @password
|
||||
@username && @password
|
||||
end
|
||||
|
||||
def token_authentication
|
||||
Base64.strict_encode64("#{user}:#{password}")
|
||||
Base64.strict_encode64("#{user}:#{password}")
|
||||
end
|
||||
end
|
||||
|
||||
@ -32,7 +32,7 @@ module HTTPX
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
|
||||
def proxy_params(uri)
|
||||
return @options.proxy if @options.proxy
|
||||
uri = URI(uri).find_proxy
|
||||
@ -43,9 +43,9 @@ module HTTPX
|
||||
def find_channel(request)
|
||||
uri = URI(request.uri)
|
||||
proxy = proxy_params(uri)
|
||||
return super unless proxy
|
||||
return super unless proxy
|
||||
@connection.find_channel(proxy) || begin
|
||||
channel = build_proxy_channel(proxy)
|
||||
channel = build_proxy_channel(proxy)
|
||||
set_channel_callbacks(channel)
|
||||
channel
|
||||
end
|
||||
@ -71,7 +71,7 @@ module HTTPX
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def self.configure(klass, *)
|
||||
klass.plugin(:"proxy/http")
|
||||
klass.plugin(:"proxy/socks4")
|
||||
@ -105,4 +105,4 @@ module HTTPX
|
||||
@state = :connected
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -7,10 +7,9 @@ module HTTPX
|
||||
module Proxy
|
||||
module HTTP
|
||||
class HTTPProxyChannel < ProxyChannel
|
||||
|
||||
private
|
||||
|
||||
def proxy_connect
|
||||
def proxy_connect
|
||||
req, _ = @pending.first
|
||||
# if the first request after CONNECT is to an https address, it is assumed that
|
||||
# all requests in the queue are not only ALL HTTPS, but they also share the certificate,
|
||||
@ -52,7 +51,7 @@ module HTTPX
|
||||
super
|
||||
end
|
||||
|
||||
def on_connect(request, response)
|
||||
def on_connect(_request, response)
|
||||
if response.status == 200
|
||||
req, _ = @pending.first
|
||||
request_uri = req.uri
|
||||
@ -70,16 +69,16 @@ module HTTPX
|
||||
|
||||
class ProxyParser < Channel::HTTP1
|
||||
def headline_uri(request)
|
||||
"#{request.uri.to_s}"
|
||||
request.uri.to_s
|
||||
end
|
||||
|
||||
|
||||
def set_request_headers(request)
|
||||
super
|
||||
request.headers["proxy-connection"] = request.headers["connection"]
|
||||
request.headers.delete("connection")
|
||||
request.headers.delete("connection")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
class ConnectProxyParser < ProxyParser
|
||||
attr_reader :pending
|
||||
|
||||
@ -92,7 +91,6 @@ module HTTPX
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
class ConnectRequest < Request
|
||||
def initialize(uri, options = {})
|
||||
super(:connect, uri, options)
|
||||
@ -105,7 +103,7 @@ module HTTPX
|
||||
end
|
||||
|
||||
Parameters.register("http", HTTPProxyChannel)
|
||||
end
|
||||
end
|
||||
end
|
||||
register_plugin :"proxy/http", Proxy::HTTP
|
||||
end
|
||||
|
@ -16,23 +16,21 @@ module HTTPX
|
||||
class Socks4ProxyChannel < ProxyChannel
|
||||
private
|
||||
|
||||
def proxy_connect
|
||||
def proxy_connect
|
||||
@parser = SocksParser.new(@write_buffer, @options)
|
||||
@parser.once(:packet, &method(:on_packet))
|
||||
end
|
||||
|
||||
|
||||
def on_packet(packet)
|
||||
version, status, port, ip = packet.unpack("CCnN")
|
||||
if status == GRANTED
|
||||
req, _ = @pending.first
|
||||
request_uri = req.uri
|
||||
if request_uri.scheme == "https"
|
||||
@io = ProxySSL.new(@io, request_uri, @options)
|
||||
end
|
||||
@io = ProxySSL.new(@io, request_uri, @options) if request_uri.scheme == "https"
|
||||
transition(:open)
|
||||
throw(:called)
|
||||
else
|
||||
response = ErrorResponse.new("socks error: #{status}", 0)
|
||||
response = ErrorResponse.new("socks error: #{status}", 0)
|
||||
until @pending.empty?
|
||||
req, _ = @pending.shift
|
||||
emit(:response, req, response)
|
||||
@ -54,7 +52,7 @@ module HTTPX
|
||||
return unless @state == :connecting
|
||||
@parser = nil
|
||||
end
|
||||
log(1, "SOCKS4: ") { "#{nextstate.to_s}: #{@write_buffer.to_s.inspect}" }
|
||||
log(1, "SOCKS4: ") { "#{nextstate}: #{@write_buffer.to_s.inspect}" }
|
||||
super
|
||||
end
|
||||
end
|
||||
@ -69,11 +67,9 @@ module HTTPX
|
||||
@options = Options.new(options)
|
||||
end
|
||||
|
||||
def close
|
||||
end
|
||||
def close; end
|
||||
|
||||
def consume(*)
|
||||
end
|
||||
def consume(*); end
|
||||
|
||||
def empty?
|
||||
true
|
||||
@ -87,11 +83,11 @@ module HTTPX
|
||||
module Packet
|
||||
module_function
|
||||
|
||||
def connect(parameters, uri)
|
||||
def connect(parameters, uri)
|
||||
packet = [VERSION, CONNECT, uri.port].pack("CCn")
|
||||
begin
|
||||
ip = IPAddr.new(uri.host)
|
||||
raise Error, "Socks4 connection to #{ip.to_s} not supported" unless ip.ipv4?
|
||||
raise Error, "Socks4 connection to #{ip} not supported" unless ip.ipv4?
|
||||
packet << [ip.to_i].pack("N")
|
||||
rescue IPAddr::InvalidAddressError
|
||||
if parameters.uri.scheme == "socks4"
|
||||
@ -111,4 +107,3 @@ module HTTPX
|
||||
register_plugin :"proxy/socks4", Proxy::Socks4
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -14,18 +14,17 @@ module HTTPX
|
||||
IPV6 = 4
|
||||
SUCCESS = 0
|
||||
|
||||
Error = Class.new(Error)
|
||||
Error = Class.new(Error)
|
||||
|
||||
class Socks5ProxyChannel < ProxyChannel
|
||||
|
||||
private
|
||||
|
||||
def proxy_connect
|
||||
def proxy_connect
|
||||
@parser = SocksParser.new(@write_buffer, @options)
|
||||
@parser.on(:packet, &method(:on_packet))
|
||||
transition(:negotiating)
|
||||
end
|
||||
|
||||
|
||||
def on_packet(packet)
|
||||
case @state
|
||||
when :connecting
|
||||
@ -51,9 +50,7 @@ module HTTPX
|
||||
return on_error_response("socks5 negotiation error: #{reply}") unless reply == SUCCESS
|
||||
req, _ = @pending.first
|
||||
request_uri = req.uri
|
||||
if request_uri.scheme == "https"
|
||||
@io = ProxySSL.new(@io, request_uri, @options)
|
||||
end
|
||||
@io = ProxySSL.new(@io, request_uri, @options) if request_uri.scheme == "https"
|
||||
transition(:open)
|
||||
throw(:called)
|
||||
end
|
||||
@ -79,7 +76,7 @@ module HTTPX
|
||||
return unless @state == :negotiating
|
||||
@parser = nil
|
||||
end
|
||||
log(1, "SOCKS5: ") { "#{nextstate.to_s}: #{@write_buffer.to_s.inspect}" }
|
||||
log(1, "SOCKS5: ") { "#{nextstate}: #{@write_buffer.to_s.inspect}" }
|
||||
super
|
||||
end
|
||||
|
||||
@ -88,7 +85,7 @@ module HTTPX
|
||||
end
|
||||
|
||||
def on_error_response(error)
|
||||
response = ErrorResponse.new(error, 0)
|
||||
response = ErrorResponse.new(error, 0)
|
||||
until @pending.empty?
|
||||
req, _ = @pending.shift
|
||||
emit(:response, req, response)
|
||||
@ -105,11 +102,9 @@ module HTTPX
|
||||
@options = Options.new(options)
|
||||
end
|
||||
|
||||
def close
|
||||
end
|
||||
def close; end
|
||||
|
||||
def consume(*)
|
||||
end
|
||||
def consume(*); end
|
||||
|
||||
def empty?
|
||||
true
|
||||
@ -130,18 +125,18 @@ module HTTPX
|
||||
methods.unshift(VERSION)
|
||||
methods.pack("C*")
|
||||
end
|
||||
|
||||
def authenticate(parameters)
|
||||
|
||||
def authenticate(parameters)
|
||||
user = parameters.username
|
||||
pass = parameters.password
|
||||
[0x01, user.bytesize, user, pass.bytesize, password].pack("CCA*CA*")
|
||||
end
|
||||
|
||||
|
||||
def connect(uri)
|
||||
packet = [VERSION, CONNECT, 0].pack("C*")
|
||||
begin
|
||||
ip = IPAddr.new(uri.host)
|
||||
raise Error, "Socks4 connection to #{ip.to_s} not supported" unless ip.ipv4?
|
||||
raise Error, "Socks4 connection to #{ip} not supported" unless ip.ipv4?
|
||||
packet << [IPV4, ip.to_i].pack("CN")
|
||||
rescue IPAddr::InvalidAddressError
|
||||
packet << [DOMAIN, uri.host.bytesize, uri.host].pack("CCA*")
|
||||
@ -155,5 +150,3 @@ module HTTPX
|
||||
register_plugin :"proxy/socks5", Proxy::Socks5
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
@ -4,7 +4,7 @@ module HTTPX
|
||||
module Plugins
|
||||
module PushPromise
|
||||
PUSH_OPTIONS = { http2_settings: { settings_enable_push: 1 },
|
||||
max_concurrent_requests: 1 }
|
||||
max_concurrent_requests: 1 }.freeze
|
||||
|
||||
module RequestMethods
|
||||
def headers=(h)
|
||||
@ -15,7 +15,7 @@ module HTTPX
|
||||
module InstanceMethods
|
||||
def initialize(opts = {})
|
||||
super(PUSH_OPTIONS.merge(opts))
|
||||
@promise_headers = {}
|
||||
@promise_headers = {}
|
||||
end
|
||||
|
||||
private
|
||||
@ -59,4 +59,4 @@ module HTTPX
|
||||
end
|
||||
register_plugin(:push_promise, PushPromise)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -86,4 +86,3 @@ module HTTPX
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -36,9 +36,9 @@ module HTTPX
|
||||
attr_accessor :response
|
||||
|
||||
def_delegator :@body, :<<
|
||||
|
||||
|
||||
def_delegator :@body, :empty?
|
||||
|
||||
|
||||
def_delegator :@body, :chunk!
|
||||
|
||||
def initialize(verb, uri, options = {})
|
||||
@ -50,8 +50,8 @@ module HTTPX
|
||||
|
||||
@headers = @options.headers_class.new(@options.headers)
|
||||
@headers["user-agent"] ||= USER_AGENT
|
||||
@headers["accept"] ||= "*/*"
|
||||
|
||||
@headers["accept"] ||= "*/*"
|
||||
|
||||
@body = @options.request_body_class.new(@headers, @options)
|
||||
@state = :idle
|
||||
end
|
||||
@ -106,12 +106,11 @@ module HTTPX
|
||||
|
||||
def initialize(headers, options)
|
||||
@headers = headers
|
||||
@body = case
|
||||
when options.body
|
||||
@body = if options.body
|
||||
Transcoder.registry("body").encode(options.body)
|
||||
when options.form
|
||||
elsif options.form
|
||||
Transcoder.registry("form").encode(options.form)
|
||||
when options.json
|
||||
elsif options.json
|
||||
Transcoder.registry("json").encode(options.json)
|
||||
end
|
||||
return if @body.nil?
|
||||
@ -151,14 +150,12 @@ module HTTPX
|
||||
|
||||
def stream(body)
|
||||
encoded = body
|
||||
if chunked?
|
||||
encoded = Transcoder.registry("chunker").encode(body)
|
||||
end
|
||||
encoded = Transcoder.registry("chunker").encode(body) if chunked?
|
||||
encoded
|
||||
end
|
||||
|
||||
def unbounded_body?
|
||||
chunked? || @body.bytesize == Float::INFINITY
|
||||
chunked? || @body.bytesize == Float::INFINITY
|
||||
end
|
||||
|
||||
def chunked?
|
||||
@ -204,7 +201,7 @@ module HTTPX
|
||||
|
||||
def expects?
|
||||
@headers["expect"] == "100-continue" &&
|
||||
@response && @response.status == 100
|
||||
@response && @response.status == 100
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -11,12 +11,12 @@ module HTTPX
|
||||
|
||||
attr_reader :status, :headers, :body, :version
|
||||
|
||||
def_delegator :@body, :to_s
|
||||
|
||||
def_delegator :@body, :to_s
|
||||
|
||||
def_delegator :@body, :read
|
||||
|
||||
|
||||
def_delegator :@body, :copy_to
|
||||
|
||||
|
||||
def_delegator :@body, :close
|
||||
|
||||
def_delegator :@request, :uri
|
||||
@ -29,7 +29,7 @@ module HTTPX
|
||||
@headers = @options.headers_class.new(headers)
|
||||
@body = @options.response_body_class.new(self, threshold_size: @options.body_threshold_size,
|
||||
window_size: @options.window_size)
|
||||
end
|
||||
end
|
||||
|
||||
def <<(data)
|
||||
@body.write(data)
|
||||
@ -37,11 +37,11 @@ module HTTPX
|
||||
|
||||
def bodyless?
|
||||
@request.verb == :head ||
|
||||
@status < 200 ||
|
||||
@status == 201 ||
|
||||
@status == 204 ||
|
||||
@status == 205 ||
|
||||
@status == 304
|
||||
@status < 200 ||
|
||||
@status == 201 ||
|
||||
@status == 204 ||
|
||||
@status == 205 ||
|
||||
@status == 304
|
||||
end
|
||||
|
||||
def content_type
|
||||
@ -53,17 +53,17 @@ module HTTPX
|
||||
end
|
||||
|
||||
class Body
|
||||
def initialize(response, threshold_size: , window_size: 1 << 14)
|
||||
def initialize(response, threshold_size:, window_size: 1 << 14)
|
||||
@response = response
|
||||
@headers = response.headers
|
||||
@threshold_size = threshold_size
|
||||
@window_size = window_size
|
||||
@window_size = window_size
|
||||
@encoding = response.content_type.charset || Encoding::BINARY
|
||||
@length = 0
|
||||
@buffer = nil
|
||||
@buffer = nil
|
||||
@state = :idle
|
||||
end
|
||||
|
||||
|
||||
def write(chunk)
|
||||
@length += chunk.bytesize
|
||||
transition
|
||||
@ -92,7 +92,7 @@ module HTTPX
|
||||
close
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def to_s
|
||||
rewind
|
||||
return @buffer.read if @buffer
|
||||
@ -100,14 +100,14 @@ module HTTPX
|
||||
ensure
|
||||
close
|
||||
end
|
||||
|
||||
|
||||
def empty?
|
||||
@length.zero?
|
||||
@length.zero?
|
||||
end
|
||||
|
||||
|
||||
def copy_to(dest)
|
||||
return unless @buffer
|
||||
if dest.respond_to?(:path) and @buffer.respond_to?(:path)
|
||||
if dest.respond_to?(:path) && @buffer.respond_to?(:path)
|
||||
FileUtils.mv(@buffer.path, dest.path)
|
||||
else
|
||||
@buffer.rewind
|
||||
@ -124,18 +124,18 @@ module HTTPX
|
||||
@length = 0
|
||||
@state = :idle
|
||||
end
|
||||
|
||||
|
||||
def ==(other)
|
||||
to_s == other.to_s
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
|
||||
def rewind
|
||||
return if @state == :idle
|
||||
@buffer.rewind
|
||||
end
|
||||
|
||||
|
||||
def transition
|
||||
case @state
|
||||
when :idle
|
||||
@ -160,7 +160,7 @@ module HTTPX
|
||||
@state = :buffer
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return unless %i[memory buffer].include?(@state)
|
||||
end
|
||||
end
|
||||
@ -200,10 +200,9 @@ module HTTPX
|
||||
end
|
||||
|
||||
class ErrorResponse
|
||||
|
||||
attr_reader :error, :retries
|
||||
|
||||
alias :status :error
|
||||
alias_method :status, :error
|
||||
|
||||
def initialize(error, retries)
|
||||
@error = error
|
||||
@ -214,5 +213,4 @@ module HTTPX
|
||||
@retries.positive?
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -1,7 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "thread"
|
||||
|
||||
class HTTPX::Selector
|
||||
#
|
||||
# I/O monitor
|
||||
@ -103,9 +101,7 @@ class HTTPX::Selector
|
||||
|
||||
readers, writers = IO.select(r, w, nil, interval)
|
||||
|
||||
if readers.nil? and writers.nil?
|
||||
raise HTTPX::TimeoutError, "timed out while waiting on select"
|
||||
end
|
||||
raise HTTPX::TimeoutError, "timed out while waiting on select" if readers.nil? && writers.nil?
|
||||
rescue IOError, SystemCallError
|
||||
@lock.synchronize do
|
||||
@readers.reject! { |io, _| io.closed? }
|
||||
|
@ -17,54 +17,52 @@ module HTTPX
|
||||
reset_counter
|
||||
end
|
||||
|
||||
def timeout
|
||||
@loop_timeout || @total_timeout
|
||||
ensure
|
||||
log_time
|
||||
end
|
||||
def timeout
|
||||
@loop_timeout || @total_timeout
|
||||
ensure
|
||||
log_time
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
def ==(other)
|
||||
if other.is_a?(Timeout)
|
||||
@loop_timeout == other.instance_variable_get(:@loop_timeout) &&
|
||||
@total_timeout == other.instance_variable_get(:@total_timeout)
|
||||
@total_timeout == other.instance_variable_get(:@total_timeout)
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def merge(other)
|
||||
case other
|
||||
when Hash
|
||||
timeout = Timeout.new(other)
|
||||
merge(timeout)
|
||||
when Timeout
|
||||
def merge(other)
|
||||
case other
|
||||
when Hash
|
||||
timeout = Timeout.new(other)
|
||||
merge(timeout)
|
||||
when Timeout
|
||||
loop_timeout = other.instance_variable_get(:@loop_timeout) || @loop_timeout
|
||||
total_timeout = other.instance_variable_get(:@total_timeout) || @total_timeout
|
||||
Timeout.new(loop_timeout: loop_timeout, total_timeout: total_timeout)
|
||||
else
|
||||
raise ArgumentError, "can't merge with #{other.class}"
|
||||
end
|
||||
end
|
||||
else
|
||||
raise ArgumentError, "can't merge with #{other.class}"
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
private
|
||||
|
||||
def reset_counter
|
||||
@time_left = @total_timeout
|
||||
end
|
||||
def reset_counter
|
||||
@time_left = @total_timeout
|
||||
end
|
||||
|
||||
def reset_timer
|
||||
@started = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
||||
end
|
||||
|
||||
def log_time
|
||||
return unless @time_left
|
||||
return reset_timer unless @started
|
||||
@time_left -= (Process.clock_gettime(Process::CLOCK_MONOTONIC) - @started)
|
||||
if @time_left <= 0
|
||||
raise TimeoutError, "Timed out after #{@total_timeout} seconds"
|
||||
end
|
||||
def reset_timer
|
||||
@started = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
||||
end
|
||||
|
||||
reset_timer
|
||||
end
|
||||
def log_time
|
||||
return unless @time_left
|
||||
return reset_timer unless @started
|
||||
@time_left -= (Process.clock_gettime(Process::CLOCK_MONOTONIC) - @started)
|
||||
raise TimeoutError, "Timed out after #{@total_timeout} seconds" if @time_left <= 0
|
||||
|
||||
reset_timer
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -52,5 +52,5 @@ module HTTPX::Transcoder
|
||||
Encoder.new(body)
|
||||
end
|
||||
end
|
||||
register "body", Body
|
||||
register "body", Body
|
||||
end
|
||||
|
@ -8,11 +8,11 @@ module HTTPX::Transcoder
|
||||
|
||||
class Encoder
|
||||
extend Forwardable
|
||||
|
||||
|
||||
CRLF = "\r\n"
|
||||
|
||||
def initialize(body)
|
||||
@raw = body
|
||||
@raw = body
|
||||
end
|
||||
|
||||
def each
|
||||
@ -32,6 +32,5 @@ module HTTPX::Transcoder
|
||||
Encoder.new(chunks)
|
||||
end
|
||||
end
|
||||
register "chunker", Chunker
|
||||
register "chunker", Chunker
|
||||
end
|
||||
|
||||
|
@ -11,9 +11,9 @@ module HTTPX::Transcoder
|
||||
extend Forwardable
|
||||
|
||||
def_delegator :@raw, :content_type
|
||||
|
||||
|
||||
def_delegator :@raw, :to_s
|
||||
|
||||
|
||||
def_delegator :@raw, :read
|
||||
|
||||
def initialize(form)
|
||||
@ -27,10 +27,10 @@ module HTTPX::Transcoder
|
||||
def force_encoding(*args)
|
||||
@raw.to_s.force_encoding(*args)
|
||||
end
|
||||
|
||||
|
||||
def to_str
|
||||
@raw.to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def encode(form)
|
||||
|
@ -9,13 +9,13 @@ module HTTPX::Transcoder
|
||||
|
||||
class Encoder
|
||||
extend Forwardable
|
||||
|
||||
|
||||
def_delegator :@raw, :to_str
|
||||
|
||||
|
||||
def_delegator :@raw, :to_s
|
||||
|
||||
|
||||
def_delegator :@raw, :bytesize
|
||||
|
||||
|
||||
def_delegator :@raw, :force_encoding
|
||||
|
||||
def initialize(json)
|
||||
@ -32,5 +32,5 @@ module HTTPX::Transcoder
|
||||
Encoder.new(json)
|
||||
end
|
||||
end
|
||||
register "json", JSON
|
||||
register "json", JSON
|
||||
end
|
||||
|
@ -16,16 +16,16 @@ class ClientTest < Minitest::Test
|
||||
def test_client_plugin
|
||||
klient_class = Class.new(Client)
|
||||
klient_class.plugin(TestPlugin)
|
||||
client = klient_class.new
|
||||
client = klient_class.new
|
||||
assert client.respond_to?(:foo), "instance methods weren't added"
|
||||
assert client.foo == "client-foo", "instance method is unexpected"
|
||||
assert client.respond_to?(:bar), "load and configure didn't work"
|
||||
assert client.bar == "config-load-bar", "load and configure didn't work"
|
||||
|
||||
|
||||
assert client.respond_to?(:options), "instance methods weren't added"
|
||||
assert client.options.respond_to?(:foo), "options methods weren't added"
|
||||
assert client.options.foo == "options-foo", "option method is unexpected"
|
||||
|
||||
|
||||
request = client.options.request_class.new(:get, "/", client.options)
|
||||
assert request.respond_to?(:foo), "request methods haven't been added"
|
||||
assert request.foo == "request-foo", "request method is unexpected"
|
||||
@ -34,17 +34,17 @@ class ClientTest < Minitest::Test
|
||||
assert client.respond_to?(:response), "response constructor was added"
|
||||
|
||||
req_body = request.body
|
||||
assert req_body.respond_to?(:foo), "request body methods haven't been added"
|
||||
assert req_body.respond_to?(:foo), "request body methods haven't been added"
|
||||
assert req_body.foo == "request-body-foo", "request body method is unexpected"
|
||||
|
||||
response = client.response(nil, 200, "2.0", {})
|
||||
assert response.respond_to?(:foo), "response methods haven't been added"
|
||||
assert response.respond_to?(:foo), "response methods haven't been added"
|
||||
assert response.foo == "response-foo", "response method is unexpected"
|
||||
assert request.headers.respond_to?(:foo), "headers methods haven't been added"
|
||||
assert request.headers.foo == "headers-foo", "headers method is unexpected"
|
||||
|
||||
body = response.body
|
||||
assert body.respond_to?(:foo), "response body methods haven't been added"
|
||||
assert body.respond_to?(:foo), "response body methods haven't been added"
|
||||
assert body.foo == "response-body-foo", "response body method is unexpected"
|
||||
end
|
||||
|
||||
@ -53,7 +53,7 @@ class ClientTest < Minitest::Test
|
||||
TestPlugin = Module.new do
|
||||
self::ClassMethods = Module.new do
|
||||
def foo
|
||||
"client-foo"
|
||||
"client-foo"
|
||||
end
|
||||
end
|
||||
self::InstanceMethods = Module.new do
|
||||
@ -61,9 +61,7 @@ class ClientTest < Minitest::Test
|
||||
self.class.foo
|
||||
end
|
||||
|
||||
def options
|
||||
@options
|
||||
end
|
||||
attr_reader :options
|
||||
|
||||
def response(*args)
|
||||
@options.response_class.new(*args, @options)
|
||||
@ -71,17 +69,17 @@ class ClientTest < Minitest::Test
|
||||
end
|
||||
self::OptionsClassMethods = Module.new do
|
||||
def foo
|
||||
"options-foo"
|
||||
"options-foo"
|
||||
end
|
||||
end
|
||||
self::OptionsMethods = Module.new do
|
||||
def foo
|
||||
self.class.foo
|
||||
self.class.foo
|
||||
end
|
||||
end
|
||||
self::RequestClassMethods = Module.new do
|
||||
def foo
|
||||
'request-foo'
|
||||
def foo
|
||||
"request-foo"
|
||||
end
|
||||
end
|
||||
self::RequestMethods = Module.new do
|
||||
@ -133,7 +131,7 @@ class ClientTest < Minitest::Test
|
||||
def self.load_dependencies(mod)
|
||||
mod.__send__(:include, Module.new do
|
||||
def bar
|
||||
"load-bar"
|
||||
"load-bar"
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
@ -31,8 +31,8 @@ class HeadersTest < Minitest::Test
|
||||
|
||||
def test_header_key?
|
||||
h1 = Headers.new("accept" => "text/html")
|
||||
assert h1.key?("accept"), "header field should exist"
|
||||
assert !h1.key?("content-encoding"), "header field should no exist"
|
||||
assert h1.key?("accept"), "header field should exist"
|
||||
assert !h1.key?("content-encoding"), "header field should no exist"
|
||||
end
|
||||
|
||||
def test_header_each
|
||||
|
@ -2,21 +2,21 @@
|
||||
|
||||
require_relative "support/http_test"
|
||||
|
||||
class HTTP1Test < HTTPTest
|
||||
class HTTP1Test < HTTPTest
|
||||
include Requests
|
||||
include Head
|
||||
include Get
|
||||
include ChunkedGet
|
||||
include WithBody
|
||||
include WithChunkedBody
|
||||
include Headers
|
||||
include ResponseBody
|
||||
include WithChunkedBody
|
||||
include Headers
|
||||
include ResponseBody
|
||||
include IO
|
||||
include Timeouts
|
||||
|
||||
include Plugins::Proxy
|
||||
include Plugins::Authentication
|
||||
include Plugins::FollowRedirects
|
||||
include Plugins::FollowRedirects
|
||||
include Plugins::Cookies
|
||||
include Plugins::Compression
|
||||
include Plugins::H2C
|
||||
|
@ -7,19 +7,17 @@ class HTTP2Test < HTTPTest
|
||||
include Get
|
||||
include Head
|
||||
include WithBody
|
||||
include Headers
|
||||
include ResponseBody
|
||||
include IO
|
||||
include Headers
|
||||
include ResponseBody
|
||||
include IO
|
||||
include Timeouts
|
||||
|
||||
|
||||
include Plugins::Proxy
|
||||
include Plugins::Authentication
|
||||
include Plugins::FollowRedirects
|
||||
include Plugins::Cookies
|
||||
include Plugins::Compression
|
||||
if OpenSSL::SSL::SSLContext.instance_methods.include?(:alpn_protocols)
|
||||
include Plugins::PushPromise
|
||||
end
|
||||
include Plugins::PushPromise if OpenSSL::SSL::SSLContext.instance_methods.include?(:alpn_protocols)
|
||||
|
||||
private
|
||||
|
||||
|
@ -18,19 +18,19 @@ class OptionsSpec < Minitest::Test
|
||||
define_method :"test_options_#{meth}" do
|
||||
opt1 = Options.new
|
||||
assert opt1.public_send(meth).nil?, "#{meth} shouldn't be set by default"
|
||||
opt2 = Options.new(meth => {"foo" => "bar"})
|
||||
assert opt2.public_send(meth) == {"foo" => "bar"}, "#{meth} was not set"
|
||||
opt3 = opt1.public_send(:"with_#{meth}", {"foo" => "bar"})
|
||||
assert opt3.public_send(meth) == {"foo" => "bar"}, "option was not set"
|
||||
opt2 = Options.new(meth => { "foo" => "bar" })
|
||||
assert opt2.public_send(meth) == { "foo" => "bar" }, "#{meth} was not set"
|
||||
opt3 = opt1.public_send(:"with_#{meth}", "foo" => "bar")
|
||||
assert opt3.public_send(meth) == { "foo" => "bar" }, "option was not set"
|
||||
end
|
||||
end
|
||||
|
||||
def test_options_headers
|
||||
opt1 = Options.new
|
||||
assert opt1.headers.to_a.empty?, "headers should be empty"
|
||||
opt2 = Options.new({:headers => {"accept" => "*/*"}})
|
||||
opt2 = Options.new(:headers => { "accept" => "*/*" })
|
||||
assert opt2.headers.to_a == [%w[accept */*]], "headers are unexpected"
|
||||
opt3 = opt1.with_headers({"accept" => "*/*"})
|
||||
opt3 = opt1.with_headers("accept" => "*/*")
|
||||
assert opt3.headers.to_a == [%w[accept */*]], "headers are unexpected"
|
||||
end
|
||||
|
||||
@ -43,14 +43,14 @@ class OptionsSpec < Minitest::Test
|
||||
assert opts.merge(opt2).body == "short", "options parameter hasn't been merged"
|
||||
|
||||
foo = Options.new(
|
||||
:form => {:foo => "foo"},
|
||||
:headers => {:accept => "json", :foo => "foo"},
|
||||
:form => { :foo => "foo" },
|
||||
:headers => { :accept => "json", :foo => "foo" },
|
||||
)
|
||||
|
||||
bar = Options.new(
|
||||
:form => {:bar => "bar"},
|
||||
:headers => {:accept => "xml", :bar => "bar"},
|
||||
:ssl => {:foo => "bar"},
|
||||
:form => { :bar => "bar" },
|
||||
:headers => { :accept => "xml", :bar => "bar" },
|
||||
:ssl => { :foo => "bar" },
|
||||
)
|
||||
|
||||
assert foo.merge(bar).to_hash == {
|
||||
@ -63,12 +63,12 @@ class OptionsSpec < Minitest::Test
|
||||
:follow => nil,
|
||||
:window_size => 16_384,
|
||||
:body_threshold_size => 114_688,
|
||||
:form => {:bar => "bar"},
|
||||
:form => { :bar => "bar" },
|
||||
:timeout => Timeout.new,
|
||||
:ssl => {:foo => "bar" },
|
||||
:ssl => { :foo => "bar" },
|
||||
:http2_settings => { :settings_enable_push => 0 },
|
||||
:fallback_protocol => "http/1.1",
|
||||
:headers => {"Foo" => "foo", "Accept" => "xml", "Bar" => "bar"},
|
||||
:headers => { "Foo" => "foo", "Accept" => "xml", "Bar" => "bar" },
|
||||
:max_concurrent_requests => 100,
|
||||
:max_retries => 3,
|
||||
:request_class => bar.request_class,
|
||||
|
@ -13,7 +13,7 @@ class RequestTest < Minitest::Test
|
||||
end
|
||||
|
||||
def test_request_headers
|
||||
assert resource.headers.is_a?(Headers), "headers should have been coerced"
|
||||
assert resource.headers.is_a?(Headers), "headers should have been coerced"
|
||||
end
|
||||
|
||||
def test_request_scheme
|
||||
@ -49,18 +49,19 @@ class RequestTest < Minitest::Test
|
||||
end
|
||||
|
||||
def test_request_body_form
|
||||
req = Request.new(:post, "/", form: {"foo" => "bar"})
|
||||
req = Request.new(:post, "/", form: { "foo" => "bar" })
|
||||
assert !req.body.empty?, "body should exist"
|
||||
assert req.headers["content-type"] == "application/x-www-form-urlencoded", "content type is wrong"
|
||||
assert req.headers["content-length"] == "7", "content length is wrong"
|
||||
end
|
||||
|
||||
def test_request_body_json
|
||||
req = Request.new(:post, "/", json: {"foo" => "bar"})
|
||||
req = Request.new(:post, "/", json: { "foo" => "bar" })
|
||||
assert !req.body.empty?, "body should exist"
|
||||
assert req.headers["content-type"] == "application/json; charset=utf-8", "content type is wrong"
|
||||
assert req.headers["content-length"] == "13", "content length is wrong"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def resource
|
||||
|
@ -13,7 +13,7 @@ class ResponseTest < Minitest::Test
|
||||
end
|
||||
|
||||
def test_response_headers
|
||||
assert resource.headers.is_a?(Headers), "headers should have been coerced"
|
||||
assert resource.headers.is_a?(Headers), "headers should have been coerced"
|
||||
end
|
||||
|
||||
def test_response_body_write
|
||||
@ -35,17 +35,16 @@ class ResponseTest < Minitest::Test
|
||||
body3 = Response::Body.new(Response.new(request("head"), 200, "2.0", {}), opts)
|
||||
assert body3.empty?, "body must be empty after initialization"
|
||||
assert body3 == "", "HEAD requets body must be empty"
|
||||
|
||||
end
|
||||
|
||||
def test_response_body_each
|
||||
opts = { threshold_size: 1024 }
|
||||
body1 = Response::Body.new(Response.new(request, 200, "2.0", {}), opts)
|
||||
body1.write("foo")
|
||||
assert body1.each.to_a == %w(foo), "must yield buffer"
|
||||
assert body1.each.to_a == %w[foo], "must yield buffer"
|
||||
body1.write("foo")
|
||||
body1.write("bar")
|
||||
assert body1.each.to_a == %w(foobar), "must yield buffers"
|
||||
assert body1.each.to_a == %w[foobar], "must yield buffers"
|
||||
end
|
||||
|
||||
def test_response_body_buffer
|
||||
@ -63,7 +62,7 @@ class ResponseTest < Minitest::Test
|
||||
|
||||
private
|
||||
|
||||
def request(verb=:get, uri="http://google.com")
|
||||
def request(verb = :get, uri = "http://google.com")
|
||||
Request.new(verb, uri)
|
||||
end
|
||||
|
||||
|
@ -7,7 +7,7 @@ module ResponseHelpers
|
||||
assert value == expect, "status assertion failed: #{value} (expected: #{expect})"
|
||||
end
|
||||
|
||||
%w(header param).each do |meth|
|
||||
%w[header param].each do |meth|
|
||||
class_eval <<-DEFINE, __FILE__, __LINE__ + 1
|
||||
def verify_#{meth}(#{meth}s, key, expect)
|
||||
assert #{meth}s.key?(key), "#{meth}s don't contain the given key (\#{key})"
|
||||
@ -25,9 +25,8 @@ module ResponseHelpers
|
||||
DEFINE
|
||||
end
|
||||
|
||||
def verify_body_length(response, expect=response.headers["content-length"].to_i)
|
||||
def verify_body_length(response, expect = response.headers["content-length"].to_i)
|
||||
len = response.body.to_s.bytesize
|
||||
assert len == expect, "length assertion failed: #{len} (expected: #{expect})"
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -7,7 +7,7 @@ class HTTPTest < Minitest::Spec
|
||||
|
||||
private
|
||||
|
||||
def build_uri(suffix="/")
|
||||
def build_uri(suffix = "/")
|
||||
"#{origin}#{suffix || "/"}"
|
||||
end
|
||||
|
||||
|
@ -42,7 +42,7 @@ module ProxyHelper
|
||||
proxies_list(parse_http_proxies)
|
||||
.map do |line|
|
||||
ip, port, _, _, _, _, https, _ = line.css("td").map(&:text)
|
||||
[ip, port, https == "yes" ]
|
||||
[ip, port, https == "yes"]
|
||||
end
|
||||
end
|
||||
|
||||
@ -50,7 +50,7 @@ module ProxyHelper
|
||||
proxies_list(parse_socks_proxies)
|
||||
.map do |line|
|
||||
ip, port, _, _, version, _, https, _ = line.css("td").map(&:text)
|
||||
[ip, port, version, https == "Yes" ]
|
||||
[ip, port, version, https == "Yes"]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
module ProxyRetry
|
||||
def run(*)
|
||||
return super unless self.name.include?("_proxy")
|
||||
return super unless name.include?("_proxy")
|
||||
result = nil
|
||||
3.times.each do |i|
|
||||
3.times.each do |_i|
|
||||
result = super
|
||||
break if result.passed?
|
||||
self.failures = []
|
||||
|
@ -9,4 +9,4 @@ module Requests
|
||||
verify_body_length(response)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,7 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Requests
|
||||
module Head
|
||||
module Head
|
||||
def test_http_head
|
||||
uri = build_uri("/")
|
||||
response = HTTPX.head(uri)
|
||||
|
@ -22,4 +22,3 @@ module Requests
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -33,4 +33,4 @@ module Requests
|
||||
raise "#{uri.scheme}: unsupported scheme"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -6,7 +6,7 @@ module Requests
|
||||
def test_plugin_basic_authentication
|
||||
no_auth_response = HTTPX.get(basic_auth_uri)
|
||||
verify_status(no_auth_response.status, 401)
|
||||
verify_header(no_auth_response.headers, "www-authenticate", "Basic realm=\"Fake Realm\"")
|
||||
verify_header(no_auth_response.headers, "www-authenticate", "Basic realm=\"Fake Realm\"")
|
||||
|
||||
client = HTTPX.plugin(:basic_authentication)
|
||||
response = client.basic_authentication(user, pass).get(basic_auth_uri)
|
||||
@ -34,7 +34,7 @@ module Requests
|
||||
build_uri("/basic-auth/#{user}/#{pass}")
|
||||
end
|
||||
|
||||
def digest_auth_uri(qop="auth")
|
||||
def digest_auth_uri(qop = "auth")
|
||||
build_uri("/digest-auth/#{qop}/#{user}/#{pass}")
|
||||
end
|
||||
|
||||
|
@ -78,7 +78,6 @@ module Requests
|
||||
compressed_data = body["data"]
|
||||
assert body["data"].bytesize < 8012, "body hasn't been compressed"
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -3,7 +3,6 @@
|
||||
module Requests
|
||||
module Plugins
|
||||
module Cookies
|
||||
|
||||
def test_plugin_cookies_get
|
||||
client = HTTPX.plugin(:cookies)
|
||||
assert client.respond_to?(:cookies), "client should be cookie-enabled"
|
||||
|
@ -8,8 +8,8 @@ module Requests
|
||||
def test_plugin_follow_redirects
|
||||
no_redirect_response = HTTPX.get(redirect_uri)
|
||||
verify_status(no_redirect_response.status, 302)
|
||||
verify_header(no_redirect_response.headers, "location", redirect_location)
|
||||
|
||||
verify_header(no_redirect_response.headers, "location", redirect_location)
|
||||
|
||||
client = HTTPX.plugin(:follow_redirects)
|
||||
redirect_response = client.get(redirect_uri)
|
||||
verify_status(redirect_response.status, 200)
|
||||
@ -23,17 +23,17 @@ module Requests
|
||||
|
||||
response = client.get(max_redirect_uri(3))
|
||||
verify_status(response.status, 200)
|
||||
|
||||
|
||||
response = client.get(max_redirect_uri(4))
|
||||
verify_status(response.status, 302)
|
||||
end
|
||||
|
||||
def test_plugin_follow_redirects_max_redirects
|
||||
client = HTTPX.plugin(:follow_redirects)
|
||||
|
||||
|
||||
response = client.max_redirects(1).get(max_redirect_uri(1))
|
||||
verify_status(response.status, 200)
|
||||
|
||||
|
||||
response = client.max_redirects(1).get(max_redirect_uri(2))
|
||||
verify_status(response.status, 302)
|
||||
end
|
||||
@ -54,4 +54,3 @@ module Requests
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -38,4 +38,4 @@ module Requests
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -29,11 +29,10 @@ module Requests
|
||||
def push_html_uri
|
||||
"#{push_origin}/"
|
||||
end
|
||||
|
||||
|
||||
def push_css_uri
|
||||
"#{push_origin}/stylesheets/screen.css"
|
||||
"#{push_origin}/stylesheets/screen.css"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -5,7 +5,7 @@ module Requests
|
||||
def test_http_copy_to_file
|
||||
file = Tempfile.new(%w[cat .jpeg])
|
||||
uri = build_uri("/image")
|
||||
response = HTTPX.get(uri, headers: {"accept" => "image/jpeg"})
|
||||
response = HTTPX.get(uri, headers: { "accept" => "image/jpeg" })
|
||||
verify_status(response.status, 200)
|
||||
verify_header(response.headers, "content-type", "image/jpeg")
|
||||
response.copy_to(file)
|
||||
@ -20,24 +20,24 @@ module Requests
|
||||
end
|
||||
|
||||
def test_http_copy_to_io
|
||||
io = StringIO.new
|
||||
io = StringIO.new
|
||||
uri = build_uri("/image")
|
||||
response = HTTPX.get(uri, headers: {"accept" => "image/jpeg"})
|
||||
response = HTTPX.get(uri, headers: { "accept" => "image/jpeg" })
|
||||
verify_status(response.status, 200)
|
||||
verify_header(response.headers, "content-type", "image/jpeg")
|
||||
response.copy_to(io)
|
||||
content_length = response.headers["content-length"].to_i
|
||||
assert io.size == content_length, "file should contain the content of response"
|
||||
ensure
|
||||
io.close if io
|
||||
io.close if io
|
||||
end
|
||||
|
||||
def test_http_buffer_to_custom
|
||||
uri = build_uri("/")
|
||||
custom_body = Class.new do
|
||||
custom_body = Class.new do
|
||||
attr_reader :file
|
||||
|
||||
def initialize(response, **)
|
||||
def initialize(_response, **)
|
||||
@file = Tempfile.new("httpx-test")
|
||||
end
|
||||
|
||||
@ -63,4 +63,4 @@ module Requests
|
||||
response.close if response
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,7 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Requests
|
||||
module Timeouts
|
||||
module Timeouts
|
||||
# def test_http_timeouts_loop_timeout
|
||||
# uri = build_uri("/delay/2")
|
||||
# client = HTTPX.timeout(loop_timeout: 1)
|
||||
|
@ -5,29 +5,29 @@ module Requests
|
||||
%w[post put patch delete].each do |meth|
|
||||
define_method :"test_#{meth}_query_params" do
|
||||
uri = build_uri("/#{meth}")
|
||||
response = HTTPX.send(meth, uri, params: {"q" => "this is a test"})
|
||||
response = HTTPX.send(meth, uri, params: { "q" => "this is a test" })
|
||||
verify_status(response.status, 200)
|
||||
body = json_body(response)
|
||||
verify_uploaded(body, "args", {"q" => "this is a test"})
|
||||
verify_uploaded(body, "url", build_uri("/#{meth}?q=this+is+a+test"))
|
||||
verify_uploaded(body, "args", "q" => "this is a test")
|
||||
verify_uploaded(body, "url", build_uri("/#{meth}?q=this+is+a+test"))
|
||||
end
|
||||
|
||||
define_method :"test_#{meth}_form_params" do
|
||||
uri = build_uri("/#{meth}")
|
||||
response = HTTPX.send(meth, uri, form: {"foo" => "bar"})
|
||||
response = HTTPX.send(meth, uri, form: { "foo" => "bar" })
|
||||
verify_status(response.status, 200)
|
||||
body = json_body(response)
|
||||
verify_header(body["headers"], "Content-Type", "application/x-www-form-urlencoded")
|
||||
verify_uploaded(body, "form", {"foo" => "bar"})
|
||||
verify_uploaded(body, "form", "foo" => "bar")
|
||||
end
|
||||
|
||||
define_method :"test_#{meth}_json_params" do
|
||||
uri = build_uri("/#{meth}")
|
||||
response = HTTPX.send(meth, uri, json: {"foo" => "bar"})
|
||||
response = HTTPX.send(meth, uri, json: { "foo" => "bar" })
|
||||
verify_status(response.status, 200)
|
||||
body = json_body(response)
|
||||
verify_header(body["headers"], "Content-Type", "application/json")
|
||||
verify_uploaded(body, "json", {"foo" => "bar"})
|
||||
verify_uploaded(body, "json", "foo" => "bar")
|
||||
end
|
||||
|
||||
define_method :"test_#{meth}_body_params" do
|
||||
@ -76,7 +76,7 @@ module Requests
|
||||
|
||||
define_method :"test_#{meth}_form_file_params" do
|
||||
uri = build_uri("/#{meth}")
|
||||
response = HTTPX.send(meth, uri, form: {image: HTTP::FormData::File.new(fixture_file_path)})
|
||||
response = HTTPX.send(meth, uri, form: { image: HTTP::FormData::File.new(fixture_file_path) })
|
||||
verify_status(response.status, 200)
|
||||
body = json_body(response)
|
||||
verify_header(body["headers"], "Content-Type", "multipart/form-data")
|
||||
@ -86,7 +86,7 @@ module Requests
|
||||
define_method :"test_#{meth}_expect_100_form_file_params" do
|
||||
uri = build_uri("/#{meth}")
|
||||
response = HTTPX.headers("expect" => "100-continue")
|
||||
.send(meth, uri, form: {image: HTTP::FormData::File.new(fixture_file_path)})
|
||||
.send(meth, uri, form: { image: HTTP::FormData::File.new(fixture_file_path) })
|
||||
verify_status(response.status, 200)
|
||||
body = json_body(response)
|
||||
verify_header(body["headers"], "Content-Type", "multipart/form-data")
|
||||
|
@ -11,7 +11,7 @@ module Requests
|
||||
# body = json_body(response)
|
||||
# verify_header(body["headers"], "Transfer-Encoding", "chunked")
|
||||
# assert body.key?("data")
|
||||
# assert body["data"] == "thisisachunkedresponse"
|
||||
# assert body["data"] == "thisisachunkedresponse"
|
||||
# end
|
||||
end
|
||||
end
|
||||
|
Loading…
x
Reference in New Issue
Block a user