Module: Puppet::Network::HTTP::Handler

Includes:
Issues
Defined in:
lib/puppet/network/http/handler.rb

Constant Summary collapse

DISALLOWED_KEYS =

These shouldn't be allowed to be set by clients in the query string, for security reasons.

["node", "ip"]

Constants included from Issues

Issues::ENVIRONMENT_NOT_FOUND, Issues::FAILED_AUTHORIZATION, Issues::HANDLER_NOT_FOUND, Issues::MISSING_HEADER_FIELD, Issues::NO_INDIRECTION_REMOTE_REQUESTS, Issues::RESOURCE_NOT_FOUND, Issues::RUNTIME_ERROR, Issues::UNSUPPORTED_FORMAT, Issues::UNSUPPORTED_MEDIA_TYPE, Issues::UNSUPPORTED_METHOD

Instance Method Summary collapse

Instance Method Details

#find_route_or_raise(request) ⇒ Object


107
108
109
110
111
112
113
114
115
116
# File 'lib/puppet/network/http/handler.rb', line 107

def find_route_or_raise(request)
  route = @routes.find { |r| r.matches?(request) }
  if route
    return route
  else
    raise Puppet::Network::HTTP::Error::HTTPNotFoundError.new(
            _("No route for %{request} %{path}") % { request: request.method, path: request.path },
            HANDLER_NOT_FOUND)
  end
end

#format_to_mime(format) ⇒ Object

Deprecated.

The mime type is always passed to the `set_content_type` method, so it is no longer necessary to retrieve the Format's mime type.


43
44
45
# File 'lib/puppet/network/http/handler.rb', line 43

def format_to_mime(format)
  format.is_a?(Puppet::Network::Format) ? format.mime : format
end

#headers(request) ⇒ Object

Retrieve all headers from the http request, as a hash with the header names (lower-cased) as the keys

Raises:

  • (NotImplementedError)

35
36
37
# File 'lib/puppet/network/http/handler.rb', line 35

def headers(request)
  raise NotImplementedError
end

#make_generic_request(request) ⇒ Object

Create a generic puppet request from the implementation-specific request created by the web server


49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/puppet/network/http/handler.rb', line 49

def make_generic_request(request)
  request_path = path(request)

  Puppet::Network::HTTP::Request.new(
    headers(request),
    params(request),
    http_method(request),
    request_path, # path
    request_path, # routing_path
    client_cert(request),
    body(request)
  )
end

#process(external_request, response) ⇒ Object

handle an HTTP request


77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/puppet/network/http/handler.rb', line 77

def process(external_request, response)
  # The response_wrapper stores the response and modifies it as a side effect.
  # The caller will use the original response
  response_wrapper = Puppet::Network::HTTP::Response.new(self, response)
  request = make_generic_request(external_request)

  set_puppet_version_header(response)

  respond_to_errors(response_wrapper) do
    with_request_profiling(request) do
      find_route_or_raise(request).process(request, response_wrapper)
    end
  end
end

#register(routes) ⇒ Object


17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/puppet/network/http/handler.rb', line 17

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: %{regexes}") % { regexes: dupes.map{ |rgx| rgx.inspect }.join(', ') }
  end

  @routes = routes
  Puppet.debug("Routes Registered:")
  @routes.each do |route|
    Puppet.debug(route.inspect)
  end
end

#resolve_node(result) ⇒ Object

resolve node name from peer's ip address this is used when the request is unauthenticated


134
135
136
137
138
139
140
141
# File 'lib/puppet/network/http/handler.rb', line 134

def resolve_node(result)
  begin
    return Resolv.getname(result[:ip])
  rescue => detail
    Puppet.err _("Could not resolve %{ip}: %{detail}") % { ip: result[:ip], detail: detail }
  end
  result[:ip]
end

#respond_to_errors(response) ⇒ Object


92
93
94
95
96
97
98
99
100
101
# File 'lib/puppet/network/http/handler.rb', line 92

def respond_to_errors(response)
  yield
rescue Puppet::Network::HTTP::Error::HTTPError => e
  Puppet.info(e.message)
  respond_with_http_error(response, e)
rescue StandardError => e
  http_e = Puppet::Network::HTTP::Error::HTTPServerError.new(e)
  Puppet.err([http_e.message, *e.backtrace].join("\n"))
  respond_with_http_error(response, http_e)
end

#respond_with_http_error(response, exception) ⇒ Object


103
104
105
# File 'lib/puppet/network/http/handler.rb', line 103

def respond_with_http_error(response, exception)
  response.respond_with(exception.status, "application/json", exception.to_json)
end

#set_content_type(response, format) ⇒ Object

Set the specified format as the content type of the response.

Raises:

  • (NotImplementedError)

128
129
130
# File 'lib/puppet/network/http/handler.rb', line 128

def set_content_type(response, format)
  raise NotImplementedError
end

#set_puppet_version_header(response) ⇒ Object


118
119
120
# File 'lib/puppet/network/http/handler.rb', line 118

def set_puppet_version_header(response)
  response[Puppet::Network::HTTP::HEADER_PUPPET_VERSION] = Puppet.version
end

#set_response(response, body, status = 200) ⇒ Object

Set the response up, with the body and status.

Raises:

  • (NotImplementedError)

123
124
125
# File 'lib/puppet/network/http/handler.rb', line 123

def set_response(response, body, status = 200)
  raise NotImplementedError
end

#with_request_profiling(request) ⇒ Object


63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/puppet/network/http/handler.rb', line 63

def with_request_profiling(request)
  profiler = configure_profiler(request.headers, request.params)

  Puppet::Util::Profiler.profile(
    _("Processed request %{request_method} %{request_path}") % { request_method: request.method, request_path: request.path },
    [:http, request.method, request.path]
  ) do
    yield
  end
ensure
  remove_profiler(profiler) if profiler
end