On Jul 5, 2009, at 3:47 AM, Brice Figureau wrote:

>
> On 5/07/09 1:57, Jordan Curzon wrote:
>> On Jul 4, 2:52 pm, Brice Figureau <[email protected]>
>> wrote:
>>> The way the format was given to the server was kind of broken when
>>> we were saving to the server.
>>> It was using the first member of the Accept header.
>>> The Accept header is usually reserved for the other side, ie what
>>> the client will accept when the server will respond.
>>>
>>> This patch adds a Content-Type header containing the mime-type of
>>> the object sent by the client when saving.
>>>
>>> Signed-off-by: Brice Figureau <[email protected]>
>>> ---
>>> lib/puppet/indirector/rest.rb           |    2 +-
>>> lib/puppet/network/format_handler.rb    |    8 +++++++-
>>> lib/puppet/network/http/handler.rb      |   17 ++++++++++++++---
>>> lib/puppet/network/http/mongrel/rest.rb |    4 ++++
>>> lib/puppet/network/http/rack/rest.rb    |    5 +++++
>>> lib/puppet/network/http/webrick/rest.rb |    4 ++++
>>> spec/unit/indirector/rest.rb            |    9 ++++++++-
>>> spec/unit/network/format_handler.rb     |   26 ++++++++++++++++++++ 
>>> ++++++
>>> spec/unit/network/http/handler.rb       |   26 +++++++++++++++++ 
>>> +--------
>>> spec/unit/network/http/mongrel/rest.rb  |    5 +++++
>>> spec/unit/network/http/rack/rest.rb     |    5 +++++
>>> spec/unit/network/http/webrick/rest.rb  |    5 +++++
>>> 12 files changed, 102 insertions(+), 14 deletions(-)
>>>
>>> diff --git a/lib/puppet/indirector/rest.rb b/lib/puppet/indirector/ 
>>> rest.rb
>>> index 6903f9a..909be9a 100644
>>> --- a/lib/puppet/indirector/rest.rb
>>> +++ b/lib/puppet/indirector/rest.rb
>>> @@ -81,7 +81,7 @@ class Puppet::Indirector::REST <  
>>> Puppet::Indirector::Terminus
>>>
>>>     def save(request)
>>>         raise ArgumentError, "PUT does not accept options" unless  
>>> request.options.empty?
>>> -        deserialize  
>>> network(request).put(indirection2uri(request),  
>>> request.instance.render, headers)
>>> +        deserialize  
>>> network(request).put(indirection2uri(request),  
>>> request.instance.render, headers.merge({ "Content-Type" =>  
>>> request.instance.mime }))
>>>     end
>>
>> I like the idea of using proper mime types in the Content-Type
>> headers, Hopefully we can get the server responses to send proper  
>> mime
>> types too.
>
> It already does, AFAIK.
>
>>>     private
>>> diff --git a/lib/puppet/network/format_handler.rb b/lib/puppet/ 
>>> network/format_handler.rb
>>> index 0a7e9dc..839fe66 100644
>>> --- a/lib/puppet/network/format_handler.rb
>>> +++ b/lib/puppet/network/format_handler.rb
>>> @@ -23,7 +23,7 @@ module Puppet::Network::FormatHandler
>>>             @format = format
>>>         end
>>>
>>> -         
>>> [:intern, :intern_multiple, :render, :render_multiple].each do | 
>>> method|
>>> +         
>>> [:intern, :intern_multiple, :render, :render_multiple, :mime].each  
>>> do |method|
>>>             define_method(method) do |*args|
>>>                 protect(method, args)
>>>             end
>>> @@ -123,6 +123,12 @@ module Puppet::Network::FormatHandler
>>>              
>>> Puppet::Network::FormatHandler.protected_format(format).render(self)
>>>         end
>>>
>>> +        def mime(format = nil)
>>> +            format ||= self.class.default_format
>>> +
>>> +             
>>> Puppet::Network::FormatHandler.protected_format(format).mime
>>> +        end
>>> +
>>>         def support_format?(name)
>>>             self.class.support_format?(name)
>>>         end
>>> diff --git a/lib/puppet/network/http/handler.rb b/lib/puppet/ 
>>> network/http/handler.rb
>>> index c6b809d..0383713 100644
>>> --- a/lib/puppet/network/http/handler.rb
>>> +++ b/lib/puppet/network/http/handler.rb
>>> @@ -17,9 +17,20 @@ module Puppet::Network::HTTP::Handler
>>>         raise NotImplementedError
>>>     end
>>>
>>> -    # Which format to use when serializing our response.  Just  
>>> picks
>>> -    # the first value in the accept header, at this point.
>>> +    # Retrieve the Content-Type header from the http request.
>>> +    def content_type_header(request)
>>> +        raise NotImplementedError
>>> +    end
>>> +
>>> +    # 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.
>>>     def format_to_use(request)
>>> +        if header = content_type_header(request)
>>> +            format = Puppet::Network::FormatHandler.mime(header)
>>> +            return format.name.to_s if format.suitable?
>>> +        end
>>> +
>>
>> I'm not sure you should use format_to_use for this purpose because it
>> is used to determine what format to use for the response. If a client
>> (or a 3rd party app) sends an Accepts header different than the
>> Content-Type header and both are suitable?, the client will receive
>> content that they didn't say they can accept. I think it should be a
>> parallel method to determine the format to use to decode request
>> bodies. format_to_use should look at the accept header and the other
>> method should look at the Content-Type header.
>
> Yes, you're completely right. I'm cooking a new patch.
> The question is what to do when we don't receive a Content-Type  
> header?
> For the moment I'm raising an exception, but there might be some other
> possibilities:
>   * use the preferred format for the sent model instance
>   * try to render with all format and choose the one not giving an
> exception?

