summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/chef/rest.rb140
-rw-r--r--lib/chef/rest/decompressor.rb122
-rw-r--r--lib/chef/rest/json_to_model_inflater.rb56
3 files changed, 191 insertions, 127 deletions
diff --git a/lib/chef/rest.rb b/lib/chef/rest.rb
index 104eb67d20..cbceb66946 100644
--- a/lib/chef/rest.rb
+++ b/lib/chef/rest.rb
@@ -20,12 +20,12 @@
# limitations under the License.
#
-require 'zlib'
require 'net/https'
require 'uri'
-require 'chef/json_compat'
require 'tempfile'
require 'chef/rest/auth_credentials'
+require 'chef/rest/decompressor'
+require 'chef/rest/json_to_model_inflater'
require 'chef/rest/rest_request'
require 'chef/monkey_patches/string'
require 'chef/monkey_patches/net_http'
@@ -39,130 +39,6 @@ class Chef
# authentication.
class REST
- class ChefJSONInflater
-
- def initialize(opts={})
- end
-
- def handle_request(method, url, headers={}, data=false)
- headers['Accept'] = "application/json"
- headers["Content-Type"] = 'application/json' if data
- json_body = data ? Chef::JSONCompat.to_json(data) : nil
- # Force encoding to binary to fix SSL related EOFErrors
- # cf. http://tickets.opscode.com/browse/CHEF-2363
- # http://redmine.ruby-lang.org/issues/5233
- json_body.force_encoding(Encoding::BINARY) if json_body.respond_to?(:force_encoding)
- [method, url, headers, json_body]
- end
-
- def handle_response(http_response, rest_request, return_value)
- # temporary hack, skip processing if return_value is false
- # needed to keep conditional get stuff working correctly.
- return [http_response, rest_request, return_value] if return_value == false
- if http_response['content-type'] =~ /json/
- [http_response, rest_request, Chef::JSONCompat.from_json(http_response.body.chomp)]
- else
- Chef::Log.warn("Expected JSON response, but got content-type '#{http_response['content-type']}'")
- return [http_response, rest_request, http_response.body.to_s]
- end
- end
-
- end
-
- class Decompressor
- class NoopInflater
- def inflate(chunk)
- chunk
- end
- end
-
- CONTENT_ENCODING = "content-encoding".freeze
- GZIP = "gzip".freeze
- DEFLATE = "deflate".freeze
- IDENTITY = "identity".freeze
-
- def initialize(opts={})
- @disable_gzip = false
- handle_options(opts)
- end
-
- def handle_request(method, url, headers={}, data=false)
- headers[RESTRequest::ACCEPT_ENCODING] = RESTRequest::ENCODING_GZIP_DEFLATE unless gzip_disabled?
- [method, url, headers, data]
- end
-
- def handle_response(http_response, rest_request, return_value)
- # temporary hack, skip processing if return_value is false
- # needed to keep conditional get stuff working correctly.
- return [http_response, rest_request, return_value] if return_value == false
- response_body = decompress_body(http_response)
- http_response.body.replace(response_body) if http_response.body.respond_to?(:replace)
- [http_response, rest_request, return_value]
- end
-
- def decompress_body(response)
- if gzip_disabled? || response.body.nil?
- response.body
- else
- case response[CONTENT_ENCODING]
- when GZIP
- Chef::Log.debug "decompressing gzip response"
- Zlib::Inflate.new(Zlib::MAX_WBITS + 16).inflate(response.body)
- when DEFLATE
- Chef::Log.debug "decompressing deflate response"
- Zlib::Inflate.inflate(response.body)
- else
- response.body
- end
- end
- end
-
- # This isn't used when this class is used as middleware; it returns an
- # object you can use to unzip/inflate a streaming response.
- def stream_decompressor_for(response)
- if gzip_disabled?
- NoopInflater.new
- else
- case response[CONTENT_ENCODING]
- when GZIP
- Chef::Log.debug "decompressing gzip stream"
- Zlib::Inflate.new(Zlib::MAX_WBITS + 16)
- when DEFLATE
- Chef::Log.debug "decompressing inflate stream"
- Zlib::Inflate.new
- else
- NoopInflater.new
- end
- end
- end
-
-
- # gzip is disabled using the disable_gzip => true option in the
- # constructor. When gzip is disabled, no 'Accept-Encoding' header will be
- # set, and the response will not be decompressed, no matter what the
- # Content-Encoding header of the response is. The intended use case for
- # this is to work around situations where you request +file.tar.gz+, but
- # the server responds with a content type of tar and a content encoding of
- # gzip, tricking the client into decompressing the response so you end up
- # with a tar archive (no gzip) named file.tar.gz
- def gzip_disabled?
- @disable_gzip
- end
-
- private
-
- def handle_options(opts)
- opts.each do |name, value|
- case name.to_s
- when 'disable_gzip'
- @disable_gzip = value
- end
- end
- end
-
-
- end
-
attr_reader :auth_credentials
attr_accessor :url, :cookies, :sign_on_redirect, :redirect_limit
@@ -182,7 +58,7 @@ class Chef
@redirects_followed = 0
@redirect_limit = 10
- @chef_json_inflater = ChefJSONInflater.new(options)
+ @chef_json_inflater = JSONToModelInflater.new(options)
@decompressor = Decompressor.new(options)
end
@@ -501,5 +377,15 @@ class Chef
raise Chef::Exceptions::InvalidPrivateKey, msg
end
+ public
+
+ ############################################################################
+ # DEPRECATED
+ ############################################################################
+
+ def decompress_body(body)
+ @decompressor.decompress_body(body)
+ end
+
end
end
diff --git a/lib/chef/rest/decompressor.rb b/lib/chef/rest/decompressor.rb
new file mode 100644
index 0000000000..1ce586a36a
--- /dev/null
+++ b/lib/chef/rest/decompressor.rb
@@ -0,0 +1,122 @@
+#--
+# Author:: Daniel DeLeo (<dan@opscode.com>)
+# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'zlib'
+require 'chef/rest/rest_request'
+
+class Chef
+ class REST
+
+ # Middleware-esque class for handling compression in HTTP responses.
+ class Decompressor
+ class NoopInflater
+ def inflate(chunk)
+ chunk
+ end
+ end
+
+ CONTENT_ENCODING = "content-encoding".freeze
+ GZIP = "gzip".freeze
+ DEFLATE = "deflate".freeze
+ IDENTITY = "identity".freeze
+
+ def initialize(opts={})
+ @disable_gzip = false
+ handle_options(opts)
+ end
+
+ def handle_request(method, url, headers={}, data=false)
+ headers[RESTRequest::ACCEPT_ENCODING] = RESTRequest::ENCODING_GZIP_DEFLATE unless gzip_disabled?
+ [method, url, headers, data]
+ end
+
+ def handle_response(http_response, rest_request, return_value)
+ # temporary hack, skip processing if return_value is false
+ # needed to keep conditional get stuff working correctly.
+ return [http_response, rest_request, return_value] if return_value == false
+ response_body = decompress_body(http_response)
+ http_response.body.replace(response_body) if http_response.body.respond_to?(:replace)
+ [http_response, rest_request, return_value]
+ end
+
+ def decompress_body(response)
+ if gzip_disabled? || response.body.nil?
+ response.body
+ else
+ case response[CONTENT_ENCODING]
+ when GZIP
+ Chef::Log.debug "decompressing gzip response"
+ Zlib::Inflate.new(Zlib::MAX_WBITS + 16).inflate(response.body)
+ when DEFLATE
+ Chef::Log.debug "decompressing deflate response"
+ Zlib::Inflate.inflate(response.body)
+ else
+ response.body
+ end
+ end
+ end
+
+ # This isn't used when this class is used as middleware; it returns an
+ # object you can use to unzip/inflate a streaming response.
+ def stream_decompressor_for(response)
+ if gzip_disabled?
+ NoopInflater.new
+ else
+ case response[CONTENT_ENCODING]
+ when GZIP
+ Chef::Log.debug "decompressing gzip stream"
+ Zlib::Inflate.new(Zlib::MAX_WBITS + 16)
+ when DEFLATE
+ Chef::Log.debug "decompressing inflate stream"
+ Zlib::Inflate.new
+ else
+ NoopInflater.new
+ end
+ end
+ end
+
+
+ # gzip is disabled using the disable_gzip => true option in the
+ # constructor. When gzip is disabled, no 'Accept-Encoding' header will be
+ # set, and the response will not be decompressed, no matter what the
+ # Content-Encoding header of the response is. The intended use case for
+ # this is to work around situations where you request +file.tar.gz+, but
+ # the server responds with a content type of tar and a content encoding of
+ # gzip, tricking the client into decompressing the response so you end up
+ # with a tar archive (no gzip) named file.tar.gz
+ def gzip_disabled?
+ @disable_gzip
+ end
+
+ private
+
+ def handle_options(opts)
+ opts.each do |name, value|
+ case name.to_s
+ when 'disable_gzip'
+ @disable_gzip = value
+ end
+ end
+ end
+
+
+ end
+ end
+end
+
+
diff --git a/lib/chef/rest/json_to_model_inflater.rb b/lib/chef/rest/json_to_model_inflater.rb
new file mode 100644
index 0000000000..f68cc76d37
--- /dev/null
+++ b/lib/chef/rest/json_to_model_inflater.rb
@@ -0,0 +1,56 @@
+#--
+# Author:: Daniel DeLeo (<dan@opscode.com>)
+# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'chef/json_compat'
+class Chef
+ class REST
+
+ # A Middleware-ish thing that takes an HTTP response, parses it as JSON if
+ # possible, and converts it into an appropriate model object if it contains
+ # a `json_class` key.
+ class JSONToModelInflater
+
+ def initialize(opts={})
+ end
+
+ def handle_request(method, url, headers={}, data=false)
+ headers['Accept'] = "application/json"
+ headers["Content-Type"] = 'application/json' if data
+ json_body = data ? Chef::JSONCompat.to_json(data) : nil
+ # Force encoding to binary to fix SSL related EOFErrors
+ # cf. http://tickets.opscode.com/browse/CHEF-2363
+ # http://redmine.ruby-lang.org/issues/5233
+ json_body.force_encoding(Encoding::BINARY) if json_body.respond_to?(:force_encoding)
+ [method, url, headers, json_body]
+ end
+
+ def handle_response(http_response, rest_request, return_value)
+ # temporary hack, skip processing if return_value is false
+ # needed to keep conditional get stuff working correctly.
+ return [http_response, rest_request, return_value] if return_value == false
+ if http_response['content-type'] =~ /json/
+ [http_response, rest_request, Chef::JSONCompat.from_json(http_response.body.chomp)]
+ else
+ Chef::Log.warn("Expected JSON response, but got content-type '#{http_response['content-type']}'")
+ return [http_response, rest_request, http_response.body.to_s]
+ end
+ end
+
+ end
+ end
+end