tcp-client 0.9.1 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,7 +2,8 @@
2
2
 
3
3
  class TCPClient
4
4
  #
5
- # Raised when a SSL connection should be establshed but the OpenSSL gem is not available.
5
+ # Raised when a SSL connection should be established but the OpenSSL gem is
6
+ # not available.
6
7
  #
7
8
  class NoOpenSSLError < RuntimeError
8
9
  def initialize
@@ -11,7 +12,8 @@ class TCPClient
11
12
  end
12
13
 
13
14
  #
14
- # Raised when a method requires a callback block but no such block is specified.
15
+ # Raised when a method requires a callback block but no such block is
16
+ # specified.
15
17
  #
16
18
  class NoBlockGivenError < ArgumentError
17
19
  def initialize
@@ -20,9 +22,12 @@ class TCPClient
20
22
  end
21
23
 
22
24
  #
23
- # Raised when a an invalid timeout value was specified.
25
+ # Raised when an invalid timeout value was specified.
24
26
  #
25
27
  class InvalidDeadLineError < ArgumentError
28
+ #
29
+ # @param timeout [Object] the invalid value
30
+ #
26
31
  def initialize(timeout)
27
32
  super("invalid deadline - #{timeout}")
28
33
  end
@@ -32,6 +37,9 @@ class TCPClient
32
37
  # Raised by {Configuration} when an undefined attribute should be set.
33
38
  #
34
39
  class UnknownAttributeError < ArgumentError
40
+ #
41
+ # @param attribute [Object] the undefined attribute
42
+ #
35
43
  def initialize(attribute)
36
44
  super("unknown attribute - #{attribute}")
37
45
  end
@@ -41,6 +49,9 @@ class TCPClient
41
49
  # Raised when a given timeout exception parameter is not an exception class.
42
50
  #
43
51
  class NotAnExceptionError < TypeError
52
+ #
53
+ # @param object [Object] the invalid object
54
+ #
44
55
  def initialize(object)
45
56
  super("exception class required - #{object.inspect}")
46
57
  end
@@ -49,15 +60,18 @@ class TCPClient
49
60
  #
50
61
  # Base exception class for all network related errors.
51
62
  #
52
- # Will be raised for any system level network error when {Configuration.normalize_network_errors} is configured.
63
+ # Will be raised for any system level network error when
64
+ # {Configuration.normalize_network_errors} is configured.
53
65
  #
54
- # You should catch this exception class when you like to handle any relevant {TCPClient} error.
66
+ # You should catch this exception class when you like to handle any relevant
67
+ # {TCPClient} error.
55
68
  #
56
69
  class NetworkError < StandardError
57
70
  end
58
71
 
59
72
  #
60
- # Raised when a {TCPClient} instance should read/write from/to the network but is not connected.
73
+ # Raised when a {TCPClient} instance should read/write from/to the network
74
+ # but is not connected.
61
75
  #
62
76
  class NotConnectedError < NetworkError
63
77
  def initialize
@@ -68,23 +82,26 @@ class TCPClient
68
82
  #
69
83
  # Base exception class for a detected timeout.
70
84
  #
71
- # You should catch this exception class when you like to handle any timeout error.
85
+ # You should catch this exception class when you like to handle any timeout
86
+ # error.
72
87
  #
73
88
  class TimeoutError < NetworkError
74
89
  #
75
90
  # Initializes the instance with an optional message.
76
91
  #
77
- # the message will be generated from {#action} when not specified.
92
+ # The message will be generated from {#action} when not specified.
93
+ #
78
94
  # @overload initialize
79
95
  # @overload initialize(message)
80
96
  #
81
- # @param message [String, #to_s] the error message
97
+ # @param message [#to_s] the error message
82
98
  #
83
99
  def initialize(message = nil)
84
100
  super(message || "unable to #{action} in time")
85
101
  end
86
102
 
87
103
  #
104
+ # @attribute [r] action
88
105
  # @return [Symbol] the action which timed out
89
106
  #
90
107
  def action
@@ -97,7 +114,8 @@ class TCPClient
97
114
  #
98
115
  class ConnectTimeoutError < TimeoutError
99
116
  #
100
- # @return [Symbol] the action which timed out: +:connect+
117
+ # @attribute [r] action
118
+ # @return [Symbol] the action which timed out: `:connect`
101
119
  #
102
120
  def action
103
121
  :connect
