httpx 0.19.1 → 0.19.4

Sign up to get free protection for your applications and to get access to all the features.
data/lib/httpx/io/tls.rb DELETED
@@ -1,218 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "openssl"
4
-
5
- module HTTPX
6
- class TLS < TCP
7
- class Error < StandardError; end
8
-
9
- def initialize(_, _, options)
10
- super
11
- @encrypted = Buffer.new(Connection::BUFFER_SIZE)
12
- @decrypted = "".b
13
- tls_options = convert_tls_options(options.ssl)
14
- @sni_hostname = tls_options[:hostname]
15
- @ctx = TLS::Box.new(false, self, tls_options)
16
- @state = :negotiated if @keep_open
17
- end
18
-
19
- def interests
20
- @interests || super
21
- end
22
-
23
- def protocol
24
- @protocol || super
25
- end
26
-
27
- def connected?
28
- @state == :negotiated
29
- end
30
-
31
- def connect
32
- super
33
- if @keep_open
34
- @state = :negotiated
35
- return
36
- end
37
- return if @state == :negotiated ||
38
- @state != :connected
39
-
40
- super
41
- @ctx.start
42
- @interests = :r
43
- read(@options.window_size, @decrypted)
44
- end
45
-
46
- # :nocov:
47
- def inspect
48
- id = @io.closed? ? "closed" : @io
49
- "#<TLS(fd: #{id}): #{@ip}:#{@port} state: #{@state}>"
50
- end
51
- # :nocov:
52
-
53
- alias_method :transport_close, :close
54
- def close
55
- transport_close
56
- @ctx.cleanup
57
- end
58
-
59
- def read(*, buffer)
60
- ret = super
61
- return ret if !ret || ret.zero?
62
-
63
- @ctx.decrypt(buffer.to_s.dup)
64
- buffer.replace(@decrypted)
65
- @decrypted.clear
66
- buffer.bytesize
67
- end
68
-
69
- alias_method :unencrypted_write, :write
70
- def write(buffer)
71
- @ctx.encrypt(buffer.to_s.dup)
72
- buffer.clear
73
- do_write
74
- end
75
-
76
- # TLS callback.
77
- #
78
- # buffers the encrypted +data+
79
- def transmit_cb(data)
80
- log { "TLS encrypted: #{data.bytesize} bytes" }
81
- log(level: 2) { data.inspect }
82
- @encrypted << data
83
- do_write
84
- end
85
-
86
- # TLS callback.
87
- #
88
- # buffers the decrypted +data+
89
- def dispatch_cb(data)
90
- log { "TLS decrypted: #{data.bytesize} bytes" }
91
- log(level: 2) { data.inspect }
92
-
93
- @decrypted << data
94
- end
95
-
96
- # TLS callback.
97
- #
98
- # signals TLS invalid status / shutdown.
99
- def close_cb(msg = nil)
100
- log { "TLS Error: #{msg}, closing" }
101
- raise Error, "certificate verify failed (#{msg})"
102
- end
103
-
104
- # TLS callback.
105
- #
106
- # alpn protocol negotiation (+protocol+).
107
- #
108
- def alpn_protocol_cb(protocol)
109
- @protocol = protocol
110
- log { "TLS ALPN protocol negotiated: #{@protocol}" }
111
- end
112
-
113
- # TLS callback.
114
- #
115
- # handshake finished.
116
- #
117
- def handshake_cb
118
- log { "TLS handshake completed" }
119
- transition(:negotiated)
120
- end
121
-
122
- # TLS callback.
123
- #
124
- # passed the peer +cert+ to be verified.
125
- #
126
- def verify_cb(cert)
127
- raise Error, "Peer verification enabled, but no certificate received." if cert.nil?
128
-
129
- log { "TLS verifying #{cert}" }
130
- @peer_cert = OpenSSL::X509::Certificate.new(cert)
131
-
132
- # by default one doesn't verify client certificates in the server
133
- verify_hostname(@sni_hostname)
134
- end
135
-
136
- # copied from:
137
- # https://github.com/ruby/ruby/blob/8cbf2dae5aadfa5d6241b0df2bf44d55db46704f/ext/openssl/lib/openssl/ssl.rb#L395-L409
138
- #
139
- def verify_hostname(host)
140
- return false unless @ctx.verify_peer && @peer_cert
141
-
142
- OpenSSL::SSL.verify_certificate_identity(@peer_cert, host)
143
- end
144
-
145
- private
146
-
147
- def do_write
148
- nwritten = 0
149
- until @encrypted.empty?
150
- siz = unencrypted_write(@encrypted)
151
- break unless !siz || siz.zero?
152
-
153
- nwritten += siz
154
- end
155
- nwritten
156
- end
157
-
158
- def convert_tls_options(ssl_options)
159
- options = {}
160
- options[:verify_peer] = !ssl_options.key?(:verify_mode) || ssl_options[:verify_mode] != OpenSSL::SSL::VERIFY_NONE
161
- options[:version] = ssl_options[:ssl_version] if ssl_options.key?(:ssl_version)
162
-
163
- if ssl_options.key?(:key)
164
- private_key = ssl_options[:key]
165
- private_key = private_key.to_pem if private_key.respond_to?(:to_pem)
166
- options[:private_key] = private_key
167
- end
168
-
169
- if ssl_options.key?(:ca_path) || ssl_options.key?(:ca_file)
170
- ca_path = ssl_options[:ca_path] || ssl_options[:ca_file].path
171
- options[:cert_chain] = ca_path
172
- end
173
-
174
- options[:ciphers] = ssl_options[:ciphers] if ssl_options.key?(:ciphers)
175
- options[:protocols] = ssl_options.fetch(:alpn_protocols, %w[h2 http/1.1])
176
- options[:hostname] = ssl_options.fetch(:hostname, @hostname)
177
- options
178
- end
179
-
180
- def transition(nextstate)
181
- case nextstate
182
- when :negotiated
183
- return unless @state == :connected
184
- when :closed
185
- return unless @state == :negotiated ||
186
- @state == :connected
187
- end
188
- do_transition(nextstate)
189
- end
190
-
191
- def log_transition_state(nextstate)
192
- return super unless nextstate == :negotiated
193
-
194
- server_cert = @peer_cert
195
-
196
- "#{super}\n\n" \
197
- "SSL connection using #{@ctx.ssl_version} / #{Array(@ctx.cipher).first}\n" \
198
- "ALPN, server accepted to use #{protocol}\n" +
199
- (if server_cert
200
- "Server certificate:\n" \
201
- " subject: #{server_cert.subject}\n" \
202
- " start date: #{server_cert.not_before}\n" \
203
- " expire date: #{server_cert.not_after}\n" \
204
- " issuer: #{server_cert.issuer}\n" \
205
- " SSL certificate verify ok."
206
- else
207
- "SSL certificate verify failed."
208
- end
209
- )
210
- end
211
- end
212
-
213
- TLSError = TLS::Error
214
- end
215
-
216
- require "httpx/io/tls/ffi"
217
- require "httpx/io/tls/context"
218
- require "httpx/io/tls/box"