http_streaming_client 0.8.11 → 0.9.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bad5818f3b5c3df8b92149668be7618937a5ab38
4
- data.tar.gz: bd4781fb0f3a4d79469ebaa4687db83bf795eb31
3
+ metadata.gz: d5b7c831d1e6fc8a96a13ddf7966f34da78fd5d2
4
+ data.tar.gz: b73177edd8c134f63d5cc45fd7e0607a6e6d792a
5
5
  SHA512:
6
- metadata.gz: 9991fdf019ed5302bff0d160140034eb728eca8c0ddbae6855d47e742edfe67b4b1c46c51aeaa41804c043bdda0692f4c48a0d7c72d40ffb7db131c725113afd
7
- data.tar.gz: 3862ea3aaa235b50a5d9d2b1928188ca394ebaa260484805bd085ab0e71aed7e3b45115c442972bf3985380c1c6fbab79e689e09334dbfc905d008131d0e17d4
6
+ metadata.gz: db040d0205a52db9e8677a6d1ff66c226fbb7c516f688ba01513ddeb5c6b7d7493981c50ef990cc3b42503583b536482e3efb5b04813cb47ae86c6021d81b057
7
+ data.tar.gz: 956e0283d6173983c79b364b212fc3a403c958ca409b8b2c4545a828dba2dd831ac496b2a451fe081c47416d9110e5efe3bc92e61b568c22d8a489f17c8249d3
data/CHANGELOG CHANGED
@@ -1,3 +1,8 @@
1
+ http_streaming_client 0.9.0 (04.28.2014)
2
+ ========================================
3
+ * Tested and fixed for MRI ruby-2.0.0-p451 and JRuby jruby-1.7.12
4
+ * Fixed chunked encoding support handler, support for gzip'd blocks spanning chunks
5
+
1
6
  http_streaming_client 0.8.11 ()
2
7
  ========================================
3
8
  * Fixed warn logging for non-200 HTTP response codes
data/README.md CHANGED
@@ -7,7 +7,7 @@ Ruby HTTP client with support for HTTP 1.1 streaming, GZIP and zlib compressed s
7
7
 
8
8
  ## Ruby Version
9
9
 
10
- MRI ruby-2.0.0-p353. If you need it, install via rvm: https://rvm.io/
10
+ MRI ruby-2.0.0-p451 and JRuby jruby-1.7.12. Install via rvm: https://rvm.io/
11
11
 
12
12
  ## Installation
13
13
 
@@ -35,6 +35,7 @@ require "http_streaming_client/version"
35
35
  require "http_streaming_client/custom_logger"
36
36
  require "http_streaming_client/errors"
37
37
  require "http_streaming_client/decoders/gzip"
38
+ require "http_streaming_client/decoders/chunked"
38
39
 
39
40
  module HttpStreamingClient
40
41
 
@@ -231,7 +232,7 @@ module HttpStreamingClient
231
232
  response = ""
232
233
 
233
234
  if response_compression then
234
- logger.debug "response compression detected"
235
+ logger.debug "chunked transfer encoding with compression detected"
235
236
  if block_given? then
236
237
  decoder = HttpStreamingClient::Decoders::GZip.new { |line|
237
238
  logger.debug "read #{line.size} uncompressed bytes, decoder queue bytes:#{decoder.size}"
@@ -241,6 +242,17 @@ module HttpStreamingClient
241
242
  logger.debug "read #{line.size} uncompressed bytes, #{response.size} bytes total, decoder queue bytes:#{decoder.size}"
242
243
  response << line unless @interrupted }
243
244
  end
245
+ else
246
+ logger.debug "chunked transfer encoding with no compression detected"
247
+ if block_given? then
248
+ decoder = HttpStreamingClient::Decoders::Chunked.new { |line|
249
+ logger.debug "read #{line.size} uncompressed bytes, decoder queue bytes:#{decoder.size}"
250
+ block.call(line) unless @interrupted }
251
+ else
252
+ decoder = HttpStreamingClient::Decoders::Chunked.new { |line|
253
+ logger.debug "read #{line.size} uncompressed bytes, #{response.size} bytes total, decoder queue bytes:#{decoder.size}"
254
+ response << line unless @interrupted }
255
+ end
244
256
  end
