ld-eventsource 1.0.3 → 2.1.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
- SHA1:
3
- metadata.gz: 8af7db395f6a4a500ea56ff3f742aab25b8ca416
4
- data.tar.gz: ee59c90efdf456e277a6f6ea7209a62941dbe96b
2
+ SHA256:
3
+ metadata.gz: e62fdcf615bb0c699746e63a929e5eb582b8680cf873659d2be9e7e018fb0a89
4
+ data.tar.gz: f5f2b5694a3049e4f5dc2fd5f49de948ab6a8d040151d506a5589b0da4bca0f6
5
5
  SHA512:
6
- metadata.gz: 3c1c5e63d0f8bcff6c27a60f9a8cb04f5d1ffc3e4128bc5d9822f19663934b70ab3f90725ba747b4e13cc77c154c8d23605ed677c392dab980fd56c3d87d8cef
7
- data.tar.gz: eec5bfce676d858bca4d8c687c043d45f2e200d3fb8819d693e81812e5504f597fcbed9bbe011d29f4aba967ee17de1e1302b3b673fbb5d2b9af03ba6558a823
6
+ metadata.gz: dd8ec3f6a4719860f1bf32bef767917a6b97753b8c9eb060c5478fa93b9115c3090313d5cfe4d00137dd1f764cb4bdfb3af000246718dd446691912f4c17ee1d
7
+ data.tar.gz: 23a6178d006572791caddbfb372bd9a4c68c5e9f32c272c7b3230008698744e973fcecee8d51b2bfc5471ba99f18190b95e0f074307b77dee81d1274b0416d07
data/.circleci/config.yml CHANGED
@@ -1,92 +1,39 @@
1
- version: 2
2
-
1
+ # This CircleCI configuration was generated by Releaser for a specific release. It is not to be used
2
+ # for regular CI builds. Be aware that rerunning this build may cause it to repeat release actions
3
+ # such as publishing to a package manager. However, it will not perform any Git actions other than
4
+ # reading the repository.
5
+ version: 2.1
3
6
  workflows:
4
- version: 2
5
7
  test:
6
8
  jobs:
7
- - test-misc-rubies
8
- - test-2.2
9
- - test-2.3
10
- - test-2.4
11
- - test-2.5
12
- - test-jruby-9.2
13
-
14
- ruby-docker-template: &ruby-docker-template
15
- steps:
16
- - checkout
17
- - run: |
18
- if [[ $CIRCLE_JOB == test-jruby* ]]; then
19
- gem install jruby-openssl; # required by bundler, no effect on Ruby MRI
20
- fi
21
- - run: ruby -v
22
- - run: gem install bundler -v "~> 1.17"
23
- - run: bundle install
24
- - run: mkdir ./rspec
25
- - run: bundle exec rspec --format progress --format RspecJunitFormatter -o ./rspec/rspec.xml spec
26
- - store_test_results:
27
- path: ./rspec
28
- - store_artifacts:
29
- path: ./rspec
30
-
9
+ - release_linux:
10
+ context: org-global
31
11
  jobs:
32
- test-2.2:
33
- <<: *ruby-docker-template
12
+ release_linux:
34
13
  docker:
35
- - image: circleci/ruby:2.2.10-jessie
36
- test-2.3:
37
- <<: *ruby-docker-template
38
- docker:
39
- - image: circleci/ruby:2.3.7-jessie
40
- test-2.4:
41
- <<: *ruby-docker-template
42
- docker:
43
- - image: circleci/ruby:2.4.5-stretch
44
- test-2.5:
45
- <<: *ruby-docker-template
46
- docker:
47
- - image: circleci/ruby:2.5.3-stretch
48
- test-jruby-9.2:
49
- <<: *ruby-docker-template
50
- docker:
51
- - image: circleci/jruby:9-jdk
52
-
53
- # The following very slow job uses an Ubuntu container to run the Ruby versions that
54
- # CircleCI doesn't provide Docker images for.
55
- test-misc-rubies:
56
- machine:
57
- image: circleci/classic:latest
14
+ - image: cimg/ruby:2.5
58
15
  environment:
