httpx 0.11.0 → 0.13.0

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.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/doc/release_notes/0_11_1.md +5 -0
  4. data/doc/release_notes/0_11_2.md +5 -0
  5. data/doc/release_notes/0_11_3.md +5 -0
  6. data/doc/release_notes/0_12_0.md +55 -0
  7. data/doc/release_notes/0_13_0.md +58 -0
  8. data/lib/httpx.rb +2 -1
  9. data/lib/httpx/adapters/faraday.rb +4 -6
  10. data/lib/httpx/altsvc.rb +1 -0
  11. data/lib/httpx/chainable.rb +2 -2
  12. data/lib/httpx/connection.rb +80 -28
  13. data/lib/httpx/connection/http1.rb +19 -6
  14. data/lib/httpx/connection/http2.rb +32 -25
  15. data/lib/httpx/io.rb +16 -3
  16. data/lib/httpx/io/ssl.rb +35 -24
  17. data/lib/httpx/io/tcp.rb +48 -28
  18. data/lib/httpx/io/tls.rb +218 -0
  19. data/lib/httpx/io/tls/box.rb +365 -0
  20. data/lib/httpx/io/tls/context.rb +199 -0
  21. data/lib/httpx/io/tls/ffi.rb +390 -0
  22. data/lib/httpx/io/udp.rb +3 -2
  23. data/lib/httpx/io/unix.rb +27 -12
  24. data/lib/httpx/options.rb +11 -23
  25. data/lib/httpx/parser/http1.rb +4 -4
  26. data/lib/httpx/plugins/aws_sdk_authentication.rb +81 -0
  27. data/lib/httpx/plugins/aws_sigv4.rb +218 -0
  28. data/lib/httpx/plugins/compression.rb +21 -9
  29. data/lib/httpx/plugins/compression/brotli.rb +8 -6
  30. data/lib/httpx/plugins/compression/deflate.rb +4 -7
  31. data/lib/httpx/plugins/compression/gzip.rb +2 -2
  32. data/lib/httpx/plugins/cookies/set_cookie_parser.rb +1 -1
  33. data/lib/httpx/plugins/digest_authentication.rb +1 -1
  34. data/lib/httpx/plugins/follow_redirects.rb +1 -1
  35. data/lib/httpx/plugins/h2c.rb +43 -58
  36. data/lib/httpx/plugins/internal_telemetry.rb +93 -0
  37. data/lib/httpx/plugins/multipart.rb +2 -0
  38. data/lib/httpx/plugins/multipart/encoder.rb +4 -9
  39. data/lib/httpx/plugins/proxy.rb +1 -1
  40. data/lib/httpx/plugins/proxy/http.rb +1 -1
  41. data/lib/httpx/plugins/proxy/socks4.rb +8 -0
  42. data/lib/httpx/plugins/proxy/socks5.rb +8 -0
  43. data/lib/httpx/plugins/push_promise.rb +3 -2
  44. data/lib/httpx/plugins/retries.rb +2 -2
  45. data/lib/httpx/plugins/stream.rb +6 -6
  46. data/lib/httpx/plugins/upgrade.rb +83 -0
  47. data/lib/httpx/plugins/upgrade/h2.rb +54 -0
  48. data/lib/httpx/pool.rb +14 -6
  49. data/lib/httpx/registry.rb +1 -7
  50. data/lib/httpx/request.rb +11 -1
  51. data/lib/httpx/resolver/https.rb +3 -11
  52. data/lib/httpx/response.rb +14 -7
  53. data/lib/httpx/selector.rb +5 -0
  54. data/lib/httpx/session.rb +25 -2
  55. data/lib/httpx/transcoder/body.rb +3 -5
  56. data/lib/httpx/version.rb +1 -1
  57. data/sig/chainable.rbs +2 -1
  58. data/sig/connection/http1.rbs +3 -2
  59. data/sig/connection/http2.rbs +5 -3
  60. data/sig/options.rbs +7 -20
  61. data/sig/plugins/aws_sdk_authentication.rbs +17 -0
  62. data/sig/plugins/aws_sigv4.rbs +64 -0
  63. data/sig/plugins/compression.rbs +5 -3
  64. data/sig/plugins/compression/brotli.rbs +1 -1
  65. data/sig/plugins/compression/deflate.rbs +1 -1
  66. data/sig/plugins/compression/gzip.rbs +1 -1
  67. data/sig/plugins/cookies.rbs +0 -1
  68. data/sig/plugins/digest_authentication.rbs +0 -1
  69. data/sig/plugins/expect.rbs +0 -2
  70. data/sig/plugins/follow_redirects.rbs +0 -2
  71. data/sig/plugins/h2c.rbs +5 -10
  72. data/sig/plugins/persistent.rbs +0 -1
  73. data/sig/plugins/proxy.rbs +0 -1
  74. data/sig/plugins/push_promise.rbs +1 -1
  75. data/sig/plugins/retries.rbs +0 -4
  76. data/sig/plugins/upgrade.rbs +23 -0
  77. data/sig/response.rbs +3 -1
  78. metadata +48 -26