If we're expecting it to be encoded and no content-type header is  
provided, that's an exception IMO.

>
>>>         unless header = accept_header(request)
>>>             raise ArgumentError, "An Accept header must be  
>>> provided to pick the right format"
>>>         end
>>> @@ -118,7 +129,7 @@ module Puppet::Network::HTTP::Handler
>>>
>>>         format = format_to_use(request)
>>>
>>> -        obj =  
>>> indirection_request.model.convert_from(format_to_use(request), data)
>>> +        obj = indirection_request.model.convert_from(format, data)
>>>         result = save_object(indirection_request, obj)
>>>
>>>         set_content_type(response, "yaml")
>>> diff --git a/lib/puppet/network/http/mongrel/rest.rb b/lib/puppet/ 
>>> network/http/mongrel/rest.rb
>>> index 369d4c6..6b1fafb 100644
>>> --- a/lib/puppet/network/http/mongrel/rest.rb
>>> +++ b/lib/puppet/network/http/mongrel/rest.rb
>>> @@ -15,6 +15,10 @@ class Puppet::Network::HTTP::MongrelREST <  
>>> Mongrel::HttpHandler
>>>         request.params[ACCEPT_HEADER]
>>>     end
>>>
>>> +    def content_type_header(request)
>>> +        request.params[Mongrel::Const::CONTENT_TYPE]
>>> +    end
>>> +
>>>     # which HTTP verb was used in this request
>>>     def http_method(request)
>>>         request.params[Mongrel::Const::REQUEST_METHOD]
>>> diff --git a/lib/puppet/network/http/rack/rest.rb b/lib/puppet/ 
>>> network/http/rack/rest.rb
>>> index e98bffc..a4d475d 100644
>>> --- a/lib/puppet/network/http/rack/rest.rb
>>> +++ b/lib/puppet/network/http/rack/rest.rb
>>> @@ -28,6 +28,11 @@ class Puppet::Network::HTTP::RackREST <  
>>> Puppet::Network::HTTP::RackHttpHandler
>>>         request.env[HEADER_ACCEPT]
>>>     end
>>>
>>> +    # Retrieve the accept header from the http request.
>>> +    def content_type_header(request)
>>> +        request.env['HTTP_CONTENT_TYPE']
>>> +    end
>>> +
>>>     # Return which HTTP verb was used in this request.
>>>     def http_method(request)
>>>         request.request_method
>>> diff --git a/lib/puppet/network/http/webrick/rest.rb b/lib/puppet/ 
>>> network/http/webrick/rest.rb
>>> index 5f77da8..b27b304 100644
>>> --- a/lib/puppet/network/http/webrick/rest.rb
>>> +++ b/lib/puppet/network/http/webrick/rest.rb
>>> @@ -27,6 +27,10 @@ class Puppet::Network::HTTP::WEBrickREST <  
>>> WEBrick::HTTPServlet::AbstractServlet
>>>         request["accept"]
>>>     end
>>>
>>> +    def content_type_header(request)
>>> +        request["content-type"]
>>> +    end
>>> +
>>>     def http_method(request)
>>>         request.request_method
>>>     end
>>> diff --git a/spec/unit/indirector/rest.rb b/spec/unit/indirector/ 
>>> rest.rb
>>> index 9f77deb..696af9a 100755
>>> --- a/spec/unit/indirector/rest.rb
>>> +++ b/spec/unit/indirector/rest.rb
>>> @@ -306,7 +306,7 @@ describe Puppet::Indirector::REST do
>>>             @connection = stub('mock http connection', :put =>  
>>> @response)
>>>             @searcher.stubs(:network).returns(@connection)    #  
>>> neuter the network connection
>>>
>>> -            @instance = stub 'instance', :render => "mydata"
>>> +            @instance = stub 'instance', :render =>  
>>> "mydata", :mime => "mime"
>>>             @request =  
>>> Puppet::Indirector::Request.new(:foo, :save, "foo bar")
>>>             @request.instance = @instance
>>>         end
>>> @@ -350,6 +350,13 @@ describe Puppet::Indirector::REST do
>>>             @searcher.save(@request)
>>>         end
>>>
>>> +        it "should provide a Content-Type header containing the  
>>> mime-type of the sent object" do
>>> +            @connection.expects(:put).with { |path, data, args|  
>>> args['Content-Type'] == "mime" }.returns(@response)
>>> +
>>> +            @instance.expects(:mime).returns "mime"
>>> +            @searcher.save(@request)
>>> +        end
>>> +
>>>         it "should deserialize and return the network response" do
>>>              
>>> @searcher.expects(:deserialize).with(@response).returns @instance
>>>             @searcher.save(@request).should equal(@instance)
>>> diff --git a/spec/unit/network/format_handler.rb b/spec/unit/ 
>>> network/format_handler.rb
>>> index 54409b9..74ee4f5 100755
>>> --- a/spec/unit/network/format_handler.rb
>>> +++ b/spec/unit/network/format_handler.rb
>>> @@ -202,6 +202,10 @@ describe Puppet::Network::FormatHandler do
>>>             FormatTester.new.should respond_to(:render)
>>>         end
>>>
>>> +        it "should be able to get a format mime-type" do
>>> +            FormatTester.new.should respond_to(:mime)
>>> +        end
>>> +
>>>         it "should raise a FormatError when a rendering error is  
>>> encountered" do
>>>             format = stub 'rendering format', :supported? => true
>>>              
>>> Puppet::Network::FormatHandler.stubs(:format).with(:foo).returns  
>>> format
>>> @@ -233,5 +237,27 @@ describe Puppet::Network::FormatHandler do
>>>             format.expects(:render).with(tester)
>>>             tester.render
>>>         end
>>> +
>>> +        it "should call the format-specific converter when asked  
>>> for the mime-type of a given format" do
>>> +            format = stub 'rendering format', :supported? => true
>>> +
>>> +             
>>> Puppet::Network::FormatHandler.stubs(:format).with(:foo).returns  
>>> format
>>> +
>>> +            tester = FormatTester.new
>>> +            format.expects(:mime).returns "foo"
>>> +
>>> +            tester.mime(:foo).should == "foo"
>>> +        end
>>> +
>>> +        it "should return the default format mime-type if no  
>>> format is provided" do
>>> +            format = stub 'rendering format', :supported? => true
>>> +             
>>> Puppet::Network::FormatHandler.stubs(:format).with("foo").returns  
>>> format
>>> +
>>> +            FormatTester.expects(:default_format).returns "foo"
>>> +            tester = FormatTester.new
>>> +
>>> +            format.expects(:mime).returns "foo"
>>> +            tester.mime.should == "foo"
>>> +        end
>>>     end
>>> end
>>> diff --git a/spec/unit/network/http/handler.rb b/spec/unit/network/ 
>>> http/handler.rb
>>> index 8ef6e00..97ad2d2 100755
>>> --- a/spec/unit/network/http/handler.rb
>>> +++ b/spec/unit/network/http/handler.rb
>>> @@ -57,13 +57,14 @@ describe Puppet::Network::HTTP::Handler do
>>>         # Stub out the interface we require our including classes to
>>>         # implement.
>>>         def stub_server_interface
>>> -            @handler.stubs(:accept_header   ).returns  
>>> "format_one,format_two"
>>> -            @handler.stubs(:set_content_type).returns "my_result"
>>> -            @handler.stubs(:set_response    ).returns "my_result"
>>> -            @handler.stubs(:path            ).returns "/ 
>>> my_handler/my_result"
>>> -            @handler.stubs(:http_method     ).returns("GET")
>>> -            @handler.stubs(:params          ).returns({})
>>> -            @handler.stubs(:content_type
>>> ...
>>>
>
>
> -- 
> Brice Figureau
> My Blog: http://www.masterzen.fr/
>
>
> >


-- 
No one who cannot rejoice in the discovery of his own mistakes
deserves to be called a scholar. --Donald Foster
---------------------------------------------------------------------
Luke Kanies | http://reductivelabs.com | http://madstop.com


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