245
257
 
246
258
  while !socket.eof? && (line = socket.gets)
@@ -268,19 +280,16 @@ module HttpStreamingClient
268
280
  logger.debug "read #{partial.size} bytes, #{remaining} bytes remaining"
269
281
  end
270
282
 
271
- if response_compression then
272
- return if @interrupted
273
- decoder << partial
283
+ decoder << partial
284
+
285
+ if !block_given? then
286
+ logger.debug "no block specified, returning chunk results and halting streaming response"
287
+ return response
274
288
  else
275
- if block_given? then
276
- yield partial
277
- else
278
- return response if @interrupted
279
- logger.debug "no block specified, returning chunk results and halting streaming response"
280
- response << partial
281
- return response
282
- end
289
+ return if @interrupted and response_compression
290
+ return response if @interrupted
283
291
  end
292
+
284
293
  end
285
294
 
286
295
  logger.debug "socket EOF detected" if socket.eof?
@@ -0,0 +1,98 @@
1
+ ###########################################################################
2
+ ##
3
+ ## http_streaming_client
4
+ ##
5
+ ## Ruby HTTP client with support for HTTP 1.1 streaming, GZIP compressed
6
+ ## streams, and chunked transfer encoding. Includes extensible OAuth
7
+ ## support for the Adobe Analytics Firehose and Twitter Streaming APIs.
8
+ ##
9
+ ## David Tompkins -- 4/25/2014
10
+ ## tompkins@adobe_dot_com
11
+ ##
12
+ ###########################################################################
13
+ ##
14
+ ## Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved.
15
+ ##
16
+ ## Licensed under the Apache License, Version 2.0 (the "License");
17
+ ## you may not use this file except in compliance with the License.
18
+ ## You may obtain a copy of the License at
19
+ ##
20
+ ## http://www.apache.org/licenses/LICENSE-2.0
21
+ ##
22
+ ## Unless required by applicable law or agreed to in writing, software
23
+ ## distributed under the License is distributed on an "AS IS" BASIS,
24
+ ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25
+ ## See the License for the specific language governing permissions and
26
+ ## limitations under the License.
27
+ ##
28
+ ###########################################################################
29
+
30
+ require "http_streaming_client/errors"
31
+
32
+ module HttpStreamingClient
33
+
34
+ module Decoders
35
+
36
+ class Chunked
37
+
38
+ def logger
39
+ HttpStreamingClient.logger
40
+ end
41
+
42
+ def initialize(&packet_callback)
43
+ logger.debug "Chunked:initialize"
44
+ @packet_callback = packet_callback
45
+ end
46
+
47
+ def <<(chunk)
48
+ return unless chunk && chunk.size > 0
49
+ chunk_io = StringIO.new(chunk)
50
+ while true
51
+ line = nonblock_readline(chunk_io)
52
+ break if line.nil?
53
+ process_line(line)
54
+ end
55
+ end
56
+
57
+ def size
58
+ logger.debug "Chunked:size"
59
+ return @line_buffer.size unless @line_buffer.nil?
60
+ return 0
61
+ end
62
+
63
+ def close
64
+ logger.debug "Chunked:close"
65
+ end
66
+
67
+ protected
68
+
69
+ def nonblock_readline(io)
70
+ @line_buffer ||= ""
71
+ ch = nil
72
+ begin
73
+ while ch = io.getc
74
+ @line_buffer += ch
75
+ if ch == "\n" then
76
+ result = @line_buffer
77
+ @line_buffer = ""
78
+ return result
79
+ end
80
+ end
81
+ rescue => e
82
+ logger.debug "nonblock_readline:error received:#{e.class}:#{e}"
83
+ return nil
84
+ end
85
+ end
86
+
87
+ private
88
+
89
+ def process_line(line)
90
+ logger.debug "Chunked:process_line:size:#{line.nil? ? "nil" : line.size}"
91
+ if line && line.size > 0
92
+ @packet_callback.call(line) unless @packet_callback.nil?
93
+ end
94
+ end
95
+
96
+ end
97
+ end
98
+ end
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  ###########################################################################
2
4
  ##
