class Chef::HTTP::ValidateContentLength

Middleware that validates the Content-Length header against the downloaded number of bytes.

This must run before the decompressor middleware, since otherwise we will count the uncompressed streamed bytes, rather than the on-the-wire compressed bytes.

Public Class Methods

new(opts = {}) click to toggle source
# File lib/chef/http/validate_content_length.rb, line 44
def initialize(opts = {})
end

Public Instance Methods

handle_request(method, url, headers = {}, data = false) click to toggle source
# File lib/chef/http/validate_content_length.rb, line 47
def handle_request(method, url, headers = {}, data = false)
  [method, url, headers, data]
end
handle_response(http_response, rest_request, return_value) click to toggle source
# File lib/chef/http/validate_content_length.rb, line 51
def handle_response(http_response, rest_request, return_value)
  validate(http_response, http_response.body.bytesize) if http_response && http_response.body
  [http_response, rest_request, return_value]
end
handle_stream_complete(http_response, rest_request, return_value) click to toggle source
# File lib/chef/http/validate_content_length.rb, line 56
def handle_stream_complete(http_response, rest_request, return_value)
  if @content_length_counter.nil?
    Chef::Log.trace("No content-length information collected for the streamed download, cannot identify streamed download.")
  else
    validate(http_response, @content_length_counter.content_length)
  end

  # Make sure the counter is reset since this object might get used
  # again. See CHEF-5100
  @content_length_counter = nil
  [http_response, rest_request, return_value]
end
stream_response_handler(response) click to toggle source
# File lib/chef/http/validate_content_length.rb, line 69
def stream_response_handler(response)
  @content_length_counter = ContentLengthCounter.new
end

Private Instance Methods

response_content_length(response) click to toggle source
# File lib/chef/http/validate_content_length.rb, line 75
def response_content_length(response)
  return nil if response["content-length"].nil?
  if response["content-length"].is_a?(Array)
    response["content-length"].first.to_i
  else
    response["content-length"].to_i
  end
end
validate(http_response, response_length) click to toggle source
# File lib/chef/http/validate_content_length.rb, line 84
def validate(http_response, response_length)
  content_length    = response_content_length(http_response)
  transfer_encoding = http_response["transfer-encoding"]

  if content_length.nil?
    Chef::Log.trace "HTTP server did not include a Content-Length header in response, cannot identify truncated downloads."
    return true
  end

  if content_length < 0
    Chef::Log.trace "HTTP server responded with a negative Content-Length header (#{content_length}), cannot identify truncated downloads."
    return true
  end

  # if Transfer-Encoding is set the RFC states that we must ignore the Content-Length field
  # CHEF-5041: some proxies uncompress gzip content, leave the incorrect content-length, but set the transfer-encoding field
  unless transfer_encoding.nil?
    Chef::Log.trace "Transfer-Encoding header is set, skipping Content-Length check."
    return true
  end

  if response_length != content_length
    raise Chef::Exceptions::ContentLengthMismatch.new(response_length, content_length)
  end

  Chef::Log.trace "Content-Length validated correctly."
  true
end