Re: filter question

2014-03-14 Thread André Warnier

Brendan Miller wrote:

I have a filter with doFilter method like this:

public void doFilter(ServletRequest request,
 ServletResponse response,
 FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;

resp.setHeader(Cache-Control,
   must-revalidate, max-age=0, post-check=0,
pre-check=0);

chain.doFilter(request, response);
}

This sets the header. However, if I set the header *after* chain.doFilter,
the header is not set. Why is this?

public void doFilter(ServletRequest request,
 ServletResponse response,
 FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;

chain.doFilter(request, response);

resp.setHeader(Cache-Control,
   must-revalidate, max-age=0, post-check=0,
pre-check=0);
}

Programmatically I can see the header is null.

Has the content already been sent to the web browser after chain.doFilter?
If so, is there a way to delay sending data to the browser? I need to
inspect the status code in the response before setting my header (to
prevent 404's from being cached).



Not a direct answer to your question, but this subject comes up so often that maybe a 
generic explanation may help.


What is the meaning of the response is already committed ?

In the HTTP protocol, a HTTP Response consists of :

- a HTTP status line  (like : 200 OK)
- 0 or more response headers (like Content-length: 1234)
- a blank line
- the response content (like : a html page, or a jpeg image)

(The last 2 elements are optional, as some responses do not have a content part, by 
definition)


The above is what a HTTP client (e.g. a browser) will be waiting for, after it has sent a 
request to a HTTP server (e.g., Tomcat). The client will expect the above response lines 
to arrive to it strictly in the order above.  It would not expect for example the HTTP 
status line to come after a HTTP response header or after the content of the response.
That means that the HTTP server will need to ensure that the above response lines are 
written to the client socket also in the order above.


In the course of processing a request, at some point Tomcat will be setting up a Response 
object, which is an internal representation of (and a buffer for) the HTTP response that 
will at some point be sent to the client.


When a webapp is run, the main thing it will usually be doing is to prepare the response 
content.  In the Response object, the status code and the response headers are also being 
set gradually, as a kind of side-effect (or explicitly).  But for the moment, all of this 
happens in the Response object, in memory, and nothing has yet been sent to the client.


In other words, at this point the Response is still uncommitted, and the webapp can 
still manipulate the response status code and the response headers in the Response object.


However, as soon as the webapp starts outputting the response *content* to the client, and 
before even the first byte of the response content is effectively sent over the client 
socket, the server has no choice : in order to preserve the expected order in the HTTP 
response, it must first send the HTTP status line, then the HTTP headers, then a blank 
line, then the first byte of the response.


That is when the response is commmitted (and the server will now set a flag to that 
effect in the Response object).


From that point on, it is too late to still modify the HTTP status code or the HTTP 
response headers, because they are already on their way to the client, and the server 
cannot grab them back.


So any attempt at that point by the webapp (filters, servlet, whatever) to modify the 
status or the headers will be met by a refusal : can't do that, the response is already 
committed.





-
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org



Re: filter question

2014-03-14 Thread Mikolaj Rydzewski

On 14.03.2014 13:25, André Warnier wrote:


Not a direct answer to your question, but this subject comes up so
often that maybe a generic explanation may help.

[...]

So any attempt at that point by the webapp (filters, servlet,
whatever) to modify the status or the headers will be met by a refusal
: can't do that, the response is already committed.


+100

Wow, great explanation!

--
Mikolaj Rydzewski m...@ceti.pl


-
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org



Re: filter question

2014-03-14 Thread Christopher Schultz
-BEGIN PGP SIGNED MESSAGE-
Hash: SHA256

Makilaj,

On 3/14/14, 8:32 AM, Mikolaj Rydzewski wrote:
 On 14.03.2014 13:25, André Warnier wrote:
 
 Not a direct answer to your question, but this subject comes up
 so often that maybe a generic explanation may help.
 [...]
 So any attempt at that point by the webapp (filters, servlet, 
 whatever) to modify the status or the headers will be met by a
 refusal : can't do that, the response is already committed.
 
 +100
 
 Wow, great explanation!

Agreed.

André, would you care to turn that into an entry on the Tomcat Wiki
FAQ page? The concept of a committed response is certainly one that
could use some clarification for those who don't understand it.

- -chris
-BEGIN PGP SIGNATURE-
Version: GnuPG v1
Comment: GPGTools - http://gpgtools.org
Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/

iQIcBAEBCAAGBQJTIwBBAAoJEBzwKT+lPKRYdDgP/0KM0avcuK4OEpGkgovMVq8A
OZD1GazPTM/a62zzSfsjH1uPrNl4pOIRKpXAjS+lg8c8JH8UME4mj25aPD/mvw7O
t6RZxmCTr7ogDRPvRPyQd5bQQl/WYcfzKOnQXKfOyVTprbe/byDimjCJfE6mWknY
XFXJJdp2OjMx1ft1g8Ht94G9ZPZOH2RhXm1pKCaDypelmoXo0PSeaXkeeBBYzqIn
LHFSbpy7lZ+EFKred2GDVNCI1IC+a4KXKb7N2UrMm9n7zfgcXqWCwyuVqAh3Sixj
SKs5czeLtnGdXRcsspGB8gQHCMTh2Dc9PAukLSKZEiWyT063DQCSikcOj9u7P1kF
BrLwW8I8g8fmyfrY17aNAPemBFoKyeUijhHUzw64oMxlu+VtfOTM2pfzaklCD5f9
kRJ9CQ0WkODdMWgrhFD2dC5hbbpVbSi8c9OHFM8pqRwcMaQZtY0DxeOo6xZDBLUW
sYV10Hu0xeLpH/uKfh1hKBnR8oMiOoviOrJI+oUPirLMlRvM5xgB7XLE2zWDGjRV
LkrItJLX9HxT730Qk/ZqfTaJbt/KnGNjHcqIGOzUx+iOeHxfnR6ULeEt3vbYaYHX
41d9+Navk0c9z5VwDu548onA5vYAdZYnm48KNKWUktjXzV3bo69Xb0K3+JgPIbHe
1r9awD88NkDmuyZ/gF9B
=BkUs
-END PGP SIGNATURE-

-
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org



Re: filter question

2014-03-14 Thread André Warnier

Christopher Schultz wrote:

-BEGIN PGP SIGNED MESSAGE-
Hash: SHA256

Makilaj,

On 3/14/14, 8:32 AM, Mikolaj Rydzewski wrote:

On 14.03.2014 13:25, André Warnier wrote:


Not a direct answer to your question, but this subject comes up
so often that maybe a generic explanation may help.

[...]
So any attempt at that point by the webapp (filters, servlet, 
whatever) to modify the status or the headers will be met by a

refusal : can't do that, the response is already committed.

+100

Wow, great explanation!


Agreed.

André, would you care to turn that into an entry on the Tomcat Wiki
FAQ page? The concept of a committed response is certainly one that
could use some clarification for those who don't understand it.

I would happily do so, except that I am just at the point of leaving for a week where I'll 
have little time for that kind of thing.  Let's do this : I donate the response and all 
concommittant rights to the Apache Foundation, and will happily let someone else create 
the FAQ article and do some cut-and-paste in my stead.


-
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org



RE: filter question

2014-03-13 Thread Martin Gainty
you'll need to pass your modified response to service method of servlet which 
is *in* the filterChain


ApplicationFilterChain::internalDoFilter(ServletRequest request, 
ServletResponse response)
throws IOException, ServletException 

{

servlet.service(request, response);

...

}

Martin 


  



 Date: Thu, 13 Mar 2014 17:51:59 -0700
 Subject: filter question
 From: catph...@catphive.net
 To: users@tomcat.apache.org
 
 I have a filter with doFilter method like this:
 
 public void doFilter(ServletRequest request,
 ServletResponse response,
 FilterChain chain)
 throws IOException, ServletException {
 HttpServletRequest req = (HttpServletRequest) request;
 HttpServletResponse resp = (HttpServletResponse) response;
 
 resp.setHeader(Cache-Control,
 must-revalidate, max-age=0, post-check=0,
 pre-check=0);
 
 chain.doFilter(request, response);
 }
 
 This sets the header. However, if I set the header *after* chain.doFilter,
 the header is not set. Why is this?
 
 public void doFilter(ServletRequest request,
 ServletResponse response,
 FilterChain chain)
 throws IOException, ServletException {
 HttpServletRequest req = (HttpServletRequest) request;
 HttpServletResponse resp = (HttpServletResponse) response;
 
 chain.doFilter(request, response);
 
 resp.setHeader(Cache-Control,
 must-revalidate, max-age=0, post-check=0,
 pre-check=0);
 }
 
 Programmatically I can see the header is null.
 
 Has the content already been sent to the web browser after chain.doFilter?
 If so, is there a way to delay sending data to the browser? I need to
 inspect the status code in the response before setting my header (to
 prevent 404's from being cached).
 
 Thanks,
 Brendan Miller
  

Re: filter question

2014-03-13 Thread Tim Watts
On Thu, 2014-03-13 at 17:51 -0700, Brendan Miller wrote:
 I have a filter with doFilter method like this:
 
 public void doFilter(ServletRequest request,
  ServletResponse response,
  FilterChain chain)
 throws IOException, ServletException {
 HttpServletRequest req = (HttpServletRequest) request;
 HttpServletResponse resp = (HttpServletResponse) response;
 
 resp.setHeader(Cache-Control,
must-revalidate, max-age=0, post-check=0,
 pre-check=0);
 
 chain.doFilter(request, response);
 }
 
 This sets the header. However, if I set the header *after* chain.doFilter,
 the header is not set. Why is this?
 
A similar question came up last week.  Basically, it's because the
response has already been committed.  A response becomes committed once
the 1st byte is sent back to the client -- e.g. if flush() is called or
the buffer becomes full while more response data is written.

You can search the archive for how it was resolved.  Don't recall the
subject line.  Sorry.

-- Tim

 public void doFilter(ServletRequest request,
  ServletResponse response,
  FilterChain chain)
 throws IOException, ServletException {
 HttpServletRequest req = (HttpServletRequest) request;
 HttpServletResponse resp = (HttpServletResponse) response;
 
 chain.doFilter(request, response);
 
 resp.setHeader(Cache-Control,
must-revalidate, max-age=0, post-check=0,
 pre-check=0);
 }
 
 Programmatically I can see the header is null.
 
 Has the content already been sent to the web browser after chain.doFilter?
 If so, is there a way to delay sending data to the browser? I need to
 inspect the status code in the response before setting my header (to
 prevent 404's from being cached).
 
 Thanks,
 Brendan Miller



-
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org



RE: filter question

2014-03-13 Thread Tim Watts
On Thu, 2014-03-13 at 21:20 -0400, Martin Gainty wrote:
 you'll need to pass your modified response to service method of
 servlet which is *in* the filterChain

Utter nonsense.

 ApplicationFilterChain::internalDoFilter(ServletRequest request,
 ServletResponse response)
 throws IOException, ServletException 
 
 {
 
 servlet.service(request, response);
 
 ...
 
 }
 
 Martin 
 
 
   
 
 
 
  Date: Thu, 13 Mar 2014 17:51:59 -0700
  Subject: filter question
  From: catph...@catphive.net
  To: users@tomcat.apache.org
  
  I have a filter with doFilter method like this:
  
  public void doFilter(ServletRequest request,
  ServletResponse response,
  FilterChain chain)
  throws IOException, ServletException {
  HttpServletRequest req = (HttpServletRequest) request;
  HttpServletResponse resp = (HttpServletResponse) response;
  
  resp.setHeader(Cache-Control,
  must-revalidate, max-age=0, post-check=0,
  pre-check=0);
  
  chain.doFilter(request, response);
  }
  
  This sets the header. However, if I set the header *after* chain.doFilter,
  the header is not set. Why is this?
  
  public void doFilter(ServletRequest request,
  ServletResponse response,
  FilterChain chain)
  throws IOException, ServletException {
  HttpServletRequest req = (HttpServletRequest) request;
  HttpServletResponse resp = (HttpServletResponse) response;
  
  chain.doFilter(request, response);
  
  resp.setHeader(Cache-Control,
  must-revalidate, max-age=0, post-check=0,
  pre-check=0);
  }
  
  Programmatically I can see the header is null.
  
  Has the content already been sent to the web browser after chain.doFilter?
  If so, is there a way to delay sending data to the browser? I need to
  inspect the status code in the response before setting my header (to
  prevent 404's from being cached).
  
  Thanks,
  Brendan Miller
 



-
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org



Re: filter question

2014-03-13 Thread Brendan Miller
I'm confused by what you mean by that. Are you saying I need to somehow
rewrite the class of the FilterChain object passed to my filter?

To be clear, I'm trying to modify the response that comes back from the
service. I have a header that I may or may not need to set based on the
response code. I believe the service sets the response code?


On Thu, Mar 13, 2014 at 6:20 PM, Martin Gainty mgai...@hotmail.com wrote:

 you'll need to pass your modified response to service method of servlet
 which is *in* the filterChain


 ApplicationFilterChain::internalDoFilter(ServletRequest request,
 ServletResponse response)
 throws IOException, ServletException

 {
 
 servlet.service(request, response);

 ...

 }

 Martin






  Date: Thu, 13 Mar 2014 17:51:59 -0700
  Subject: filter question
  From: catph...@catphive.net
  To: users@tomcat.apache.org
 
  I have a filter with doFilter method like this:
 
  public void doFilter(ServletRequest request,
  ServletResponse response,
  FilterChain chain)
  throws IOException, ServletException {
  HttpServletRequest req = (HttpServletRequest) request;
  HttpServletResponse resp = (HttpServletResponse) response;
 
  resp.setHeader(Cache-Control,
  must-revalidate, max-age=0, post-check=0,
  pre-check=0);
 
  chain.doFilter(request, response);
  }
 
  This sets the header. However, if I set the header *after*
 chain.doFilter,
  the header is not set. Why is this?
 
  public void doFilter(ServletRequest request,
  ServletResponse response,
  FilterChain chain)
  throws IOException, ServletException {
  HttpServletRequest req = (HttpServletRequest) request;
  HttpServletResponse resp = (HttpServletResponse) response;
 
  chain.doFilter(request, response);
 
  resp.setHeader(Cache-Control,
  must-revalidate, max-age=0, post-check=0,
  pre-check=0);
  }
 
  Programmatically I can see the header is null.
 
  Has the content already been sent to the web browser after
 chain.doFilter?
  If so, is there a way to delay sending data to the browser? I need to
  inspect the status code in the response before setting my header (to
  prevent 404's from being cached).
 
  Thanks,
  Brendan Miller




RE: filter question

2014-03-13 Thread Caldarale, Charles R
 From: Brendan Miller [mailto:catph...@catphive.net] 
 Subject: Re: filter question

 On Thu, Mar 13, 2014 at 6:20 PM, Martin Gainty mgai...@hotmail.com wrote:
  you'll need to pass your modified response to service method of servlet
  which is *in* the filterChain

 I'm confused by what you mean by that.

As is pretty much everyone with regard to every post from Martin G.  After 
you've been on the list a bit, you'll learn to simply drop his messages in the 
rubbish bin.

 - Chuck


THIS COMMUNICATION MAY CONTAIN CONFIDENTIAL AND/OR OTHERWISE PROPRIETARY 
MATERIAL and is thus for use only by the intended recipient. If you received 
this in error, please contact the sender and delete the e-mail and its 
attachments from all computers.


-
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org



Re: filter question

2014-03-13 Thread Tim Watts
On Thu, 2014-03-13 at 19:11 -0700, Brendan Miller wrote:
 I'm confused by what you mean by that. Are you saying I need to somehow
 rewrite the class of the FilterChain object passed to my filter?
 
I think you're somewhat new to the list.  Mr. Gainty is notorious here
and seems to pride himself on concocting the most off-the-wall red
herrings imaginable.  I'll admit some of them are truly breathtaking.  I
guess it's some sort of quest to build a global reputation as the
world's most incompetent developer.  I dunno.

 To be clear, I'm trying to modify the response that comes back from the
 service. I have a header that I may or may not need to set based on the
 response code. I believe the service sets the response code?

That's true.  Unfortunately, by the time your filter gets control again,
the response will very likely be committed thus shutting out any
possibility of setting any headers.

Doing this in a Filter, while intuitively sensible, will always be a
highly fragile solution.  You would have to set a buffer large enough to
accommodate the largest conceivable response size.  Once a response is
committed you can't set the response code or headers -- they're already
on their way to the client.  There's no getting around this.

I think the best approach is to conditionally set the header before any
response is generated.  If your application has an MVC structure you
could do this just before the Controller invokes the View.  You should
know the response code by then.

HTH

-- Tim

 
 
 On Thu, Mar 13, 2014 at 6:20 PM, Martin Gainty mgai...@hotmail.com wrote:
 
  you'll need to pass your modified response to service method of servlet
  which is *in* the filterChain
 
 
  ApplicationFilterChain::internalDoFilter(ServletRequest request,
  ServletResponse response)
  throws IOException, ServletException
 
  {
  
  servlet.service(request, response);
 
  ...
 
  }
 
  Martin
 
 
 
 
 
 
   Date: Thu, 13 Mar 2014 17:51:59 -0700
   Subject: filter question
   From: catph...@catphive.net
   To: users@tomcat.apache.org
  
   I have a filter with doFilter method like this:
  
   public void doFilter(ServletRequest request,
   ServletResponse response,
   FilterChain chain)
   throws IOException, ServletException {
   HttpServletRequest req = (HttpServletRequest) request;
   HttpServletResponse resp = (HttpServletResponse) response;
  
   resp.setHeader(Cache-Control,
   must-revalidate, max-age=0, post-check=0,
   pre-check=0);
  
   chain.doFilter(request, response);
   }
  
   This sets the header. However, if I set the header *after*
  chain.doFilter,
   the header is not set. Why is this?
  
   public void doFilter(ServletRequest request,
   ServletResponse response,
   FilterChain chain)
   throws IOException, ServletException {
   HttpServletRequest req = (HttpServletRequest) request;
   HttpServletResponse resp = (HttpServletResponse) response;
  
   chain.doFilter(request, response);
  
   resp.setHeader(Cache-Control,
   must-revalidate, max-age=0, post-check=0,
   pre-check=0);
   }
  
   Programmatically I can see the header is null.
  
   Has the content already been sent to the web browser after
  chain.doFilter?
   If so, is there a way to delay sending data to the browser? I need to
   inspect the status code in the response before setting my header (to
   prevent 404's from being cached).
  
   Thanks,
   Brendan Miller
 
 



-
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org



Re: filter question

2014-03-13 Thread Tim Watts
On Thu, 2014-03-13 at 23:16 -0400, Tim Watts wrote:
 On Thu, 2014-03-13 at 19:11 -0700, Brendan Miller wrote:
  To be clear, I'm trying to modify the response that comes back from the
  service. I have a header that I may or may not need to set based on the
  response code. I believe the service sets the response code?
 
 That's true.  
Actually, let me correct myself: that may not be strictly true.  I don't
think there's anything in the spec that says the response code will be
set when service() returns UNLESS the request results in an error.

-- Tim.

 Unfortunately, by the time your filter gets control again,
 the response will very likely be committed thus shutting out any
 possibility of setting any headers.
 
 Doing this in a Filter, while intuitively sensible, will always be a
 highly fragile solution.  You would have to set a buffer large enough to
 accommodate the largest conceivable response size.  Once a response is
 committed you can't set the response code or headers -- they're already
 on their way to the client.  There's no getting around this.
 
 I think the best approach is to conditionally set the header before any
 response is generated.  If your application has an MVC structure you
 could do this just before the Controller invokes the View.  You should
 know the response code by then.
 
 HTH
 
 -- Tim
 
  
  
  On Thu, Mar 13, 2014 at 6:20 PM, Martin Gainty mgai...@hotmail.com wrote:
  
   you'll need to pass your modified response to service method of servlet
   which is *in* the filterChain
  
  
   ApplicationFilterChain::internalDoFilter(ServletRequest request,
   ServletResponse response)
   throws IOException, ServletException
  
   {
   
   servlet.service(request, response);
  
   ...
  
   }
  
   Martin
  
  
  
  
  
  
Date: Thu, 13 Mar 2014 17:51:59 -0700
Subject: filter question
From: catph...@catphive.net
To: users@tomcat.apache.org
   
I have a filter with doFilter method like this:
   
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
   
resp.setHeader(Cache-Control,
must-revalidate, max-age=0, post-check=0,
pre-check=0);
   
chain.doFilter(request, response);
}
   
This sets the header. However, if I set the header *after*
   chain.doFilter,
the header is not set. Why is this?
   
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
   
chain.doFilter(request, response);
   
resp.setHeader(Cache-Control,
must-revalidate, max-age=0, post-check=0,
pre-check=0);
}
   
Programmatically I can see the header is null.
   
Has the content already been sent to the web browser after
   chain.doFilter?
If so, is there a way to delay sending data to the browser? I need to
inspect the status code in the response before setting my header (to
prevent 404's from being cached).
   
Thanks,
Brendan Miller
  
  
 
 
 
 -
 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



RE: filter question

2014-03-13 Thread Caldarale, Charles R
 From: Tim Watts [mailto:t...@cliftonfarm.org] 
 Subject: Re: filter question

 Doing this in a Filter, while intuitively sensible, will always be a
 highly fragile solution.  You would have to set a buffer large enough to
 accommodate the largest conceivable response size.  Once a response is
 committed you can't set the response code or headers -- they're already
 on their way to the client.  There's no getting around this.

The filter could wrap the original response object with its own creation, and 
thereby control what gets written through it.  The wrapper object can determine 
when to add the header, based on whatever criteria you like, such as amount of 
data so far written, internal state of the webapp, etc.  Examples of such 
wrappering have been posted on this list a few times in the recent past.

 - Chuck


THIS COMMUNICATION MAY CONTAIN CONFIDENTIAL AND/OR OTHERWISE PROPRIETARY 
MATERIAL and is thus for use only by the intended recipient. If you received 
this in error, please contact the sender and delete the e-mail and its 
attachments from all computers.


-
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org