nethttputils 0.3.3.0 → 0.4.1.3

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
  SHA1:
3
- metadata.gz: 9afa291d86c40f37b207744ca23c7e12c330e055
4
- data.tar.gz: 3afb6030d76642efed329bdf322c68dbb3eb2d00
3
+ metadata.gz: aa8c5d5ae78a7dbad64fe4d0e624666cfcbe1642
4
+ data.tar.gz: 8d09dcf215b50515dc6033f5ef6b6760f14c844c
5
5
  SHA512:
6
- metadata.gz: a91b3cf20cbb611ff5e77d8efef83b37c01cabe413431dfb7edf7df9fe4c5eae4d92cf177891b04fd2e4a96b399871fcdc9b9afc2d2dd9926101b2321da5f28c
7
- data.tar.gz: 137f44eee308529b23e5c6d9c592801950ddca31e156a6e0010b0a98f34cd8f758d6810143d34c0994b3ff17e42f1cc8a6d7608cdba9b7638c143781822732fa
6
+ metadata.gz: c315180c06335286428ffb1aff4c41ba6b1648644dc2c41b3f199c8fe2102238e0323359590bb74db31b487e4499b27c5d9823c0a300bae1eafe9f114a62cc59
7
+ data.tar.gz: 07b47969d1d87ffd4bdd409b038aef316b770f5d3b4d00d7ad0faa419ac559dfa362548c5f942df3300629a6ba9f5ef630370412e73a80afaef785dfde938bb3
data/lib/nethttputils.rb CHANGED
@@ -18,19 +18,23 @@ module NetHTTPUtils
18
18
  attr_reader :code
19
19
  def initialize body, code = nil
20
20
  @code = code
21
+ body = body[0...997] + "..." if body.size > 1000
21
22
  super "HTTP error ##{code.inspect} #{body}"
22
23
  end
23
24
  end
25
+ class EOFError_from_rbuf_fill < StandardError
26
+ end
24
27
 
25
28
  class << self
26
29
 
27
30
  def remove_tags str