@@ -105,11 +123,12 @@ class TCPClient
105
123
  end
106
124
 
107
125
  #
108
- # Raised by default whenever a {TCPClient.read} timed out.
126
+ # Raised by default whenever a {TCPClient#read} timed out.
109
127
  #
110
128
  class ReadTimeoutError < TimeoutError
111
129
  #
112
- # @return [Symbol] the action which timed out: +:read+
130
+ # @attribute [r] action
131
+ # @return [Symbol] the action which timed out: :read`
113
132
  #
114
133
  def action
115
134
  :read
@@ -117,11 +136,12 @@ class TCPClient
117
136
  end
118
137
 
119
138
  #
120
- # Raised by default whenever a {TCPClient.write} timed out.
139
+ # Raised by default whenever a {TCPClient#write} timed out.
121
140
  #
122
141
  class WriteTimeoutError < TimeoutError
123
142
  #
124
- # @return [Symbol] the action which timed out: +:write+
143
+ # @attribute [r] action
144
+ # @return [Symbol] the action which timed out: `:write`
125
145
  #
126
146
  def action
127
147
  :write
@@ -13,25 +13,30 @@ module IOWithDeadlineMixin # :nodoc:
13
13
  end
14
14
  end
15
15
 
16
- def read_with_deadline(bytes_to_read, deadline, exception)
16
+ def read_with_deadline(nbytes, deadline, exception)
17
17
  raise(exception) unless deadline.remaining_time
18
- if bytes_to_read.nil?
19
- return(
20
- with_deadline(deadline, exception) do
21
- read_nonblock(65_536, exception: false)
22
- end
23
- )
18
+ return fetch_avail(deadline, exception) if nbytes.nil?
19
+ return ''.b if nbytes.zero?
20
+ @buf ||= ''.b
21
+ while @buf.bytesize < nbytes
22
+ read = fetch_next(deadline, exception) and next @buf << read
23
+ close
24
+ break
24
25
  end
25
- result = ''.b
26
- while result.bytesize < bytes_to_read
27
- read =
28
- with_deadline(deadline, exception) do
29
- read_nonblock(bytes_to_read - result.bytesize, exception: false)
30
- end
31
- next result += read if read
26
+ fetch_buffer_slice(nbytes)
27
+ end
28
+
29
+ def readto_with_deadline(sep, deadline, exception)
30
+ raise(exception) unless deadline.remaining_time
31
+ @buf ||= ''.b
32
+ while (index = @buf.index(sep)).nil?
33
+ read = fetch_next(deadline, exception) and next @buf << read
32
34
  close
33
35
  break
34
36
  end
37
+ index = @buf.index(sep) and return fetch_buffer_slice(index + sep.bytesize)
38
+ result = @buf
39
+ @buf = nil
35
40
  result
36
41
  end
37
42
 
@@ -44,12 +49,37 @@ module IOWithDeadlineMixin # :nodoc:
44
49
  with_deadline(deadline, exception) do
45
50
  write_nonblock(data, exception: false)
46
51
  end
47
- result += written
48
- return result if result >= size
52
+ (result += written) >= size and return result
49
53
  data = data.byteslice(written, data.bytesize - written)
50
54
  end
51
55
  end
52
56
 
57
+ private
58
+
59
+ def fetch_avail(deadline, exception)
60
+ if @buf.nil?
61
+ result = fetch_next(deadline, exception) and return result
62
+ close
63
+ return ''.b
64
+ end
65
+ result = @buf
66
+ @buf = nil
67
+ result
68
+ end
69
+
70
+ def fetch_buffer_slice(size)
71
+ result = @buf.byteslice(0, size)
72
+ rest = @buf.bytesize - result.bytesize
73
+ @buf = rest.zero? ? nil : @buf.byteslice(size, rest)
74
+ result
75
+ end
76
+
77
+ def fetch_next(deadline, exception)
78
+ with_deadline(deadline, exception) do
79
+ read_nonblock(65_536, exception: false)
80
+ end
81
+ end
82
+
53
83
  module ViaWaitMethod
54
84
  private def with_deadline(deadline, exception)
55
85
  loop do
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class TCPClient
4
- #
5
- # The current gem version.
6
- #
7
- VERSION = '0.9.1'
4
+ # The current version number.
5
+ VERSION = '0.10.0'
8
6
  end