@@ -0,0 +1,390 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ffi"
4
+ require "ffi-compiler/loader"
5
+ require "concurrent"
6
+
7
+ # Copyright (c) 2004-2013 Cotag Media
8
+ #
9
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
10
+ # of this software and associated documentation files (the "Software"), to deal
11
+ # in the Software without restriction, including without limitation the rights
12
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
+ # copies of the Software, and to permit persons to whom the Software is furnished
14
+ # to do so, subject to the following conditions:
15
+ #
16
+ # The above copyright notice and this permission notice shall be included in all
17
+ # copies or substantial portions of the Software.
18
+ #
19
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
+ # THE SOFTWARE.
26
+ #
27
+
28
+ module HTTPX::TLS::SSL
29
+ Error = HTTPX::TLS::Error
30
+
31
+ extend FFI::Library
32
+
33
+ if FFI::Platform.windows?
34
+ begin
35
+ ffi_lib "libeay32", "ssleay32"
36
+ rescue LoadError
37
+ ffi_lib "libcrypto-1_1-x64", "libssl-1_1-x64"
38
+ end
39
+ else
40
+ ffi_lib "ssl"
41
+ end
42
+
43
+ # Common structures
44
+ typedef :pointer, :user_data
45
+ typedef :pointer, :bio
46
+ typedef :pointer, :evp_key
47
+ typedef :pointer, :evp_key_pointer
48
+ typedef :pointer, :x509
49
+ typedef :pointer, :x509_pointer
50
+ typedef :pointer, :ssl
51
+ typedef :pointer, :cipher
52
+ typedef :pointer, :ssl_ctx
53
+ typedef :int, :buffer_length
54
+ typedef :int, :pass_length
55
+ typedef :int, :read_write_flag
56
+
57
+ SSL_ST_OK = 0x03
58
+ begin
59
+ attach_function :SSL_library_init, [], :int
60
+ attach_function :SSL_load_error_strings, [], :void
61
+ attach_function :ERR_load_crypto_strings, [], :void
62
+
63
+ attach_function :SSL_state, [:ssl], :int
64
+ def self.is_init_finished(ssl)
65
+ SSL_state(ssl) == SSL_ST_OK
66
+ end
67
+
68
+ OPENSSL_V1_1 = false
69
+ rescue FFI::NotFoundError
70
+ OPENSSL_V1_1 = true
71
+ OPENSSL_INIT_LOAD_SSL_STRINGS = 0x200000
72
+ OPENSSL_INIT_NO_LOAD_SSL_STRINGS = 0x100000
73
+ attach_function :OPENSSL_init_ssl, %i[uint64 pointer], :int
74
+
75
+ attach_function :SSL_get_state, [:ssl], :int
76
+ attach_function :SSL_is_init_finished, [:ssl], :bool
77
+
78
+ def self.is_init_finished(ssl)
79
+ SSL_is_init_finished(ssl)
80
+ end
81
+ end
82
+
83
+ # Multi-threaded support
84
+ # callback :locking_cb, [:int, :int, :string, :int], :void
85
+ # callback :thread_id_cb, [], :ulong
86
+ # attach_function :CRYPTO_num_locks, [], :int
87
+ # attach_function :CRYPTO_set_locking_callback, [:locking_cb], :void
88
+ # attach_function :CRYPTO_set_id_callback, [:thread_id_cb], :void
89
+
90
+ # InitializeDefaultCredentials
91
+ attach_function :BIO_new_mem_buf, %i[string buffer_length], :bio
92
+ attach_function :EVP_PKEY_free, [:evp_key], :void
93
+
94
+ callback :pem_password_cb, %i[pointer buffer_length read_write_flag user_data], :pass_length
95
+ attach_function :PEM_read_bio_PrivateKey, %i[bio evp_key_pointer pem_password_cb user_data], :evp_key
96
+
97
+ attach_function :X509_free, [:x509], :void
98
+ attach_function :PEM_read_bio_X509, %i[bio x509_pointer pem_password_cb user_data], :x509
99
+
100
+ attach_function :BIO_free, [:bio], :int
101
+
102
+ # GetPeerCert
103
+ attach_function :SSL_get_peer_certificate, [:ssl], :x509
104
+
105
+ # PutPlaintext
106
+ attach_function :SSL_write, %i[ssl buffer_in buffer_length], :int
107
+ attach_function :SSL_get_error, %i[ssl int], :int
108
+
109
+ # GetCiphertext
110
+ attach_function :BIO_read, %i[bio buffer_out buffer_length], :int
111
+
112
+ # CanGetCiphertext
113
+ attach_function :BIO_ctrl, %i[bio int long pointer], :long
114
+ BIO_CTRL_PENDING = 10 # opt - is their more data buffered?
115
+ def self.BIO_pending(bio)
116
+ BIO_ctrl(bio, BIO_CTRL_PENDING, 0, nil)
117
+ end
118
+
119
+ # GetPlaintext
120
+ attach_function :SSL_accept, [:ssl], :int
121
+ attach_function :SSL_read, %i[ssl buffer_out buffer_length], :int
122
+ attach_function :SSL_pending, [:ssl], :int
123
+
124
+ # PutCiphertext
125
+ attach_function :BIO_write, %i[bio buffer_in buffer_length], :int
126
+
127
+ # Deconstructor
128
+ attach_function :SSL_get_shutdown, [:ssl], :int
129
+ attach_function :SSL_shutdown, [:ssl], :int
130
+ attach_function :SSL_clear, [:ssl], :void
131
+ attach_function :SSL_free, [:ssl], :void
132
+
133
+ # Constructor
134
+ attach_function :BIO_s_mem, [], :pointer
135
+ attach_function :BIO_new, [:pointer], :bio
136
+ attach_function :SSL_new, [:ssl_ctx], :ssl
137
+ # r, w
138
+ attach_function :SSL_set_bio, %i[ssl bio bio], :void
139
+
140
+ attach_function :SSL_set_ex_data, %i[ssl int string], :int
141
+ callback :verify_callback, %i[int x509], :int
142
+ attach_function :SSL_set_verify, %i[ssl int verify_callback], :void
143
+ attach_function :SSL_CTX_set_verify, %i[ssl int verify_callback], :void
144
+ attach_function :SSL_get_verify_result, %i[ssl], :long
145
+ attach_function :SSL_connect, [:ssl], :int
146
+
147
+ # Verify callback
148
+ X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT = 2
149
+ X509_V_ERR_HOSTNAME_MISMATCH = 62
150
+ X509_V_ERR_CERT_REJECTED = 28
151
+ attach_function :X509_STORE_CTX_get_current_cert, [:pointer], :x509
152
+ attach_function :SSL_get_ex_data_X509_STORE_CTX_idx, [], :int
153
+ attach_function :X509_STORE_CTX_get_ex_data, %i[pointer int], :ssl
154
+ attach_function :X509_STORE_CTX_get_error_depth, %i[x509], :int
155
+ attach_function :PEM_write_bio_X509, %i[bio x509], :bool
156
+ attach_function :X509_verify_cert_error_string, %i[long], :string
157
+ attach_function :X509_STORE_CTX_set_error, %i[ssl_ctx long], :void
158
+
159
+ # SSL Context Class
160
+ # OpenSSL before 1.1.0 do not have these methods
161
+ # https://www.openssl.org/docs/man1.1.0/ssl/TLSv1_2_server_method.html
162
+ begin
163
+ attach_function :TLS_server_method, [], :pointer
164
+ attach_function :TLS_client_method, [], :pointer
165
+ rescue FFI::NotFoundError
166
+ attach_function :SSLv23_server_method, [], :pointer
167
+ attach_function :SSLv23_client_method, [], :pointer
168
+
169
+ def self.TLS_server_method
170
+ self.SSLv23_server_method
171
+ end
172
+
173
+ def self.TLS_client_method
174
+ self.SSLv23_client_method
175
+ end
176
+ end
177
+
178
+ # Version can be one of:
179
+ # :SSL3, :TLS1, :TLS1_1, :TLS1_2, :TLS1_3, :TLS_MAX
180
+ begin
181
+ attach_function :SSL_get_version, %i[ssl], :string
182
+ attach_function :SSL_get_current_cipher, %i[ssl], :cipher
183
+ attach_function :SSL_CIPHER_get_name, %i[cipher], :string
184
+ attach_function :SSL_CTX_set_min_proto_version, %i[ssl_ctx int], :int
185
+ attach_function :SSL_CTX_set_max_proto_version, %i[ssl_ctx int], :int
186
+
187
+ VERSION_SUPPORTED = true
188
+
189
+ SSL3_VERSION = 0x0300
190
+ TLS1_VERSION = 0x0301
191
+ TLS1_1_VERSION = 0x0302
192
+ TLS1_2_VERSION = 0x0303
193
+ TLS1_3_VERSION = 0x0304
194
+ TLS_MAX_VERSION = TLS1_3_VERSION
195
+ ANY_VERSION = 0
196
+ rescue FFI::NotFoundError
197
+ VERSION_SUPPORTED = false
198
+ end
199
+
200
+ def self.get_version(ssl)
201
+ SSL_get_version(ssl)
202
+ end
203
+
204
+ def self.get_current_cipher(ssl)
205
+ cipher = SSL_get_current_cipher(ssl)
206
+ SSL_CIPHER_get_name(cipher)
207
+ end
208
+
209
+ attach_function :SSL_CTX_new, [:pointer], :ssl_ctx
210
+
211
+ attach_function :SSL_CTX_ctrl, %i[ssl_ctx int ulong pointer], :long
212
+ SSL_CTRL_OPTIONS = 32
213
+ def self.SSL_CTX_set_options(ssl_ctx, op)
214
+ SSL_CTX_ctrl(ssl_ctx, SSL_CTRL_OPTIONS, op, nil)
215
+ end
216
+ SSL_CTRL_MODE = 33
217
+ def self.SSL_CTX_set_mode(ssl_ctx, op)
218
+ SSL_CTX_ctrl(ssl_ctx, SSL_CTRL_MODE, op, nil)
219
+ end
220
+ SSL_CTRL_SET_SESS_CACHE_SIZE = 42
221
+ def self.SSL_CTX_sess_set_cache_size(ssl_ctx, op)
222
+ SSL_CTX_ctrl(ssl_ctx, SSL_CTRL_SET_SESS_CACHE_SIZE, op, nil)
223
+ end
224
+
225
+ attach_function :SSL_ctrl, %i[ssl int long pointer], :long
226
+ SSL_CTRL_SET_TLSEXT_HOSTNAME = 55
227
+
228
+ def self.SSL_set_tlsext_host_name(ssl, host_name)
229
+ name_ptr = FFI::MemoryPointer.from_string(host_name)
230
+ raise Error, "error setting SNI hostname" if SSL_ctrl(ssl, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name, name_ptr).zero?
231
+ end
232
+
233
+ # Server Name Indication (SNI) Support
234
+ # NOTE:: We've hard coded the callback here (SSL defines a NULL callback)
235
+ callback :ssl_servername_cb, %i[ssl pointer pointer], :int
236
+ attach_function :SSL_CTX_callback_ctrl, %i[ssl_ctx int ssl_servername_cb], :long
237
+ SSL_CTRL_SET_TLSEXT_SERVERNAME_CB = 53
238
+ def self.SSL_CTX_set_tlsext_servername_callback(ctx, callback)
239
+ SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_TLSEXT_SERVERNAME_CB, callback)
240
+ end
241
+
242
+ attach_function :SSL_get_servername, %i[ssl int], :string
243
+ TLSEXT_NAMETYPE_host_name = 0
244
+
245
+ attach_function :SSL_set_SSL_CTX, %i[ssl ssl_ctx], :ssl_ctx
246
+
247
+ SSL_TLSEXT_ERR_OK = 0
248
+ SSL_TLSEXT_ERR_ALERT_WARNING = 1
249
+ SSL_TLSEXT_ERR_ALERT_FATAL = 2
250
+ SSL_TLSEXT_ERR_NOACK = 3
251
+
252
+ attach_function :SSL_CTX_use_PrivateKey_file, %i[ssl_ctx string int], :int, :blocking => true
253
+ attach_function :SSL_CTX_use_PrivateKey, %i[ssl_ctx pointer], :int
254
+ attach_function :ERR_print_errors_fp, [:pointer], :void # Pointer == File Handle
255
+ attach_function :SSL_CTX_use_certificate_chain_file, %i[ssl_ctx string], :int, :blocking => true
256
+ attach_function :SSL_CTX_use_certificate, %i[ssl_ctx x509], :int
257
+ attach_function :SSL_CTX_set_cipher_list, %i[ssl_ctx string], :int
258
+ attach_function :SSL_CTX_set_session_id_context, %i[ssl_ctx string buffer_length], :int
259
+ attach_function :SSL_load_client_CA_file, [:string], :pointer
260
+ attach_function :SSL_CTX_set_client_CA_list, %i[ssl_ctx pointer], :void
261
+ attach_function :SSL_CTX_load_verify_locations, %i[ssl_ctx pointer], :int, :blocking => true
262
+
263
+ # OpenSSL before 1.0.2 do not have these methods
264
+ begin
265
+ attach_function :SSL_CTX_set_alpn_protos, %i[ssl_ctx string uint], :int
266
+
267
+ OPENSSL_NPN_UNSUPPORTED = 0
268
+ OPENSSL_NPN_NEGOTIATED = 1
269
+ OPENSSL_NPN_NO_OVERLAP = 2
270
+
271
+ attach_function :SSL_select_next_proto, %i[pointer pointer string uint string uint], :int
272
+
273
+ # array of str, unit8 out,uint8 in, *arg
274
+ callback :alpn_select_cb, %i[ssl pointer pointer string uint pointer], :int
275
+ attach_function :SSL_CTX_set_alpn_select_cb, %i[ssl_ctx alpn_select_cb pointer], :void
276
+
277
+ attach_function :SSL_get0_alpn_selected, %i[ssl pointer pointer], :void
278
+ ALPN_SUPPORTED = true
279
+ rescue FFI::NotFoundError
280
+ ALPN_SUPPORTED = false
281
+ end
282
+
283
+ # Deconstructor
284
+ attach_function :SSL_CTX_free, [:ssl_ctx], :void
285
+
286
+ PrivateMaterials = <<~KEYSTR
287
+ -----BEGIN RSA PRIVATE KEY-----
288
+ MIICXAIBAAKBgQDCYYhcw6cGRbhBVShKmbWm7UVsEoBnUf0cCh8AX+MKhMxwVDWV
289
+ Igdskntn3cSJjRtmgVJHIK0lpb/FYHQB93Ohpd9/Z18pDmovfFF9nDbFF0t39hJ/
290
+ AqSzFB3GiVPoFFZJEE1vJqh+3jzsSF5K56bZ6azz38VlZgXeSozNW5bXkQIDAQAB
291
+ AoGALA89gIFcr6BIBo8N5fL3aNHpZXjAICtGav+kTUpuxSiaym9cAeTHuAVv8Xgk
292
+ H2Wbq11uz+6JMLpkQJH/WZ7EV59DPOicXrp0Imr73F3EXBfR7t2EQDYHPMthOA1D
293
+ I9EtCzvV608Ze90hiJ7E3guGrGppZfJ+eUWCPgy8CZH1vRECQQDv67rwV/oU1aDo
294
+ 6/+d5nqjeW6mWkGqTnUU96jXap8EIw6B+0cUKskwx6mHJv+tEMM2748ZY7b0yBlg
295
+ w4KDghbFAkEAz2h8PjSJG55LwqmXih1RONSgdN9hjB12LwXL1CaDh7/lkEhq0PlK
296
+ PCAUwQSdM17Sl0Xxm2CZiekTSlwmHrtqXQJAF3+8QJwtV2sRJp8u2zVe37IeH1cJ
297
+ xXeHyjTzqZ2803fnjN2iuZvzNr7noOA1/Kp+pFvUZUU5/0G2Ep8zolPUjQJAFA7k
298
+ xRdLkzIx3XeNQjwnmLlncyYPRv+qaE3FMpUu7zftuZBnVCJnvXzUxP3vPgKTlzGa
299
+ dg5XivDRfsV+okY5uQJBAMV4FesUuLQVEKb6lMs7rzZwpeGQhFDRfywJzfom2TLn
300
+ 2RdJQQ3dcgnhdVDgt5o1qkmsqQh8uJrJ9SdyLIaZQIc=
301
+ -----END RSA PRIVATE KEY-----
302
+ -----BEGIN CERTIFICATE-----
303
+ MIID6TCCA1KgAwIBAgIJANm4W/Tzs+s+MA0GCSqGSIb3DQEBBQUAMIGqMQswCQYD
304
+ VQQGEwJVUzERMA8GA1UECBMITmV3IFlvcmsxETAPBgNVBAcTCE5ldyBZb3JrMRYw
305
+ FAYDVQQKEw1TdGVhbWhlYXQubmV0MRQwEgYDVQQLEwtFbmdpbmVlcmluZzEdMBsG
306
+ A1UEAxMUb3BlbmNhLnN0ZWFtaGVhdC5uZXQxKDAmBgkqhkiG9w0BCQEWGWVuZ2lu
307
+ ZWVyaW5nQHN0ZWFtaGVhdC5uZXQwHhcNMDYwNTA1MTcwNjAzWhcNMjQwMjIwMTcw
308
+ NjAzWjCBqjELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5ldyBZb3JrMREwDwYDVQQH
309
+ EwhOZXcgWW9yazEWMBQGA1UEChMNU3RlYW1oZWF0Lm5ldDEUMBIGA1UECxMLRW5n
310
+ aW5lZXJpbmcxHTAbBgNVBAMTFG9wZW5jYS5zdGVhbWhlYXQubmV0MSgwJgYJKoZI
311
+ hvcNAQkBFhllbmdpbmVlcmluZ0BzdGVhbWhlYXQubmV0MIGfMA0GCSqGSIb3DQEB
312
+ AQUAA4GNADCBiQKBgQDCYYhcw6cGRbhBVShKmbWm7UVsEoBnUf0cCh8AX+MKhMxw
313
+ VDWVIgdskntn3cSJjRtmgVJHIK0lpb/FYHQB93Ohpd9/Z18pDmovfFF9nDbFF0t3
314
+ 9hJ/AqSzFB3GiVPoFFZJEE1vJqh+3jzsSF5K56bZ6azz38VlZgXeSozNW5bXkQID
315
+ AQABo4IBEzCCAQ8wHQYDVR0OBBYEFPJvPd1Fcmd8o/Tm88r+NjYPICCkMIHfBgNV
316
+ HSMEgdcwgdSAFPJvPd1Fcmd8o/Tm88r+NjYPICCkoYGwpIGtMIGqMQswCQYDVQQG
317
+ EwJVUzERMA8GA1UECBMITmV3IFlvcmsxETAPBgNVBAcTCE5ldyBZb3JrMRYwFAYD
318
+ VQQKEw1TdGVhbWhlYXQubmV0MRQwEgYDVQQLEwtFbmdpbmVlcmluZzEdMBsGA1UE
319
+ AxMUb3BlbmNhLnN0ZWFtaGVhdC5uZXQxKDAmBgkqhkiG9w0BCQEWGWVuZ2luZWVy
320
+ aW5nQHN0ZWFtaGVhdC5uZXSCCQDZuFv087PrPjAMBgNVHRMEBTADAQH/MA0GCSqG
321
+ SIb3DQEBBQUAA4GBAC1CXey/4UoLgJiwcEMDxOvW74plks23090iziFIlGgcIhk0
322
+ Df6hTAs7H3MWww62ddvR8l07AWfSzSP5L6mDsbvq7EmQsmPODwb6C+i2aF3EDL8j
323
+ uw73m4YIGI0Zw2XdBpiOGkx2H56Kya6mJJe/5XORZedh1wpI7zki01tHYbcy
324
+ -----END CERTIFICATE-----
325
+ KEYSTR
326
+
327
+ BuiltinPasswdCB = FFI::Function.new(:int, %i[pointer int int pointer]) do |buffer, _len, _flag, _data|
328
+ buffer.write_string("kittycat")
329
+ 8
330
+ end
331
+
332
+ # Save RAM by releasing read and write buffers when they're empty
333
+ SSL_MODE_RELEASE_BUFFERS = 0x00000010
334
+ SSL_OP_ALL = 0x80000BFF
335
+ SSL_FILETYPE_PEM = 1
336
+
337
+ # Locking isn't provided as long as all writes are done on the same thread.
338
+ # This is my main use case. Happy to enable it if someone requires it and can
339
+ # get it to work on MRI Ruby (Currently only works on JRuby and Rubinius)
340
+ # as MRI callbacks occur on a thread pool?
341
+
342
+ # CRYPTO_LOCK = 0x1
343
+ # LockingCB = FFI::Function.new(:void, [:int, :int, :string, :int]) do |mode, type, file, line|
344
+ # if (mode & CRYPTO_LOCK) != 0
345
+ # SSL_LOCKS[type].lock
346
+ # else
347
+ # Unlock a lock
348
+ # SSL_LOCKS[type].unlock
349
+ # end
350
+ # end
351
+ # ThreadIdCB = FFI::Function.new(:ulong, []) do
352
+ # Thread.current.object_id
353
+ # end
354
+
355
+ # INIT CODE
356
+ @init_required ||= false
357
+ unless @init_required
358
+ if OPENSSL_V1_1
359
+ self.OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, ::FFI::Pointer::NULL)
360
+ else
361
+ self.SSL_load_error_strings
362
+ self.SSL_library_init
363
+ self.ERR_load_crypto_strings
364
+ end
365
+
366
+ # Setup multi-threaded support
367
+ # SSL_LOCKS = []
368
+ # num_locks = self.CRYPTO_num_locks
369
+ # num_locks.times { SSL_LOCKS << Mutex.new }
370
+
371
+ # self.CRYPTO_set_locking_callback(LockingCB)
372
+ # self.CRYPTO_set_id_callback(ThreadIdCB)
373
+
374
+ bio = self.BIO_new_mem_buf(PrivateMaterials, PrivateMaterials.bytesize)
375
+
376
+ # Get the private key structure
377
+ pointer = FFI::MemoryPointer.new(:pointer)
378
+ self.PEM_read_bio_PrivateKey(bio, pointer, BuiltinPasswdCB, nil)
379
+ DEFAULT_PRIVATE = pointer.get_pointer(0)
380
+
381
+ # Get the certificate structure
382
+ pointer = FFI::MemoryPointer.new(:pointer)
383
+ self.PEM_read_bio_X509(bio, pointer, nil, nil)
384
+ DEFAULT_CERT = pointer.get_pointer(0)
385
+
386
+ self.BIO_free(bio)
387
+
388
+ @init_required = true
389
+ end
390
+ end
data/lib/httpx/io/udp.rb CHANGED
@@ -40,14 +40,15 @@ module HTTPX
40
40
  end