59
- - RUBIES: "jruby-9.1.17.0"
16
+ LD_RELEASE_CIRCLECI_TYPE: linux
17
+ LD_RELEASE_BRANCH: "master"
18
+ LD_RELEASE_CIRCLECI_BRANCH: ""
19
+ LD_RELEASE_DOCS_GITHUB_PAGES: ""
20
+ LD_RELEASE_DOCS_TITLE: ""
21
+ LD_RELEASE_PROJECT: "ruby-eventsource"
22
+ LD_RELEASE_PROJECT_TEMPLATE: "ruby"
23
+ LD_RELEASE_VERSION: "2.1.0"
60
24
  steps:
61
25
  - checkout
62
26
  - run:
63
- name: install all Ruby versions
64
- command: "parallel rvm install ::: $RUBIES"
27
+ name: "Releaser: prepare"
28
+ command: .ldrelease/circleci/mac/execute.sh prepare .ldrelease/circleci/template/prepare.sh
29
+ - run:
30
+ name: "Releaser: build"
31
+ command: .ldrelease/circleci/mac/execute.sh build .ldrelease/circleci/template/build.sh
65
32
  - run:
66
- name: bundle install for all versions
67
- shell: /bin/bash -leo pipefail # need -l in order for "rvm use" to work
68
- command: |
69
- set -e;
70
- for i in $RUBIES;
71
- do
72
- rvm use $i;
73
- if [[ $i == jruby* ]]; then
74
- gem install jruby-openssl; # required by bundler, no effect on Ruby MRI
75
- fi;
76
- # bundler 2.0 may be preinstalled, we need to remove it if so
77
- yes | gem uninstall bundler --version '>=2.0' || true;
78
- gem install bundler -v "~> 1.17";
79
- bundle install;
80
- mv Gemfile.lock "Gemfile.lock.$i"
81
- done
33
+ name: "Releaser: test"
34
+ command: .ldrelease/circleci/mac/execute.sh test .ldrelease/circleci/template/test.sh
82
35
  - run:
83
- name: run tests for all versions
84
- shell: /bin/bash -leo pipefail
85
- command: |
86
- set -e;
87
- for i in $RUBIES;
88
- do
89
- rvm use $i;
90
- cp "Gemfile.lock.$i" Gemfile.lock;
91
- bundle exec rspec spec;
92
- done
36
+ name: "Releaser: publish"
37
+ command: .ldrelease/circleci/mac/execute.sh publish .ldrelease/circleci/template/publish.sh
38
+ - store_artifacts:
39
+ path: artifacts
data/.gitignore CHANGED
@@ -13,3 +13,5 @@
13
13
  mkmf.log
14
14
  *.gem
15
15
  .DS_Store
