You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@sling.apache.org by Robert Munteanu <ro...@apache.org> on 2019/09/26 11:08:45 UTC

Changing the resource to render and the handling servlet in a request

Hi,

I'm playing around with setting up a Maven repository using Sling. The
basic setup is to have a /content/maven
[sling:resourceType=sling/maven/repo] sling:Folder and then the whole
repository contents as nt:folder and nt:file objects.

Serving files with the default GET servlet works perfectly, but uploads
(using PUT) do not, since parent directories are not auto-created. I am
reluctat to extend the Simple WebDav Servlet since that's not always
deployed; I would rather use something that is always available.

So I came up with the idea of serving the repository using suffixes,
e.g.

/content/maven.html/org/apache/sling/sling-foo/1.0/sling-foo-1.0.jar

would actually serve 

/content/maven.html/org/apache/sling/sling-foo/1.0/sling-foo-1.0.jar

Note that I am breaking the pattern of referencing the whole resource
path in the suffix, since that looks awkward. But it's not a big deal.

I would like to resources to be served by the default GET servlet,
since it contains lots of logic and optimisation around downloads.
However, I did not yet find a very good way to do so.

My solution has two steps:

1. wrap the original request using a SlingHttpServletRequestWrapper and
overriding getResource() to return the new resource. Also overriding
getRequestPathInfo to return an object that points to the new resource

2. obtain a reference to the DefaultGetServlet via 

@Reference(target = "(component.name=org.apache.sling.servlets.get.DefaultGetServlet)")
private Servlet getServlet;

(I guess I could use the component pid as a slight improvement).

and invoke its service() method with the altered request and the same response.

However, both steps seems brittle to me.

Does anyone have any suggestions on how to improve this solution?

Thanks,
Robert


Re: Changing the resource to render and the handling servlet in a request

Posted by Robert Munteanu <ro...@apache.org>.

Re: Changing the resource to render and the handling servlet in a request

Posted by Jason E Bailey <ja...@24601.org>.
Would a possible API enhancement be to set the content type in the request to the desired content type you are expecting to download?


--
Jason

On Mon, Sep 30, 2019, at 3:40 PM, Julian Sedding wrote:
> Hi Robert (again)
> 
> I tried what I suggested and found exactly what you described: the
> extension of the forwarded request is not changed.
> 
> However, there is a workaround. You can change the extension if you
> append one to the path passed into the RequestDispatcher, i.e. the
> path to your binary. The default GET servlet supports stream rendering
> (spooling binaries) for both the "null" extension and for ".res"[0].
> Therefore the following should work.
> 
>     String suffix = request.getRequestPathInfo().getSuffix();
>     request
>         .getRequestDispatcher("/content/maven" + suffix + ".res")
>         .forward(request, response);
> 
> Not particularly obvious or nice, so an API enhancement would still be
> a good thing.
> 
> Regards
> Julian
> 
> [0] 
> https://github.com/apache/sling-org-apache-sling-servlets-get/blob/master/src/main/java/org/apache/sling/servlets/get/impl/DefaultGetServlet.java#L223-L227
> 
> On Fri, Sep 27, 2019 at 11:21 AM Julian Sedding <js...@gmail.com> wrote:
> >
> > Hi Robert
> >
> > Have you tried "forwarding" instead of "including"? AFAIK that should
> > clear any previous reuest path info etc.
> >
> > Regards
> > Julian
> >
> > On Thu, Sep 26, 2019 at 4:54 PM Robert Munteanu <ro...@apache.org> wrote:
> > >
> > > On Thu, 2019-09-26 at 13:32 +0200, Radu Cotescu wrote:
> > > > Hi Robert,
> > > >
> > > > > On 26 Sep 2019, at 13:08, Robert Munteanu <ro...@apache.org>
> > > > > wrote:
> > > > >
> > > > >
> > > > > My solution has two steps:
> > > > >
> > > > > 1. wrap the original request using a SlingHttpServletRequestWrapper
> > > > > and
> > > > > overriding getResource() to return the new resource. Also
> > > > > overriding
> > > > > getRequestPathInfo to return an object that points to the new
> > > > > resource
> > > > >
> > > > > 2. obtain a reference to the DefaultGetServlet via
> > > > >
> > > > > @Reference(target =
> > > > > "(component.name=org.apache.sling.servlets.get.DefaultGetServlet)")
> > > > > private Servlet getServlet;
> > > > >
> > > > > (I guess I could use the component pid as a slight improvement).
> > > > >
> > > > > and invoke its service() method with the altered request and the
> > > > > same response.
> > > > >
> > > >
> > > > Why can’t you use the RequestDispatcher in the second step instead of
> > > > directly referencing the DefaultGetServlet?
> > >
> > > Good question :-) There are two answers to this:
> > >
> > > 1. I did not think of that
> > > 2. It does not allow me to override the extension. But that should be a
> > > simple change. So I filed
> > >
> > >   https://issues.apache.org/jira/browse/SLING-8742
> > >
> > > to allow overriding the extension when including a resource.
> > >
> > > Thanks,
> > > Robert
> > >
>

