Module: Jpzip::Http

Defined in:
lib/jpzip/http.rb

Overview

Internal HTTP helpers. Pinned to the Ruby stdlib (net/http) so the gem has zero runtime dependencies.

Defined Under Namespace

Classes: HttpError, Result

Constant Summary collapse

MAX_ATTEMPTS =
3
BASE_BACKOFF =
0.2
DEFAULT_TIMEOUT =

seconds

30

Class Method Summary collapse

Class Method Details

.get(url, http_client: nil, sleeper: nil) ⇒ Object

Get fetches url with bounded retries on 5xx / network failures.

Returns a Result where status is the HTTP status code. On 404 body is nil so callers can distinguish “absent” from “fetch error”. On repeated failure this raises the last error encountered.



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/jpzip/http.rb', line 22

def self.get(url, http_client: nil, sleeper: nil)
  uri = URI(url)
  last_error = nil

  MAX_ATTEMPTS.times do |attempt|
    if attempt.positive?
      delay = BASE_BACKOFF * (2**attempt)
      (sleeper || method(:sleep)).call(delay)
    end

    begin
      response = perform_request(uri, http_client)
      status = response.code.to_i

      return Result.new(body: nil, status: 404) if status == 404

      if status >= 500
        last_error = HttpError.new("jpzip: #{url} returned #{status}")
        next
      end

      if status >= 400
        raise HttpError, "jpzip: #{url} returned #{status}"
      end

      return Result.new(body: response.body, status: status)
    rescue HttpError
      raise
    rescue StandardError => e
      last_error = e
      next
    end
  end

  raise(last_error || HttpError.new("jpzip: #{url} failed after #{MAX_ATTEMPTS} attempts"))
end

.perform_request(uri, http_client) ⇒ Object



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/jpzip/http.rb', line 59

def self.perform_request(uri, http_client)
  if http_client
    return http_client.call(uri)
  end

  Net::HTTP.start(
    uri.host,
    uri.port,
    use_ssl: uri.scheme == "https",
    open_timeout: DEFAULT_TIMEOUT,
    read_timeout: DEFAULT_TIMEOUT
  ) do |http|
    req = Net::HTTP::Get.new(uri.request_uri)
    req["Accept"] = "application/json"
    req["Accept-Encoding"] = "gzip"
    http.request(req)
  end
end