data/lib/tcp-client.rb CHANGED
@@ -15,71 +15,85 @@ require_relative 'tcp-client/version'
15
15
  # All connect/read/write actions can be monitored to ensure that all actions
16
16
  # terminate before given time limits - or raise an exception.
17
17
  #
18
- # @example - request to Google.com and limit all network interactions to 1.5 seconds
19
- # TCPClient.with_deadline(1.5, 'www.google.com:443') do |client|
20
- # client.write("GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n")
21
- # client.read(12)
22
- # end
23
- # # => "HTTP/1.1 200"
18
+ # @example request to Google.com and limit network interactions to 1.5 seconds
19
+ # # create a configuration to use at least TLS 1.2
20
+ # cfg = TCPClient::Configuration.create(ssl_params: {min_version: :TLS1_2})
24
21
  #
22
+ # response =
23
+ # TCPClient.with_deadline(1.5, 'www.google.com:443', cfg) do |client|
24
+ # client.write("GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n") #=> 40
25
+ # client.readline("\r\n\r\n") #=> see response
26
+ # end
27
+ # # response contains the returned message and header
25
28
  #
26
29
  class TCPClient
27
30
  #
28
31
  # Creates a new instance which is connected to the server on the given
29
- # address and uses the given or the {.default_configuration}.
32
+ # `address`.
33
+ #
34
+ # If no `configuration` is given, the {.default_configuration} will be used.
35
+ #
36
+ # @overload open(address, configuration = nil)
37
+ # @yieldparam client [TCPClient] the connected client
38
+ #
39
+ # @return [Object] the block result
40
+ #
41
+ # @overload open(address, configuration = nil)
42
+ # @return [TCPClient] the connected client
30
43
  #
31
44
  # If an optional block is given, then the block's result is returned and the
32
45
  # connection will be closed when the block execution ends.
33
- # This can be used to create an ad-hoc connection which is garanteed to be
46
+ # This can be used to create an ad-hoc connection which is guaranteed to be
34
47
  # closed.
35
48
  #
36
- # If no block is giiven the connected client instance is returned.
49
+ # If no block is given the connected client instance is returned.
37
50
  # This can be used as a shorthand to create & connect a client.
38
51
  #
39
- # @param address [Address, String, Addrinfo, Integer] the address to connect to, see {Address#initialize} for valid formats
40
- # @param configuration [Configuration] the {Configuration} to be used for this instance
41
- #
42
- # @yieldparam client [TCPClient] the connected client
43
- # @yieldreturn [Object] any result
44
- #
45
- # @return [Object, TCPClient] the block result or the connected client
52
+ # @param address [Address, String, Addrinfo, Integer] the target address see
53
+ # {Address#initialize} for valid formats
54
+ # @param configuration [Configuration] the {Configuration} to be used for
55
+ # the new instance
46
56
  #
47
57
  # @see #connect
48
58
  #
49
59
  def self.open(address, configuration = nil)
50
60
  client = new
51
- client.connect(Address.new(address), configuration)
61
+ client.connect(address, configuration)
52
62
  block_given? ? yield(client) : client
53
63
  ensure
54
64
  client.close if block_given?
55
65
  end
56
66
 
57
67
  #
58
- # Yields a new instance which is connected to the server on the given
59
- # address and uses the given or the {.default_configuration}.
60
- # It ensures to close the connection when the block execution ends.
61
- # It also limits all {#read} and {#write} actions within the block to a given
62
- # time.
68
+ # Yields an instance which is connected to the server on the given
69
+ # `address`. It limits all {#read} and {#write} actions within the block to
70
+ # the given time.
63
71
  #
64
- # This can be used to create an ad-hoc connection which is garanteed to be
65
- # closed and which read/write calls should not last longer than the timeout
66
- # limit.
72
+ # It ensures to close the connection when the block execution ends and returns
73
+ # the block's result.
67
74
  #
68
- # @param timeout [Numeric] maximum time in seconds for all {#read} and {#write} calls within the block
69
- # @param address [Address, String, Addrinfo, Integer] the address to connect to, see {Address#initialize} for valid formats
70
- # @param configuration [Configuration] the {Configuration} to be used for this instance
75
+ # This can be used to create an ad-hoc connection which is guaranteed to be
76
+ # closed and which {#read}/{#write} call sequence should not last longer than
77
+ # the `timeout` seconds.
78
+ #
79
+ # If no `configuration` is given, the {.default_configuration} will be used.
80
+ #
81
+ # @param timeout [Numeric] maximum time in seconds for all {#read} and
82
+ # {#write} calls within the block
83
+ # @param address [Address, String, Addrinfo, Integer] the target address see
84
+ # {Address#initialize} for valid formats
85
+ # @param configuration [Configuration] the {Configuration} to be used for
86
+ # the instance
71
87
  #