41
41
 
42
42
  def write(buffer)
43
- siz = @io.send(buffer, 0, @host, @port)
43
+ siz = @io.send(buffer.to_s, 0, @host, @port)
44
44
  log { "WRITE: #{siz} bytes..." }
45
45
  buffer.shift!(siz)
46
46
  siz
47
47
  end
48
48
 
49
49
  # :nocov:
50
- if RUBY_VERSION < "2.3"
50
+ if (RUBY_ENGINE == "truffleruby" && RUBY_ENGINE_VERSION < "21.1.0") ||
51
+ RUBY_VERSION < "2.3"
51
52
  def read(size, buffer)
52
53
  data, _ = @io.recvfrom_nonblock(size)
53
54
  buffer.replace(data)
data/lib/httpx/io/unix.rb CHANGED
@@ -6,34 +6,43 @@ module HTTPX
6
6
  class UNIX < TCP
7
7
  extend Forwardable
8
8
 
9
- def_delegator :@uri, :port, :scheme
9
+ using URIExtensions
10
10
 
11
- def initialize(uri, addresses, options)
12
- @uri = uri
11
+ attr_reader :path
12
+
13
+ alias_method :host, :path
14
+
15
+ def initialize(origin, addresses, options)
13
16
  @addresses = addresses
17
+ @hostname = origin.host
14
18
  @state = :idle
