httpx 0.11.0 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
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