72
88
  # @yieldparam client [TCPClient] the connected client
73
- # @yieldreturn [Object] any result
74
89
  #
75
- # @return [Object] the block result
90
+ # @return [Object] the block's result
76
91
  #
77
92
  # @see #with_deadline
78
93
  #
79
94
  def self.with_deadline(timeout, address, configuration = nil)
80
95
  client = nil
81
96
  raise(NoBlockGivenError) unless block_given?
82
- address = Address.new(address)
83
97
  client = new
84
98
  client.with_deadline(timeout) do
85
99
  yield(client.connect(address, configuration))
@@ -89,89 +103,168 @@ class TCPClient
89
103
  end
90
104
 
91
105
  #
92
- # @return [Address] the address used for this client
106
+ # @return [Address] the address used by this client instance
93
107
  #
94
108
  attr_reader :address
95
109
 
96
110
  #
97
- # @return [Configuration] the configuration used by this client.
111
+ # @return [Configuration] the configuration used by this client instance
98
112
  #
99
113
  attr_reader :configuration
100
114
 
101
115
  #
102
- # @attribute [r] closed?
103
- # @return [Boolean] true when the connection is closed, false when connected
116
+ # @!parse attr_reader :closed?
117
+ # @return [Boolean] whether the connection is closed
104
118
  #
105
119
  def closed?
106
120
  @socket.nil? || @socket.closed?
107
121
  end
108
122
 
109
123
  #
110
- # @return [String] the currently used address as text.
124
+ # Close the current connection if connected.
111
125
  #
112
- # @see Address#to_s
126
+ # @return [TCPClient] itself
113
127
  #
114
- def to_s
115
- @address&.to_s || ''
128
+ def close
129
+ @socket&.close
130
+ self
131
+ rescue *NETWORK_ERRORS
132
+ self
133
+ ensure
134
+ @socket = @deadline = nil
116
135
  end
117
136
 
118
137
  #
119
- # Establishes a new connection to a given address.
138
+ # Establishes a new connection to a server on given `address`.
139
+ #
140
+ # It accepts a connection-specific `configuration` or uses the
141
+ # {.default_configuration}.
120
142
  #
121
- # It accepts a connection-specific configuration or uses the global {.default_configuration}. The {#configuration} used by this instance will
122
- # be a copy of the configuration used for this method call. This allows to
123
- # configure the behavior per connection.
143
+ # The optional `timeout` and `exception` parameters allow to override the
144
+ # `connect_timeout` and `connect_timeout_error` values.
124
145
  #
125
- # @param address [Address, String, Addrinfo, Integer] the address to connect to, see {Address#initialize} for valid formats
126
- # @param configuration [Configuration] the {Configuration} to be used for this instance
127
- # @param timeout [Numeric] maximum time in seconds to read; used to override the configuration's +connect_timeout+.
128
- # @param exception [Class] exception class to be used when the read timeout reached; used to override the configuration's +connect_timeout_error+.
146
+ # @param address [Address, String, Addrinfo, Integer] the target address, see
147
+ # {Address#initialize} for valid formats
148
+ # @param configuration [Configuration] the {Configuration} to be used for
149
+ # this instance
150
+ # @param timeout [Numeric] maximum time in seconds to connect
151
+ # @param exception [Class<Exception>] exception class to be used when the
152
+ # connect timeout reached
129
153
  #
130
- # @return [self]
154
+ # @return [TCPClient] itself
131
155
  #
132
156
  # @raise {NoOpenSSLError} if SSL should be used but OpenSSL is not avail
133
157
  #
158
+ # @see NetworkError
159
+ #
134
160
  def connect(address, configuration = nil, timeout: nil, exception: nil)
135
161
  close if @socket
136
- @address = Address.new(address)
137
162
  @configuration = (configuration || Configuration.default).dup
138
163
  raise(NoOpenSSLError) if @configuration.ssl? && !defined?(SSLSocket)
164
+ @address = stem_errors { Address.new(address) }
139
165
  @socket = create_socket(timeout, exception)
140
166
  self
