summaryrefslogtreecommitdiffstats
path: root/lib/puppet/network/http/mongrel/rest.rb
blob: 7ef13f046712d9af5d42e5d4109f29307e0109e9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
require 'puppet/network/http/handler'

class Puppet::Network::HTTP::MongrelREST < Mongrel::HttpHandler

  include Puppet::Network::HTTP::Handler

  ACCEPT_HEADER = "HTTP_ACCEPT".freeze # yay, zed's a crazy-man

  def initialize(args={})
    super()
    initialize_for_puppet(args)
  end

  def accept_header(request)
    request.params[ACCEPT_HEADER]
  end

  def content_type_header(request)
    request.params["HTTP_CONTENT_TYPE"]
  end

  # which HTTP verb was used in this request
  def http_method(request)
    request.params[Mongrel::Const::REQUEST_METHOD]
  end

  # Return the query params for this request.  We had to expose this method for
  # testing purposes.
  def params(request)
    params = Mongrel::HttpRequest.query_parse(request.params["QUERY_STRING"])
    params = decode_params(params)
    params.merge(client_info(request))
  end

  # what path was requested?
  def path(request)
    # LAK:NOTE See http://snurl.com/21zf8  [groups_google_com]
    #x = '/' + request.params[Mongrel::Const::REQUEST_PATH]
    request.params[Mongrel::Const::REQUEST_PATH]
  end

  # return the request body
  def body(request)
    request.body.read
  end

  def set_content_type(response, format)
    response.header['Content-Type'] = format_to_mime(format)
  end

  # produce the body of the response
  def set_response(response, result, status = 200)
    # Set the 'reason' (or 'message', as it's called in Webrick), when
    # we have a failure, unless we're on a version of mongrel that doesn't
    # support this.
    if status < 300
      unless result.is_a?(File)
        response.start(status) { |head, body| body.write(result) }
      else
        response.start(status) { |head, body| }
        response.send_status(result.stat.size)
        response.send_header
        response.send_file(result.path)
      end
    else
      begin
        response.start(status,false,result) { |head, body| body.write(result) }
      rescue ArgumentError
        response.start(status)              { |head, body| body.write(result) }
      end
    end
  end

  def client_info(request)
    result = {}
    params = request.params
    result[:ip] = params["HTTP_X_FORWARDED_FOR"] ? params["HTTP_X_FORWARDED_FOR"].split(',').last.strip : params["REMOTE_ADDR"]

    # JJM #906 The following dn.match regular expression is forgiving
    # enough to match the two Distinguished Name string contents
    # coming from Apache, Pound or other reverse SSL proxies.
    if dn = params[Puppet[:ssl_client_header]] and dn_matchdata = dn.match(/^.*?CN\s*=\s*(.*)/)
      result[:node] = dn_matchdata[1].to_str
      result[:authenticated] = (params[Puppet[:ssl_client_verify_header]] == 'SUCCESS')
    else
      result[:node] = resolve_node(result)
      result[:authenticated] = false
    end

    result
  end
end