summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLamont Granquist <lamont@scriptkiddie.org>2014-03-20 16:33:41 -0700
committersersut <serdar@opscode.com>2014-03-27 15:37:26 -0700
commitce72c3d3e01700c7f3f14af22fbaef6b65486192 (patch)
tree903a46dab7a98414bd7a7156237cbc67e55173b1
parentcc292cf145e1b6da7a600aa65f15adae79c4eb45 (diff)
downloadchef-ce72c3d3e01700c7f3f14af22fbaef6b65486192.tar.gz
CHEF-5041: check for transfer-encoding header
- skip content-length check in the presence of a transfer-encoding header - also adds debugging and some refactoring
-rw-r--r--lib/chef/http.rb3
-rw-r--r--lib/chef/http/decompressor.rb5
-rw-r--r--lib/chef/http/validate_content_length.rb40
3 files changed, 35 insertions, 13 deletions
diff --git a/lib/chef/http.rb b/lib/chef/http.rb
index 78c47735d2..06de37fc69 100644
--- a/lib/chef/http.rb
+++ b/lib/chef/http.rb
@@ -210,18 +210,21 @@ class Chef
def apply_request_middleware(method, url, headers, data)
middlewares.inject([method, url, headers, data]) do |req_data, middleware|
+ Chef::Log.debug "calling handle_request for the #{middleware.class} middleware"
middleware.handle_request(*req_data)
end
end
def apply_response_middleware(response, rest_request, return_value)
middlewares.reverse.inject([response, rest_request, return_value]) do |res_data, middleware|
+ Chef::Log.debug "calling handle_response for the #{middleware.class} middleware"
middleware.handle_response(*res_data)
end
end
def apply_stream_complete_middleware(response, rest_request, return_value)
middlewares.reverse.inject([response, rest_request, return_value]) do |res_data, middleware|
+ Chef::Log.debug "calling handle_stream_complete for the #{middleware.class} middleware"
middleware.handle_stream_complete(*res_data)
end
end
diff --git a/lib/chef/http/decompressor.rb b/lib/chef/http/decompressor.rb
index 78af47798c..c760dad11c 100644
--- a/lib/chef/http/decompressor.rb
+++ b/lib/chef/http/decompressor.rb
@@ -26,6 +26,7 @@ class Chef
class Decompressor
class NoopInflater
def inflate(chunk)
+ Chef::Log.debug "decompressing compressed chunk"
chunk
end
alias :handle_chunk :inflate
@@ -98,10 +99,10 @@ class Chef
else
case response[CONTENT_ENCODING]
when GZIP
- Chef::Log.debug "decompressing gzip stream"
+ Chef::Log.debug "initializing gzip stream deflator"
GzipInflater.new
when DEFLATE
- Chef::Log.debug "decompressing inflate stream"
+ Chef::Log.debug "initializing deflate stream deflator"
DeflateInflater.new
else
NoopInflater.new
diff --git a/lib/chef/http/validate_content_length.rb b/lib/chef/http/validate_content_length.rb
index 49f1738d42..834bb023e8 100644
--- a/lib/chef/http/validate_content_length.rb
+++ b/lib/chef/http/validate_content_length.rb
@@ -32,10 +32,12 @@ class Chef
attr_accessor :content_length
def initialize
+ Chef::Log.debug "initializing stream counter for response body size"
@content_length = 0
end
def handle_chunk(chunk)
+ Chef::Log.debug "adding chunk to response body size: #{@content_length}"
@content_length += chunk.bytesize
chunk
end
@@ -49,21 +51,15 @@ class Chef
end
def handle_response(http_response, rest_request, return_value)
- unless http_response['content-length']
- Chef::Log.debug("HTTP server did not include a Content-Length header in response, cannot identify truncated downloads.")
- return [http_response, rest_request, return_value]
- end
- validate(response_content_length(http_response), http_response.body.bytesize)
+ validate(http_response, http_response.body.bytesize)
return [http_response, rest_request, return_value]
end
def handle_stream_complete(http_response, rest_request, return_value)
- if http_response['content-length'].nil?
- Chef::Log.debug("HTTP server did not include a Content-Length header in response, cannot idenfity streamed download.")
- elsif @content_length_counter.nil?
+ if @content_length_counter.nil?
Chef::Log.debug("No content-length information collected for the streamed download, cannot identify streamed download.")
else
- validate(response_content_length(http_response), @content_length_counter.content_length)
+ validate(http_response, @content_length_counter.content_length)
end
return [http_response, rest_request, return_value]
end
@@ -73,6 +69,7 @@ class Chef
end
private
+
def response_content_length(response)
if response['content-length'].is_a?(Array)
response['content-length'].first.to_i
@@ -81,12 +78,33 @@ class Chef
end
end
- def validate(content_length, response_length)
+ def validate(http_response, response_length)
+ content_length = response_content_length(http_response)
+ transfer_encoding = http_response['transfer_encoding']
+ content_encoding = http_response['content_encoding']
+
+ Chef::Log.debug "Attempting to validate the Content-Length header of the response"
Chef::Log.debug "Content-Length header = #{content_length}"
- Chef::Log.debug "Response body length = #{response_length}"
+ Chef::Log.debug "Transfer-Encoding header = #{transfer_encoding}"
+ Chef::Log.debug "Content-Encoding header = #{content_encoding}"
+ Chef::Log.debug "Actual response body length = #{response_length}"
+
+ if content_length.nil?
+ Chef::Log.debug "HTTP server did not include a Content-Length header in response, 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.debug "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
+
true
end
end