All requests should now have an ipaddress add to them, they
should always be marked authenticated or not, and they should
have the certificate name set as their 'node' if a certificate
is present.

They both use the same methods they use for xmlrpc,
although there's no common code, to facilitate deprecation
of xmlrpc.

Signed-off-by: Luke Kanies <[EMAIL PROTECTED]>
---
 lib/puppet/network/http/handler.rb      |   56 +++++------
 lib/puppet/network/http/mongrel/rest.rb |   49 +++++++---
 lib/puppet/network/http/webrick/rest.rb |   51 +++++++---
 spec/unit/network/http/mongrel/rest.rb  |  164 ++++++++++++++++++++++++-------
 spec/unit/network/http/webrick/rest.rb  |  165 ++++++++++++++++++++-----------
 5 files changed, 332 insertions(+), 153 deletions(-)

diff --git a/lib/puppet/network/http/handler.rb 
b/lib/puppet/network/http/handler.rb
index 7113c92..8c6abde 100644
--- a/lib/puppet/network/http/handler.rb
+++ b/lib/puppet/network/http/handler.rb
@@ -1,30 +1,30 @@
 module Puppet::Network::HTTP::Handler
-    
+
     def initialize_for_puppet(args = {})
         raise ArgumentError unless @server = args[:server]
         raise ArgumentError unless @handler = args[:handler]
         @model = find_model_for_handler(@handler)
     end
-    
+
     # handle an HTTP request
     def process(request, response)
         return do_find(request, response)       if get?(request)    and 
singular?(request)
         return do_search(request, response)     if get?(request)    and 
plural?(request)
         return do_destroy(request, response)    if delete?(request) and 
singular?(request)
-        return do_save(request, response)       if put?(request) and 
singular?(request)
+        return do_save(request, response)       if put?(request)    and 
singular?(request)
         raise ArgumentError, "Did not understand HTTP #{http_method(request)} 
request for '#{path(request)}'"
     rescue Exception => e
         return do_exception(request, response, e)
     end
-    
+
   private
 
     def model
-      @model
+        @model
     end
-    
+
     def do_find(request, response)