141
167
  end
142
168
 
143
169
  #
144
- # Close the current connection.
170
+ # Flushes all internal buffers (write all buffered data).
145
171
  #
146
- # @return [self]
172
+ # @return [TCPClient] itself
147
173
  #
148
- def close
149
- @socket&.close
150
- self
151
- rescue *NETWORK_ERRORS
174
+ def flush
175
+ stem_errors { @socket&.flush }
152
176
  self
153
- ensure
154
- @socket = @deadline = nil
155
177
  end
156
178
 
157
179
  #
158
- # Executes a block with a given overall timeout.
180
+ # Read the given `nbytes` or the next available buffer from server.
181
+ #
182
+ # The optional `timeout` and `exception` parameters allow to override the
183
+ # `read_timeout` and `read_timeout_error` values of the used {#configuration}.
184
+ #
185
+ # @param nbytes [Integer] the number of bytes to read
186
+ # @param timeout [Numeric] maximum time in seconds to read
187
+ # @param exception [Class<Exception>] exception class to be used when the
188
+ # read timeout reached
189
+ #
190
+ # @return [String] the read buffer
191
+ #
192
+ # @raise [NotConnectedError] if {#connect} was not called before
193
+ #
194
+ # @see NetworkError
195
+ #
196
+ def read(nbytes = nil, timeout: nil, exception: nil)
197
+ raise(NotConnectedError) if closed?
198
+ deadline = create_deadline(timeout, configuration.read_timeout)
199
+ return stem_errors { @socket.read(nbytes) } unless deadline.valid?
200
+ exception ||= configuration.read_timeout_error
201
+ stem_errors(exception) do
202
+ @socket.read_with_deadline(nbytes, deadline, exception)
203
+ end
204
+ end
205
+
206
+ #
207
+ # Reads the next line from server.
208
+ #
209
+ # The standard record separator is used as `separator`.
159
210
  #
160
- # When you like to ensure that a complete read/write communication sequence
161
- # with the server is finished before a given amount of time you can use this
162
- # method to define such a deadline.
211
+ # The optional `timeout` and `exception` parameters allow to override the
212
+ # `read_timeout` and `read_timeout_error` values of the used {#configuration}.
163
213
  #
164
- # @example - ensure to send a welcome message and receive a 64 byte answer from server
214
+ # @param separator [String] the line separator to be used
215
+ # @param timeout [Numeric] maximum time in seconds to read
216
+ # @param exception [Class<Exception>] exception class to be used when the
217
+ # read timeout reached
218
+ #
219
+ # @return [String] the read line
220
+ #
221
+ # @raise [NotConnectedError] if {#connect} was not called before
222
+ #
223
+ # @see NetworkError
224
+ #
225
+ def readline(separator = $/, chomp: false, timeout: nil, exception: nil)
226
+ raise(NotConnectedError) if closed?
227
+ deadline = create_deadline(timeout, configuration.read_timeout)
228
+ unless deadline.valid?
229
+ return stem_errors { @socket.readline(separator, chomp: chomp) }
230
+ end
231
+ exception ||= configuration.read_timeout_error
232
+ line =
233
+ stem_errors(exception) do
234
+ @socket.readto_with_deadline(separator, deadline, exception)
235
+ end
236
+ chomp ? line.chomp : line
237
+ end
238
+
239
+ #
240
+ # @return [String] the currently used address as text.
241
+ #
242
+ # @see Address#to_s
243
+ #
244
+ def to_s
245
+ @address&.to_s || ''
246
+ end
247
+
248
+ #
249
+ # Executes a block with a given overall time limit.
250
+ #
251
+ # When you like to ensure that a complete {#read}/{#write} communication
252
+ # sequence with the server is finished before a given amount of time you use
253
+ # this method.
254
+ #
255
+ # @example ensure to send SMTP welcome message and receive a 4 byte answer
165
256
  # answer = client.with_deadline(2.5) do
166
- # client.write('Helo')
167
- # client.read(64)
257
+ # client.write('HELO')
258
+ # client.read(4)
168
259
  # end
260
+ # # answer is EHLO when server speaks fluent SMPT
169
261
  #
170
- # @param timeout [Numeric] maximum time in seconds for all {#read} and {#write} calls within the block
262
+ # @param timeout [Numeric] maximum time in seconds for all {#read} and
263
+ # {#write} calls within the block
171
264
  #
