ld-eventsource 1.0.2 → 2.0.1

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: a5949132cfd8b9aa8ce29c12de9b7eb37bb7b12f
4
- data.tar.gz: db91678ed8ed19ef586c1acafbe926a3ad57d1ce
2
+ SHA256:
3
+ metadata.gz: 4e0485d46aab9fb8bb9ac32ae49c013dde072d0695372089989a2f5e8799b6de
4
+ data.tar.gz: 7ca30c7591596b56925da6f157bb2ba39a41eaf8a23679bfd823c05ac83edb81
5
5
  SHA512:
6
- metadata.gz: d8b525565f92caf2f15b692e06afd484da52cd82959d1d862e9ed994842a29fa0074e78be032ea81ec0bd4051540a38055fd1aa90a46599f95550ee75f41c0a2
7
- data.tar.gz: 69605c60dabfebcddcde3fd23eb3f8f7962d69ff81a9f6975a2a2b9a93851bf78a8444c7f25ef41e3a0bc60ab13debd8347a8a8f6ed4a68fecb983f6ba6571a5
6
+ metadata.gz: 8a41b9daef952bc55ada55788415d25da1bf5bbfcbd071b52d8f39693132281a654c59cbfb05165af49f189be52bdf579ae130b21a974a67a0d96e239b67861e
7
+ data.tar.gz: 650358cf13547c6db91e0a793ed45f32bdd6221f0d96224121132e6055453fb88d1977c13657c1c4230894873c90a0c66761865ae8db232bc355326d34fdbd3b
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.0.1"
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,30 @@
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
+
24
+ ## [1.0.2] - 2020-03-10
25
+ ### Removed:
26
+ - Removed an unused dependency on `rake`. There are no other changes in this release.
27
+
28
+
5
29
  ## [1.0.1] - 2019-07-10
6
30
  ### Fixed:
7
31
  - Calling `close` on the client could cause a misleading warning message in the log, such as `Unexpected error from event source: #<IOError: stream closed in another thread>`.
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,56 @@ 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
 
171
193
  private
194
+
195
+ def reset_http
196
+ @http_client.close if !@http_client.nil?
197
+ @cxn = nil
198
+ @buffer = ""
199
+ end
200
+
201
+ def read_lines
202
+ Enumerator.new do |gen|
203
+ loop do
204
+ line = read_line
205
+ break if line.nil?
206
+ gen.yield line
207
+ end
208
+ end
209
+ end
210
+
211
+ def read_line
212
+ loop do
213
+ @lock.synchronize do
214
+ i = @buffer.index(/[\r\n]/)
215
+ if !i.nil? && !(i == @buffer.length - 1 && @buffer[i] == "\r")
216
+ i += 1 if (@buffer[i] == "\r" && @buffer[i + 1] == "\n")
217
+ return @buffer.slice!(0, i + 1).force_encoding(Encoding::UTF_8)
218
+ end
219
+ end
220
+ return nil if !read_chunk_into_buffer
221
+ end
222
+ end
223
+
224
+ def read_chunk_into_buffer
225
+ # If @done is set, it means the Parser has signaled end of response body
226
+ @lock.synchronize { return false if @done }
227
+ begin
228
+ data = @cxn.readpartial
229
+ rescue HTTP::TimeoutError
230
+ # We rethrow this as our own type so the caller doesn't have to know the httprb API
231
+ raise Errors::ReadTimeoutError.new(@read_timeout)
232
+ end
233
+ return false if data == nil
234
+ @buffer << data
235
+ # We are piping the content through the parser so that it can handle things like chunked
236
+ # encoding for us. The content ends up being appended to @buffer via our callback.
237
+ true
238
+ end
172
239
 
173
240
  def default_logger
174
241
  log = ::Logger.new($stdout)
@@ -196,7 +263,7 @@ module SSE
196
263
  end
197
264
  end
198
265
  begin
199
- @cxn.close if !@cxn.nil?
266
+ reset_http
200
267
  rescue StandardError => e
201
268
  log_and_dispatch_error(e, "Unexpected error while closing stream")
202
269
  end
@@ -215,31 +282,28 @@ module SSE
215
282
  cxn = nil
216
283
  begin
217
284
  @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
285
+ cxn = @http_client.request("GET", @uri, {
286
+ headers: build_headers
287
+ })
288
+ if cxn.status.code == 200
225
289
  content_type = cxn.headers["content-type"]
226
290
  if content_type && content_type.start_with?("text/event-stream")
227
291
  return cxn # we're good to proceed
228
292
  else
229
- cxn.close
293
+ reset_http
230
294
  err = Errors::HTTPContentTypeError.new(cxn.headers["content-type"])
231
295
  @on[:error].call(err)
232
296
  @logger.warn { "Event source returned unexpected content type '#{cxn.headers["content-type"]}'" }
233
297
  end
234
298
  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)
299
+ body = cxn.to_s # grab the whole response body in case it has error details
300
+ reset_http
301
+ @logger.info { "Server returned error status #{cxn.status.code}" }
302
+ err = Errors::HTTPStatusError.new(cxn.status.code, body)
239
303
  @on[:error].call(err)
240
304
  end
241
305
  rescue
242
- cxn.close if !cxn.nil?
306
+ reset_http
243
307
  raise # will be handled in run_stream
244
308
  end
245
309
  # if unsuccessful, continue the loop to connect again
@@ -253,7 +317,7 @@ module SSE
253
317
  # it can automatically reset itself if enough time passes between failures.
254
318
  @backoff.mark_success
255
319
 
256
- event_parser = Impl::EventParser.new(cxn.read_lines)
320
+ event_parser = Impl::EventParser.new(read_lines)
257
321
  event_parser.items.each do |item|
258
322
  return if @stopped.value
259
323
  case item
@@ -288,7 +352,8 @@ module SSE
288
352
  def build_headers
289
353
  h = {
290
354
  'Accept' => 'text/event-stream',
291
- 'Cache-Control' => 'no-cache'
355
+ 'Cache-Control' => 'no-cache',
356
+ 'User-Agent' => 'ruby-eventsource'
292
357
  }
293
358
  h['Last-Event-Id'] = @last_id if !@last_id.nil?
294
359
  h.merge(@headers)