I don't believe that your suggestion works, but correct me if I'm wrong.
You aren't overwriting the getInputStream or getReader method. You are
wrapping them, which is a big difference. Since the internal
Request#parseParameter() won't use your wrapped version of the method but
rather uses it's own version which won't work since you've already called
getInputStream or getReader.

In your case it works since you aren't calling getParameter(). You're
implementation works as long as you restrict your application to using
getReader or getInputStream. Again, correct me if I'm wrong. Calling
HttpRequestRecorderWrapper.getParameter() in the web application, should
mess up your wrapper since it doesn't intercepts this method call and will
invoke the Request.getParameter() which will call Request.getStream() and
not HttpRequestRecorderWrapper.getStream() as you're implementation
requires.

Overwriting the getStream, getInputStream and getReader methods would
indeed solve the problem, but the problem is that you aren't overwriting
the method. By the way, I believe that parseParameter uses getStream. But
again, a wrapper does not overwrite the Request.getInputStream or
getReader. I made this same mistake when trying a similar solution to yours.

So in order for getParameter to work in a wrapper, you need to wrap
parseParameter and implement all the other methods that depend on
getStream, getInputStream or getReader, in the wrapper itself. I did the
research and I would have to rewrite more then you suggest (getReader(),
getStream(), getInputStream(), parseParameter(), readPostBody(),
readChunkedPostBody, getParameterMap, getParameterNames,
getParameterValues)  and maybe it's not even possible since some fields
that are used by these implementations are protected and have been set
before the Valve is encountered. These fields don't always have getters and
you might not be able to reproduce the behavior of getParameter (or any
other method) in a wrapper due to this fact. This last part is just an
assumption. I haven't validated that this last issue, indeed renders an
implementation in a wrapper impossible, but it makes it fairly difficult
and error prone. By the way, this is not my only reason for diving into
Tomcat. I need modification to the Manager as well and since it is just a
proof of concept, I am not worried about maintaining this code, which would
indeed be almost impossible.

Thanks for the advice on the size of requests. I'm still pondering on that
issue.

Roel


2015-12-15 2:10 GMT+01:00 Christopher Schultz <ch...@christopherschultz.net>
:

> Roel,
>
> On 12/12/15 11:17 AM, Roel Storms wrote:
> > I believe that this is not entirely what I need. As far as I understand
> the
> > code it will detect if getInputStream or getReader has been called by the
> > servlet application. Depending on the usingReader boolean that was set
> as a
> > result, it will either use _inputReaderBuffer or _inputStreamBuffer to
> > fetch the body.
> >
> > In my case I need to retrieve the body in advance and still allow the web
> > application to call either method, getInputStream, getReader,
> getParameter.
> > If I choose to call getInputStream in my Valve to retrieve the body then
> > the web application will be restricted to using getInputStream. If I
> choose
> > getReader then the web application will be restricted to using getReader.
> > If a web application would use ServletRequest.getParameter the
> > documentation says the following:
> >
> > "If the parameter data was sent in the request body, such as occurs with
> an
> > HTTP POST request, then reading the body directly via getInputStream()
> > <
> https://tomcat.apache.org/tomcat-8.0-doc/servletapi/javax/servlet/ServletRequest.html#getInputStream()
> >
> >  or getReader()
> > <
> https://tomcat.apache.org/tomcat-8.0-doc/servletapi/javax/servlet/ServletRequest.html#getReader()
> >
> > can
> > interfere with the execution of this method."
> >
> > According to my understanding of the original Tomcat request code,
> > Request.getParam depends on Request.parseParameters which in turn uses
> > Request.readPostBody that uses Request.getStream to obtain the data.
> > getStream also fetches the inputStream of a request so I believe it won't
> > work in combination with a call to getReader.
> >
> > Since your wrapper is not overwriting any method like getParam
> > (getParameterNames, getParameterValues, getParameterMap) I believe these
> > methods will still behave incorrectly when called by the target
> application.
> >
> > I could indeed build a wrapper that would overwrite getStream, getReader,
> > getInputStream, getParam, getParameterNames, etc. But then I would be
> > generating a lot of duplicate code. Since my implementation is purely
> > experimental I don't think it's such big of a problem to modify Tomcat
> > internals (the Connector class).
>
> Honestly, it will be easier to implement this as a Valve. I have posted
> all the code you need for what you want... you might need to move some
> of it around a bit in order to get the behavior you want. Note that
> getParameter* calls getInputStream/getReader to get the data, so if you
> override the stream methods, you'll be able to support everything.
>
> Whatever you do, remember to put a limit on the amount of data you'll
> cache in memory, or you risk introducing a very trivial and nasty DOS
> vulnerability.
>
> -chris
>
> > 2015-12-09 18:06 GMT+01:00 Christopher Schultz <
> ch...@christopherschultz.net
> >> :
> >
> >> Roel,
> >>
> >> On 12/9/15 8:03 AM, Roel Storms wrote:
> >>> The real requirement is being able to process the body of a request in
> a
> >>> Valve without restricting the servlet to call request.getInputStream,
> >>> getReader and getStream. I have tried by wrapping the request but some
> >>> behavior can't be masked. It is also much more simple to implement by
> >> just
> >>> extending the Request class and using this in
> Connector.createRequest().
> >>>
> >>> So the actual requirement is a Valve wanting to process the body but
> >> still
> >>> allowing the target application to call whatever processing method they
> >>> chose. When the Valve would chose to process the body by calling
> >>> Request.getInputStream(). The servlet wouldn't be able to call
> getReader
> >> or
> >>> getParam anymore. I would like my Valve to be transparent in that
> sense.
> >>
> >> What you want to do can be done with a Valve as long as you don't mind a
> >> bit of typing.
> >>
> >> See this thread where I built pretty much exactly what you're
> requesting:
> >> http://tomcat.markmail.org/thread/fumpfuspt7a3nesz
> >>
> >> I implemented mine as a Filter, not as a Valve.
> >>
> >> There's no need to go writing your own Request implementation.
> >>
> >> -chris
> >>
> >> ---------------------------------------------------------------------
> >> To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
> >> For additional commands, e-mail: users-h...@tomcat.apache.org
> >>
> >>
> >
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
> For additional commands, e-mail: users-h...@tomcat.apache.org
>
>

Reply via email to