httpx-patched 1.6.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE.txt +191 -0
- data/README.md +162 -0
- data/doc/release_notes/0_0_1.md +7 -0
- data/doc/release_notes/0_0_2.md +9 -0
- data/doc/release_notes/0_0_3.md +9 -0
- data/doc/release_notes/0_0_4.md +7 -0
- data/doc/release_notes/0_0_5.md +5 -0
- data/doc/release_notes/0_10_0.md +66 -0
- data/doc/release_notes/0_10_1.md +37 -0
- data/doc/release_notes/0_10_2.md +5 -0
- data/doc/release_notes/0_11_0.md +74 -0
- data/doc/release_notes/0_11_1.md +5 -0
- data/doc/release_notes/0_11_2.md +5 -0
- data/doc/release_notes/0_11_3.md +5 -0
- data/doc/release_notes/0_12_0.md +55 -0
- data/doc/release_notes/0_13_0.md +58 -0
- data/doc/release_notes/0_13_1.md +5 -0
- data/doc/release_notes/0_13_2.md +9 -0
- data/doc/release_notes/0_14_0.md +79 -0
- data/doc/release_notes/0_14_1.md +7 -0
- data/doc/release_notes/0_14_2.md +6 -0
- data/doc/release_notes/0_14_3.md +5 -0
- data/doc/release_notes/0_14_4.md +5 -0
- data/doc/release_notes/0_14_5.md +11 -0
- data/doc/release_notes/0_15_0.md +53 -0
- data/doc/release_notes/0_15_1.md +8 -0
- data/doc/release_notes/0_15_2.md +9 -0
- data/doc/release_notes/0_15_3.md +5 -0
- data/doc/release_notes/0_15_4.md +5 -0
- data/doc/release_notes/0_16_0.md +93 -0
- data/doc/release_notes/0_16_1.md +5 -0
- data/doc/release_notes/0_17_0.md +49 -0
- data/doc/release_notes/0_18_0.md +69 -0
- data/doc/release_notes/0_18_1.md +12 -0
- data/doc/release_notes/0_18_2.md +10 -0
- data/doc/release_notes/0_18_3.md +7 -0
- data/doc/release_notes/0_18_4.md +14 -0
- data/doc/release_notes/0_18_5.md +10 -0
- data/doc/release_notes/0_18_6.md +5 -0
- data/doc/release_notes/0_18_7.md +5 -0
- data/doc/release_notes/0_19_0.md +39 -0
- data/doc/release_notes/0_19_1.md +5 -0
- data/doc/release_notes/0_19_2.md +7 -0
- data/doc/release_notes/0_19_3.md +6 -0
- data/doc/release_notes/0_19_4.md +14 -0
- data/doc/release_notes/0_19_5.md +13 -0
- data/doc/release_notes/0_19_6.md +5 -0
- data/doc/release_notes/0_19_7.md +5 -0
- data/doc/release_notes/0_19_8.md +5 -0
- data/doc/release_notes/0_1_0.md +9 -0
- data/doc/release_notes/0_20_0.md +36 -0
- data/doc/release_notes/0_20_1.md +5 -0
- data/doc/release_notes/0_20_2.md +7 -0
- data/doc/release_notes/0_20_3.md +6 -0
- data/doc/release_notes/0_20_4.md +17 -0
- data/doc/release_notes/0_20_5.md +3 -0
- data/doc/release_notes/0_21_0.md +96 -0
- data/doc/release_notes/0_21_1.md +12 -0
- data/doc/release_notes/0_22_0.md +13 -0
- data/doc/release_notes/0_22_1.md +11 -0
- data/doc/release_notes/0_22_2.md +5 -0
- data/doc/release_notes/0_22_3.md +55 -0
- data/doc/release_notes/0_22_4.md +6 -0
- data/doc/release_notes/0_22_5.md +6 -0
- data/doc/release_notes/0_23_0.md +42 -0
- data/doc/release_notes/0_23_1.md +5 -0
- data/doc/release_notes/0_23_2.md +5 -0
- data/doc/release_notes/0_23_3.md +6 -0
- data/doc/release_notes/0_23_4.md +5 -0
- data/doc/release_notes/0_24_0.md +48 -0
- data/doc/release_notes/0_24_1.md +12 -0
- data/doc/release_notes/0_24_2.md +12 -0
- data/doc/release_notes/0_24_3.md +12 -0
- data/doc/release_notes/0_24_4.md +18 -0
- data/doc/release_notes/0_24_5.md +6 -0
- data/doc/release_notes/0_24_6.md +5 -0
- data/doc/release_notes/0_24_7.md +10 -0
- data/doc/release_notes/0_2_0.md +5 -0
- data/doc/release_notes/0_2_1.md +16 -0
- data/doc/release_notes/0_3_0.md +12 -0
- data/doc/release_notes/0_3_1.md +6 -0
- data/doc/release_notes/0_4_0.md +51 -0
- data/doc/release_notes/0_4_1.md +3 -0
- data/doc/release_notes/0_5_0.md +15 -0
- data/doc/release_notes/0_5_1.md +14 -0
- data/doc/release_notes/0_6_0.md +5 -0
- data/doc/release_notes/0_6_1.md +6 -0
- data/doc/release_notes/0_6_2.md +6 -0
- data/doc/release_notes/0_6_3.md +13 -0
- data/doc/release_notes/0_6_4.md +21 -0
- data/doc/release_notes/0_6_5.md +22 -0
- data/doc/release_notes/0_6_6.md +19 -0
- data/doc/release_notes/0_6_7.md +5 -0
- data/doc/release_notes/0_7_0.md +46 -0
- data/doc/release_notes/0_8_0.md +27 -0
- data/doc/release_notes/0_8_1.md +8 -0
- data/doc/release_notes/0_8_2.md +7 -0
- data/doc/release_notes/0_9_0.md +38 -0
- data/doc/release_notes/1_0_0.md +60 -0
- data/doc/release_notes/1_0_1.md +5 -0
- data/doc/release_notes/1_0_2.md +7 -0
- data/doc/release_notes/1_1_0.md +32 -0
- data/doc/release_notes/1_1_1.md +17 -0
- data/doc/release_notes/1_1_2.md +12 -0
- data/doc/release_notes/1_1_3.md +18 -0
- data/doc/release_notes/1_1_4.md +6 -0
- data/doc/release_notes/1_1_5.md +12 -0
- data/doc/release_notes/1_2_0.md +49 -0
- data/doc/release_notes/1_2_1.md +6 -0
- data/doc/release_notes/1_2_2.md +10 -0
- data/doc/release_notes/1_2_3.md +16 -0
- data/doc/release_notes/1_2_4.md +8 -0
- data/doc/release_notes/1_2_5.md +7 -0
- data/doc/release_notes/1_2_6.md +13 -0
- data/doc/release_notes/1_3_0.md +18 -0
- data/doc/release_notes/1_3_1.md +17 -0
- data/doc/release_notes/1_3_2.md +6 -0
- data/doc/release_notes/1_3_3.md +5 -0
- data/doc/release_notes/1_3_4.md +6 -0
- data/doc/release_notes/1_4_0.md +43 -0
- data/doc/release_notes/1_4_1.md +19 -0
- data/doc/release_notes/1_4_2.md +20 -0
- data/doc/release_notes/1_4_3.md +11 -0
- data/doc/release_notes/1_4_4.md +14 -0
- data/doc/release_notes/1_5_0.md +126 -0
- data/doc/release_notes/1_5_1.md +6 -0
- data/doc/release_notes/1_6_0.md +50 -0
- data/doc/release_notes/1_6_1.md +17 -0
- data/doc/release_notes/1_6_2.md +11 -0
- data/lib/httpx/adapters/datadog.rb +359 -0
- data/lib/httpx/adapters/faraday.rb +303 -0
- data/lib/httpx/adapters/sentry.rb +121 -0
- data/lib/httpx/adapters/webmock.rb +175 -0
- data/lib/httpx/altsvc.rb +163 -0
- data/lib/httpx/base64.rb +27 -0
- data/lib/httpx/buffer.rb +61 -0
- data/lib/httpx/callbacks.rb +35 -0
- data/lib/httpx/chainable.rb +106 -0
- data/lib/httpx/connection/http1.rb +399 -0
- data/lib/httpx/connection/http2.rb +468 -0
- data/lib/httpx/connection.rb +954 -0
- data/lib/httpx/domain_name.rb +145 -0
- data/lib/httpx/errors.rb +111 -0
- data/lib/httpx/extensions.rb +59 -0
- data/lib/httpx/headers.rb +176 -0
- data/lib/httpx/io/ssl.rb +163 -0
- data/lib/httpx/io/tcp.rb +239 -0
- data/lib/httpx/io/udp.rb +62 -0
- data/lib/httpx/io/unix.rb +71 -0
- data/lib/httpx/io.rb +11 -0
- data/lib/httpx/loggable.rb +56 -0
- data/lib/httpx/options.rb +463 -0
- data/lib/httpx/parser/http1.rb +186 -0
- data/lib/httpx/plugins/auth/basic.rb +20 -0
- data/lib/httpx/plugins/auth/digest.rb +102 -0
- data/lib/httpx/plugins/auth/ntlm.rb +35 -0
- data/lib/httpx/plugins/auth/socks5.rb +22 -0
- data/lib/httpx/plugins/auth.rb +25 -0
- data/lib/httpx/plugins/aws_sdk_authentication.rb +111 -0
- data/lib/httpx/plugins/aws_sigv4.rb +239 -0
- data/lib/httpx/plugins/basic_auth.rb +29 -0
- data/lib/httpx/plugins/brotli.rb +50 -0
- data/lib/httpx/plugins/callbacks.rb +127 -0
- data/lib/httpx/plugins/circuit_breaker/circuit.rb +100 -0
- data/lib/httpx/plugins/circuit_breaker/circuit_store.rb +53 -0
- data/lib/httpx/plugins/circuit_breaker.rb +147 -0
- data/lib/httpx/plugins/content_digest.rb +204 -0
- data/lib/httpx/plugins/cookies/cookie.rb +174 -0
- data/lib/httpx/plugins/cookies/jar.rb +95 -0
- data/lib/httpx/plugins/cookies/set_cookie_parser.rb +143 -0
- data/lib/httpx/plugins/cookies.rb +107 -0
- data/lib/httpx/plugins/digest_auth.rb +67 -0
- data/lib/httpx/plugins/expect.rb +120 -0
- data/lib/httpx/plugins/fiber_concurrency.rb +195 -0
- data/lib/httpx/plugins/follow_redirects.rb +233 -0
- data/lib/httpx/plugins/grpc/call.rb +63 -0
- data/lib/httpx/plugins/grpc/grpc_encoding.rb +90 -0
- data/lib/httpx/plugins/grpc/message.rb +55 -0
- data/lib/httpx/plugins/grpc.rb +282 -0
- data/lib/httpx/plugins/h2c.rb +127 -0
- data/lib/httpx/plugins/internal_telemetry.rb +107 -0
- data/lib/httpx/plugins/ntlm_auth.rb +62 -0
- data/lib/httpx/plugins/oauth.rb +183 -0
- data/lib/httpx/plugins/persistent.rb +82 -0
- data/lib/httpx/plugins/proxy/http.rb +184 -0
- data/lib/httpx/plugins/proxy/socks4.rb +135 -0
- data/lib/httpx/plugins/proxy/socks5.rb +194 -0
- data/lib/httpx/plugins/proxy/ssh.rb +94 -0
- data/lib/httpx/plugins/proxy.rb +349 -0
- data/lib/httpx/plugins/push_promise.rb +81 -0
- data/lib/httpx/plugins/query.rb +35 -0
- data/lib/httpx/plugins/rate_limiter.rb +55 -0
- data/lib/httpx/plugins/response_cache/file_store.rb +140 -0
- data/lib/httpx/plugins/response_cache/store.rb +33 -0
- data/lib/httpx/plugins/response_cache.rb +333 -0
- data/lib/httpx/plugins/retries.rb +230 -0
- data/lib/httpx/plugins/ssrf_filter.rb +145 -0
- data/lib/httpx/plugins/stream.rb +183 -0
- data/lib/httpx/plugins/stream_bidi.rb +315 -0
- data/lib/httpx/plugins/upgrade/h2.rb +64 -0
- data/lib/httpx/plugins/upgrade.rb +86 -0
- data/lib/httpx/plugins/webdav.rb +86 -0
- data/lib/httpx/plugins/xml.rb +76 -0
- data/lib/httpx/pmatch_extensions.rb +33 -0
- data/lib/httpx/pool.rb +190 -0
- data/lib/httpx/punycode.rb +22 -0
- data/lib/httpx/request/body.rb +158 -0
- data/lib/httpx/request.rb +328 -0
- data/lib/httpx/resolver/entry.rb +30 -0
- data/lib/httpx/resolver/https.rb +256 -0
- data/lib/httpx/resolver/multi.rb +102 -0
- data/lib/httpx/resolver/native.rb +547 -0
- data/lib/httpx/resolver/resolver.rb +173 -0
- data/lib/httpx/resolver/system.rb +255 -0
- data/lib/httpx/resolver.rb +189 -0
- data/lib/httpx/response/body.rb +242 -0
- data/lib/httpx/response/buffer.rb +115 -0
- data/lib/httpx/response.rb +304 -0
- data/lib/httpx/selector.rb +282 -0
- data/lib/httpx/session.rb +612 -0
- data/lib/httpx/session_extensions.rb +30 -0
- data/lib/httpx/timers.rb +133 -0
- data/lib/httpx/transcoder/body.rb +43 -0
- data/lib/httpx/transcoder/chunker.rb +115 -0
- data/lib/httpx/transcoder/deflate.rb +37 -0
- data/lib/httpx/transcoder/form.rb +68 -0
- data/lib/httpx/transcoder/gzip.rb +71 -0
- data/lib/httpx/transcoder/json.rb +71 -0
- data/lib/httpx/transcoder/multipart/decoder.rb +141 -0
- data/lib/httpx/transcoder/multipart/encoder.rb +120 -0
- data/lib/httpx/transcoder/multipart/mime_type_detector.rb +78 -0
- data/lib/httpx/transcoder/multipart/part.rb +35 -0
- data/lib/httpx/transcoder/multipart.rb +31 -0
- data/lib/httpx/transcoder/utils/body_reader.rb +46 -0
- data/lib/httpx/transcoder/utils/deflater.rb +75 -0
- data/lib/httpx/transcoder.rb +91 -0
- data/lib/httpx/utils.rb +75 -0
- data/lib/httpx/version.rb +5 -0
- data/lib/httpx.rb +66 -0
- data/sig/altsvc.rbs +33 -0
- data/sig/buffer.rbs +27 -0
- data/sig/callbacks.rbs +15 -0
- data/sig/chainable.rbs +55 -0
- data/sig/connection/http1.rbs +85 -0
- data/sig/connection/http2.rbs +116 -0
- data/sig/connection.rbs +169 -0
- data/sig/domain_name.rbs +17 -0
- data/sig/errors.rbs +69 -0
- data/sig/headers.rbs +49 -0
- data/sig/httpx.rbs +27 -0
- data/sig/io/ssl.rbs +27 -0
- data/sig/io/tcp.rbs +72 -0
- data/sig/io/udp.rbs +25 -0
- data/sig/io/unix.rbs +26 -0
- data/sig/io.rbs +3 -0
- data/sig/loggable.rbs +17 -0
- data/sig/options.rbs +202 -0
- data/sig/parser/http1.rbs +59 -0
- data/sig/plugins/auth/basic.rbs +17 -0
- data/sig/plugins/auth/digest.rbs +25 -0
- data/sig/plugins/auth/ntlm.rbs +20 -0
- data/sig/plugins/auth/socks5.rbs +18 -0
- data/sig/plugins/auth.rbs +13 -0
- data/sig/plugins/aws_sdk_authentication.rbs +43 -0
- data/sig/plugins/aws_sigv4.rbs +78 -0
- data/sig/plugins/basic_auth.rbs +15 -0
- data/sig/plugins/brotli.rbs +22 -0
- data/sig/plugins/callbacks.rbs +38 -0
- data/sig/plugins/circuit_breaker.rbs +71 -0
- data/sig/plugins/compression.rbs +57 -0
- data/sig/plugins/content_digest.rbs +51 -0
- data/sig/plugins/cookies/cookie.rbs +55 -0
- data/sig/plugins/cookies/jar.rbs +26 -0
- data/sig/plugins/cookies/set_cookie_parser.rbs +22 -0
- data/sig/plugins/cookies.rbs +28 -0
- data/sig/plugins/digest_auth.rbs +21 -0
- data/sig/plugins/expect.rbs +15 -0
- data/sig/plugins/fiber_concurrency.rbs +51 -0
- data/sig/plugins/follow_redirects.rbs +47 -0
- data/sig/plugins/grpc/call.rbs +23 -0
- data/sig/plugins/grpc/grpc_encoding.rbs +37 -0
- data/sig/plugins/grpc/message.rbs +17 -0
- data/sig/plugins/grpc.rbs +65 -0
- data/sig/plugins/h2c.rbs +27 -0
- data/sig/plugins/ntlm_auth.rbs +21 -0
- data/sig/plugins/oauth.rbs +68 -0
- data/sig/plugins/persistent.rbs +14 -0
- data/sig/plugins/proxy/http.rbs +30 -0
- data/sig/plugins/proxy/socks4.rbs +37 -0
- data/sig/plugins/proxy/socks5.rbs +49 -0
- data/sig/plugins/proxy/ssh.rbs +18 -0
- data/sig/plugins/proxy.rbs +70 -0
- data/sig/plugins/push_promise.rbs +23 -0
- data/sig/plugins/query.rbs +18 -0
- data/sig/plugins/rate_limiter.rbs +13 -0
- data/sig/plugins/response_cache/file_store.rbs +19 -0
- data/sig/plugins/response_cache/store.rbs +13 -0
- data/sig/plugins/response_cache.rbs +86 -0
- data/sig/plugins/retries.rbs +66 -0
- data/sig/plugins/ssrf_filter.rbs +26 -0
- data/sig/plugins/stream.rbs +54 -0
- data/sig/plugins/stream_bidi.rbs +68 -0
- data/sig/plugins/upgrade/h2.rbs +9 -0
- data/sig/plugins/upgrade.rbs +29 -0
- data/sig/plugins/webdav.rbs +23 -0
- data/sig/plugins/xml.rbs +37 -0
- data/sig/pool.rbs +51 -0
- data/sig/punycode.rbs +5 -0
- data/sig/request/body.rbs +34 -0
- data/sig/request.rbs +88 -0
- data/sig/resolver/entry.rbs +13 -0
- data/sig/resolver/https.rbs +45 -0
- data/sig/resolver/multi.rbs +32 -0
- data/sig/resolver/native.rbs +74 -0
- data/sig/resolver/resolver.rbs +64 -0
- data/sig/resolver/system.rbs +34 -0
- data/sig/resolver.rbs +48 -0
- data/sig/response/body.rbs +52 -0
- data/sig/response/buffer.rbs +23 -0
- data/sig/response.rbs +103 -0
- data/sig/selector.rbs +68 -0
- data/sig/session.rbs +104 -0
- data/sig/timers.rbs +54 -0
- data/sig/transcoder/body.rbs +24 -0
- data/sig/transcoder/chunker.rbs +49 -0
- data/sig/transcoder/deflate.rbs +12 -0
- data/sig/transcoder/form.rbs +34 -0
- data/sig/transcoder/gzip.rbs +27 -0
- data/sig/transcoder/json.rbs +28 -0
- data/sig/transcoder/multipart.rbs +103 -0
- data/sig/transcoder/utils/body_reader.rbs +15 -0
- data/sig/transcoder/utils/deflater.rbs +28 -0
- data/sig/transcoder.rbs +43 -0
- data/sig/utils.rbs +19 -0
- metadata +518 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module HTTPX
|
|
4
|
+
module Plugins
|
|
5
|
+
#
|
|
6
|
+
# https://gitlab.com/os85/httpx/wikis/OAuth
|
|
7
|
+
#
|
|
8
|
+
module OAuth
|
|
9
|
+
class << self
|
|
10
|
+
def load_dependencies(_klass)
|
|
11
|
+
require_relative "auth/basic"
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
SUPPORTED_GRANT_TYPES = %w[client_credentials refresh_token].freeze
|
|
16
|
+
SUPPORTED_AUTH_METHODS = %w[client_secret_basic client_secret_post].freeze
|
|
17
|
+
|
|
18
|
+
class OAuthSession
|
|
19
|
+
attr_reader :grant_type, :client_id, :client_secret, :access_token, :refresh_token, :scope, :audience
|
|
20
|
+
|
|
21
|
+
def initialize(
|
|
22
|
+
issuer:,
|
|
23
|
+
client_id:,
|
|
24
|
+
client_secret:,
|
|
25
|
+
access_token: nil,
|
|
26
|
+
refresh_token: nil,
|
|
27
|
+
scope: nil,
|
|
28
|
+
audience: nil,
|
|
29
|
+
token_endpoint: nil,
|
|
30
|
+
response_type: nil,
|
|
31
|
+
grant_type: nil,
|
|
32
|
+
token_endpoint_auth_method: nil
|
|
33
|
+
)
|
|
34
|
+
@issuer = URI(issuer)
|
|
35
|
+
@client_id = client_id
|
|
36
|
+
@client_secret = client_secret
|
|
37
|
+
@token_endpoint = URI(token_endpoint) if token_endpoint
|
|
38
|
+
@response_type = response_type
|
|
39
|
+
@scope = case scope
|
|
40
|
+
when String
|
|
41
|
+
scope.split
|
|
42
|
+
when Array
|
|
43
|
+
scope
|
|
44
|
+
end
|
|
45
|
+
@audience = audience
|
|
46
|
+
@access_token = access_token
|
|
47
|
+
@refresh_token = refresh_token
|
|
48
|
+
@token_endpoint_auth_method = String(token_endpoint_auth_method) if token_endpoint_auth_method
|
|
49
|
+
@grant_type = grant_type || (@refresh_token ? "refresh_token" : "client_credentials")
|
|
50
|
+
|
|
51
|
+
unless @token_endpoint_auth_method.nil? || SUPPORTED_AUTH_METHODS.include?(@token_endpoint_auth_method)
|
|
52
|
+
raise Error, "#{@token_endpoint_auth_method} is not a supported auth method"
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
return if SUPPORTED_GRANT_TYPES.include?(@grant_type)
|
|
56
|
+
|
|
57
|
+
raise Error, "#{@grant_type} is not a supported grant type"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def token_endpoint
|
|
61
|
+
@token_endpoint || "#{@issuer}/token"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def token_endpoint_auth_method
|
|
65
|
+
@token_endpoint_auth_method || "client_secret_basic"
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def load(http)
|
|
69
|
+
return if @grant_type && @scope
|
|
70
|
+
|
|
71
|
+
metadata = http.get("#{@issuer}/.well-known/oauth-authorization-server").raise_for_status.json
|
|
72
|
+
|
|
73
|
+
@token_endpoint = metadata["token_endpoint"]
|
|
74
|
+
@scope = metadata["scopes_supported"]
|
|
75
|
+
@grant_type = Array(metadata["grant_types_supported"]).find { |gr| SUPPORTED_GRANT_TYPES.include?(gr) }
|
|
76
|
+
@token_endpoint_auth_method = Array(metadata["token_endpoint_auth_methods_supported"]).find do |am|
|
|
77
|
+
SUPPORTED_AUTH_METHODS.include?(am)
|
|
78
|
+
end
|
|
79
|
+
nil
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def merge(other)
|
|
83
|
+
obj = dup
|
|
84
|
+
|
|
85
|
+
case other
|
|
86
|
+
when OAuthSession
|
|
87
|
+
other.instance_variables.each do |ivar|
|
|
88
|
+
val = other.instance_variable_get(ivar)
|
|
89
|
+
next unless val
|
|
90
|
+
|
|
91
|
+
obj.instance_variable_set(ivar, val)
|
|
92
|
+
end
|
|
93
|
+
when Hash
|
|
94
|
+
other.each do |k, v|
|
|
95
|
+
obj.instance_variable_set(:"@#{k}", v) if obj.instance_variable_defined?(:"@#{k}")
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
obj
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
module OptionsMethods
|
|
103
|
+
private
|
|
104
|
+
|
|
105
|
+
def option_oauth_session(value)
|
|
106
|
+
case value
|
|
107
|
+
when Hash
|
|
108
|
+
OAuthSession.new(**value)
|
|
109
|
+
when OAuthSession
|
|
110
|
+
value
|
|
111
|
+
else
|
|
112
|
+
raise TypeError, ":oauth_session must be a #{OAuthSession}"
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
module InstanceMethods
|
|
118
|
+
def oauth_auth(**args)
|
|
119
|
+
with(oauth_session: OAuthSession.new(**args))
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def with_access_token
|
|
123
|
+
oauth_session = @options.oauth_session
|
|
124
|
+
|
|
125
|
+
oauth_session.load(self)
|
|
126
|
+
|
|
127
|
+
grant_type = oauth_session.grant_type
|
|
128
|
+
|
|
129
|
+
headers = {}
|
|
130
|
+
form_post = {
|
|
131
|
+
"grant_type" => grant_type,
|
|
132
|
+
"scope" => Array(oauth_session.scope).join(" "),
|
|
133
|
+
"audience" => oauth_session.audience,
|
|
134
|
+
}.compact
|
|
135
|
+
|
|
136
|
+
# auth
|
|
137
|
+
case oauth_session.token_endpoint_auth_method
|
|
138
|
+
when "client_secret_post"
|
|
139
|
+
form_post["client_id"] = oauth_session.client_id
|
|
140
|
+
form_post["client_secret"] = oauth_session.client_secret
|
|
141
|
+
when "client_secret_basic"
|
|
142
|
+
headers["authorization"] = Authentication::Basic.new(oauth_session.client_id, oauth_session.client_secret).authenticate
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
case grant_type
|
|
146
|
+
when "client_credentials"
|
|
147
|
+
# do nothing
|
|
148
|
+
when "refresh_token"
|
|
149
|
+
form_post["refresh_token"] = oauth_session.refresh_token
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
token_request = build_request("POST", oauth_session.token_endpoint, headers: headers, form: form_post)
|
|
153
|
+
token_request.headers.delete("authorization") unless oauth_session.token_endpoint_auth_method == "client_secret_basic"
|
|
154
|
+
|
|
155
|
+
token_response = request(token_request)
|
|
156
|
+
token_response.raise_for_status
|
|
157
|
+
|
|
158
|
+
payload = token_response.json
|
|
159
|
+
|
|
160
|
+
access_token = payload["access_token"]
|
|
161
|
+
refresh_token = payload["refresh_token"]
|
|
162
|
+
|
|
163
|
+
with(oauth_session: oauth_session.merge(access_token: access_token, refresh_token: refresh_token))
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def build_request(*)
|
|
167
|
+
request = super
|
|
168
|
+
|
|
169
|
+
return request if request.headers.key?("authorization")
|
|
170
|
+
|
|
171
|
+
oauth_session = @options.oauth_session
|
|
172
|
+
|
|
173
|
+
return request unless oauth_session && oauth_session.access_token
|
|
174
|
+
|
|
175
|
+
request.headers["authorization"] = "Bearer #{oauth_session.access_token}"
|
|
176
|
+
|
|
177
|
+
request
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
register_plugin :oauth, OAuth
|
|
182
|
+
end
|
|
183
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module HTTPX
|
|
4
|
+
module Plugins
|
|
5
|
+
# This plugin implements a session that persists connections over the duration of the process.
|
|
6
|
+
#
|
|
7
|
+
# This will improve connection reuse in a long-running process.
|
|
8
|
+
#
|
|
9
|
+
# One important caveat to note is, although this session might not close connections,
|
|
10
|
+
# other sessions from the same process that don't have this plugin turned on might.
|
|
11
|
+
#
|
|
12
|
+
# This session will still be able to work with it, as if, when expecting a connection
|
|
13
|
+
# terminated by a different session, it will just retry on a new one and keep it open.
|
|
14
|
+
#
|
|
15
|
+
# This plugin is also not recommendable when connecting to >9000 (like, a lot) different origins.
|
|
16
|
+
# So when you use this, make sure that you don't fall into this trap.
|
|
17
|
+
#
|
|
18
|
+
# https://gitlab.com/os85/httpx/wikis/Persistent
|
|
19
|
+
#
|
|
20
|
+
module Persistent
|
|
21
|
+
class << self
|
|
22
|
+
def load_dependencies(klass)
|
|
23
|
+
klass.plugin(:fiber_concurrency)
|
|
24
|
+
|
|
25
|
+
max_retries = if klass.default_options.respond_to?(:max_retries)
|
|
26
|
+
[klass.default_options.max_retries, 1].max
|
|
27
|
+
else
|
|
28
|
+
1
|
|
29
|
+
end
|
|
30
|
+
klass.plugin(:retries, max_retries: max_retries)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def self.extra_options(options)
|
|
35
|
+
options.merge(persistent: true)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
module InstanceMethods
|
|
39
|
+
def close(*)
|
|
40
|
+
super
|
|
41
|
+
|
|
42
|
+
# traverse other threads and unlink respective selector
|
|
43
|
+
# WARNING: this is not thread safe, make sure that the session isn't being
|
|
44
|
+
# used anymore, or all non-main threads are stopped.
|
|
45
|
+
Thread.list.each do |th|
|
|
46
|
+
store = thread_selector_store(th)
|
|
47
|
+
|
|
48
|
+
next unless store && store.key?(self)
|
|
49
|
+
|
|
50
|
+
selector = store.delete(self)
|
|
51
|
+
|
|
52
|
+
selector_close(selector)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
def repeatable_request?(request, _)
|
|
59
|
+
super || begin
|
|
60
|
+
response = request.response
|
|
61
|
+
|
|
62
|
+
return false unless response && response.is_a?(ErrorResponse)
|
|
63
|
+
|
|
64
|
+
error = response.error
|
|
65
|
+
|
|
66
|
+
Retries::RECONNECTABLE_ERRORS.any? { |klass| error.is_a?(klass) }
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def retryable_error?(ex)
|
|
71
|
+
super &&
|
|
72
|
+
# under the persistent plugin rules, requests are only retried for connection related errors,
|
|
73
|
+
# which do not include request timeout related errors. This only gets overriden if the end user
|
|
74
|
+
# manually changed +:max_retries+ to something else, which means it is aware of the
|
|
75
|
+
# consequences.
|
|
76
|
+
(!ex.is_a?(RequestTimeoutError) || @options.max_retries != 1)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
register_plugin :persistent, Persistent
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module HTTPX
|
|
4
|
+
module Plugins
|
|
5
|
+
module Proxy
|
|
6
|
+
module HTTP
|
|
7
|
+
class << self
|
|
8
|
+
def extra_options(options)
|
|
9
|
+
options.merge(supported_proxy_protocols: options.supported_proxy_protocols + %w[http])
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
module InstanceMethods
|
|
14
|
+
def with_proxy_basic_auth(opts)
|
|
15
|
+
with(proxy: opts.merge(scheme: "basic"))
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def with_proxy_digest_auth(opts)
|
|
19
|
+
with(proxy: opts.merge(scheme: "digest"))
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def with_proxy_ntlm_auth(opts)
|
|
23
|
+
with(proxy: opts.merge(scheme: "ntlm"))
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def fetch_response(request, selector, options)
|
|
27
|
+
response = super
|
|
28
|
+
|
|
29
|
+
if response &&
|
|
30
|
+
response.is_a?(Response) &&
|
|
31
|
+
response.status == 407 &&
|
|
32
|
+
!request.headers.key?("proxy-authorization") &&
|
|
33
|
+
response.headers.key?("proxy-authenticate") && options.proxy.can_authenticate?(response.headers["proxy-authenticate"])
|
|
34
|
+
request.transition(:idle)
|
|
35
|
+
request.headers["proxy-authorization"] =
|
|
36
|
+
options.proxy.authenticate(request, response.headers["proxy-authenticate"])
|
|
37
|
+
send_request(request, selector, options)
|
|
38
|
+
return
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
response
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
module ConnectionMethods
|
|
46
|
+
def connecting?
|
|
47
|
+
super || @state == :connecting || @state == :connected
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
def handle_transition(nextstate)
|
|
53
|
+
return super unless @options.proxy && @options.proxy.uri.scheme == "http"
|
|
54
|
+
|
|
55
|
+
case nextstate
|
|
56
|
+
when :connecting
|
|
57
|
+
return unless @state == :idle
|
|
58
|
+
|
|
59
|
+
@io.connect
|
|
60
|
+
return unless @io.connected?
|
|
61
|
+
|
|
62
|
+
@parser || begin
|
|
63
|
+
@parser = parser_type(@io.protocol).new(@write_buffer, @options.merge(max_concurrent_requests: 1))
|
|
64
|
+
parser = @parser
|
|
65
|
+
parser.extend(ProxyParser)
|
|
66
|
+
parser.on(:response, &method(:__http_on_connect))
|
|
67
|
+
parser.on(:close) do |force|
|
|
68
|
+
next unless @parser
|
|
69
|
+
|
|
70
|
+
if force
|
|
71
|
+
reset
|
|
72
|
+
emit(:terminate)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
parser.on(:reset) do
|
|
76
|
+
if parser.empty?
|
|
77
|
+
reset
|
|
78
|
+
else
|
|
79
|
+
transition(:closing)
|
|
80
|
+
transition(:closed)
|
|
81
|
+
|
|
82
|
+
parser.reset if @parser
|
|
83
|
+
transition(:idle)
|
|
84
|
+
transition(:connecting)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
__http_proxy_connect(parser)
|
|
88
|
+
end
|
|
89
|
+
return if @state == :connected
|
|
90
|
+
when :connected
|
|
91
|
+
return unless @state == :idle || @state == :connecting
|
|
92
|
+
|
|
93
|
+
case @state
|
|
94
|
+
when :connecting
|
|
95
|
+
parser = @parser
|
|
96
|
+
@parser = nil
|
|
97
|
+
parser.close
|
|
98
|
+
when :idle
|
|
99
|
+
@parser.callbacks.clear
|
|
100
|
+
set_parser_callbacks(@parser)
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
super
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def __http_proxy_connect(parser)
|
|
107
|
+
req = @pending.first
|
|
108
|
+
if req && req.uri.scheme == "https"
|
|
109
|
+
# if the first request after CONNECT is to an https address, it is assumed that
|
|
110
|
+
# all requests in the queue are not only ALL HTTPS, but they also share the certificate,
|
|
111
|
+
# and therefore, will share the connection.
|
|
112
|
+
#
|
|
113
|
+
connect_request = ConnectRequest.new(req.uri, @options)
|
|
114
|
+
@inflight += 1
|
|
115
|
+
parser.send(connect_request)
|
|
116
|
+
else
|
|
117
|
+
handle_transition(:connected)
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def __http_on_connect(request, response)
|
|
122
|
+
@inflight -= 1
|
|
123
|
+
if response.is_a?(Response) && response.status == 200
|
|
124
|
+
req = @pending.first
|
|
125
|
+
request_uri = req.uri
|
|
126
|
+
@io = ProxySSL.new(@io, request_uri, @options)
|
|
127
|
+
transition(:connected)
|
|
128
|
+
throw(:called)
|
|
129
|
+
elsif response.is_a?(Response) &&
|
|
130
|
+
response.status == 407 &&
|
|
131
|
+
!request.headers.key?("proxy-authorization") &&
|
|
132
|
+
@options.proxy.can_authenticate?(response.headers["proxy-authenticate"])
|
|
133
|
+
|
|
134
|
+
request.transition(:idle)
|
|
135
|
+
request.headers["proxy-authorization"] = @options.proxy.authenticate(request, response.headers["proxy-authenticate"])
|
|
136
|
+
@parser.send(request)
|
|
137
|
+
@inflight += 1
|
|
138
|
+
else
|
|
139
|
+
pending = @pending + @parser.pending
|
|
140
|
+
while (req = pending.shift)
|
|
141
|
+
response.finish!
|
|
142
|
+
req.response = response
|
|
143
|
+
req.emit(:response, response)
|
|
144
|
+
end
|
|
145
|
+
reset
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
module ProxyParser
|
|
151
|
+
def join_headline(request)
|
|
152
|
+
return super if request.verb == "CONNECT"
|
|
153
|
+
|
|
154
|
+
"#{request.verb} #{request.uri} HTTP/#{@version.join(".")}"
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def set_protocol_headers(request)
|
|
158
|
+
extra_headers = super
|
|
159
|
+
|
|
160
|
+
proxy_params = @options.proxy
|
|
161
|
+
if proxy_params.scheme == "basic"
|
|
162
|
+
# opt for basic auth
|
|
163
|
+
extra_headers["proxy-authorization"] = proxy_params.authenticate(extra_headers)
|
|
164
|
+
end
|
|
165
|
+
extra_headers["proxy-connection"] = extra_headers.delete("connection") if extra_headers.key?("connection")
|
|
166
|
+
extra_headers
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
class ConnectRequest < Request
|
|
171
|
+
def initialize(uri, options)
|
|
172
|
+
super("CONNECT", uri, options)
|
|
173
|
+
@headers.delete("accept")
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def path
|
|
177
|
+
"#{@uri.hostname}:#{@uri.port}"
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
register_plugin :"proxy/http", Proxy::HTTP
|
|
183
|
+
end
|
|
184
|
+
end
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "resolv"
|
|
4
|
+
require "ipaddr"
|
|
5
|
+
|
|
6
|
+
module HTTPX
|
|
7
|
+
class Socks4Error < ProxyError; end
|
|
8
|
+
|
|
9
|
+
module Plugins
|
|
10
|
+
module Proxy
|
|
11
|
+
module Socks4
|
|
12
|
+
VERSION = 4
|
|
13
|
+
CONNECT = 1
|
|
14
|
+
GRANTED = 0x5A
|
|
15
|
+
PROTOCOLS = %w[socks4 socks4a].freeze
|
|
16
|
+
|
|
17
|
+
Error = Socks4Error
|
|
18
|
+
|
|
19
|
+
class << self
|
|
20
|
+
def extra_options(options)
|
|
21
|
+
options.merge(supported_proxy_protocols: options.supported_proxy_protocols + PROTOCOLS)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
module ConnectionMethods
|
|
26
|
+
def interests
|
|
27
|
+
if @state == :connecting
|
|
28
|
+
return @write_buffer.empty? ? :r : :w
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
super
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def handle_transition(nextstate)
|
|
37
|
+
return super unless @options.proxy && PROTOCOLS.include?(@options.proxy.uri.scheme)
|
|
38
|
+
|
|
39
|
+
case nextstate
|
|
40
|
+
when :connecting
|
|
41
|
+
return unless @state == :idle
|
|
42
|
+
|
|
43
|
+
@io.connect
|
|
44
|
+
return unless @io.connected?
|
|
45
|
+
|
|
46
|
+
req = @pending.first
|
|
47
|
+
return unless req
|
|
48
|
+
|
|
49
|
+
request_uri = req.uri
|
|
50
|
+
@write_buffer << Packet.connect(@options.proxy, request_uri)
|
|
51
|
+
__socks4_proxy_connect
|
|
52
|
+
when :connected
|
|
53
|
+
return unless @state == :connecting
|
|
54
|
+
|
|
55
|
+
@parser = nil
|
|
56
|
+
end
|
|
57
|
+
log(level: 1) { "SOCKS4: #{nextstate}: #{@write_buffer.to_s.inspect}" } unless nextstate == :open
|
|
58
|
+
super
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def __socks4_proxy_connect
|
|
62
|
+
@parser = SocksParser.new(@write_buffer, @options)
|
|
63
|
+
@parser.once(:packet, &method(:__socks4_on_packet))
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def __socks4_on_packet(packet)
|
|
67
|
+
_version, status, _port, _ip = packet.unpack("CCnN")
|
|
68
|
+
if status == GRANTED
|
|
69
|
+
req = @pending.first
|
|
70
|
+
request_uri = req.uri
|
|
71
|
+
@io = ProxySSL.new(@io, request_uri, @options) if request_uri.scheme == "https"
|
|
72
|
+
transition(:connected)
|
|
73
|
+
throw(:called)
|
|
74
|
+
else
|
|
75
|
+
on_socks4_error("socks error: #{status}")
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def on_socks4_error(message)
|
|
80
|
+
ex = Error.new(message)
|
|
81
|
+
ex.set_backtrace(caller)
|
|
82
|
+
on_error(ex)
|
|
83
|
+
throw(:called)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
class SocksParser
|
|
88
|
+
include HTTPX::Callbacks
|
|
89
|
+
|
|
90
|
+
def initialize(buffer, options)
|
|
91
|
+
@buffer = buffer
|
|
92
|
+
@options = options
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def close; end
|
|
96
|
+
|
|
97
|
+
def consume(*); end
|
|
98
|
+
|
|
99
|
+
def empty?
|
|
100
|
+
true
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def <<(packet)
|
|
104
|
+
emit(:packet, packet)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
module Packet
|
|
109
|
+
module_function
|
|
110
|
+
|
|
111
|
+
def connect(parameters, uri)
|
|
112
|
+
packet = [VERSION, CONNECT, uri.port].pack("CCn")
|
|
113
|
+
|
|
114
|
+
case parameters.uri.scheme
|
|
115
|
+
when "socks4"
|
|
116
|
+
socks_host = uri.host
|
|
117
|
+
begin
|
|
118
|
+
ip = IPAddr.new(socks_host)
|
|
119
|
+
packet << ip.hton
|
|
120
|
+
rescue IPAddr::InvalidAddressError
|
|
121
|
+
socks_host = Resolv.getaddress(socks_host)
|
|
122
|
+
retry
|
|
123
|
+
end
|
|
124
|
+
packet << [parameters.username].pack("Z*")
|
|
125
|
+
when "socks4a"
|
|
126
|
+
packet << "\x0\x0\x0\x1" << [parameters.username].pack("Z*") << uri.host << "\x0"
|
|
127
|
+
end
|
|
128
|
+
packet
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
register_plugin :"proxy/socks4", Proxy::Socks4
|
|
134
|
+
end
|
|
135
|
+
end
|