16
+ rspec
17
+ Gemfile.lock
@@ -0,0 +1,18 @@
1
+ #!/bin/bash
2
+
3
+ set -ue
4
+
5
+ # Performs a delegated release step in a CircleCI Linux container. This mechanism is described
6
+ # in scripts/circleci/README.md. All of the necessary environment variables should already be
7
+ # in the generated CircleCI configuration.
8
+
9
+ mkdir -p artifacts
10
+
11
+ export LD_RELEASE_TEMP_DIR=/tmp/project-releaser-temp
12
+ mkdir -p ${LD_RELEASE_TEMP_DIR}
13
+
14
+ STEP="$1"
15
+ SCRIPT="$2"
16
+ echo
17
+ echo "[${STEP}] executing ${SCRIPT}"
18
+ "./${SCRIPT}"
@@ -0,0 +1,18 @@
1
+ #!/bin/bash
2
+
3
+ set -ue
4
+
5
+ # Performs a delegated release step in a CircleCI Mac container. This mechanism is described
6
+ # in scripts/circleci/README.md. All of the necessary environment variables should already be
7
+ # in the generated CircleCI configuration.
8
+
9
+ mkdir -p artifacts
10
+
11
+ export LD_RELEASE_TEMP_DIR=/tmp/project-releaser-temp
12
+ mkdir -p ${LD_RELEASE_TEMP_DIR}
13
+
14
+ STEP="$1"
15
+ SCRIPT="$2"
16
+ echo
17
+ echo "[${STEP}] executing ${SCRIPT}"
18
+ "./${SCRIPT}"
@@ -0,0 +1,19 @@
1
+ #!/bin/bash
2
+
3
+ set -ue
4
+
5
+ # Standard build.sh for Ruby-based projects that publish a gem
6
+
7
+ echo "Using gem $(gem --version)"
8
+
9
+ #shellcheck source=/dev/null
10
+ source "$(dirname "$0")/gems-setup.sh"
11
+
12
+ echo; echo "Installing dependencies"
13
+ ${BUNDLER_COMMAND} install
14
+
15
+ # Build Ruby Gem - this assumes there is a single .gemspec file in the main project directory
16
+ # Note that the gemspec must be able to get the project version either from $LD_RELEASE_VERSION,
17
+ # or from somewhere in the source code that the project-specific update-version.sh has updated.
18
+ echo "Running gem build"
19
+ gem build ./*.gemspec || { echo "gem build failed" >&2; exit 1; }
@@ -0,0 +1,16 @@
1
+ #!/bin/bash
2
+
3
+ # helper script to set GEM_HOME, PATH, and BUNDLER_COMMAND for Ruby - must be sourced, not executed
4
+
5
+ mkdir -p "${LD_RELEASE_TEMP_DIR}/gems"
6
+ export GEM_HOME="${LD_RELEASE_TEMP_DIR}/gems"
7
+ export PATH="${GEM_HOME}/bin:${PATH}"
8
+
9
+ # also, determine whether we'll need to run a specific version of Bundler
10
+
11
+ GEMSPEC_BUNDLER_VERSION=$(sed -n -e "s/.*['\"]bundler['\"], *['\"]\([^'\"]*\)['\"]/\1/p" ./*.gemspec | tr -d ' ')
12
+ if [ -n "${GEMSPEC_BUNDLER_VERSION}" ]; then
13
+ BUNDLER_COMMAND="bundler _${GEMSPEC_BUNDLER_VERSION}_"
14
+ else
15
+ BUNDLER_COMMAND="bundler"
16
+ fi
@@ -0,0 +1,17 @@
1
+ #!/bin/bash
2
+
3
+ set -ue
4
+
5
+ echo "Using gem $(gem --version)"
6
+
7
+ #shellcheck source=/dev/null
8
+ source "$(dirname "$0")/gems-setup.sh"
9
+
10
+ # If the gemspec specifies a certain version of bundler, we need to make sure we install that version.
11
+ echo "Installing bundler"
12
+ if [ -n "${GEMSPEC_BUNDLER_VERSION:-}" ]; then
13
+ GEMSPEC_OPTIONS="-v ${GEMSPEC_BUNDLER_VERSION}"
14
+ else
15
+ GEMSPEC_OPTIONS=""
16
+ fi
17
+ gem install bundler ${GEMSPEC_OPTIONS} || { echo "installing bundler failed" >&2; exit 1; }
@@ -0,0 +1,19 @@
1
+ #!/bin/bash
2
+
3
+ set -ue
4
+
5
+ # Standard publish.sh for Ruby-based projects - we can assume build.sh has already been run
6
+
7
+ #shellcheck source=/dev/null
8
+ source "$(dirname "$0")/gems-setup.sh"
9
+
10
+ # If we're running in CircleCI, the RubyGems credentials will be in an environment
11
+ # variable and should be copied to the variable the gem command expects
12
+ if [ -n "${LD_RELEASE_RUBYGEMS_API_KEY:-}" ]; then
13
+ export GEM_HOST_API_KEY="${LD_RELEASE_RUBYGEMS_API_KEY}"
14
+ fi
15
+
16
+ # Since all Releaser builds are clean builds, we can assume that the only .gem file here
17
+ # is the one we just built
18
+ echo "Running gem push"
19
+ gem push ./*.gem || { echo "gem push failed" >&2; exit 1; }
@@ -0,0 +1,10 @@
1
+ #!/bin/bash
2
+
3
+ set -ue
4
+
5
+ # Standard test.sh for Ruby-based projects
6
+
7
+ #shellcheck source=/dev/null
8
+ source "$(dirname "$0")/gems-setup.sh"
9
+
10
+ ${BUNDLER_COMMAND} exec rspec spec
@@ -0,0 +1,8 @@
1
+ #!/bin/bash
2
+
3
+ set -ue
4
+
5
+ # Standard update-version.sh for Ruby-based projects - this will work only if the version string
6
+ # is in a source file under lib/ that has a line like his: VERSION = "2.0.0"
7
+
8
+ "$(dirname "$0")/../update-version-constant.sh" lib '*.rb'
@@ -0,0 +1,19 @@
1
+ param(
2
+ [string]$step,
3
+ [string]$script
4
+ )
5
+
6
+ # Performs a delegated release step in a CircleCI Windows container using PowerShell. This
7
+ # mechanism is described in scripts/circleci/README.md. All of the necessary environment
8
+ # variables should already be in the generated CircleCI configuration.
9
+
10
+ $ErrorActionPreference = "Stop"
11
+
12
+ New-Item -Path "./artifacts" -ItemType "directory" -Force | Out-Null
13
+
14
+ $env:LD_RELEASE_TEMP_DIR = "$env:TEMP\project-releaser-temp"
15
+ New-Item -Path $env:LD_RELEASE_TEMP_DIR -ItemType "directory" -Force | Out-Null
16
+
17
+ Write-Host
18
+ Write-Host "[$step] executing $script"
19
+ & "./$script"
@@ -1,3 +1,5 @@
1
+ repo:
2
+ public: ruby-eventsource
1
3
 
2
4
  publications:
3
5
  - url: https://rubygems.org/gems/ld-eventsource
@@ -5,5 +7,16 @@ publications:
5
7
  - url: https://www.rubydoc.info/gems/ld-eventsource
6
8
  description: documentation
7
9
 
10
+ releasableBranches:
11
+ - name: master
12
+ description: 2.x - based on the http gem
13
+ - name: 1.x
14
+ description: 1.x - based on the socketry gem
15
+
16
+ circleci:
17
+ linux:
18
+ image: cimg/ruby:2.5
19
+ context: org-global
20
+
8
21
  template:
9
22
  name: ruby
data/CHANGELOG.md CHANGED
@@ -2,6 +2,25 @@
2
2
 
3
3
  All notable changes to the LaunchDarkly SSE Client for Ruby will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org).
4
4
 
5
+ ## [2.0.1] - 2021-08-10
6
+ ### Changed:
7
+ - The dependency version constraint for the `http` gem is now looser: it allows 5.x versions as well as 4.x. The breaking changes in `http` v5.0.0 do not affect `ld-eventsource`.
8
+ - The project&#39;s build now uses v2.2.10 of `bundler` due to known vulnerabilities in other versions.
9
+ - `Gemfile.lock` has been removed from source control. As this is a library project, the lockfile never affected application code that used this gem, but only affected the gem&#39;s own CI build. It is preferable for the CI build to refer only to the gemspec so that it resolves dependencies the same way an application using this gem would, rather than using pinned dependencies that an application would not use.
10
+
11
+ ## [2.0.0] - 2021-01-26
12
+ ### Added:
13
+ - Added a `socket_factory` configuration option which can be used for socket creation by the HTTP client if provided. The value of `socket_factory` must be an object providing an `open(uri, timeout)` method and returning a connected socket.
14
+
15
+ ### Changed:
16
+ - Switched to the `http` gem instead of `socketry` and a custom HTTP client.
17
+ - Dropped support for Ruby &lt; version 2.5
18
+ - Dropped support for JRuby &lt; version 9.2
19
+
20
+ ## [1.0.3] - 2020-03-17
21
+ ### Fixed:
22
+ - The backoff delay logic for reconnecting after a stream failure was broken so that if a failure occurred after a stream had been active for at least `reconnect_reset_interval` (default 60 seconds), retries would use _no_ delay, potentially causing a flood of requests and a spike in CPU usage.
23
+
5
24
  ## [1.0.2] - 2020-03-10
6
25
  ### Removed:
7
26
  - Removed an unused dependency on `rake`. There are no other changes in this release.
data/README.md CHANGED
@@ -3,14 +3,14 @@ LaunchDarkly SSE Client for Ruby
3
3
 
4
4
  [![Gem Version](https://badge.fury.io/rb/ld-eventsource.svg)](http://badge.fury.io/rb/ld-eventsource) [![Circle CI](https://circleci.com/gh/launchdarkly/ruby-eventsource/tree/master.svg?style=svg)](https://circleci.com/gh/launchdarkly/ruby-eventsource/tree/master)
5
5
 
6
- A client for the [Server-Sent Events](https://www.w3.org/TR/eventsource/) protocol. This implementation runs on a worker thread, and uses the [`socketry`](https://rubygems.org/gems/socketry) gem to manage a persistent connection. Its primary purpose is to support the [LaunchDarkly SDK for Ruby](https://github.com/launchdarkly/ruby-client), but it can be used independently.
6
+ A client for the [Server-Sent Events](https://www.w3.org/TR/eventsource/) protocol. This implementation runs on a worker thread, and uses the [`http`](https://rubygems.org/gems/http) gem to manage a persistent connection. Its primary purpose is to support the [LaunchDarkly SDK for Ruby](https://github.com/launchdarkly/ruby-client), but it can be used independently.
7
7
 
8
8
  Parts of this code are based on https://github.com/Tonkpils/celluloid-eventsource, but it does not use Celluloid.
9
9
 
10
10
  Supported Ruby versions
11
11
  -----------------------
12
12
 
13
- This gem has a minimum Ruby version of 2.2.6, or 9.1.6 for JRuby.
13
+ This gem has a minimum Ruby version of 2.5, or 9.2 for JRuby.
14
14
 
15
15
  Quick setup
16
16
  -----------
@@ -20,11 +20,11 @@ Gem::Specification.new do |spec|
20
20
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
21
  spec.require_paths = ["lib"]
22
22
 
23
- spec.add_development_dependency "bundler", "~> 1.7"
23
+ spec.add_development_dependency "bundler", "2.2.10"
24
24
  spec.add_development_dependency "rspec", "~> 3.2"
25
25
  spec.add_development_dependency "rspec_junit_formatter", "~> 0.3.0"
26
+ spec.add_development_dependency "webrick", "~> 1.7"
26
27
 
27
28
  spec.add_runtime_dependency "concurrent-ruby", "~> 1.0"
28
- spec.add_runtime_dependency "http_tools", '~> 0.4.5'
29
- spec.add_runtime_dependency "socketry", "~> 0.5.1"
29
+ spec.add_runtime_dependency "http", ">= 4.4.1", "< 6.0.0"
30
30
  end
@@ -1,6 +1,5 @@
1
1
  require "ld-eventsource/impl/backoff"
2
2
  require "ld-eventsource/impl/event_parser"
3
- require "ld-eventsource/impl/streaming_http"
4
3
  require "ld-eventsource/events"
5
4
  require "ld-eventsource/errors"
6
5
 
@@ -8,6 +7,7 @@ require "concurrent/atomics"
8
7
  require "logger"
9
8
  require "thread"
10
9
  require "uri"
10
+ require "http"
11
11
 
12
12
  module SSE
13
13
  #
@@ -80,6 +80,9 @@ module SSE
80
80
  # proxy with the `HTTP_PROXY` or `HTTPS_PROXY` environment variable)
81
81
  # @param logger [Logger] a Logger instance for the client to use for diagnostic output;
82
82
  # defaults to a logger with WARN level that goes to standard output
83
+ # @param socket_factory [#open] (nil) an optional factory object for creating sockets,
84
+ # if you want to use something other than the default `TCPSocket`; it must implement
85
+ # `open(uri, timeout)` to return a connected `Socket`
83
86
  # @yieldparam [Client] client the new client instance, before opening the connection
84
87
  #
85
88
  def initialize(uri,
@@ -90,7 +93,8 @@ module SSE
90
93
  reconnect_reset_interval: DEFAULT_RECONNECT_RESET_INTERVAL,
91
94
  last_event_id: nil,
92
95
  proxy: nil,
93
- logger: nil)
96
+ logger: nil,
97
+ socket_factory: nil)
94
98
  @uri = URI(uri)
95
99
  @stopped = Concurrent::AtomicBoolean.new(false)
96
100
 
@@ -98,7 +102,11 @@ module SSE
98
102
  @connect_timeout = connect_timeout
99
103
  @read_timeout = read_timeout
100
104
  @logger = logger || default_logger
101
-
105
+ http_client_options = {}
106
+ if socket_factory
107
+ http_client_options["socket_class"] = socket_factory
108
+ end
109
+
102
110
  if proxy
103
111
  @proxy = proxy
104
112
  else
@@ -108,6 +116,21 @@ module SSE
108
116
  end
109
117
  end
110
118
 
119
+ if @proxy
120
+ http_client_options["proxy"] = {
121
+ :proxy_address => @proxy.host,
122
+ :proxy_port => @proxy.port
123
+ }
124
+ end
125
+
126
+ @http_client = HTTP::Client.new(http_client_options)
127
+ .timeout({
128
+ read: read_timeout,
129
+ connect: connect_timeout
130
+ })
131
+ @buffer = ""
132
+ @lock = Mutex.new
133
+
111
134
  @backoff = Impl::Backoff.new(reconnect_time || DEFAULT_RECONNECT_TIME, MAX_RECONNECT_TIME,
112
135
  reconnect_reset_interval: reconnect_reset_interval)
113
136
 
@@ -163,12 +186,65 @@ module SSE
163
186
  #
164
187
  def close
165
188
  if @stopped.make_true
166
- @cxn.close if !@cxn.nil?
167
- @cxn = nil
189
+ reset_http
168
190
  end
169
191
  end
170
192
 
193
+ #
194
+ # Tests whether the client has been shut down by a call to {Client#close}.
195
+ #
196
+ # @return [Boolean] true if the client has been shut down
197
+ #
198
+ def closed?
199
+ @stopped.value
200
+ end
201
+
171
202
  private
203
+
204
+ def reset_http
205
+ @http_client.close if !@http_client.nil?
206
+ @cxn = nil
207
+ @buffer = ""
208
+ end
209
+
210
+ def read_lines
211
+ Enumerator.new do |gen|
212
+ loop do
213
+ line = read_line
214
+ break if line.nil?
215
+ gen.yield line
216
+ end
217
+ end
218
+ end
219
+
220
+ def read_line
221
+ loop do
222
+ @lock.synchronize do
223
+ i = @buffer.index(/[\r\n]/)
224
+ if !i.nil? && !(i == @buffer.length - 1 && @buffer[i] == "\r")
225
+ i += 1 if (@buffer[i] == "\r" && @buffer[i + 1] == "\n")
226
+ return @buffer.slice!(0, i + 1).force_encoding(Encoding::UTF_8)
227
+ end
228
+ end
229
+ return nil if !read_chunk_into_buffer
230
+ end
231
+ end
232
+
233
+ def read_chunk_into_buffer
234
+ # If @done is set, it means the Parser has signaled end of response body
235
+ @lock.synchronize { return false if @done }
236
+ begin
237
+ data = @cxn.readpartial
238
+ rescue HTTP::TimeoutError
239
+ # We rethrow this as our own type so the caller doesn't have to know the httprb API
240
+ raise Errors::ReadTimeoutError.new(@read_timeout)
241
+ end
242
+ return false if data == nil
243
+ @buffer << data
244
+ # We are piping the content through the parser so that it can handle things like chunked
245
+ # encoding for us. The content ends up being appended to @buffer via our callback.
246
+ true
247
+ end
172
248
 
173
249
  def default_logger
174
250
  log = ::Logger.new($stdout)
@@ -196,7 +272,7 @@ module SSE
196
272
  end
197
273
  end
198
274
  begin
199
- @cxn.close if !@cxn.nil?
275
+ reset_http
200
276
  rescue StandardError => e
201
277
  log_and_dispatch_error(e, "Unexpected error while closing stream")
202
278
  end
@@ -215,31 +291,28 @@ module SSE
215
291
  cxn = nil
216
292
  begin
217
293
  @logger.info { "Connecting to event stream at #{@uri}" }
218
- cxn = Impl::StreamingHTTPConnection.new(@uri,
219
- proxy: @proxy,
220
- headers: build_headers,
221
- connect_timeout: @connect_timeout,
222
- read_timeout: @read_timeout
223
- )
224
- if cxn.status == 200
294
+ cxn = @http_client.request("GET", @uri, {
295
+ headers: build_headers
296
+ })
297
+ if cxn.status.code == 200
225
298
  content_type = cxn.headers["content-type"]
226
299
  if content_type && content_type.start_with?("text/event-stream")
227
300
  return cxn # we're good to proceed
228
301
  else
229
- cxn.close
302
+ reset_http
230
303
  err = Errors::HTTPContentTypeError.new(cxn.headers["content-type"])
231
304
  @on[:error].call(err)
232
305
  @logger.warn { "Event source returned unexpected content type '#{cxn.headers["content-type"]}'" }
233
306
  end
234
307
  else
235
- body = cxn.read_all # grab the whole response body in case it has error details
236
- cxn.close
237
- @logger.info { "Server returned error status #{cxn.status}" }
238
- err = Errors::HTTPStatusError.new(cxn.status, body)
308
+ body = cxn.to_s # grab the whole response body in case it has error details
309
+ reset_http
310
+ @logger.info { "Server returned error status #{cxn.status.code}" }
311
+ err = Errors::HTTPStatusError.new(cxn.status.code, body)
239
312
  @on[:error].call(err)
240
313
  end
241
314
  rescue
242
- cxn.close if !cxn.nil?
315
+ reset_http
243
316
  raise # will be handled in run_stream
244
317
  end
245
318
  # if unsuccessful, continue the loop to connect again
@@ -253,7 +326,7 @@ module SSE
253
326
  # it can automatically reset itself if enough time passes between failures.
254
327
  @backoff.mark_success
255
328
 
256
- event_parser = Impl::EventParser.new(cxn.read_lines)
329
+ event_parser = Impl::EventParser.new(read_lines)
257
330
  event_parser.items.each do |item|
258
331
  return if @stopped.value
259
332
  case item
@@ -288,7 +361,8 @@ module SSE
288
361
  def build_headers
289
362
  h = {
290
363
  'Accept' => 'text/event-stream',
291
- 'Cache-Control' => 'no-cache'
364
+ 'Cache-Control' => 'no-cache',
365
+ 'User-Agent' => 'ruby-eventsource'
292
366
  }
293
367
  h['Last-Event-Id'] = @last_id if !@last_id.nil?
294
368
  h.merge(@headers)