3
5
  ## http_streaming_client
@@ -37,6 +39,14 @@ module HttpStreamingClient
37
39
 
38
40
  class GZip
39
41
 
42
+ if defined?(JRUBY_VERSION) then
43
+ # JRuby: pass at least 8k bytes to GzipReader to avoid zlib EOF
44
+ GZIP_READER_MIN_BUF_SIZE = 8192
45
+ else
46
+ # MRI: pass at least 2k bytes to GzipReader to avoid zlib EOF
47
+ GZIP_READER_MIN_BUF_SIZE = 2048
48
+ end
49
+
40
50
  def logger
41
51
  HttpStreamingClient.logger
42
52
  end
@@ -46,37 +56,19 @@ module HttpStreamingClient
46
56
  @packet_callback = packet_callback
47
57
  end
48
58
 
49
- def nonblock_readline(io)
50
- @line_buffer ||= ""
51
- ch = nil
52
- begin
53
- while ch = io.getc
54
- @line_buffer += ch
55
- if ch == "\n" then
56
- result = @line_buffer
57
- @line_buffer = ""
58
- return result
59
- end
60
- end
61
- rescue Zlib::GzipFile::Error
62
- # this is raised on EOF by ZLib, return nil to indicate EOF and leave partial line in the buffer
63
- return nil
64
- end
65
- end
66
-
67
59
  def <<(compressed_packet)
68
60
  return unless compressed_packet && compressed_packet.size > 0
69
61
  @buf ||= GZipBufferIO.new
70
62
  @buf << compressed_packet
71
63
 
72
- # pass at least 2k bytes to GzipReader to avoid zlib EOF
73
- if @buf.size > 2048 then
64
+ # pass at least GZIP_READER_MIN_BUF_SIZE bytes to GzipReader to avoid zlib EOF
65
+ if @buf.size > GZIP_READER_MIN_BUF_SIZE then
74
66
 
75
67
  @gzip ||= Zlib::GzipReader.new @buf
76
68
 
77
69
  while true do
78
70
  decompressed_packet = nonblock_readline(@gzip)
79
- #logger.debug "decompressed_packet:#{decompressed_packet}"
71
+ #logger.debug "GZip:<<:decompressed_packet:#{decompressed_packet}"
80
72
  break if decompressed_packet.nil?
81
73
  process_decompressed_packet(decompressed_packet)
82
74
  end
@@ -91,7 +83,7 @@ module HttpStreamingClient
91
83
 
92
84
  while true do
93
85
  decompressed_packet = nonblock_readline(@gzip)
94
- #logger.debug "decompressed_packet:#{decompressed_packet}"
86
+ #logger.debug "GZip:close:decompressed_packet:#{decompressed_packet}"
95
87
  break if decompressed_packet.nil?
96
88
  process_decompressed_packet(decompressed_packet)
97
89
  end
@@ -100,14 +92,40 @@ module HttpStreamingClient
100
92
  raise HttpStreamingClient::DecoderError.new(e.message)
101
93
  end
102
94
  end
103
-
95
+
104
96
  def size
105
97
  @buf.size
106
98
  end
107
99
 
100
+ def nonblock_readline(io)
101
+ @line_buffer ||= ""
102
+ ch = nil
103
+ begin
104
+ while ch = io.getc
105
+ @line_buffer += ch
106
+ if ch == "\n" then
107
+ result = @line_buffer
108
+ @line_buffer = ""
109
+ return result
110
+ end
111
+ end
112
+ rescue Zlib::GzipFile::Error
113
+ # this is raised on EOF by ZLib in MRI, return nil to indicate EOF and leave partial line in the buffer
114
+ logger.debug "Gzip:nonblock_readline:Zlib::GzipFile::Error:line_buffer.size:#{@line_buffer.size}"
115
+ return nil
116
+ rescue IOError
117
+ # this is raised on EOF by ZLib in JRuby, return nil to indicate EOF and leave partial line in the buffer
118
+ logger.debug "Gzip:nonblock_readline:IOError:line_buffer.size:#{@line_buffer.size}"
119
+ return nil
120
+ rescue => e
121
+ logger.debug "Gzip:nonblock_readline:error received:#{e.class}:#{e}"
122
+ raise e
123
+ end
124
+ end
125
+
108
126
  protected
