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,282 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module HTTPX
|
|
4
|
+
GRPCError = Class.new(Error) do
|
|
5
|
+
attr_reader :status, :details, :metadata
|
|
6
|
+
|
|
7
|
+
def initialize(status, details, metadata)
|
|
8
|
+
@status = status
|
|
9
|
+
@details = details
|
|
10
|
+
@metadata = metadata
|
|
11
|
+
super("GRPC error, code=#{status}, details=#{details}, metadata=#{metadata}")
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
module Plugins
|
|
16
|
+
#
|
|
17
|
+
# This plugin adds DSL to build GRPC interfaces.
|
|
18
|
+
#
|
|
19
|
+
# https://gitlab.com/os85/httpx/wikis/GRPC
|
|
20
|
+
#
|
|
21
|
+
module GRPC
|
|
22
|
+
unless String.method_defined?(:underscore)
|
|
23
|
+
module StringExtensions
|
|
24
|
+
refine String do
|
|
25
|
+
def underscore
|
|
26
|
+
s = dup # Avoid mutating the argument, as it might be frozen.
|
|
27
|
+
s.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
|
28
|
+
s.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
|
|
29
|
+
s.tr!("-", "_")
|
|
30
|
+
s.downcase!
|
|
31
|
+
s
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
using StringExtensions
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
DEADLINE = 60
|
|
39
|
+
MARSHAL_METHOD = :encode
|
|
40
|
+
UNMARSHAL_METHOD = :decode
|
|
41
|
+
HEADERS = {
|
|
42
|
+
"content-type" => "application/grpc",
|
|
43
|
+
"te" => "trailers",
|
|
44
|
+
"accept" => "application/grpc",
|
|
45
|
+
# metadata fits here
|
|
46
|
+
# ex "foo-bin" => base64("bar")
|
|
47
|
+
}.freeze
|
|
48
|
+
|
|
49
|
+
class << self
|
|
50
|
+
def load_dependencies(*)
|
|
51
|
+
require "stringio"
|
|
52
|
+
require "httpx/plugins/grpc/grpc_encoding"
|
|
53
|
+
require "httpx/plugins/grpc/message"
|
|
54
|
+
require "httpx/plugins/grpc/call"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def configure(klass)
|
|
58
|
+
klass.plugin(:persistent)
|
|
59
|
+
klass.plugin(:stream)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def extra_options(options)
|
|
63
|
+
options.merge(
|
|
64
|
+
fallback_protocol: "h2",
|
|
65
|
+
grpc_rpcs: {}.freeze,
|
|
66
|
+
grpc_compression: false,
|
|
67
|
+
grpc_deadline: DEADLINE
|
|
68
|
+
)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
module OptionsMethods
|
|
73
|
+
private
|
|
74
|
+
|
|
75
|
+
def option_grpc_service(value)
|
|
76
|
+
String(value)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def option_grpc_compression(value)
|
|
80
|
+
case value
|
|
81
|
+
when true, false
|
|
82
|
+
value
|
|
83
|
+
else
|
|
84
|
+
value.to_s
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def option_grpc_rpcs(value)
|
|
89
|
+
Hash[value]
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def option_grpc_deadline(value)
|
|
93
|
+
raise TypeError, ":grpc_deadline must be positive" unless value.positive?
|
|
94
|
+
|
|
95
|
+
value
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def option_call_credentials(value)
|
|
99
|
+
raise TypeError, ":call_credentials must respond to #call" unless value.respond_to?(:call)
|
|
100
|
+
|
|
101
|
+
value
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
module ResponseMethods
|
|
106
|
+
attr_reader :trailing_metadata
|
|
107
|
+
|
|
108
|
+
def merge_headers(trailers)
|
|
109
|
+
@trailing_metadata = Hash[trailers]
|
|
110
|
+
super
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
module RequestBodyMethods
|
|
115
|
+
def initialize(*, **)
|
|
116
|
+
super
|
|
117
|
+
|
|
118
|
+
if (compression = @headers["grpc-encoding"])
|
|
119
|
+
deflater_body = self.class.initialize_deflater_body(@body, compression)
|
|
120
|
+
@body = Transcoder::GRPCEncoding.encode(deflater_body || @body, compressed: !deflater_body.nil?)
|
|
121
|
+
else
|
|
122
|
+
@body = Transcoder::GRPCEncoding.encode(@body, compressed: false)
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
module InstanceMethods
|
|
128
|
+
def with_channel_credentials(ca_path, key = nil, cert = nil, **ssl_opts)
|
|
129
|
+
# @type var ssl_params: ::Hash[::Symbol, untyped]
|
|
130
|
+
ssl_params = {
|
|
131
|
+
**ssl_opts,
|
|
132
|
+
ca_file: ca_path,
|
|
133
|
+
}
|
|
134
|
+
if key
|
|
135
|
+
key = File.read(key) if File.file?(key)
|
|
136
|
+
ssl_params[:key] = OpenSSL::PKey.read(key)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
if cert
|
|
140
|
+
cert = File.read(cert) if File.file?(cert)
|
|
141
|
+
ssl_params[:cert] = OpenSSL::X509::Certificate.new(cert)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
with(ssl: ssl_params)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def rpc(rpc_name, input, output, **opts)
|
|
148
|
+
rpc_name = rpc_name.to_s
|
|
149
|
+
raise Error, "rpc #{rpc_name} already defined" if @options.grpc_rpcs.key?(rpc_name)
|
|
150
|
+
|
|
151
|
+
rpc_opts = {
|
|
152
|
+
deadline: @options.grpc_deadline,
|
|
153
|
+
}.merge(opts)
|
|
154
|
+
|
|
155
|
+
local_rpc_name = rpc_name.underscore
|
|
156
|
+
|
|
157
|
+
session_class = Class.new(self.class) do
|
|
158
|
+
# define rpc method with ruby style name
|
|
159
|
+
class_eval(<<-OUT, __FILE__, __LINE__ + 1)
|
|
160
|
+
def #{local_rpc_name}(input, **opts) # def grpc_action(input, **opts)
|
|
161
|
+
rpc_execute("#{local_rpc_name}", input, **opts) # rpc_execute("grpc_action", input, **opts)
|
|
162
|
+
end # end
|
|
163
|
+
OUT
|
|
164
|
+
|
|
165
|
+
# define rpc method with original name
|
|
166
|
+
unless local_rpc_name == rpc_name
|
|
167
|
+
class_eval(<<-OUT, __FILE__, __LINE__ + 1)
|
|
168
|
+
def #{rpc_name}(input, **opts) # def grpcAction(input, **opts)
|
|
169
|
+
rpc_execute("#{local_rpc_name}", input, **opts) # rpc_execute("grpc_action", input, **opts)
|
|
170
|
+
end # end
|
|
171
|
+
OUT
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
session_class.new(@options.merge(
|
|
176
|
+
grpc_rpcs: @options.grpc_rpcs.merge(
|
|
177
|
+
local_rpc_name => [rpc_name, input, output, rpc_opts]
|
|
178
|
+
).freeze
|
|
179
|
+
))
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def build_stub(origin, service: nil, compression: false)
|
|
183
|
+
scheme = @options.ssl.empty? ? "http" : "https"
|
|
184
|
+
|
|
185
|
+
origin = URI.parse("#{scheme}://#{origin}")
|
|
186
|
+
|
|
187
|
+
session = self
|
|
188
|
+
|
|
189
|
+
if service && service.respond_to?(:rpc_descs)
|
|
190
|
+
# it's a grpc generic service
|
|
191
|
+
service.rpc_descs.each do |rpc_name, rpc_desc|
|
|
192
|
+
rpc_opts = {
|
|
193
|
+
marshal_method: rpc_desc.marshal_method,
|
|
194
|
+
unmarshal_method: rpc_desc.unmarshal_method,
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
input = rpc_desc.input
|
|
198
|
+
input = input.type if input.respond_to?(:type)
|
|
199
|
+
|
|
200
|
+
output = rpc_desc.output
|
|
201
|
+
if output.respond_to?(:type)
|
|
202
|
+
rpc_opts[:stream] = true
|
|
203
|
+
output = output.type
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
session = session.rpc(rpc_name, input, output, **rpc_opts)
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
service = service.service_name
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
session.with(origin: origin, grpc_service: service, grpc_compression: compression)
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def execute(rpc_method, input,
|
|
216
|
+
deadline: DEADLINE,
|
|
217
|
+
metadata: nil,
|
|
218
|
+
**opts)
|
|
219
|
+
grpc_request = build_grpc_request(rpc_method, input, deadline: deadline, metadata: metadata, **opts)
|
|
220
|
+
response = request(grpc_request, **opts)
|
|
221
|
+
response.raise_for_status unless opts[:stream]
|
|
222
|
+
GRPC::Call.new(response)
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
private
|
|
226
|
+
|
|
227
|
+
def rpc_execute(rpc_name, input, **opts)
|
|
228
|
+
rpc_name, input_enc, output_enc, rpc_opts = @options.grpc_rpcs[rpc_name]
|
|
229
|
+
|
|
230
|
+
exec_opts = rpc_opts.merge(opts)
|
|
231
|
+
|
|
232
|
+
marshal_method ||= exec_opts.delete(:marshal_method) || MARSHAL_METHOD
|
|
233
|
+
unmarshal_method ||= exec_opts.delete(:unmarshal_method) || UNMARSHAL_METHOD
|
|
234
|
+
|
|
235
|
+
messages = if input.respond_to?(:each)
|
|
236
|
+
Enumerator.new do |y|
|
|
237
|
+
input.each do |message|
|
|
238
|
+
y << input_enc.__send__(marshal_method, message)
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
else
|
|
242
|
+
input_enc.__send__(marshal_method, input)
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
call = execute(rpc_name, messages, **exec_opts)
|
|
246
|
+
|
|
247
|
+
call.decoder = output_enc.method(unmarshal_method)
|
|
248
|
+
|
|
249
|
+
call
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def build_grpc_request(rpc_method, input, deadline:, metadata: nil, **)
|
|
253
|
+
uri = @options.origin.dup
|
|
254
|
+
rpc_method = "/#{rpc_method}" unless rpc_method.start_with?("/")
|
|
255
|
+
rpc_method = "/#{@options.grpc_service}#{rpc_method}" if @options.grpc_service
|
|
256
|
+
uri.path = rpc_method
|
|
257
|
+
|
|
258
|
+
headers = HEADERS.merge(
|
|
259
|
+
"grpc-accept-encoding" => ["identity", *@options.supported_compression_formats]
|
|
260
|
+
)
|
|
261
|
+
unless deadline == Float::INFINITY
|
|
262
|
+
# convert to milliseconds
|
|
263
|
+
deadline = (deadline * 1000.0).to_i
|
|
264
|
+
headers["grpc-timeout"] = "#{deadline}m"
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
headers = headers.merge(metadata.transform_keys(&:to_s)) if metadata
|
|
268
|
+
|
|
269
|
+
# prepare compressor
|
|
270
|
+
compression = @options.grpc_compression == true ? "gzip" : @options.grpc_compression
|
|
271
|
+
|
|
272
|
+
headers["grpc-encoding"] = compression if compression
|
|
273
|
+
|
|
274
|
+
headers.merge!(@options.call_credentials.call.transform_keys(&:to_s)) if @options.call_credentials
|
|
275
|
+
|
|
276
|
+
build_request("POST", uri, headers: headers, body: input)
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
register_plugin :grpc, GRPC
|
|
281
|
+
end
|
|
282
|
+
end
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module HTTPX
|
|
4
|
+
module Plugins
|
|
5
|
+
#
|
|
6
|
+
# This plugin adds support for upgrading a plaintext HTTP/1.1 connection to HTTP/2
|
|
7
|
+
# (https://datatracker.ietf.org/doc/html/rfc7540#section-3.2)
|
|
8
|
+
#
|
|
9
|
+
# https://gitlab.com/os85/httpx/wikis/Connection-Upgrade#h2c
|
|
10
|
+
#
|
|
11
|
+
module H2C
|
|
12
|
+
VALID_H2C_VERBS = %w[GET OPTIONS HEAD].freeze
|
|
13
|
+
|
|
14
|
+
class << self
|
|
15
|
+
def load_dependencies(klass)
|
|
16
|
+
klass.plugin(:upgrade)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def call(connection, request, response)
|
|
20
|
+
connection.upgrade_to_h2c(request, response)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def extra_options(options)
|
|
24
|
+
options.merge(
|
|
25
|
+
h2c_class: Class.new(options.http2_class) { include(H2CParser) },
|
|
26
|
+
max_concurrent_requests: 1,
|
|
27
|
+
upgrade_handlers: options.upgrade_handlers.merge("h2c" => self),
|
|
28
|
+
)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
module OptionsMethods
|
|
33
|
+
def option_h2c_class(value)
|
|
34
|
+
value
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
module RequestMethods
|
|
39
|
+
def valid_h2c_verb?
|
|
40
|
+
VALID_H2C_VERBS.include?(@verb)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
module ConnectionMethods
|
|
45
|
+
using URIExtensions
|
|
46
|
+
|
|
47
|
+
def initialize(*)
|
|
48
|
+
super
|
|
49
|
+
@h2c_handshake = false
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def send(request)
|
|
53
|
+
return super if @h2c_handshake
|
|
54
|
+
|
|
55
|
+
return super unless request.valid_h2c_verb? && request.scheme == "http"
|
|
56
|
+
|
|
57
|
+
return super if @upgrade_protocol == "h2c"
|
|
58
|
+
|
|
59
|
+
@h2c_handshake = true
|
|
60
|
+
|
|
61
|
+
# build upgrade request
|
|
62
|
+
request.headers.add("connection", "upgrade")
|
|
63
|
+
request.headers.add("connection", "http2-settings")
|
|
64
|
+
request.headers["upgrade"] = "h2c"
|
|
65
|
+
request.headers["http2-settings"] = ::HTTP2::Client.settings_header(request.options.http2_settings)
|
|
66
|
+
|
|
67
|
+
super
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def upgrade_to_h2c(request, response)
|
|
71
|
+
prev_parser = @parser
|
|
72
|
+
|
|
73
|
+
if prev_parser
|
|
74
|
+
prev_parser.reset
|
|
75
|
+
@inflight -= prev_parser.requests.size
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
@parser = request.options.h2c_class.new(@write_buffer, @options)
|
|
79
|
+
set_parser_callbacks(@parser)
|
|
80
|
+
@inflight += 1
|
|
81
|
+
@parser.upgrade(request, response)
|
|
82
|
+
@upgrade_protocol = "h2c"
|
|
83
|
+
|
|
84
|
+
prev_parser.requests.each do |req|
|
|
85
|
+
req.transition(:idle)
|
|
86
|
+
send(req)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
private
|
|
91
|
+
|
|
92
|
+
def send_request_to_parser(request)
|
|
93
|
+
super
|
|
94
|
+
|
|
95
|
+
return unless request.headers["upgrade"] == "h2c" && parser.is_a?(Connection::HTTP1)
|
|
96
|
+
|
|
97
|
+
max_concurrent_requests = parser.max_concurrent_requests
|
|
98
|
+
|
|
99
|
+
return if max_concurrent_requests == 1
|
|
100
|
+
|
|
101
|
+
parser.max_concurrent_requests = 1
|
|
102
|
+
request.once(:response) do
|
|
103
|
+
parser.max_concurrent_requests = max_concurrent_requests
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
module H2CParser
|
|
109
|
+
def upgrade(request, response)
|
|
110
|
+
# skip checks, it is assumed that this is the first
|
|
111
|
+
# request in the connection
|
|
112
|
+
stream = @connection.upgrade
|
|
113
|
+
|
|
114
|
+
# on_settings
|
|
115
|
+
handle_stream(stream, request)
|
|
116
|
+
@streams[request] = stream
|
|
117
|
+
|
|
118
|
+
# clean up data left behind in the buffer, if the server started
|
|
119
|
+
# sending frames
|
|
120
|
+
data = response.read
|
|
121
|
+
@connection << data
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
register_plugin(:h2c, H2C)
|
|
126
|
+
end
|
|
127
|
+
end
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module HTTPX
|
|
4
|
+
module Plugins
|
|
5
|
+
#
|
|
6
|
+
# The InternalTelemetry plugin is for internal use only. It is therefore undocumented, and
|
|
7
|
+
# its use is disencouraged, as API compatiblity will **not be guaranteed**.
|
|
8
|
+
#
|
|
9
|
+
# The gist of it is: when debug_level of logger is enabled to 3 or greater, considered internal-only
|
|
10
|
+
# supported log levels, it'll be loaded by default.
|
|
11
|
+
#
|
|
12
|
+
# Against a specific point of time, which will be by default the session initialization, but can be set
|
|
13
|
+
# by the end user in $http_init_time, different diff metrics can be shown. The "point of time" is calculated
|
|
14
|
+
# using the monotonic clock.
|
|
15
|
+
module InternalTelemetry
|
|
16
|
+
DEBUG_LEVEL = 3
|
|
17
|
+
|
|
18
|
+
def self.extra_options(options)
|
|
19
|
+
options.merge(debug_level: 3)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
module TrackTimeMethods
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def elapsed_time
|
|
26
|
+
yield
|
|
27
|
+
ensure
|
|
28
|
+
meter_elapsed_time("#{self.class.superclass}##{caller_locations(1, 1)[0].label}")
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def meter_elapsed_time(label)
|
|
32
|
+
$http_init_time ||= Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond)
|
|
33
|
+
prev_time = $http_init_time
|
|
34
|
+
after_time = Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond)
|
|
35
|
+
# $http_init_time = after_time
|
|
36
|
+
elapsed = after_time - prev_time
|
|
37
|
+
# klass = self.class
|
|
38
|
+
|
|
39
|
+
# until (class_name = klass.name)
|
|
40
|
+
# klass = klass.superclass
|
|
41
|
+
# end
|
|
42
|
+
log(
|
|
43
|
+
level: DEBUG_LEVEL,
|
|
44
|
+
color: :red,
|
|
45
|
+
debug_level: @options ? @options.debug_level : DEBUG_LEVEL,
|
|
46
|
+
debug: nil
|
|
47
|
+
) do
|
|
48
|
+
"[ELAPSED TIME]: #{label}: #{elapsed} (ms)" << "\e[0m"
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
module InstanceMethods
|
|
54
|
+
def self.included(klass)
|
|
55
|
+
klass.prepend TrackTimeMethods
|
|
56
|
+
super
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def initialize(*)
|
|
60
|
+
meter_elapsed_time("Session: initializing...")
|
|
61
|
+
super
|
|
62
|
+
meter_elapsed_time("Session: initialized!!!")
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def close(*)
|
|
66
|
+
super
|
|
67
|
+
meter_elapsed_time("Session -> close")
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
def build_requests(*)
|
|
73
|
+
elapsed_time { super }
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def fetch_response(*)
|
|
77
|
+
response = super
|
|
78
|
+
meter_elapsed_time("Session -> response") if response
|
|
79
|
+
response
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def coalesce_connections(conn1, conn2, selector, *)
|
|
83
|
+
result = super
|
|
84
|
+
|
|
85
|
+
meter_elapsed_time("Connection##{conn2.object_id} coalescing to Connection##{conn1.object_id}") if result
|
|
86
|
+
|
|
87
|
+
result
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
module PoolMethods
|
|
92
|
+
def self.included(klass)
|
|
93
|
+
klass.prepend Loggable
|
|
94
|
+
klass.prepend TrackTimeMethods
|
|
95
|
+
super
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def checkin_connection(connection)
|
|
99
|
+
super.tap do
|
|
100
|
+
meter_elapsed_time("Pool##{object_id}: checked in connection for Connection##{connection.object_id}[#{connection.origin}]}")
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
register_plugin :internal_telemetry, InternalTelemetry
|
|
106
|
+
end
|
|
107
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module HTTPX
|
|
4
|
+
module Plugins
|
|
5
|
+
#
|
|
6
|
+
# https://gitlab.com/os85/httpx/wikis/Auth#ntlm-auth
|
|
7
|
+
#
|
|
8
|
+
module NTLMAuth
|
|
9
|
+
class << self
|
|
10
|
+
def load_dependencies(_klass)
|
|
11
|
+
require_relative "auth/ntlm"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def extra_options(options)
|
|
15
|
+
options.merge(max_concurrent_requests: 1)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
module OptionsMethods
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def option_ntlm(value)
|
|
23
|
+
raise TypeError, ":ntlm must be a #{Authentication::Ntlm}" unless value.is_a?(Authentication::Ntlm)
|
|
24
|
+
|
|
25
|
+
value
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
module InstanceMethods
|
|
30
|
+
def ntlm_auth(user, password, domain = nil)
|
|
31
|
+
with(ntlm: Authentication::Ntlm.new(user, password, domain: domain))
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def send_requests(*requests)
|
|
37
|
+
requests.flat_map do |request|
|
|
38
|
+
ntlm = request.options.ntlm
|
|
39
|
+
|
|
40
|
+
if ntlm
|
|
41
|
+
request.headers["authorization"] = ntlm.negotiate
|
|
42
|
+
probe_response = wrap { super(request).first }
|
|
43
|
+
|
|
44
|
+
return probe_response unless probe_response.is_a?(Response)
|
|
45
|
+
|
|
46
|
+
if probe_response.status == 401 && ntlm.can_authenticate?(probe_response.headers["www-authenticate"])
|
|
47
|
+
request.transition(:idle)
|
|
48
|
+
request.headers["authorization"] = ntlm.authenticate(request, probe_response.headers["www-authenticate"])
|
|
49
|
+
super(request)
|
|
50
|
+
else
|
|
51
|
+
probe_response
|
|
52
|
+
end
|
|
53
|
+
else
|
|
54
|
+
super(request)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
register_plugin :ntlm_auth, NTLMAuth
|
|
61
|
+
end
|
|
62
|
+
end
|