Module: HTTPX::Plugins::ContentDigest::InstanceMethods

Defined in:
lib/httpx/plugins/content_digest.rb,
sig/plugins/content_digest.rbs

Instance Method Summary collapse

Instance Method Details

#base64digest(body) ⇒ String

Parameters:

Returns:

  • (String)


170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/httpx/plugins/content_digest.rb', line 170

def base64digest(body)
  digest = SUPPORTED_ALGORITHMS.fetch(@options.content_digest_algorithm).new

  if body.respond_to?(:read)
    if body.respond_to?(:to_path)
      digest.file(body.to_path).base64digest
    else
      raise ContentDigestError, "request body must be rewindable" unless body.respond_to?(:rewind)

      buffer = Tempfile.new("httpx", encoding: Encoding::BINARY, mode: File::RDWR)
      begin
        IO.copy_stream(body, buffer)
        buffer.flush

        digest.file(buffer.to_path).base64digest
      ensure
        body.rewind
        buffer.close
        buffer.unlink
      end
    end
  else
    raise ContentDigestError, "base64digest for endless enumerators is not supported" if body.unbounded_body?

    buffer = "".b
    body.each { |chunk| buffer << chunk }

    digest.base64digest(buffer)
  end
end

#build_requestObject



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/httpx/plugins/content_digest.rb', line 98

def build_request(*)
  request = super

  return request if request.empty?

  return request if request.headers.key?("content-digest")

  perform_encoding = @options.encode_content_digest
  perform_encoding = perform_encoding.call(request) if perform_encoding.respond_to?(:call)

  return request unless perform_encoding

  digest = base64digest(request.body)
  request.headers.add("content-digest", "#{@options.content_digest_algorithm}=:#{digest}:")

  request
end

#extract_content_digests(header) ⇒ Hash[String, String]

Parameters:

  • (String)

Returns:

  • (Hash[String, String])


161
162
163
164
165
166
167
168
# File 'lib/httpx/plugins/content_digest.rb', line 161

def extract_content_digests(header)
  header.split(",").to_h do |entry|
    algorithm, digest = entry.split("=", 2)
    raise Error, "#{entry} is an invalid digest format" unless algorithm && digest

    [algorithm, digest.byteslice(1..-2)]
  end
end

#validate_content_digest(response) ⇒ void

This method returns an undefined value.

Parameters:

Raises:



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/httpx/plugins/content_digest.rb', line 132

def validate_content_digest(response)
  content_digest_header = response.headers["content-digest"]

  raise MissingContentDigestError.new("response is missing a `content-digest` header", response) unless content_digest_header

  digests = extract_content_digests(content_digest_header)

  included_algorithms = SUPPORTED_ALGORITHMS.keys & digests.keys

  raise MissingContentDigestError.new("unsupported algorithms: #{digests.keys.join(", ")}", response) if included_algorithms.empty?

  content_buffer = response.body.content_digest_buffer

  included_algorithms.each do |algorithm|
    digest = SUPPORTED_ALGORITHMS.fetch(algorithm).new
    digest_received = digests[algorithm]
    digest_computed =
      if content_buffer.respond_to?(:to_path)
        content_buffer.flush
        digest.file(content_buffer.to_path).base64digest
      else
        digest.base64digest(content_buffer.to_s)
      end

    raise InvalidContentDigestError.new("#{algorithm} digest does not match content",
                                        response) unless digest_received == digest_computed
  end
end