Page MenuHomePhorge

No OneTemporary

diff --git a/lib/puppet/network/http/error.rb b/lib/puppet/network/http/error.rb
index 01b7ecb55..4e521d130 100644
--- a/lib/puppet/network/http/error.rb
+++ b/lib/puppet/network/http/error.rb
@@ -1,55 +1,69 @@
+require 'json'
+
module Puppet::Network::HTTP::Error
Issues = Puppet::Network::HTTP::Issues
class HTTPError < Exception
attr_reader :status, :issue_kind
def initialize(message, status, issue_kind)
super(message)
@status = status
@issue_kind = issue_kind
end
+
+ def to_json
+ JSON({:message => message, :issue_kind => @issue_kind})
+ end
end
class HTTPNotAcceptableError < HTTPError
CODE = 406
def initialize(message, issue_kind = Issues::RUNTIME_ERROR)
super("Not Acceptable: " + message, CODE, issue_kind)
end
end
class HTTPNotFoundError < HTTPError
CODE = 404
def initialize(message, issue_kind = Issues::RUNTIME_ERROR)
super("Not Found: " + message, CODE, issue_kind)
end
end
class HTTPNotAuthorizedError < HTTPError
CODE = 403
def initialize(message, issue_kind = Issues::RUNTIME_ERROR)
super("Not Authorized: " + message, CODE, issue_kind)
end
end
class HTTPBadRequestError < HTTPError
CODE = 400
def initialize(message, issue_kind = Issues::RUNTIME_ERROR)
super("Bad Request: " + message, CODE, issue_kind)
end
end
class HTTPMethodNotAllowedError < HTTPError
CODE = 405
def initialize(message, issue_kind = Issues::RUNTIME_ERROR)
super("Method Not Allowed: " + message, CODE, issue_kind)
end
end
class HTTPServerError < HTTPError
CODE = 500
- def initialize(message, issue_kind = Issues::RUNTIME_ERROR)
- super("Server Error: " + message, CODE, issue_kind)
+
+ attr_reader :backtrace
+
+ def initialize(original_error, issue_kind = Issues::RUNTIME_ERROR)
+ super("Server Error: " + original_error.message, CODE, issue_kind)
+ @backtrace = original_error.backtrace
+ end
+
+ def to_json
+ JSON({:message => message, :issue_kind => @issue_kind, :stacktrace => self.backtrace})
end
end
end
diff --git a/lib/puppet/network/http/handler.rb b/lib/puppet/network/http/handler.rb
index 1f6d9d546..9ca2a3b85 100644
--- a/lib/puppet/network/http/handler.rb
+++ b/lib/puppet/network/http/handler.rb
@@ -1,193 +1,189 @@
module Puppet::Network::HTTP
end
require 'puppet/environments'
require 'puppet/network/http'
require 'puppet/network/http/api/v1'
require 'puppet/network/authentication'
require 'puppet/network/rights'
require 'puppet/util/profiler'
require 'resolv'
-require 'json'
module Puppet::Network::HTTP::Handler
include Puppet::Network::Authentication
include Puppet::Network::HTTP::Issues
# These shouldn't be allowed to be set by clients
# in the query string, for security reasons.
DISALLOWED_KEYS = ["node", "ip"]
def register(routes)
# There's got to be a simpler way to do this, right?
dupes = {}
routes.each { |r| dupes[r.path_matcher] = (dupes[r.path_matcher] || 0) + 1 }
dupes = dupes.collect { |pm, count| pm if count > 1 }.compact
if dupes.count > 0
raise ArgumentError, "Given multiple routes with identical path regexes: #{dupes.map{ |rgx| rgx.inspect }.join(', ')}"
end
@routes = routes
Puppet.debug("Routes Registered:")
@routes.each do |route|
Puppet.debug(route.inspect)
end
end
# Retrieve all headers from the http request, as a hash with the header names
# (lower-cased) as the keys
def headers(request)
raise NotImplementedError
end
def format_to_mime(format)
format.is_a?(Puppet::Network::Format) ? format.mime : format
end
# handle an HTTP request
def process(request, response)
new_response = Puppet::Network::HTTP::Response.new(self, response)
request_headers = headers(request)
request_params = params(request)
request_method = http_method(request)
request_path = path(request)
new_request = Puppet::Network::HTTP::Request.new(request_headers, request_params, request_method, request_path, request_path, client_cert(request), body(request))
response[Puppet::Network::HTTP::HEADER_PUPPET_VERSION] = Puppet.version
configure_profiler(request_headers, request_params)
warn_if_near_expiration(new_request.client_cert)
Puppet::Context.override(request_bindings()) do
Puppet::Util::Profiler.profile("Processed request #{request_method} #{request_path}") do
if route = @routes.find { |route| route.matches?(new_request) }
route.process(new_request, new_response)
else
raise Puppet::Network::HTTP::Error::HTTPNotFoundError.new("No route for #{new_request.method} #{new_request.path}", HANDLER_NOT_FOUND)
end
end
end
rescue Puppet::Network::HTTP::Error::HTTPError => e
- msg = e.message
- Puppet.info(msg)
- structured_msg = JSON({:message => msg, :issue_kind => e.issue_kind})
- new_response.respond_with(e.status, "application/json", structured_msg)
+ Puppet.info(e.message)
+ new_response.respond_with(e.status, "application/json", e.to_json)
rescue Exception => e
- http_e = Puppet::Network::HTTP::Error::HTTPServerError.new(e.message)
+ http_e = Puppet::Network::HTTP::Error::HTTPServerError.new(e)
Puppet.err(http_e.message)
- structured_msg = JSON({:message => http_e.message, :issue_kind => http_e.issue_kind, :stacktrace => e.backtrace})
- new_response.respond_with(500, "application/json", structured_msg)
+ new_response.respond_with(http_e.status, "application/json", http_e.to_json)
ensure
cleanup(request)
end
# Set the response up, with the body and status.
def set_response(response, body, status = 200)
raise NotImplementedError
end
# Set the specified format as the content type of the response.
def set_content_type(response, format)
raise NotImplementedError
end
# resolve node name from peer's ip address
# this is used when the request is unauthenticated
def resolve_node(result)
begin
return Resolv.getname(result[:ip])
rescue => detail
Puppet.err "Could not resolve #{result[:ip]}: #{detail}"
end
result[:ip]
end
private
# methods to be overridden by the including web server class
def http_method(request)
raise NotImplementedError
end
def path(request)
raise NotImplementedError
end
def request_key(request)
raise NotImplementedError
end
def body(request)
raise NotImplementedError
end
def params(request)
raise NotImplementedError
end
def client_cert(request)
raise NotImplementedError
end
def cleanup(request)
# By default, there is nothing to cleanup.
end
def decode_params(params)
params.select { |key, _| allowed_parameter?(key) }.inject({}) do |result, ary|
param, value = ary
result[param.to_sym] = parse_parameter_value(param, value)
result
end
end
def allowed_parameter?(name)
not (name.nil? || name.empty? || DISALLOWED_KEYS.include?(name))
end
def parse_parameter_value(param, value)
case value
when /^---/
Puppet.debug("Found YAML while processing request parameter #{param} (value: <#{value}>)")
Puppet.deprecation_warning("YAML in network requests is deprecated and will be removed in a future version. See http://links.puppetlabs.com/deprecate_yaml_on_network")
YAML.load(value, :safe => true, :deserialize_symbols => true)
when Array
value.collect { |v| parse_primitive_parameter_value(v) }
else
parse_primitive_parameter_value(value)
end
end
def parse_primitive_parameter_value(value)
case value
when "true"
true
when "false"
false
when /^\d+$/
Integer(value)
when /^\d+\.\d+$/
value.to_f
else
value
end
end
def configure_profiler(request_headers, request_params)
if (request_headers.has_key?(Puppet::Network::HTTP::HEADER_ENABLE_PROFILING.downcase) or Puppet[:profile])
Puppet::Util::Profiler.current = Puppet::Util::Profiler::WallClock.new(Puppet.method(:debug), request_params.object_id)
else
Puppet::Util::Profiler.current = Puppet::Util::Profiler::NONE
end
end
def request_bindings
{
:environments => Puppet::Environments::OnlyProduction.new
}
end
end

File Metadata

Mime Type
text/x-diff
Expires
Fri, Nov 1, 8:02 AM (1 d, 3 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
10074675
Default Alt Text
(8 KB)

Event Timeline