excon 0.106.0 → 0.107.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f3ae04e066b4d9b67c48f71628596d7635894b7d003100ee91dc5c7ced3ee2bd
4
- data.tar.gz: 10eca55f616e0412fce96f9b779c7510467c8d38c5d823a0b19787e1127b1fbc
3
+ metadata.gz: d921bdb8ea062bd0633ce29f929a60027ba339f7c76f04d39863dcdece71c24d
4
+ data.tar.gz: d9673b03798fdbe67afdc797423b3038d683822fa7092c460797e7d67dde2185
5
5
  SHA512:
6
- metadata.gz: 2eb675d4e3e12987e942832c601eb0116e36f63c7104b4a52ffb3570edbbcc183ec350c925128bfd11aa66ad89437612570efe18c6b48fc037fcf246864336fa
7
- data.tar.gz: 41711db6ceef1e4342387b46b5e10fc76be60e519340862f945f26e5d8cacfeae7c18ba7e09471ac2b1811e4ec91402f4be4c8e13b70b0b54c45af3d3f6d4422
6
+ metadata.gz: 0f2e429edc9541f279484cefd15717f68168e5a84af9a46fd6cb133d43f5d1aa03dff4a6814d4e9f559acb65a152ae275690cbb2961a7967e9fc902b0636177f
7
+ data.tar.gz: 5996b697980f716744a97afaa7b13833618fda6a8cdab7fd7ad90cd363a4cf0c5d470f351b50bcb8fced514e51e46348618c5c4972693560806b4454fd1dbbcc
data/lib/excon/socket.rb CHANGED
@@ -53,14 +53,16 @@ module Excon
53
53
  @nonblock = data[:nonblock]
54
54
  @port ||= @data[:port] || 80
55
55
  @read_buffer = String.new
56
+ @read_offset = 0
56
57
  @eof = false
57
58
  @backend_eof = false
59
+
58
60
  connect
59
61
  end
60
62
 
61
63
  def read(max_length = nil)
62
64
  if @eof
63
- return max_length ? nil : ''
65
+ max_length ? nil : ''
64
66
  elsif @nonblock
65
67
  read_nonblock(max_length)
66
68
  else
@@ -71,20 +73,22 @@ module Excon
71
73
  def readline
72
74
  if @nonblock
73
75
  result = String.new
74
- block = @read_buffer
75
- @read_buffer = String.new
76
+ block = consume_read_buffer
76
77
 
77
78
  loop do
78
79
  idx = block.index("\n")
80
+
79
81
  if idx.nil?
80
82
  result << block
81
83
  else
82
- result << block.slice!(0, idx+1)
83
- add_to_read_buffer(block)
84
+ result << block[..idx]
85
+ rewind_read_buffer(block, idx)
84
86
  break
85
87
  end
88
+
86
89
  block = read_nonblock(@data[:chunk_size]) || raise(EOFError)
87
90
  end
91
+
88
92
  result
89
93
  else # nonblock/legacy
90
94
  begin
@@ -204,20 +208,48 @@ module Excon
204
208
  end
205
209
  end
206
210
 
207
- def add_to_read_buffer(str)
208
- @read_buffer << str
211
+ # Consume any bytes remaining in the read buffer before making a system call.
212
+ def consume_read_buffer
213
+ block = @read_buffer[@read_offset..]
214
+
215
+ @read_offset = @read_buffer.length
216
+
217
+ block
218
+ end
219
+
220
+ # Rewind the read buffer to just after the given index.
221
+ # The offset is moved back to the start of the current chunk and then forward until just after the index.
222
+ def rewind_read_buffer(chunk, idx)
223
+ @read_offset = @read_offset - chunk.length + (idx + 1)
209
224
  @eof = false
210
225
  end
211
226
 
212
227
  def read_nonblock(max_length)
213
228
  begin
229
+ if @read_offset != 0 && @read_offset >= @read_buffer.length
230
+ # Clear the buffer so we can test for emptiness below
231
+ @read_buffer.clear
232
+ # Reset the offset so it matches the length of the buffer when empty.
233
+ @read_offset = 0
234
+ end
235
+
214
236
  if max_length
215
- until @backend_eof || @read_buffer.length >= max_length
216
- @read_buffer << @socket.read_nonblock(max_length - @read_buffer.length)
237
+ until @backend_eof || readable_bytes >= max_length
238
+ if @read_buffer.empty?
239
+ # Avoid allocating a new buffer string when the read buffer is empty
240
+ @read_buffer = @socket.read_nonblock(max_length, @read_buffer)
241
+ else
242
+ @read_buffer << @socket.read_nonblock(max_length - readable_bytes)
243
+ end
217
244
  end
218
245
  else
219
- while !@backend_eof
220
- @read_buffer << @socket.read_nonblock(@data[:chunk_size])
246
+ until @backend_eof
247
+ if @read_buffer.empty?
248
+ # Avoid allocating a new buffer string when the read buffer is empty
249
+ @read_buffer = @socket.read_nonblock(@data[:chunk_size], @read_buffer)
250
+ else
251
+ @read_buffer << @socket.read_nonblock(@data[:chunk_size])
252
+ end
221
253
  end
222
254
  end
223
255
  rescue OpenSSL::SSL::SSLError => error
@@ -237,18 +269,32 @@ module Excon
237
269
  @backend_eof = true
238
270
  end
239
271
 
240
- ret = if max_length
272
+ if max_length
241
273
  if @read_buffer.empty?
242
- nil # EOF met at beginning
274
+ # EOF met at beginning
275
+ @eof = @backend_eof
276
+ nil
243
277
  else
244
- @read_buffer.slice!(0, max_length)
278
+ start = @read_offset
279
+
280
+ # Ensure that we can seek backwards when reading until a terminator string.
281
+ # The read offset must never point past the end of the read buffer.
282
+ @read_offset += max_length > readable_bytes ? readable_bytes : max_length
283
+ @read_buffer[start...@read_offset]
245
284
  end
246
285
  else
247
286
  # read until EOFError, so return everything
248
- @read_buffer.slice!(0, @read_buffer.length)
287
+ start = @read_offset
288
+
289
+ @read_offset = @read_buffer.length
290
+ @eof = @backend_eof
291
+
292
+ @read_buffer[start..]
249
293
  end
250
- @eof = @backend_eof && @read_buffer.empty?
251
- ret
294
+ end
295
+
296
+ def readable_bytes
297
+ @read_buffer.length - @read_offset
252
298
  end
253
299
 
254
300
  def read_block(max_length)
@@ -353,7 +399,7 @@ module Excon
353
399
  def request_time_remaining
354
400
  now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
355
401
  deadline = @data[:deadline]
356
-
402
+
357
403
  raise(Excon::Errors::Timeout.new('request timeout reached')) if now >= deadline
358
404
 
359
405
  deadline - now
data/lib/excon/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Excon
4
- VERSION = '0.106.0'
4
+ VERSION = '0.107.0'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: excon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.106.0
4
+ version: 0.107.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - dpiddy (Dan Peterson)
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2023-12-13 00:00:00.000000000 Z
13
+ date: 2023-12-15 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rspec