109
127
 
110
- class GZipBufferIO < IO
128
+ class GZipBufferIO < StringIO
111
129
 
112
130
  def logger
113
131
  HttpStreamingClient.logger
@@ -116,6 +134,7 @@ module HttpStreamingClient
116
134
  def initialize(string="")
117
135
  logger.debug "GZipBufferIO:initialize"
118
136
  @packet_stream = string
137
+ @packet_stream.force_encoding("BINARY")
119
138
  end
120
139
 
121
140
  def <<(string)
@@ -124,7 +143,7 @@ module HttpStreamingClient
124
143
 
125
144
  # called by GzipReader
126
145
  def readpartial(length=nil, buffer=nil)
127
- logger.debug "GZipBufferIO:readpartial:length:#{length}:@packet_stream:#{@packet_stream.nil? ? 'nil' : 'not null'}"
146
+ logger.debug "GZipBufferIO:readpartial:length:#{length}:@packet_stream:#{@packet_stream.nil? ? 'nil' : @packet_stream.size}"
128
147
  buffer ||= ""
129
148
 
130
149
  raise EOFError "" if @packet_stream.size == 0
@@ -150,14 +169,14 @@ module HttpStreamingClient
150
169
 
151
170
  # called by GzipReader
152
171
  def read(length=nil, buffer=nil)
153
- logger.debug "read:length:#{length}"
172
+ logger.debug "GZipBufferIO:read:length:#{length}"
154
173
  return nil if @packet_stream.size == 0
155
174
  readpartial(length, buffer)
156
175
  end
157
176
 
158
177
  # called by GzipReader
159
178
  def size
160
- logger.debug "size():#{@packet_stream.size}"
179
+ logger.debug "GZipBufferIO:size():#{@packet_stream.size}"
161
180
  @packet_stream.size
162
181
  end
163
182
  end
@@ -28,5 +28,5 @@
28
28
  ###########################################################################
29
29
 
30
30
  module HttpStreamingClient
31
- VERSION = "0.8.11"
31
+ VERSION = "0.9.0"
32
32
  end
@@ -5,8 +5,8 @@ describe HttpStreamingClient do
5
5
 
6
6
  # currently disabled, requires a server that can be killed to simulate dropped connections
7
7
 
8
- it "should receive exactly 10 messages, no reconnect" do
9
- #it "should receive exactly 10 messages, no reconnect", :disabled => true do
8
+ #it "should receive exactly 10 messages, no reconnect" do
9
+ it "should receive exactly 10 messages, no reconnect", :disabled => true do
10
10
 
11
11
  count = 0
12
12
  client = HttpStreamingClient::Client.new(compression: false)
@@ -18,7 +18,8 @@ describe HttpStreamingClient do
18
18
  expect(count).to be(10)
19
19
  end
20
20
 
21
- it "should reconnect on any error or EOF" do
21
+ #it "should reconnect on any error or EOF" do
22
+ it "should reconnect on any error or EOF", :disabled => true do
22
23
 
23
24
  client = HttpStreamingClient::Client.new(compression: false, reconnect: true, reconnect_attempts: 5, reconnect_interval: 1)
24
25
  count = 0
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: http_streaming_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.11
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Tompkins
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-01-29 00:00:00.000000000 Z
11
+ date: 2014-04-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -117,6 +117,7 @@ files:
117
117
  - lib/http_streaming_client/credentials/adobe.rb.sample
118
118
  - lib/http_streaming_client/credentials/twitter.rb.sample
119
119
  - lib/http_streaming_client/custom_logger.rb
120
+ - lib/http_streaming_client/decoders/chunked.rb
120
121
  - lib/http_streaming_client/decoders/gzip.rb
121
122
  - lib/http_streaming_client/errors.rb
122
123
  - lib/http_streaming_client/oauth.rb