Re: Changing the resource to render and the handling servlet in a request

Posted by Robert Munteanu <ro...@apache.org>.
On Tue, 2019-10-15 at 14:08 +0200, Julian Sedding wrote:
> You're welcome Robert.
> 
> Regarding the documentation, it may be worthwhile to highlight that
> the ".res" extension can only be used for streaming binaries (i.e.
> cases where you would normally have no extension at all). However,
> that is also the only problematic case for request dispatching,
> because it is possible to overwrite the extension, but it is not
> possible to remove it.

Good point, updated in 

  https://github.com/apache/sling-site/commit/bb0c96a1

THanks,
Robert

> 
> Thanks for adding the documentation! +1
> 
> Regards
> Julian
> 
> On Tue, Oct 15, 2019 at 11:31 AM Robert Munteanu <ro...@apache.org>
> wrote:
> > On Tue, 2019-10-15 at 11:21 +0200, Konrad Windszus wrote:
> > > Nice, can you add this to
> > > https://sling.apache.org/documentation/bundles/rendering-content-default-get-servlets.html
> > > ? <
> > > https://sling.apache.org/documentation/bundles/rendering-content-default-get-servlets.html
> > > ?>
> > 
> > Good idea, added with
> > 
> >   
> > https://github.com/apache/sling-site/commit/f1afd83d0b3b12a8c556f22b77abd6f839214481
> > 
> > Robert
> > 


Re: Changing the resource to render and the handling servlet in a request

Posted by Julian Sedding <js...@gmail.com>.
You're welcome Robert.

Regarding the documentation, it may be worthwhile to highlight that
the ".res" extension can only be used for streaming binaries (i.e.
cases where you would normally have no extension at all). However,
that is also the only problematic case for request dispatching,
because it is possible to overwrite the extension, but it is not
possible to remove it.

Thanks for adding the documentation! +1

Regards
Julian

On Tue, Oct 15, 2019 at 11:31 AM Robert Munteanu <ro...@apache.org> wrote:
>
> On Tue, 2019-10-15 at 11:21 +0200, Konrad Windszus wrote:
> > Nice, can you add this to
> > https://sling.apache.org/documentation/bundles/rendering-content-default-get-servlets.html
> > ? <
> > https://sling.apache.org/documentation/bundles/rendering-content-default-get-servlets.html
> > ?>
>
> Good idea, added with
>
>   https://github.com/apache/sling-site/commit/f1afd83d0b3b12a8c556f22b77abd6f839214481
>
> Robert
>

Re: Changing the resource to render and the handling servlet in a request

Posted by Robert Munteanu <ro...@apache.org>.
On Tue, 2019-10-15 at 11:21 +0200, Konrad Windszus wrote:
> Nice, can you add this to 
> https://sling.apache.org/documentation/bundles/rendering-content-default-get-servlets.html
> ? <
> https://sling.apache.org/documentation/bundles/rendering-content-default-get-servlets.html
> ?>

