users@jersey.java.net

Re: [Jersey] modifying jersey client requests

From: Zoltan Arnold NAGY <Zoltan.Nagy_at_Sun.COM>
Date: Tue, 13 Oct 2009 16:31:15 +0200

Paul Sandoz wrote:
>
> On Oct 9, 2009, at 10:27 AM, Zoltan Arnold NAGY wrote:
>
>> Paul Sandoz wrote:
>>>
>>> On Oct 9, 2009, at 10:13 AM, Zoltan Arnold NAGY wrote:
>>>
>>>> Zoltan Arnold NAGY wrote:
>>>>> Paul Sandoz wrote:
>>>>>>
>>>>>> On Oct 7, 2009, at 5:36 PM, Felipe Gaucho wrote:
>>>>>>
>>>>>>> A filter?
>>>>>>>
>>>>>>
>>>>>> Yes, see ClientFilter and the source code for the LoggingFilter
>>>>>> (see below because java.net is so damn slow).
>>>>>>
>>>>>> You need to return an output stream in the implementation of
>>>>>> AbstractClientRequestAdapter .adapt that buffers the bytes then
>>>>>> on the close calculates the hash, sets the header and writes out
>>>>>> the bytes of the buffered output stream to the actual output stream.
>>>>> Thanks, it seems to be working. :)
>>>> Spoken too soon.
>>>> In the message to be hashed I need to add the method, the date, and
>>>> other data as well.
>>>>
>>>> It seems to me that if I do a simple .get() (no entity present) and
>>>> I do attach an adapter with
>>>> request.setAdapter(new Adapter(request.getAdapter(), b));
>>>> then it's adapt() method wont even get called (at least I've put
>>>> logging there, and never saw
>>>> it's output).
>>>>
>>>> In all the examples I've seen one only attaches such an adapter if
>>>> there's an entity present, so
>>>> I'm thinking that maybe these request adaptert are only used to
>>>> modify the entity's serialized form?
>>>>
>>>
>>> Yes, because it is adapting a *request* entity. If there is no
>>> request entity present then no adaption will occur because there is
>>> nothing to adapt.
>>>
>>> Do you want to hash a request entity or a response entity?
>> It's a bit more complicated than that :)
>>
>> from Amazon's docs:
>> (http://docs.amazonwebservices.com/AmazonS3/2006-03-01/dev/index.html?RESTAuthentication.html):
>>
>> StringToSign = HTTP-Verb + "\n" +
>> Content-MD5 + "\n" +
>> Content-Type + "\n" +
>> Date + "\n" +
>> CanonicalizedAmzHeaders +
>> CanonicalizedResource;
>>
>> For example, let's say Jersey would send this request:
>> GET /testresource HTTP/1.1
>> Content-type: application/json
>> Host: test.something.com
>>
>> then I'd still need to alter it and calculate the hash from various
>> input fields as seen above, and add the header to it.
>> Of course, if there _is_ an entity, I'd need to include it's
>> serialized (xml/json/whatever) form in the calculations.
>>
>> Is there a way to catch the output stream before it gets written at
>> all to the server?
>>
>
> Yes, that is what a filter is for, you can modify the request headers.
>
> You just need to work out if there is an entity present or not to
> decide where the creation of the signed string and header addition
> occurs. See ClientRequest.getEntity(). If it returns null then
> adaption will not occur, unless another filter further along in the
> filter chain adds one (a security filter should really be the last one
> in the chain).
hmm, so in my own filter I should be able to do sometihng like:

        public OutputStream adapt(ClientRequest request, OutputStream
out) throws IOException {
            return new HashingOutputStream(request,
getAdapter().adapt(request, out));
        }

and in HasingOutputStream: // baos holds the copy of the stream

        @Override
        public void close() throws IOException {
            String auth = "xy";
            List<Object> x = new ArrayList<Object>();
            x.add(auth);
            request.getHeaders().put("Authorization", x);

            baos.close();
            out.close();
        }

right?

currently I'm trying this approach, and server side logging indicates
that the added header never arrives.
If not this, then what's the right way to do it?

Thanks,
Zoltan