15
19
  @options = Options.new(options)
16
- @path = @options.transport_options[:path]
17
20
  @fallback_protocol = @options.fallback_protocol
18
21
  if @options.io
19
22
  @io = case @options.io
20
23
  when Hash
21
- @options.io[@path]
24
+ @options.io[origin.authority]
22
25
  else
23
26
  @options.io
24
27
  end
25
- unless @io.nil?
26
- @keep_open = true
27
- @state = :connected
28
+ raise Error, "Given IO objects do not match the request authority" unless @io
29
+
30
+ @path = @io.path
31
+ @keep_open = true
32
+ @state = :connected
33
+ else
34
+ if @options.transport_options
35
+ # :nocov:
36
+ warn ":#{__method__} is deprecated, use :addresses instead"
37
+ @path = @options.transport_options[:path]
38
+ # :nocov:
39
+ else
40
+ @path = addresses.first
28
41
  end
29
42
  end
30
43
  @io ||= build_socket
31
44
  end
32
45
 
33
- def hostname
34
- @uri.host
35
- end
36
-
37
46
  def connect
38
47
  return unless closed?
39
48
 
@@ -51,6 +60,12 @@ module HTTPX
51
60
  ::IO::WaitReadable
52
61
  end
53
62
 
63
+ # :nocov:
64
+ def inspect
65
+ "#<#{self.class}(path: #{@path}): (state: #{@state})>"
66
+ end
67
+ # :nocov:
68
+
54
69
  private
55
70
 
56
71
  def build_socket