Good idea, added with 

  https://github.com/apache/sling-site/commit/f1afd83d0b3b12a8c556f22b77abd6f839214481

Robert


Re: Changing the resource to render and the handling servlet in a request

Posted by Konrad Windszus <ko...@gmx.de>.
Nice, can you add this to https://sling.apache.org/documentation/bundles/rendering-content-default-get-servlets.html? <https://sling.apache.org/documentation/bundles/rendering-content-default-get-servlets.html?>
Thanks,
Konrad

> On 15. Oct 2019, at 11:19, Robert Munteanu <ro...@apache.org> wrote:
> 
> Hi Julian,
> 
> On Mon, 2019-09-30 at 21:40 +0200, Julian Sedding wrote:
>> Hi Robert (again)
>> 
>> I tried what I suggested and found exactly what you described: the
>> extension of the forwarded request is not changed.
>> 
>> However, there is a workaround. You can change the extension if you
>> append one to the path passed into the RequestDispatcher, i.e. the
>> path to your binary. The default GET servlet supports stream
>> rendering
>> (spooling binaries) for both the "null" extension and for ".res"[0].
>> Therefore the following should work.
>> 
>>    String suffix = request.getRequestPathInfo().getSuffix();
>>    request
>>        .getRequestDispatcher("/content/maven" + suffix + ".res")
>>        .forward(request, response);
>> 
>> Not particularly obvious or nice, so an API enhancement would still
>> be
>> a good thing.
> 
> That works, and without an API change, so that's extra nice :-) Thanks
> for digging into this.
> 
> Robert
> 
>> 
>> Regards
>> Julian
>> 
>> [0] 
>> https://github.com/apache/sling-org-apache-sling-servlets-get/blob/master/src/main/java/org/apache/sling/servlets/get/impl/DefaultGetServlet.java#L223-L227
>> 
>> On Fri, Sep 27, 2019 at 11:21 AM Julian Sedding <js...@gmail.com>
>> wrote:
>>> Hi Robert
>>> 
>>> Have you tried "forwarding" instead of "including"? AFAIK that
>>> should
>>> clear any previous reuest path info etc.
>>> 
>>> Regards
>>> Julian
>>> 
>>> On Thu, Sep 26, 2019 at 4:54 PM Robert Munteanu <rombert@apache.org
>>>> wrote:
>>>> On Thu, 2019-09-26 at 13:32 +0200, Radu Cotescu wrote:
>>>>> Hi Robert,
>>>>> 
>>>>>> On 26 Sep 2019, at 13:08, Robert Munteanu <rombert@apache.org
>>>>>>> 
>>>>>> wrote:
>>>>>> 
>>>>>> 
>>>>>> My solution has two steps:
>>>>>> 
>>>>>> 1. wrap the original request using a
>>>>>> SlingHttpServletRequestWrapper
>>>>>> and
>>>>>> overriding getResource() to return the new resource. Also
>>>>>> overriding
>>>>>> getRequestPathInfo to return an object that points to the new
>>>>>> resource
>>>>>> 
>>>>>> 2. obtain a reference to the DefaultGetServlet via
>>>>>> 
>>>>>> @Reference(target =
>>>>>> "(component.name=org.apache.sling.servlets.get.DefaultGetServ
>>>>>> let)")
>>>>>> private Servlet getServlet;
>>>>>> 
>>>>>> (I guess I could use the component pid as a slight
>>>>>> improvement).
>>>>>> 
>>>>>> and invoke its service() method with the altered request and
>>>>>> the
>>>>>> same response.
>>>>>> 
>>>>> 
>>>>> Why can’t you use the RequestDispatcher in the second step
>>>>> instead of
>>>>> directly referencing the DefaultGetServlet?
>>>> 
>>>> Good question :-) There are two answers to this:
>>>> 
>>>> 1. I did not think of that
>>>> 2. It does not allow me to override the extension. But that
>>>> should be a
>>>> simple change. So I filed
>>>> 
>>>>  https://issues.apache.org/jira/browse/SLING-8742
>>>> 
>>>> to allow overriding the extension when including a resource.
>>>> 
>>>> Thanks,
>>>> Robert
>>>> 
> 