-        key = request_key(request) || raise(ArgumentError, "Could not locate 
lookup key in request path [#{path}]")
+        key = request_key(request) || raise(ArgumentError, "Could not locate 
lookup key in request path [#{path(request)}]")
         args = params(request)
         result = model.find(key, args).to_yaml
         encode_result(request, response, result)
@@ -37,7 +37,7 @@ module Puppet::Network::HTTP::Handler
     end
 
     def do_destroy(request, response)
-        key = request_key(request) || raise(ArgumentError, "Could not locate 
lookup key in request path [#{path}]")
+        key = request_key(request) || raise(ArgumentError, "Could not locate 
lookup key in request path [#{path(request)}]")
         args = params(request)
         result = model.destroy(key, args)
         encode_result(request, response, YAML.dump(result))
@@ -46,71 +46,67 @@ module Puppet::Network::HTTP::Handler
     def do_save(request, response)
         data = body(request).to_s
         raise ArgumentError, "No data to save" if !data or data.empty?
-        # args = params(request)
+        args = params(request)
         obj = model.from_yaml(data)
-        result = save_object(obj).to_yaml
+        result = obj.save(args).to_yaml
         encode_result(request, response, result)
     end
-    
-    def save_object(obj)
-      obj.save
-    end
-  
+
     def do_exception(request, response, exception, status=404)
         encode_result(request, response, exception.to_yaml, status)
     end
-  
+
     def find_model_for_handler(handler)
         Puppet::Indirector::Indirection.model(handler) || 
             raise(ArgumentError, "Cannot locate indirection [#{handler}].")
     end
-    
+
     def get?(request)
         http_method(request) == 'GET'
     end
-    
+
     def put?(request)
         http_method(request) == 'PUT'
     end
-    
+
     def delete?(request)
         http_method(request) == 'DELETE'
     end
-    
+
     def singular?(request)
         %r{/[EMAIL PROTECTED](path(request))
     end
-    
+
     def plural?(request)
         %r{/[EMAIL PROTECTED](path(request))
     end
-    
-  # methods to be overridden by the including web server class
-    
+
+    # methods to be overridden by the including web server class
+
     def register_handler
         raise NotImplementedError
     end
-    
+
     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 encode_result(request, response, result, status = 200)
         raise NotImplementedError
     end
diff --git a/lib/puppet/network/http/mongrel/rest.rb 
b/lib/puppet/network/http/mongrel/rest.rb
index 2a3d4f1..d1257d5 100644
--- a/lib/puppet/network/http/mongrel/rest.rb
+++ b/lib/puppet/network/http/mongrel/rest.rb
@@ -3,45 +3,64 @@ require 'puppet/network/http/handler'
 class Puppet::Network::HTTP::MongrelREST < Mongrel::HttpHandler
 
   include Puppet::Network::HTTP::Handler
-  
-  def initialize(args={})
-    super()
-    initialize_for_puppet(args)
-  end
+
+    def initialize(args={})
+        super()
+        initialize_for_puppet(args)
+    end
+
+    # Return the query params for this request.  We had to expose this method 
for
+    # testing purposes.
+    def params(request)
+        
Mongrel::HttpRequest.query_parse(request.params["QUERY_STRING"]).merge(client_info(request))
+    end
 
   private
- 
+
     # which HTTP verb was used in this request
     def http_method(request)
         request.params[Mongrel::Const::REQUEST_METHOD]
     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].split('/')[1]
     end
-    
+
     # return the key included in the request path
     def request_key(request)
         # LAK:NOTE See http://snurl.com/21zf8  [groups_google_com] 
         x = request.params[Mongrel::Const::REQUEST_PATH].split('/')[2]        
     end
-    
+
     # return the request body
     def body(request)
         request.body
     end
-    
-    # return the query params for this request
-    def params(request)
-        Mongrel::HttpRequest.query_parse(request.params["QUERY_STRING"])
-    end
-    
+
     # produce the body of the response
     def encode_result(request, response, result, status = 200)
         response.start(status) do |head, body|
             body.write(result)
         end
     end
+
+    def client_info(request)
+        result = {}
+        params = request.params
+        result[:ip] = 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[:authenticated] = false
+        end
+
+        return result
+    end
 end
diff --git a/lib/puppet/network/http/webrick/rest.rb 
b/lib/puppet/network/http/webrick/rest.rb
index b439121..a235fb4 100644
--- a/lib/puppet/network/http/webrick/rest.rb
+++ b/lib/puppet/network/http/webrick/rest.rb
@@ -1,46 +1,67 @@
 require 'puppet/network/http/handler'
 
 class Puppet::Network::HTTP::WEBrickREST < 
WEBrick::HTTPServlet::AbstractServlet
-  
+
     include Puppet::Network::HTTP::Handler
-    
+
     def initialize(server, handler)
-      raise ArgumentError, "server is required" unless server
-      super(server)
-      initialize_for_puppet(:server => server, :handler => handler)
+        raise ArgumentError, "server is required" unless server
+        super(server)
+        initialize_for_puppet(:server => server, :handler => handler)
+    end
+
+    # We had to expose this method for testing purposes.
+    def params(request)
+        result = request.query
+        result.merge(client_information(request))
     end
 
     # WEBrick uses a service() method to respond to requests.  Simply delegate 
to the handler response() method.
     def service(request, response)
         process(request, response)
     end
-    
+
   private
-    
+
     def http_method(request)
         request.request_method
     end
-    
+
     def path(request)
         # LAK:NOTE See http://snurl.com/21zf8  [groups_google_com] 
         x = '/' + request.path.split('/')[1]
     end
-    
+
     def request_key(request)
         # LAK:NOTE See http://snurl.com/21zf8  [groups_google_com] 
         x = request.path.split('/')[2]
     end
-    
+
     def body(request)
         request.body
     end
-    
-    def params(request)
-        request.query
-    end
-    
+
     def encode_result(request, response, result, status = 200)
         response.status = status
         response.body = result
     end
+
+    # Retrieve node/cert/ip information from the request object.
+    def client_information(request)
+        result = {}
+        if peer = request.peeraddr and ip = peer[3]
+            result[:ip] = ip
+        end
+
+        # If they have a certificate (which will almost always be true)
+        # then we get the hostname from the cert, instead of via IP
+        # info
+        result[:authenticated] = false
+        if cert = request.client_cert and nameary = cert.subject.to_a.find { 
|ary| ary[0] == "CN" }
+            result[:node] = nameary[1]
+            result[:authenticated] = true
+        end
+
+        result
+    end
 end
diff --git a/spec/unit/network/http/mongrel/rest.rb 
b/spec/unit/network/http/mongrel/rest.rb
index b483bbd..1dd7de4 100644
--- a/spec/unit/network/http/mongrel/rest.rb
+++ b/spec/unit/network/http/mongrel/rest.rb
@@ -3,7 +3,7 @@ require 'puppet/network/http'
 
 describe Puppet::Network::HTTP::MongrelREST, "when initializing" do
     confine "Mongrel is not available" => Puppet.features.mongrel?
-    
+
     before do
         @mock_mongrel = mock('Mongrel server')
         @mock_mongrel.stubs(:register)
@@ -11,20 +11,20 @@ describe Puppet::Network::HTTP::MongrelREST, "when 
initializing" do
         
Puppet::Indirector::Indirection.stubs(:model).with(:foo).returns(@mock_model)
         @params = { :server => @mock_mongrel, :handler => :foo }
     end
-    
+
     it "should require access to a Mongrel server" do
         Proc.new { Puppet::Network::HTTP::MongrelREST.new(@params.delete_if 
{|k,v| :server == k })}.should raise_error(ArgumentError)
     end
-    
+
     it "should require an indirection name" do
         Proc.new { Puppet::Network::HTTP::MongrelREST.new(@params.delete_if 
{|k,v| :handler == k })}.should raise_error(ArgumentError)        
     end
-    
+
     it "should look up the indirection model from the indirection name" do
         
Puppet::Indirector::Indirection.expects(:model).with(:foo).returns(@mock_model)
         Puppet::Network::HTTP::MongrelREST.new(@params)
     end
-    
+
     it "should fail if the indirection is not known" do
         Puppet::Indirector::Indirection.expects(:model).with(:foo).returns(nil)
         Proc.new { Puppet::Network::HTTP::MongrelREST.new(@params) }.should 
raise_error(ArgumentError)
@@ -33,7 +33,7 @@ end
 
 describe Puppet::Network::HTTP::MongrelREST, "when receiving a request" do
     confine "Mongrel is not available" => Puppet.features.mongrel?
-    
+
     before do
         @mock_request = stub('mongrel http request')
         @mock_head = stub('response head')
@@ -45,28 +45,28 @@ describe Puppet::Network::HTTP::MongrelREST, "when 
receiving a request" do
         
Puppet::Indirector::Indirection.stubs(:model).with(:foo).returns(@mock_model_class)
         @handler = Puppet::Network::HTTP::MongrelREST.new(:server => 
@mock_mongrel, :handler => :foo)
     end
-    
+
     def setup_find_request(params = {})
         @mock_request.stubs(:params).returns({  Mongrel::Const::REQUEST_METHOD 
=> 'GET', 
                                                 Mongrel::Const::REQUEST_PATH 
=> '/foo/key',
                                                 'QUERY_STRING' => 
''}.merge(params))
         @mock_model_class.stubs(:find)
     end
-    
+
     def setup_search_request(params = {})
         @mock_request.stubs(:params).returns({  Mongrel::Const::REQUEST_METHOD 
=> 'GET', 
                                                 Mongrel::Const::REQUEST_PATH 
=> '/foos',
                                                 'QUERY_STRING' => '' 
}.merge(params))
         @mock_model_class.stubs(:search).returns([])        
     end
-    
+
     def setup_destroy_request(params = {})
         @mock_request.stubs(:params).returns({  Mongrel::Const::REQUEST_METHOD 
=> 'DELETE', 
                                                 Mongrel::Const::REQUEST_PATH 
=> '/foo/key',
                                                 'QUERY_STRING' => '' 
}.merge(params))
         @mock_model_class.stubs(:destroy)
     end
-    
+
     def setup_save_request(params = {})
         @mock_request.stubs(:params).returns({  Mongrel::Const::REQUEST_METHOD 
=> 'PUT', 
                                                 Mongrel::Const::REQUEST_PATH 
=> '/foo',
@@ -75,26 +75,26 @@ describe Puppet::Network::HTTP::MongrelREST, "when 
receiving a request" do
         @mock_model_instance = stub('indirected model instance', :save => true)
         @mock_model_class.stubs(:from_yaml).returns(@mock_model_instance)
     end
-    
+
     def setup_bad_request
         @mock_request.stubs(:params).returns({ Mongrel::Const::REQUEST_METHOD 
=> 'POST', Mongrel::Const::REQUEST_PATH => '/foos'})        
     end
 
     it "should call the model find method if the request represents a singular 
HTTP GET" do
         setup_find_request
-        @mock_model_class.expects(:find).with('key', {})
+        @mock_model_class.expects(:find).with { |key, args| key == 'key' }
         @handler.process(@mock_request, @mock_response)
     end
 
     it "should call the model search method if the request represents a plural 
HTTP GET" do
         setup_search_request
-        @mock_model_class.expects(:search).with({}).returns([])
+        @mock_model_class.expects(:search).returns([])
         @handler.process(@mock_request, @mock_response)
     end
-    
+
     it "should call the model destroy method if the request represents an HTTP 
DELETE" do
         setup_destroy_request
-        @mock_model_class.expects(:destroy).with('key', {})
+        @mock_model_class.expects(:destroy).with { |key, args| key == 'key' }
         @handler.process(@mock_request, @mock_response)
     end
 
@@ -103,13 +103,13 @@ describe Puppet::Network::HTTP::MongrelREST, "when 
receiving a request" do
         @mock_model_instance.expects(:save)
         @handler.process(@mock_request, @mock_response)
     end
-    
+
     it "should fail if the HTTP method isn't supported" do
         @mock_request.stubs(:params).returns({ Mongrel::Const::REQUEST_METHOD 
=> 'POST', Mongrel::Const::REQUEST_PATH => '/foo'})
         @mock_response.expects(:start).with(404)
         @handler.process(@mock_request, @mock_response)
     end
-    
+
     it "should fail if the request's pluralization is wrong" do
         @mock_request.stubs(:params).returns({ Mongrel::Const::REQUEST_METHOD 
=> 'DELETE', Mongrel::Const::REQUEST_PATH => '/foos/key'})
         @mock_response.expects(:start).with(404)
@@ -127,8 +127,74 @@ describe Puppet::Network::HTTP::MongrelREST, "when 
receiving a request" do
         @mock_response.expects(:start).with(404)
         @handler.process(@mock_request, @mock_response)
     end
-    
-    
+
+    describe "and determining the request parameters", :shared => true do
+        before do
+            @mock_request.stubs(:params).returns({})
+        end
+
+        it "should include the HTTP request parameters" do
+            @mock_request.expects(:params).returns('QUERY_STRING' => 
'foo=baz&bar=xyzzy')
+            result = @handler.params(@mock_request)
+            result["foo"].should == "baz"
+            result["bar"].should == "xyzzy"
+        end
+
+        it "should pass the client's ip address to model find" do
+            @mock_request.stubs(:params).returns("REMOTE_ADDR" => "ipaddress")
+            @handler.params(@mock_request)[:ip].should == "ipaddress"
+        end
+
+        it "should use the :ssl_client_header to determine the parameter when 
looking for the certificate" do
+            Puppet.settings.stubs(:value).returns "eh"
+            Puppet.settings.expects(:value).with(:ssl_client_header).returns 
"myheader"
+            @mock_request.stubs(:params).returns("myheader" => 
"/CN=host.domain.com")
+            @handler.params(@mock_request)
+        end
+
+        it "should retrieve the hostname by matching the certificate 
parameter" do
+            Puppet.settings.stubs(:value).returns "eh"
+            Puppet.settings.expects(:value).with(:ssl_client_header).returns 
"myheader"
+            @mock_request.stubs(:params).returns("myheader" => 
"/CN=host.domain.com")
+            @handler.params(@mock_request)[:node].should == "host.domain.com"
+        end
+
+        it "should use the :ssl_client_header to determine the parameter for 
checking whether the host certificate is valid" do
+            Puppet.settings.stubs(:value).with(:ssl_client_header).returns 
"certheader"
+            
Puppet.settings.expects(:value).with(:ssl_client_verify_header).returns 
"myheader"
+            @mock_request.stubs(:params).returns("myheader" => "SUCCESS", 
"certheader" => "/CN=host.domain.com")
+            @handler.params(@mock_request)
+        end
+
+        it "should consider the host authenticated if the validity parameter 
contains 'SUCCESS'" do
+            Puppet.settings.stubs(:value).with(:ssl_client_header).returns 
"certheader"
+            
Puppet.settings.stubs(:value).with(:ssl_client_verify_header).returns "myheader"
+            @mock_request.stubs(:params).returns("myheader" => "SUCCESS", 
"certheader" => "/CN=host.domain.com")
+            @handler.params(@mock_request)[:authenticated].should be_true
+        end
+
+        it "should consider the host unauthenticated if the validity parameter 
does not contain 'SUCCESS'" do
+            Puppet.settings.stubs(:value).with(:ssl_client_header).returns 
"certheader"
+            
Puppet.settings.stubs(:value).with(:ssl_client_verify_header).returns "myheader"
+            @mock_request.stubs(:params).returns("myheader" => "whatever", 
"certheader" => "/CN=host.domain.com")
+            @handler.params(@mock_request)[:authenticated].should be_false
+        end
+
+        it "should consider the host unauthenticated if no certificate 
information is present" do
+            Puppet.settings.stubs(:value).with(:ssl_client_header).returns 
"certheader"
+            
Puppet.settings.stubs(:value).with(:ssl_client_verify_header).returns "myheader"
+            @mock_request.stubs(:params).returns("myheader" => nil, 
"certheader" => "SUCCESS")
+            @handler.params(@mock_request)[:authenticated].should be_false
+        end
+
+        it "should not pass a node name to model method if no certificate 
information is present" do
+            Puppet.settings.stubs(:value).returns "eh"
+            Puppet.settings.expects(:value).with(:ssl_client_header).returns 
"myheader"
+            @mock_request.stubs(:params).returns("myheader" => nil)
+            @handler.params(@mock_request).should_not be_include(:node)
+        end
+    end
+
     describe "when finding a model instance" do |variable|
         it "should fail to find model if key is not specified" do
             @mock_request.stubs(:params).returns({ 
Mongrel::Const::REQUEST_METHOD => 'GET', Mongrel::Const::REQUEST_PATH => 
'/foo'})
@@ -136,20 +202,21 @@ describe Puppet::Network::HTTP::MongrelREST, "when 
receiving a request" do
             @handler.process(@mock_request, @mock_response)
         end
 
-        it "should pass HTTP request parameters to model find" do
+        it "should use a common method for determining the request parameters" 
do
             setup_find_request('QUERY_STRING' => 'foo=baz&bar=xyzzy')
+            @handler.expects(:params).returns(:foo => :baz, :bar => :xyzzy)
             @mock_model_class.expects(:find).with do |key, args|
-                key == 'key' and args['foo'] == 'baz' and args['bar'] == 
'xyzzy'
+                args[:foo] == :baz and args[:bar] == :xyzzy
             end
             @handler.process(@mock_request, @mock_response)
         end
-        
+
         it "should generate a 200 response when a model find call succeeds" do
             setup_find_request
             @mock_response.expects(:start).with(200)
             @handler.process(@mock_request, @mock_response)
         end
-        
+
         it "should return a serialized object when a model find call succeeds" 
do
             setup_find_request
             @mock_model_instance = stub('model instance')
@@ -157,7 +224,7 @@ describe Puppet::Network::HTTP::MongrelREST, "when 
receiving a request" do
             @mock_model_class.stubs(:find).returns(@mock_model_instance)
             @handler.process(@mock_request, @mock_response)                  
         end
-        
+
         it "should serialize a controller exception when an exception is 
thrown by find" do
            setup_find_request
            @mock_model_class.expects(:find).raises(ArgumentError) 
@@ -172,7 +239,16 @@ describe Puppet::Network::HTTP::MongrelREST, "when 
receiving a request" do
             @mock_response.expects(:start).with(404)
             @handler.process(@mock_request, @mock_response)
         end
-        
+
+        it "should use a common method for determining the request parameters" 
do
+            setup_destroy_request('QUERY_STRING' => 'foo=baz&bar=xyzzy')
+            @handler.expects(:params).returns(:foo => :baz, :bar => :xyzzy)
+            @mock_model_class.expects(:destroy).with do |key, args|
+                args[:foo] == :baz and args[:bar] == :xyzzy
+            end
+            @handler.process(@mock_request, @mock_response)
+        end
+
         it "should pass HTTP request parameters to model destroy" do
             setup_destroy_request('QUERY_STRING' => 'foo=baz&bar=xyzzy')
             @mock_model_class.expects(:destroy).with do |key, args|
@@ -180,20 +256,20 @@ describe Puppet::Network::HTTP::MongrelREST, "when 
receiving a request" do
             end
             @handler.process(@mock_request, @mock_response)
         end
-        
+
         it "should generate a 200 response when a model destroy call succeeds" 
do
             setup_destroy_request
             @mock_response.expects(:start).with(200)
             @handler.process(@mock_request, @mock_response)
         end
-        
+
         it "should return a serialized success result when a model destroy 
call succeeds" do
             setup_destroy_request
             @mock_model_class.stubs(:destroy).returns(true)
             @mock_body.expects(:write).with("--- true\n")
             @handler.process(@mock_request, @mock_response)
         end
-        
+
         it "should serialize a controller exception when an exception is 
thrown by destroy" do
             setup_destroy_request
             @mock_model_class.expects(:destroy).raises(ArgumentError) 
@@ -201,7 +277,7 @@ describe Puppet::Network::HTTP::MongrelREST, "when 
receiving a request" do
             @handler.process(@mock_request, @mock_response)                 
         end
     end
-    
+
     describe "when saving a model instance" do |variable|    
         it "should fail to save model if data is not specified" do
             @mock_request.stubs(:params).returns({ 
Mongrel::Const::REQUEST_METHOD => 'PUT', Mongrel::Const::REQUEST_PATH => 
'/foo'})
@@ -209,20 +285,29 @@ describe Puppet::Network::HTTP::MongrelREST, "when 
receiving a request" do
             @mock_response.expects(:start).with(404)
             @handler.process(@mock_request, @mock_response)
         end
-        
+
+        it "should use a common method for determining the request parameters" 
do
+            setup_save_request('QUERY_STRING' => 'foo=baz&bar=xyzzy')
+            @handler.expects(:params).returns(:foo => :baz, :bar => :xyzzy)
+            @mock_model_instance.expects(:save).with do |args|
+                args[:foo] == :baz and args[:bar] == :xyzzy
+            end
+            @handler.process(@mock_request, @mock_response)
+        end
+
         it "should generate a 200 response when a model save call succeeds" do
             setup_save_request
             @mock_response.expects(:start).with(200)
             @handler.process(@mock_request, @mock_response)
         end
-        
+
         it "should return a serialized object when a model save call succeeds" 
do
             setup_save_request
             @mock_model_instance.stubs(:save).returns(@mock_model_instance)
             @mock_model_instance.expects(:to_yaml).returns('foo')
             @handler.process(@mock_request, @mock_response)        
         end
-        
+
         it "should serialize a controller exception when an exception is 
thrown by save" do
             setup_save_request
             @mock_model_instance.expects(:save).raises(ArgumentError) 
@@ -230,8 +315,17 @@ describe Puppet::Network::HTTP::MongrelREST, "when 
receiving a request" do
             @handler.process(@mock_request, @mock_response)                    
     
         end
     end
-    
+
     describe "when searching for model instances" do |variable|
+        it "should use a common method for determining the request parameters" 
do
+            setup_search_request('QUERY_STRING' => 'foo=baz&bar=xyzzy')
+            @handler.expects(:params).returns(:foo => :baz, :bar => :xyzzy)
+            @mock_model_class.expects(:search).with do |args|
+                args[:foo] == :baz and args[:bar] == :xyzzy
+            end
+            @handler.process(@mock_request, @mock_response)
+        end
+
         it "should pass HTTP request parameters to model search" do
             setup_search_request('QUERY_STRING' => 'foo=baz&bar=xyzzy')
             @mock_model_class.expects(:search).with do |args|
@@ -245,7 +339,7 @@ describe Puppet::Network::HTTP::MongrelREST, "when 
receiving a request" do
             @mock_response.expects(:start).with(200)
             @handler.process(@mock_request, @mock_response)
         end
-        
+
         it "should return a list of serialized objects when a model search 
call succeeds" do
             setup_search_request
             mock_matches = [1..5].collect {|i| mock("model instance #{i}", 
:to_yaml => "model instance #{i}") }
@@ -260,7 +354,7 @@ describe Puppet::Network::HTTP::MongrelREST, "when 
receiving a request" do
             @handler.process(@mock_request, @mock_response)                
         end
     end    
-    
+
     it "should serialize a controller exception if the request fails" do
         setup_bad_request     
         @mock_response.expects(:start).with(404)
diff --git a/spec/unit/network/http/webrick/rest.rb 
b/spec/unit/network/http/webrick/rest.rb
index b7bd338..1e0166d 100644
--- a/spec/unit/network/http/webrick/rest.rb
+++ b/spec/unit/network/http/webrick/rest.rb
@@ -8,23 +8,23 @@ describe Puppet::Network::HTTP::WEBrickREST, "when 
initializing" do
         Puppet::Indirector::Indirection.stubs(:model).returns(@mock_model)
         @params = [ @mock_webrick, :foo ]
     end
-    
+
     it "should require access to a WEBrick server" do
         Proc.new { 
             @params[0] = nil
             Puppet::Network::HTTP::WEBrickREST.new([EMAIL PROTECTED])
         }.should raise_error(ArgumentError)
     end
-    
+
     it "should require an indirection name" do
         Proc.new { Puppet::Network::HTTP::WEBrickREST.new(@params.first) 
}.should raise_error(ArgumentError)        
     end
-    
+
     it "should look up the indirection model from the indirection name" do
         Puppet::Indirector::Indirection.expects(:model).returns(@mock_model)
         Puppet::Network::HTTP::WEBrickREST.new([EMAIL PROTECTED])
     end
-    
+
     it "should fail if the indirection is not known" do
         Puppet::Indirector::Indirection.expects(:model).returns(nil)
         Proc.new { Puppet::Network::HTTP::WEBrickREST.new([EMAIL PROTECTED]) 
}.should raise_error(ArgumentError)
@@ -33,7 +33,7 @@ end
 
 describe Puppet::Network::HTTP::WEBrickREST, "when receiving a request" do
     before do
-        @mock_request     = stub('webrick http request', :query => {})
+        @mock_request     = stub('webrick http request', :query => {}, 
:peeraddr => %w{eh boo host ip}, :client_cert => nil)
         @mock_response    = stub('webrick http response', :status= => true, 
:body= => true)
         @mock_model_class = stub('indirected model class')
         @mock_webrick     = stub('webrick http server', :mount => true, :[] => 
{})
@@ -46,19 +46,19 @@ describe Puppet::Network::HTTP::WEBrickREST, "when 
receiving a request" do
         @mock_request.stubs(:path).returns('/foo/key')
         @mock_model_class.stubs(:find)
     end
-    
+
     def setup_search_request
         @mock_request.stubs(:request_method).returns('GET')
         @mock_request.stubs(:path).returns('/foos')
         @mock_model_class.stubs(:search).returns([])
     end
-    
+
     def setup_destroy_request
         @mock_request.stubs(:request_method).returns('DELETE')
         @mock_request.stubs(:path).returns('/foo/key')
         @mock_model_class.stubs(:destroy)
     end
-    
+
     def setup_save_request
         @mock_request.stubs(:request_method).returns('PUT')
         @mock_request.stubs(:path).returns('/foo')
@@ -66,44 +66,48 @@ describe Puppet::Network::HTTP::WEBrickREST, "when 
receiving a request" do
         @mock_model_instance = stub('indirected model instance', :save => true)
         @mock_model_class.stubs(:from_yaml).returns(@mock_model_instance)
     end
-    
+
     def setup_bad_request
         @mock_request.stubs(:request_method).returns('POST')
         @mock_request.stubs(:path).returns('/foos')
     end
-    
-    
+
+    it "should delegate its :service method to its :process method" do
+        @handler.expects(:process).with(@mock_request, @mock_response).returns 
"stuff"
+        @handler.service(@mock_request, @mock_response).should == "stuff"
+    end
+
     it "should call the model find method if the request represents a singular 
HTTP GET" do
         setup_find_request
-        @mock_model_class.expects(:find).with('key', {})
-        @handler.service(@mock_request, @mock_response)
+        @mock_model_class.expects(:find).with { |key, args| key == 'key' }
+        @handler.process(@mock_request, @mock_response)
     end
 
     it "should call the model search method if the request represents a plural 
HTTP GET" do
         setup_search_request
         @mock_model_class.expects(:search).returns([])
-        @handler.service(@mock_request, @mock_response)
+        @handler.process(@mock_request, @mock_response)
     end
-    
+
     it "should call the model destroy method if the request represents an HTTP 
DELETE" do
         setup_destroy_request
-        @mock_model_class.expects(:destroy).with('key', {})
-        @handler.service(@mock_request, @mock_response)
+        @mock_model_class.expects(:destroy).with { |key, args| key == 'key' }
+        @handler.process(@mock_request, @mock_response)
     end
 
     it "should call the model save method if the request represents an HTTP 
PUT" do
         setup_save_request
         @mock_model_instance.expects(:save)
-        @handler.service(@mock_request, @mock_response)
+        @handler.process(@mock_request, @mock_response)
     end
-    
+
     it "should fail if the HTTP method isn't supported" do
         @mock_request.stubs(:request_method).returns('POST')
         @mock_request.stubs(:path).returns('/foo')
         @mock_response.expects(:status=).with(404)
         @handler.process(@mock_request, @mock_response)            
     end
-    
+
     it "should fail if delete request's pluralization is wrong" do
         @mock_request.stubs(:request_method).returns('DELETE')
         @mock_request.stubs(:path).returns('/foos/key')
@@ -125,6 +129,42 @@ describe Puppet::Network::HTTP::WEBrickREST, "when 
receiving a request" do
         @handler.process(@mock_request, @mock_response)            
     end
 
+    describe "and determining the request parameters" do
+        it "should include the HTTP request parameters" do
+            @mock_request.stubs(:query).returns(:foo => :baz, :bar => :xyzzy)
+            result = @handler.params(@mock_request)
+            result[:foo].should == :baz
+            result[:bar].should == :xyzzy
+        end
+
+        it "should pass the client's ip address to model find" do
+            @mock_request.stubs(:peeraddr).returns(%w{noidea dunno hostname 
ipaddress})
+            @handler.params(@mock_request)[:ip].should == "ipaddress"
+        end
+
+        it "should set 'authenticated' to true if a certificate is present" do
+            cert = stub 'cert', :subject => [%w{CN host.domain.com}]
+            @mock_request.stubs(:client_cert).returns cert
+            @handler.params(@mock_request)[:authenticated].should be_true
+        end
+
+        it "should set 'authenticated' to false if no certificate is present" 
do
+            @mock_request.stubs(:client_cert).returns nil
+            @handler.params(@mock_request)[:authenticated].should be_false
+        end
+
+        it "should pass the client's certificate name to model method if a 
certificate is present" do
+            cert = stub 'cert', :subject => [%w{CN host.domain.com}]
+            @mock_request.stubs(:client_cert).returns cert
+            @handler.params(@mock_request)[:node].should == "host.domain.com"
+        end
+
+        it "should not pass a node name to model method if no certificate is 
present" do
+            @mock_request.stubs(:client_cert).returns nil
+            @handler.params(@mock_request).should_not be_include(:node)
+        end
+    end
+
     describe "when finding a model instance" do |variable|
         it "should fail to find model if key is not specified" do
             @mock_request.stubs(:request_method).returns('GET')
@@ -132,22 +172,22 @@ describe Puppet::Network::HTTP::WEBrickREST, "when 
receiving a request" do
             @mock_response.expects(:status=).with(404)
             @handler.process(@mock_request, @mock_response)            
         end
-        
-        it "should pass HTTP request parameters to model find" do
+
+        it "should use a common method for determining the request parameters" 
do
             setup_find_request
-            @mock_request.stubs(:query).returns(:foo => :baz, :bar => :xyzzy)
+            @handler.stubs(:params).returns(:foo => :baz, :bar => :xyzzy)
             @mock_model_class.expects(:find).with do |key, args|
-                key == 'key' and args[:foo] == :baz and args[:bar] == :xyzzy
+                args[:foo] == :baz and args[:bar] == :xyzzy
             end
-            @handler.service(@mock_request, @mock_response)
+            @handler.process(@mock_request, @mock_response)
         end
-        
+
         it "should generate a 200 response when a model find call succeeds" do
             setup_find_request
             @mock_response.expects(:status=).with(200)
             @handler.process(@mock_request, @mock_response)      
         end
-        
+
         it "should return a serialized object when a model find call succeeds" 
do
             setup_find_request
             @mock_model_instance = stub('model instance')
@@ -155,7 +195,7 @@ describe Puppet::Network::HTTP::WEBrickREST, "when 
receiving a request" do
             @mock_model_class.stubs(:find).returns(@mock_model_instance)
             @handler.process(@mock_request, @mock_response)                  
         end
-        
+
         it "should serialize a controller exception when an exception is 
thrown by find" do
            setup_find_request
            @mock_model_class.expects(:find).raises(ArgumentError) 
@@ -163,7 +203,7 @@ describe Puppet::Network::HTTP::WEBrickREST, "when 
receiving a request" do
            @handler.process(@mock_request, @mock_response)        
         end
     end
-    
+
     describe "when destroying a model instance" do |variable|
         it "should fail to destroy model if key is not specified" do
             @mock_request.stubs(:request_method).returns('DELETE')
@@ -171,37 +211,37 @@ describe Puppet::Network::HTTP::WEBrickREST, "when 
receiving a request" do
             @mock_response.expects(:status=).with(404)
             @handler.process(@mock_request, @mock_response)            
         end
-        
-        it "should pass HTTP request parameters to model destroy" do
+
+        it "should use a common method for determining the request parameters" 
do
             setup_destroy_request
-            @mock_request.stubs(:query).returns(:foo => :baz, :bar => :xyzzy)
+            @handler.stubs(:params).returns(:foo => :baz, :bar => :xyzzy)
             @mock_model_class.expects(:destroy).with do |key, args|
-                key == 'key' and args[:foo] == :baz and args[:bar] == :xyzzy
+                args[:foo] == :baz and args[:bar] == :xyzzy
             end
-            @handler.service(@mock_request, @mock_response)
+            @handler.process(@mock_request, @mock_response)
         end
-        
+
         it "should generate a 200 response when a model destroy call succeeds" 
do
             setup_destroy_request
             @mock_response.expects(:status=).with(200)
             @handler.process(@mock_request, @mock_response)      
         end
-        
+
         it "should return a serialized success result when a model destroy 
call succeeds" do
             setup_destroy_request
             @mock_model_class.stubs(:destroy).returns(true)
             @mock_response.expects(:body=).with("--- true\n")
             @handler.process(@mock_request, @mock_response)
         end
-        
-        it "should serialize a controller exception when an exception is 
thrown by search" do
-            setup_search_request
-            @mock_model_class.expects(:search).raises(ArgumentError) 
+
+        it "should serialize a controller exception when an exception is 
thrown by destroy" do
+            setup_destroy_request
+            @mock_model_class.expects(:destroy).raises(ArgumentError) 
             @mock_response.expects(:status=).with(404)
-            @handler.process(@mock_request, @mock_response)                
-        end
+            @handler.process(@mock_request, @mock_response)                 
+        end       
     end
-    
+
     describe "when saving a model instance" do
         it "should fail to save model if data is not specified" do
             @mock_request.stubs(:request_method).returns('PUT')
@@ -210,20 +250,29 @@ describe Puppet::Network::HTTP::WEBrickREST, "when 
receiving a request" do
             @mock_response.expects(:status=).with(404)
             @handler.process(@mock_request, @mock_response)            
         end
-        
+
+        it "should use a common method for determining the request parameters" 
do
+            setup_save_request
+            @handler.stubs(:params).returns(:foo => :baz, :bar => :xyzzy)
+            @mock_model_instance.expects(:save).with do |args|
+                args[:foo] == :baz and args[:bar] == :xyzzy
+            end
+            @handler.process(@mock_request, @mock_response)
+        end
+
         it "should generate a 200 response when a model save call succeeds" do
             setup_save_request
             @mock_response.expects(:status=).with(200)
             @handler.process(@mock_request, @mock_response)            
         end
-        
+
         it "should return a serialized object when a model save call succeeds" 
do
             setup_save_request
             @mock_model_instance.stubs(:save).returns(@mock_model_instance)
             @mock_model_instance.expects(:to_yaml).returns('foo')
             @handler.process(@mock_request, @mock_response)        
         end
-        
+
         it "should serialize a controller exception when an exception is 
thrown by save" do
             setup_save_request
             @mock_model_instance.expects(:save).raises(ArgumentError) 
@@ -231,15 +280,15 @@ describe Puppet::Network::HTTP::WEBrickREST, "when 
receiving a request" do
             @handler.process(@mock_request, @mock_response)                    
     
         end
     end
-    
+
     describe "when searching for model instances" do
-        it "should pass HTTP request parameters to model search" do
+        it "should use a common method for determining the request parameters" 
do
             setup_search_request
-            @mock_request.stubs(:query).returns(:foo => :baz, :bar => :xyzzy)
+            @handler.stubs(:params).returns(:foo => :baz, :bar => :xyzzy)
             @mock_model_class.expects(:search).with do |args|
                 args[:foo] == :baz and args[:bar] == :xyzzy
-            end.returns([])
-            @handler.service(@mock_request, @mock_response)
+            end
+            @handler.process(@mock_request, @mock_response)
         end
 
         it "should generate a 200 response when a model search call succeeds" 
do
@@ -247,20 +296,20 @@ describe Puppet::Network::HTTP::WEBrickREST, "when 
receiving a request" do
             @mock_response.expects(:status=).with(200)
             @handler.process(@mock_request, @mock_response)      
         end
-        
+
         it "should return a list of serialized objects when a model search 
call succeeds" do
             setup_search_request
             mock_matches = [1..5].collect {|i| mock("model instance #{i}", 
:to_yaml => "model instance #{i}") }
             @mock_model_class.stubs(:search).returns(mock_matches)
             @handler.process(@mock_request, @mock_response)                    
      
         end
-        
-        it "should serialize a controller exception when an exception is 
thrown by destroy" do
-            setup_destroy_request
-            @mock_model_class.expects(:destroy).raises(ArgumentError) 
+
+        it "should serialize a controller exception when an exception is 
thrown by search" do
+            setup_search_request
+            @mock_model_class.expects(:search).raises(ArgumentError) 
             @mock_response.expects(:status=).with(404)
-            @handler.process(@mock_request, @mock_response)                 
-        end       
+            @handler.process(@mock_request, @mock_response)                
+        end
     end
 
     it "should serialize a controller exception if the request fails" do
-- 
1.5.3.7


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Puppet Developers" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/puppet-dev?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to