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

Includes:
API::V1, RestAuthorization
Included in:
MongrelREST, RackREST, WEBrickREST
Defined in:
lib/vendor/puppet/network/http/handler.rb

Constant Summary

Constants included from API::V1

API::V1::METHOD_MAP

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from RestAuthorization

#authconfig, #check_authorization

Methods included from API::V1

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

Instance Attribute Details

#handlerObject (readonly)

Returns the value of attribute handler.



13
14
15
# File 'lib/vendor/puppet/network/http/handler.rb', line 13

def handler
  @handler
end

#serverObject (readonly)

Returns the value of attribute server.



13
14
15
# File 'lib/vendor/puppet/network/http/handler.rb', line 13

def server
  @server
end

Instance Method Details

#accept_header(request) ⇒ Object

Retrieve the accept header from the http request.

Raises:

  • (NotImplementedError)


16
17
18
# File 'lib/vendor/puppet/network/http/handler.rb', line 16

def accept_header(request)
  raise NotImplementedError
end

#content_type_header(request) ⇒ Object

Retrieve the Content-Type header from the http request.

Raises:

  • (NotImplementedError)


21
22
23
# File 'lib/vendor/puppet/network/http/handler.rb', line 21

def content_type_header(request)
  raise NotImplementedError
end

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

Execute our destroy.



154
155
156
157
158
# File 'lib/vendor/puppet/network/http/handler.rb', line 154

def do_destroy(indirection_name, key, params, request, response)
  result = model(indirection_name).indirection.destroy(key, params)

  return_yaml_response(response, result)
end

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



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/vendor/puppet/network/http/handler.rb', line 85

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
  if exception.is_a?(Exception)
    if Puppet[:trace] then
      puts exception.backtrace
      Puppet.err(exception.backtrace.join("\n"))
    end
    Puppet.err(exception)
  end
  set_content_type(response, "text/plain")
  set_response(response, exception.to_s, status)
end

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

Execute our find.



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/vendor/puppet/network/http/handler.rb', line 108

def do_find(indirection_name, key, params, request, response)
  unless result = model(indirection_name).indirection.find(key, params)
    Puppet.info("Could not find #{indirection_name} for '#{key}'")
    return do_exception(response, "Could not find #{indirection_name} #{key}", 404)
  end

  # The encoding of the result must include the format to use,
  # and it needs to be used for both the rendering and as
  # the content type.
  format = format_to_use(request)
  set_content_type(response, format)

  if result.respond_to?(:render)
    set_response(response, result.render(format))
  else
    set_response(response, result)
  end
end

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

Execute our head.



128
129
130
131
132
133
134
135
136
# File 'lib/vendor/puppet/network/http/handler.rb', line 128

def do_head(indirection_name, key, params, request, response)
  unless self.model(indirection_name).indirection.head(key, params)
    Puppet.info("Could not find #{indirection_name} for '#{key}'")
    return do_exception(response, "Could not find #{indirection_name} #{key}", 404)
  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_name, key, params, request, response) ⇒ Object

Execute our save.

Raises:

  • (ArgumentError)


161
162
163
164
165
166
167
168
169
# File 'lib/vendor/puppet/network/http/handler.rb', line 161

def do_save(indirection_name, key, params, request, response)
  data = body(request).to_s
  raise ArgumentError, "No data to save" if !data or data.empty?

  format = request_format(request)
  obj = model(indirection_name).convert_from(format, data)
  result = model(indirection_name).indirection.save(obj, key)
  return_yaml_response(response, result)
end

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

Execute our search.



139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/vendor/puppet/network/http/handler.rb', line 139

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

  if result.nil?
    return do_exception(response, "Could not find instances in #{indirection_name} with '#{key}'", 404)
  end

  format = format_to_use(request)
  set_content_type(response, format)

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

#format_to_mime(format) ⇒ Object



54
55
56
# File 'lib/vendor/puppet/network/http/handler.rb', line 54

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

#format_to_use(request) ⇒ Object

Which format to use when serializing our response or interpreting the request. IF the client provided a Content-Type use this, otherwise use the Accept header and just pick the first value.



28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/vendor/puppet/network/http/handler.rb', line 28

def format_to_use(request)
  unless header = accept_header(request)
    raise ArgumentError, "An Accept header must be provided to pick the right format"
  end

  format = nil
  header.split(/,\s*/).each do |name|
    next unless format = Puppet::Network::FormatHandler.format(name)
    next unless format.suitable?
    return format
  end

  raise "No specified acceptable formats (#{header}) are functional on this machine"
end

#initialize_for_puppet(server) ⇒ Object



58
59
60
# File 'lib/vendor/puppet/network/http/handler.rb', line 58

def initialize_for_puppet(server)
  @server = server
end

#model(indirection_name) ⇒ Object

Raises:

  • (ArgumentError)


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

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

#process(request, response) ⇒ Object

handle an HTTP request



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

def process(request, response)
  indirection, method, key, params = uri2indirection(http_method(request), path(request), params(request))

  check_authorization(indirection, method, key, params)

  send("do_#{method}", indirection, key, params, request, response)
rescue SystemExit,NoMemoryError
  raise
rescue Exception => e
  return do_exception(response, e)
end

#request_format(request) ⇒ Object



43
44
45
46
47
48
49
50
51
52
# File 'lib/vendor/puppet/network/http/handler.rb', line 43

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?
    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



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

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)


81
82
83
# File 'lib/vendor/puppet/network/http/handler.rb', line 81

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)


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

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