Re: Changing the resource to render and the handling servlet in a request

Posted by Robert Munteanu <ro...@apache.org>.
Hi Julian,

On Mon, 2019-09-30 at 21:40 +0200, Julian Sedding wrote:
> Hi Robert (again)
> 
> I tried what I suggested and found exactly what you described: the
> extension of the forwarded request is not changed.
> 
> However, there is a workaround. You can change the extension if you
> append one to the path passed into the RequestDispatcher, i.e. the
> path to your binary. The default GET servlet supports stream
> rendering
> (spooling binaries) for both the "null" extension and for ".res"[0].
> Therefore the following should work.
> 
>     String suffix = request.getRequestPathInfo().getSuffix();
>     request
>         .getRequestDispatcher("/content/maven" + suffix + ".res")
>         .forward(request, response);
> 
> Not particularly obvious or nice, so an API enhancement would still
> be
> a good thing.

That works, and without an API change, so that's extra nice :-) Thanks
for digging into this.

Robert

> 
> Regards
> Julian
> 
> [0] 
> https://github.com/apache/sling-org-apache-sling-servlets-get/blob/master/src/main/java/org/apache/sling/servlets/get/impl/DefaultGetServlet.java#L223-L227
> 
> On Fri, Sep 27, 2019 at 11:21 AM Julian Sedding <js...@gmail.com>
> wrote:
> > Hi Robert
> > 
> > Have you tried "forwarding" instead of "including"? AFAIK that
> > should
> > clear any previous reuest path info etc.
> > 
> > Regards
> > Julian
> > 
> > On Thu, Sep 26, 2019 at 4:54 PM Robert Munteanu <rombert@apache.org
> > > wrote:
> > > On Thu, 2019-09-26 at 13:32 +0200, Radu Cotescu wrote:
> > > > Hi Robert,
> > > > 
> > > > > On 26 Sep 2019, at 13:08, Robert Munteanu <rombert@apache.org
> > > > > >
> > > > > wrote:
> > > > > 
> > > > > 
> > > > > My solution has two steps:
> > > > > 
> > > > > 1. wrap the original request using a
> > > > > SlingHttpServletRequestWrapper
> > > > > and
> > > > > overriding getResource() to return the new resource. Also
> > > > > overriding
> > > > > getRequestPathInfo to return an object that points to the new
> > > > > resource
> > > > > 
> > > > > 2. obtain a reference to the DefaultGetServlet via
> > > > > 
> > > > > @Reference(target =
> > > > > "(component.name=org.apache.sling.servlets.get.DefaultGetServ
> > > > > let)")
> > > > > private Servlet getServlet;
> > > > > 
> > > > > (I guess I could use the component pid as a slight
> > > > > improvement).
> > > > > 
> > > > > and invoke its service() method with the altered request and
> > > > > the
> > > > > same response.
> > > > > 
> > > > 
> > > > Why can’t you use the RequestDispatcher in the second step
> > > > instead of
> > > > directly referencing the DefaultGetServlet?
> > > 
> > > Good question :-) There are two answers to this:
> > > 
> > > 1. I did not think of that
> > > 2. It does not allow me to override the extension. But that
> > > should be a
> > > simple change. So I filed
> > > 
> > >   https://issues.apache.org/jira/browse/SLING-8742
> > > 
> > > to allow overriding the extension when including a resource.
> > > 
> > > Thanks,
> > > Robert
> > > 


Re: Changing the resource to render and the handling servlet in a request

Posted by Julian Sedding <js...@gmail.com>.
Hi Robert (again)

I tried what I suggested and found exactly what you described: the
extension of the forwarded request is not changed.