28
- str.gsub(/<script( [a-z]+="[^"]*")*>.*?<\/script>/m, "").
29
- gsub(/<style( [a-z]+="[^"]*")*>.*?<\/style>/m, "").
31
+ str.gsub(/<script( [a-z-]+="[^"]*")*>.*?<\/script>/m, "").
32
+ gsub(/<style( [a-z-]+="[^"]*")*>.*?<\/style>/m, "").
30
33
  gsub(/<[^>]*>/, "").split(?\n).map(&:strip).reject(&:empty?).join(?\n)
31
34
  end
32
35
 
33
- def start_http url, max_start_http_retry_delay = 3600, timeout = 30
36
+ def start_http url, max_start_http_retry_delay = 3600, timeout = nil, no_redirect = false, proxy = nil
37
+ timeout ||= 30
34
38
  uri = url
35
39
  uri = URI.parse begin
36
40
  URI url
@@ -42,6 +46,7 @@ module NetHTTPUtils
42
46
  begin
43
47
  Net::HTTP.start(
44
48
  uri.host, uri.port,
49
+ *(proxy.split ?: if proxy),
45
50
  use_ssl: uri.scheme == "https",
46
51
  verify_mode: OpenSSL::SSL::VERIFY_NONE,
47
52
  **({open_timeout: timeout}), # if timeout
@@ -54,7 +59,7 @@ module NetHTTPUtils
54
59
  def << msg
55
60
  @@buffer ||= "[Net::HTTP debug] "
56
61
  @@buffer.concat msg
57
- @@buffer = @@buffer[0...997] + "..." if @@buffer.size > 500
62
+ @@buffer = @@buffer[0...997] + "..." if @@buffer.size > 1000
58
63
  return unless @@buffer.end_with? ?\n
59
64
  NetHTTPUtils.logger.debug @@buffer.sub ?\n, " "
60
65
  @@buffer = nil
@@ -63,7 +68,7 @@ module NetHTTPUtils
63
68
  end ) if logger.level == Logger::DEBUG # use `logger.debug?`?
64
69
  http
65
70
  end
66
- rescue Errno::ECONNREFUSED => e
71
+ rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ENETUNREACH, Errno::ECONNRESET => e
67
72
  if max_start_http_retry_delay < delay *= 2
68
73
  e.message.concat " to #{uri}"
69
74
  raise
@@ -71,10 +76,6 @@ module NetHTTPUtils
71
76
  logger.warn "retrying in #{delay} seconds because of #{e.class} '#{e.message}'"
72
77
  sleep delay
73
78
  retry
74
- rescue Errno::EHOSTUNREACH, Errno::ENETUNREACH, Errno::ECONNRESET => e
75
- logger.warn "retrying in 5 seconds because of #{e.class} '#{e.message}'"
76
- sleep 5
77
- retry
78
79
  rescue SocketError => e
79
80
  if max_start_http_retry_delay < delay *= 2
80
81
  e.message.concat " to #{uri}"
@@ -100,7 +101,8 @@ module NetHTTPUtils
100
101
  end
101
102
 
102
103
  private
103
- def read http, mtd = :GET, type = :form, form: {}, header: {}, auth: nil, timeout: 30, max_read_retry_delay: 3600, patch_request: nil, &block
104
+ def read http, mtd = :GET, type = :form, form: {}, header: {}, auth: nil, timeout: nil, no_redirect: false, max_read_retry_delay: 3600, patch_request: nil, &block
105
+ timeout ||= 30
104
106
  logger = NetHTTPUtils.logger
105
107
 
106
108
  uri = http.instance_variable_get :@uri
@@ -126,15 +128,20 @@ module NetHTTPUtils
126
128
  request.basic_auth *auth if auth
127
129
  if (mtd == :POST || mtd == :PATCH) && !form.empty?
128
130
  case type
129
- when :json ; request.body = JSON.dump form
130
- request.content_type = "application/json"
131
- when :form ; if form.any?{ |k, v| v.respond_to? :to_path }
131
+ when :json
132
+ request.body = JSON.dump form
133
+ request.content_type = "application/json"
134
+ when :multipart
135
+ request.set_form form, "multipart/form-data"
136
+ when :form
137
+ if form.any?{ |k, v| v.respond_to? :to_path }
132
138
  request.set_form form, "multipart/form-data"
133
139
  else
134
140
  request.set_form_data form
135
141
  request.content_type = "application/x-www-form-urlencoded;charset=UTF-8"
136
142
  end
137
- else ; raise "unknown content-type '#{type}'"
143
+ else
144
+ raise "unknown content-type '#{type}'"
138
145
  end
139
146
  end
140
147
  header.each{ |k, v| request[k.to_s] = v.is_a?(Array) ? v.first : v }
@@ -155,7 +162,7 @@ module NetHTTPUtils
155
162
  request.each_header.map{ |k, v| "-H \"#{k}: #{v}\" " unless k == "host" }.join
156
163
  }#{curl_form}'#{uri.scheme}://#{uri.host}#{uri.path}#{"?#{uri.query}" if uri.query && !uri.query.empty?}'"
157
164
  logger.debug "> header: #{request.each_header.to_a}"
158
- logger.debug "> body: #{request.body.inspect.tap{ |body| body[997..-1] = "..." if body.size > 500 }}"
165
+ logger.debug "> body: #{request.body.inspect.tap{ |body| body.replace body[0...997] + "..." if body.size > 1000 }}"
159
166
  # TODO this is buggy -- mixes lines from different files into one line
160
167
  stack = caller.reverse.map do |level|
161
168
  /((?:[^\/:]+\/)?[^\/:]+):([^:]+)/.match(level).captures
@@ -169,15 +176,21 @@ module NetHTTPUtils
169
176
  delay = 5
170
177
  response = begin
171
178
  http.request request, &block
172
- rescue Errno::ECONNREFUSED, Net::ReadTimeout, Net::OpenTimeout, Zlib::BufError, Errno::ECONNRESET, OpenSSL::SSL::SSLError => e
179
+ rescue Errno::ECONNREFUSED, Net::ReadTimeout, Net::OpenTimeout, Zlib::BufError, Errno::ECONNRESET, OpenSSL::SSL::SSLError, Errno::ETIMEDOUT, Errno::ENETUNREACH => e
173
180
  raise if max_read_retry_delay < delay *= 2
174
181
  logger.error "retrying in #{delay} seconds because of #{e.class} '#{e.message}' at: #{request.uri}"
175
182
  sleep delay
176
183
  retry
184
+ rescue EOFError => e
185
+ raise unless e.backtrace.empty?
186
+ # https://bugs.ruby-lang.org/issues/13018
187
+ # https://blog.kalina.tech/2019/04/exception-without-backtrace-in-ruby.html
188
+ raise EOFError_from_rbuf_fill.new "probably the old Ruby empty backtrace EOFError exception from net/protocol.rb"
177
189
  end
178
190
  # response.instance_variable_set "@nethttputils_close", http.method(:finish)
179
191
  # response.singleton_class.instance_eval{ attr_accessor :nethttputils_socket_to_close }
180
192
 
193
+ now = Time.now
181
194
  remaining, reset_time, current_timestamp = if response.key? "x-ratelimit-userremaining"
182
195
  logger.debug "x-ratelimit-clientremaining: #{response.fetch("x-ratelimit-clientremaining").to_i}"
183
196
  [
@@ -189,7 +202,13 @@ module NetHTTPUtils
189
202
  [
190
203
  response.fetch("x-rate-limit-remaining").to_i,
191
204
  response.fetch("x-rate-limit-reset").to_i,
192
- Time.now.to_i,
205
+ now.to_i,
206
+ ]
207
+ elsif response.key? "x-ratelimit-remaining"
208
+ [
209
+ response.fetch("x-ratelimit-remaining").to_i,
210
+ now + response.fetch("x-ratelimit-reset").to_i,
211
+ now.to_i,
193
212
  ]
194
213
  end
195
214
  if remaining
@@ -215,9 +234,13 @@ module NetHTTPUtils
215
234
  end
216
235
 
217
236
  case response.code
237
+ when /\A20/
238
+ response
218
239
  when /\A30\d\z/
240
+ next response if no_redirect
219
241
  logger.info "redirect: #{response["location"]}"
220
- new_uri = URI.join request.uri, response["location"]
242
+ require "addressable"
243
+ new_uri = URI.join request.uri.to_s, Addressable::URI.escape(response["location"])
221
244
  new_host = new_uri.host
222
245
  raise Error.new "redirected in place" if new_uri == http.instance_variable_get(:@uri)
223
246
  if http.address != new_host ||
@@ -225,7 +248,7 @@ module NetHTTPUtils
225
248
  http.use_ssl? != (new_uri.scheme == "https")
226
249
  logger.debug "changing host from '#{http.address}' to '#{new_host}'"
227
250
  # http.finish # why commented out?
228
- http = NetHTTPUtils.start_http new_uri, http.instance_variable_get(:@max_start_http_retry_delay), timeout
251
+ http = NetHTTPUtils.start_http new_uri, http.instance_variable_get(:@max_start_http_retry_delay), timeout, no_redirect
229
252
  end
230
253
  if request.method == "POST"
231
254
  logger.info "POST redirects to GET (RFC)"
@@ -261,8 +284,6 @@ module NetHTTPUtils
261
284
  end
262
285
  }"
263
286
  response
264
- when /\A20/
265
- response
266
287
  else
267
288
  logger.warn "code #{response.code} at #{request.method} #{request.uri} from #{
268
289
  [__FILE__, caller.map{ |i| i[/(?<=:)\d+/] }].join ?:
@@ -283,11 +304,13 @@ module NetHTTPUtils
283
304
 
284
305
  require "set"
285
306
  @@_405 ||= Set.new
286
- def request_data http, mtd = :GET, type = :form, form: {}, header: {}, auth: nil, timeout: 30,
307
+ def request_data http, mtd = :GET, type = :form, form: {}, header: {}, auth: nil, proxy: nil,
308
+ timeout: nil, no_redirect: false,
287
309
  max_start_http_retry_delay: 3600,
288
310
  max_read_retry_delay: 3600,
289
311
  patch_request: nil, &block
290
- http = start_http http, max_start_http_retry_delay, timeout unless http.is_a? Net::HTTP
312
+ timeout ||= 30
313
+ http = start_http http, max_start_http_retry_delay, timeout, no_redirect, *proxy unless http.is_a? Net::HTTP
291
314
  path = http.instance_variable_get(:@uri).path
292
315
 
293
316
  check_code = lambda do |body|
@@ -318,7 +341,8 @@ module NetHTTPUtils
318
341
  check_code.call body
319
342
  end
320
343
  end
321
- body = read http, mtd, type, form: form, header: header, auth: auth, timeout: timeout,
344
+ body = read http, mtd, type, form: form, header: header, auth: auth,
345
+ timeout: timeout, no_redirect: no_redirect,
322
346
  max_read_retry_delay: max_read_retry_delay,
323
347
  patch_request: patch_request, &block
324
348
  check_code.call body
@@ -467,16 +491,16 @@ if $0 == __FILE__
467
491
  fail unless NetHTTPUtils.method(:read).call(NetHTTPUtils.start_http("http://httpstat.us/400")) == "400 Bad Request"
468
492
  fail unless NetHTTPUtils.method(:read).call(NetHTTPUtils.start_http("http://httpstat.us/404")) == "404 Not Found"
469
493
  fail unless NetHTTPUtils.method(:read).call(NetHTTPUtils.start_http("http://httpstat.us/500")) == "500 Internal Server Error"
470
- fail unless NetHTTPUtils.method(:read).call(NetHTTPUtils.start_http("http://httpstat.us/502")) == "502 Bad Gateway"
494
+ fail unless NetHTTPUtils.method(:read).call(NetHTTPUtils.start_http("http://httpstat.us/502")).start_with? "httpstat.us | 502: Bad gateway\nError\n502\n"
471
495
  fail unless NetHTTPUtils.method(:read).call(NetHTTPUtils.start_http("http://httpstat.us/503")) == "503 Service Unavailable"
472
496
  [
473
- ["https://imgur.com/a/cccccc"],
474
- ["https://imgur.com/mM4Dh7Z"],
497
+ # ["https://imgur.com/a/oacI3gl"], # TODO: Imgur now hangs on these pages, I guess they had to be some 404 error page
498
+ # ["https://imgur.com/mM4Dh7Z"], # TODO: Imgur now hangs on these pages, I guess they had to be some 404 error page
475
499
  ["https://i.redd.it/si758zk7r5xz.jpg", "HTTP error #404 <image/png>"],
476
500
  ].each do |url, expectation|
477
501
  begin
478
502
  puts NetHTTPUtils.remove_tags NetHTTPUtils.request_data url
479
- fail
503
+ fail url
480
504
  rescue NetHTTPUtils::Error => e
481
505
  raise e.code.inspect unless e.code == 404
482
506
  raise e.to_s if e.to_s != expectation if expectation
data/nethttputils.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = "nethttputils"
3
- spec.version = "0.3.3.0"
3
+ spec.version = "0.4.1.3"
4
4
  spec.summary = "this tool is like a pet that I adopted young and now I depend on, sorry"
5
5
  spec.description = <<-EOF
6
6
  Back in 2015 I was a guy automating things at my job and two scripts had a common need --
@@ -21,5 +21,7 @@ Gem::Specification.new do |spec|
21
21
  spec.license = "MIT"
22
22
 
23
23
  spec.require_path = "lib"
24
- spec.files = `git ls-files -z`.split(?\0) - spec.test_files
24
+ spec.files = %w{ LICENSE nethttputils.gemspec lib/nethttputils.rb }
25
+
26
+ spec.add_dependency "addressable"
25
27
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nethttputils
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3.0
4
+ version: 0.4.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Victor Maslov aka Nakilon
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-11-08 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2021-06-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: addressable
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  description: |2
14
28
  Back in 2015 I was a guy automating things at my job and two scripts had a common need --
15
29
  they both had to pass the same credentials to Jenkins (via query params, I guess).
@@ -26,9 +40,7 @@ executables: []
26
40
  extensions: []
27
41
  extra_rdoc_files: []
28
42
  files:
29
- - ".travis.yml"
30
43
  - LICENSE
31
- - Rakefile
32
44
  - lib/nethttputils.rb
33
45
  - nethttputils.gemspec
34
46
  homepage: https://github.com/nakilon/nethttputils
data/.travis.yml DELETED
@@ -1,21 +0,0 @@
1
- ---
2
- language: ruby
3
-
4
- script: "ruby lib/nethttputils.rb"
5
-
6
- os:
7
- - linux
8
- - osx
9
- rvm:
10
- - ruby-head
11
- - 2.5
12
- - 2.4
13
- - 2.3
14
- - 2.2
15
- - 2.1
16
- - 2.0
17
- - jruby-head
18
- matrix:
19
- allow_failures:
20
- # something with `NetHTTPUtils.request_data("http://localhost:8000/?1=2&3=4", form: {1=>3})` test
21
- - rvm: jruby-head
data/Rakefile DELETED
@@ -1 +0,0 @@
1
- require "bundler/gem_tasks"