172
265
  # @yieldparam client [TCPClient] self
173
266
  #
174
- # @return [Object] result of the given block
267
+ # @return [Object] the block's result
175
268
  #
176
269
  # @raise [NoBlockGivenError] if the block is missing
177
270
  #
@@ -186,37 +279,23 @@ class TCPClient
186
279
  end
187
280
 
188
281
  #
189
- # Read the given nbytes or the next available buffer from server.
282
+ # Writes the given `messages` to the server.
190
283
  #
191
- # @param nbytes [Integer] the number of bytes to read
192
- # @param timeout [Numeric] maximum time in seconds to read; used to override the configuration's +read_timeout+.
193
- # @param exception [Class] exception class to be used when the read timeout reached; used to override the configuration's +read_timeout_error+.
284
+ # The optional `timeout` and `exception` parameters allow to override the
285
+ # `write_timeout` and `write_timeout_error` values of the used
286
+ # {#configuration}.
194
287
  #
195
- # @return [String] buffer read
196
- #
197
- # @raise [NotConnectedError] if {#connect} was not called before
198
- #
199
- def read(nbytes = nil, timeout: nil, exception: nil)
200
- raise(NotConnectedError) if closed?
201
- deadline = create_deadline(timeout, configuration.read_timeout)
202
- return stem_errors { @socket.read(nbytes) } unless deadline.valid?
203
- exception ||= configuration.read_timeout_error
204
- stem_errors(exception) do
205
- @socket.read_with_deadline(nbytes, deadline, exception)
206
- end
207
- end
208
-
209
- #
210
- # Write the given messages to the server.
211
- #
212
- # @param messages [Array<String>] messages to write
213
- # @param timeout [Numeric] maximum time in seconds to read; used to override the configuration's +write_timeout+.
214
- # @param exception [Class] exception class to be used when the read timeout reached; used to override the configuration's +write_timeout_error+.
288
+ # @param messages [Array<String>] one or more messages to write
289
+ # @param timeout [Numeric] maximum time in seconds to write
290
+ # @param exception [Class<Exception>] exception class to be used when the
291
+ # write timeout reached
215
292
  #
216
293
  # @return [Integer] bytes written
217
294
  #
218
295
  # @raise [NotConnectedError] if {#connect} was not called before
219
296
  #
297
+ # @see NetworkError
298
+ #
220
299
  def write(*messages, timeout: nil, exception: nil)
221
300
  raise(NotConnectedError) if closed?
222
301
  deadline = create_deadline(timeout, configuration.write_timeout)
@@ -229,16 +308,6 @@ class TCPClient
229
308
  end
230
309
  end
231
310
 
232
- #
233
- # Flush all internal buffers (write all through).
234
- #
235
- # @return [self]
236
- #
237
- def flush
238
- stem_errors { @socket&.flush }
239
- self
240
- end
241
-
242
311
  private
243
312
 
244
313
  def create_deadline(timeout, default)
data/rakefile.rb CHANGED
@@ -7,7 +7,12 @@ require 'yard'
7
7
 
8
8
  $stdout.sync = $stderr.sync = true
9
9
 
10
- CLOBBER << 'prj' << 'doc'
10
+ CLEAN << 'prj' << 'doc'
11
+
12
+ CLOBBER << '.yardoc'
13
+
11
14
  task(:default) { exec('rake --tasks') }
15
+
12
16
  RSpec::Core::RakeTask.new { |task| task.ruby_opts = %w[-w] }
17
+
13
18
  YARD::Rake::YardocTask.new { |task| task.stats_options = %w[--list-undoc] }
data/sample/google_ssl.rb CHANGED
@@ -18,8 +18,11 @@ cfg =
18
18
  # - limit all network interactions to 1.5 seconds
19
19
  # - use the Configuration cfg
20
20
  # - send a simple HTTP get request
21
- # - read 12 byte: "HTTP/1.1 " + 3 byte HTTP status code
22
- TCPClient.with_deadline(1.5, 'www.google.com:443', cfg) do |client|
23
- p client.write("GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n")
24
- p client.read(12)
25
- end
21
+ # - read the returned message and headers
22
+ response =
23
+ TCPClient.with_deadline(1.5, 'www.google.com:443', cfg) do |client|
24
+ client.write("GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n") #=> 40
25
+ client.readline("\r\n\r\n") #=> see response
26
+ end
27
+
28
+ puts(response)