However, there is a workaround. You can change the extension if you
append one to the path passed into the RequestDispatcher, i.e. the
path to your binary. The default GET servlet supports stream rendering
(spooling binaries) for both the "null" extension and for ".res"[0].
Therefore the following should work.

    String suffix = request.getRequestPathInfo().getSuffix();
    request
        .getRequestDispatcher("/content/maven" + suffix + ".res")
        .forward(request, response);

Not particularly obvious or nice, so an API enhancement would still be
a good thing.

Regards
Julian

[0] https://github.com/apache/sling-org-apache-sling-servlets-get/blob/master/src/main/java/org/apache/sling/servlets/get/impl/DefaultGetServlet.java#L223-L227

On Fri, Sep 27, 2019 at 11:21 AM Julian Sedding <js...@gmail.com> wrote:
>
> Hi Robert
>
> Have you tried "forwarding" instead of "including"? AFAIK that should
> clear any previous reuest path info etc.
>
> Regards
> Julian
>
> On Thu, Sep 26, 2019 at 4:54 PM Robert Munteanu <ro...@apache.org> wrote:
> >
> > On Thu, 2019-09-26 at 13:32 +0200, Radu Cotescu wrote:
> > > Hi Robert,
> > >
> > > > On 26 Sep 2019, at 13:08, Robert Munteanu <ro...@apache.org>
> > > > wrote:
> > > >
> > > >
> > > > My solution has two steps:
> > > >
> > > > 1. wrap the original request using a SlingHttpServletRequestWrapper
> > > > and
> > > > overriding getResource() to return the new resource. Also
> > > > overriding
> > > > getRequestPathInfo to return an object that points to the new
> > > > resource
> > > >
> > > > 2. obtain a reference to the DefaultGetServlet via
> > > >
> > > > @Reference(target =
> > > > "(component.name=org.apache.sling.servlets.get.DefaultGetServlet)")
> > > > private Servlet getServlet;
> > > >
> > > > (I guess I could use the component pid as a slight improvement).
> > > >
> > > > and invoke its service() method with the altered request and the
> > > > same response.
> > > >
> > >
> > > Why can’t you use the RequestDispatcher in the second step instead of
> > > directly referencing the DefaultGetServlet?
> >
> > Good question :-) There are two answers to this:
> >
> > 1. I did not think of that
> > 2. It does not allow me to override the extension. But that should be a
> > simple change. So I filed
> >
> >   https://issues.apache.org/jira/browse/SLING-8742
> >
> > to allow overriding the extension when including a resource.
> >
> > Thanks,
> > Robert
> >

Re: Changing the resource to render and the handling servlet in a request

Posted by Julian Sedding <js...@gmail.com>.
Hi Robert

Have you tried "forwarding" instead of "including"? AFAIK that should
clear any previous reuest path info etc.

Regards
Julian

On Thu, Sep 26, 2019 at 4:54 PM Robert Munteanu <ro...@apache.org> wrote:
>
> On Thu, 2019-09-26 at 13:32 +0200, Radu Cotescu wrote:
> > Hi Robert,
> >
> > > On 26 Sep 2019, at 13:08, Robert Munteanu <ro...@apache.org>
> > > wrote:
> > >
> > >
> > > My solution has two steps:
> > >
> > > 1. wrap the original request using a SlingHttpServletRequestWrapper
> > > and
> > > overriding getResource() to return the new resource. Also
> > > overriding
> > > getRequestPathInfo to return an object that points to the new
> > > resource
> > >
> > > 2. obtain a reference to the DefaultGetServlet via
> > >
> > > @Reference(target =
> > > "(component.name=org.apache.sling.servlets.get.DefaultGetServlet)")
> > > private Servlet getServlet;
> > >
> > > (I guess I could use the component pid as a slight improvement).
> > >
> > > and invoke its service() method with the altered request and the
> > > same response.
> > >
> >
> > Why can’t you use the RequestDispatcher in the second step instead of
> > directly referencing the DefaultGetServlet?
>
> Good question :-) There are two answers to this:
>
> 1. I did not think of that
> 2. It does not allow me to override the extension. But that should be a
> simple change. So I filed
>
>   https://issues.apache.org/jira/browse/SLING-8742
>
> to allow overriding the extension when including a resource.
>
> Thanks,
> Robert
>

