Re: filter question
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
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
-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
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
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
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
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
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
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
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
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
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