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

Includes:
Authentication, Authorization, API::V1
Included in:
RackREST, WEBrickREST
Defined in:
lib/puppet/network/http/handler.rb

Defined Under Namespace

Classes: HTTPError, HTTPNotAcceptableError, HTTPNotFoundError

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 API::V1

API::V1::METHOD_MAP

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Authentication

#warn_if_near_expiration

Methods included from Authorization

#authconfig, #check_authorization

Methods included from API::V1

#indirection2uri, #indirection_method, #plurality, #pluralize, #request_to_uri_and_body, #uri2indirection

Instance Attribute Details

#handlerObject (readonly)



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

def handler
  @handler
end

#serverObject (readonly)



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

def server
  @server
end

Instance Method Details

#accept_header(request) ⇒ Object

Retrieve the accept header from the http request.

Raises:

  • (NotImplementedError)


51
52
53
# File 'lib/puppet/network/http/handler.rb', line 51

def accept_header(request)
  raise NotImplementedError
end

#content_type_header(request) ⇒ Object

Retrieve the Content-Type header from the http request.

Raises:

  • (NotImplementedError)


56
57
58
# File 'lib/puppet/network/http/handler.rb', line 56

def content_type_header(request)
  raise NotImplementedError
end

#do_destroy(indirection, key, params, request, response) ⇒ Object

Execute our destroy.



183
184
185
186
187
188
189
190
# File 'lib/puppet/network/http/handler.rb', line 183

def do_destroy(indirection, key, params, request, response)
  formatter = accepted_response_formatter_or_yaml_for(indirection.model, request)

  result = indirection.destroy(key, params)

  set_content_type(response, formatter)
  set_response(response, formatter.render(result))
end

#do_exception(response, exception, status = 400) ⇒ Object



124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/puppet/network/http/handler.rb', line 124

def do_exception(response, exception, status=400)
  if exception.is_a?(Puppet::Network::AuthorizationError)
    # make sure we return the correct status code
    # for authorization issues
    status = 403 if status == 400
  end

  Puppet.log_exception(exception)

  set_content_type(response, "text/plain")
  set_response(response, exception.to_s, status)
end

#do_find(indirection, key, params, request, response) ⇒ Object

Execute our find.



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/puppet/network/http/handler.rb', line 138

def do_find(indirection, key, params, request, response)
  unless result = indirection.find(key, params)
    raise HTTPNotFoundError, "Could not find #{indirection.name} #{key}"
  end

  format = accepted_response_formatter_for(indirection.model, request)
  set_content_type(response, format)

  rendered_result = result
  if result.respond_to?(:render)
    Puppet::Util::Profiler.profile("Rendered result in #{format}") do
      rendered_result = result.render(format)
    end
  end

  Puppet::Util::Profiler.profile("Sent response") do
    set_response(response, rendered_result)
  end
end

#do_head(indirection, key, params, request, response) ⇒ Object

Execute our head.



159
160
161
162
163
164
165
166
# File 'lib/puppet/network/http/handler.rb', line 159

def do_head(indirection, key, params, request, response)
  unless indirection.head(key, params)
    raise HTTPNotFoundError, "Could not find #{indirection.name} #{key}"
  end

  # No need to set a response because no response is expected from a
  # HEAD request.  All we need to do is not die.
end

#do_save(indirection, key, params, request, response) ⇒ Object

Execute our save.



193
194
195
196
197
198
199
200
201
# File 'lib/puppet/network/http/handler.rb', line 193

def do_save(indirection, key, params, request, response)
  formatter = accepted_response_formatter_or_yaml_for(indirection.model, request)
  sent_object = read_body_into_model(indirection.model, request)

  result = indirection.save(sent_object, key)

  set_content_type(response, formatter)
  set_response(response, formatter.render(result))
end

#do_search(indirection, key, params, request, response) ⇒ Object

Execute our search.



169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/puppet/network/http/handler.rb', line 169

def do_search(indirection, key, params, request, response)
  result = indirection.search(key, params)

  if result.nil?
    raise HTTPNotFoundError, "Could not find instances in #{indirection.name} with '#{key}'"
  end

  format = accepted_response_formatter_for(indirection.model, request)
  set_content_type(response, format)

  set_response(response, indirection.model.render_multiple(format, result))
end

#format_to_mime(format) ⇒ Object



72
73
74
# File 'lib/puppet/network/http/handler.rb', line 72

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)


46
47
48
# File 'lib/puppet/network/http/handler.rb', line 46

def headers(request)
  raise NotImplementedError
end

#initialize_for_puppet(server) ⇒ Object



76
77
78
# File 'lib/puppet/network/http/handler.rb', line 76

def initialize_for_puppet(server)
  @server = server
end

#process(request, response) ⇒ Object

handle an HTTP request



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/puppet/network/http/handler.rb', line 81

def process(request, response)
  request_headers = headers(request)
  request_params = params(request)
  request_method = http_method(request)
  request_path = path(request)

  response[Puppet::Network::HTTP::HEADER_PUPPET_VERSION] = Puppet.version

  configure_profiler(request_headers, request_params)

  Puppet::Util::Profiler.profile("Processed request #{request_method} #{request_path}") do
    indirection_name, method, key, params = uri2indirection(request_method, request_path, request_params)

    check_authorization(indirection_name, method, key, params)
    warn_if_near_expiration(client_cert(request))

    indirection = Puppet::Indirector::Indirection.instance(indirection_name.to_sym)
    raise ArgumentError, "Could not find indirection '#{indirection_name}'" unless indirection

    if !indirection.allow_remote_requests?
      raise HTTPNotFoundError, "No handler for #{indirection.name}"
    end

    send("do_#{method}", indirection, key, params, request, response)
  end
rescue HTTPError => e
  return do_http_control_exception(response, e)
rescue Exception => e
  return do_exception(response, e)
ensure
  cleanup(request)
end

#request_format(request) ⇒ Object



60
61
62
63
64
65
66
67
68
69
70
# File 'lib/puppet/network/http/handler.rb', line 60

def request_format(request)
  if header = content_type_header(request)
    header.gsub!(/\s*;.*$/,'') # strip any charset
    format = Puppet::Network::FormatHandler.mime(header)
    raise "Client sent a mime-type (#{header}) that doesn't correspond to a format we support" if format.nil?
    report_if_deprecated(format)
    return format.name.to_s if format.suitable?
  end

  raise "No Content-Type header was received, it isn't possible to unserialize the request"
end

#resolve_node(result) ⇒ Object

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



205
206
207
208
209
210
211
212
# File 'lib/puppet/network/http/handler.rb', line 205

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

#set_content_type(response, format) ⇒ Object

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

Raises:

  • (NotImplementedError)


120
121
122
# File 'lib/puppet/network/http/handler.rb', line 120

def set_content_type(response, format)
  raise NotImplementedError
end

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

Set the response up, with the body and status.

Raises:

  • (NotImplementedError)


115
116
117
# File 'lib/puppet/network/http/handler.rb', line 115

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