Re: Changing the resource to render and the handling servlet in a request

Posted by Robert Munteanu <ro...@apache.org>.
On Thu, 2019-09-26 at 13:32 +0200, Radu Cotescu wrote:
> Hi Robert,
> 
> > On 26 Sep 2019, at 13:08, Robert Munteanu <ro...@apache.org>
> > wrote:
> > 
> > 
> > My solution has two steps:
> > 
> > 1. wrap the original request using a SlingHttpServletRequestWrapper
> > and
> > overriding getResource() to return the new resource. Also
> > overriding
> > getRequestPathInfo to return an object that points to the new
> > resource
> > 
> > 2. obtain a reference to the DefaultGetServlet via 
> > 
> > @Reference(target =
> > "(component.name=org.apache.sling.servlets.get.DefaultGetServlet)")
> > private Servlet getServlet;
> > 
> > (I guess I could use the component pid as a slight improvement).
> > 
> > and invoke its service() method with the altered request and the
> > same response.
> > 
> 
> Why can’t you use the RequestDispatcher in the second step instead of
> directly referencing the DefaultGetServlet?

Good question :-) There are two answers to this:

1. I did not think of that
2. It does not allow me to override the extension. But that should be a
simple change. So I filed

  https://issues.apache.org/jira/browse/SLING-8742

to allow overriding the extension when including a resource.

Thanks,
Robert


Re: Changing the resource to render and the handling servlet in a request

Posted by Julian Sedding <js...@gmail.com>.
Hi Robert

As Radu says - that could be as simple as this:

    String suffix = request.getRequestPathInfo().getSuffix();
    request
        .getRequestDispatcher("/content/maven" + suffix)
        .forward(request, response);

The newly dispatched request then goes through servlet resolution
again and has a fair chance of ending up with the default GET servlet.
And you can influence this selection further by adding
RequestDispatcherOptions to force e.g. the default resource type
"sling/servlet/default".

Regards
Julian

On Thu, Sep 26, 2019 at 1:32 PM Radu Cotescu <ra...@apache.org> wrote:
>
> Hi Robert,
>
> > On 26 Sep 2019, at 13:08, Robert Munteanu <ro...@apache.org> wrote:
> >
> >
> > My solution has two steps:
> >
> > 1. wrap the original request using a SlingHttpServletRequestWrapper and
> > overriding getResource() to return the new resource. Also overriding
> > getRequestPathInfo to return an object that points to the new resource
> >
> > 2. obtain a reference to the DefaultGetServlet via
> >
> > @Reference(target = "(component.name=org.apache.sling.servlets.get.DefaultGetServlet)")
> > private Servlet getServlet;
> >
> > (I guess I could use the component pid as a slight improvement).
> >
> > and invoke its service() method with the altered request and the same response.
> >
>
> Why can’t you use the RequestDispatcher in the second step instead of directly referencing the DefaultGetServlet?
>
> Cheers,
> Radu
>

Re: Changing the resource to render and the handling servlet in a request

Posted by Radu Cotescu <ra...@apache.org>.
Hi Robert,

> On 26 Sep 2019, at 13:08, Robert Munteanu <ro...@apache.org> wrote:
> 
> 
> My solution has two steps:
> 
> 1. wrap the original request using a SlingHttpServletRequestWrapper and
> overriding getResource() to return the new resource. Also overriding
> getRequestPathInfo to return an object that points to the new resource
> 
> 2. obtain a reference to the DefaultGetServlet via 
> 
> @Reference(target = "(component.name=org.apache.sling.servlets.get.DefaultGetServlet)")
> private Servlet getServlet;
> 
> (I guess I could use the component pid as a slight improvement).
> 
> and invoke its service() method with the altered request and the same response.
> 

Why can’t you use the RequestDispatcher in the second step instead of directly referencing the DefaultGetServlet?

Cheers,
Radu