You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tomcat.apache.org by Tore Eriksson <to...@po.rd.taisho.co.jp> on 2008/10/21 02:10:38 UTC

Re: Committing sendRedirect()

Hello everybody,

As I found a solution to my problem, I thought I would share it in case
someone else comes up against the same issue. The reason for the client
not acting on the redirect is that sendRedirect does not send any
Content-length header, and the client will then wait for an eventual
Content body until the servlet finishes. This could be avoided if the
sendRedirect would include "Content-length: 0" in its HTTP headers. I
solved my problem by manually constructing the redirect on the
HttpServletResponse object ('out' below).

Old code:

final int PARTIAL_HITS = 25;

for (int i = 0; i < hits.length(); i++) {

  /** Insert into table omitted */

  if (i == PARTIAL_HITS) {
    // Intermittant redirect, not acted on until doPost returns
    out.sendRedirect(resultUrl);
  }
}

if (!out.isCommitted()) {
  // Final redirect
  out.sendRedirect(resultUrl);
}

New code:

final int PARTIAL_HITS = 25;

for (int i = 0; i < hits.length(); i++) {

  /** Insert into table omitted */

  if (i == PARTIAL_HITS) {
    // Intermittant redirect, acted on immediately
    out.setHeader("Location", resultUrl);
    out.setStatus(303);
    out.setContentLength(0);
    out.flushBuffer();
  }
}

if (!out.isCommitted()) {
  // Final redirect (if case less than PARTIAL_HITS found)
  out.sendRedirect(resultUrl);
}

> Hello again,
> 
> Thanks for the response, but it seems like my phrasing was a bit unclear.
> The problem is not the second redirect - in fact there will be no
> multiple redirects. The second redirect is only there for the case when
> less than 25 hits are found and the first redirect is not called. The if
> clause will prevent the program for trying to redirect twice.
> 
> My problem is rather that the redirect is only commited - the response
> is sent to the client - until the doPost method/thread finishes. I
> expected to be able to redirect (once) in the middle of the loop. What I
> am trying to accomplish is to do a query, enter the hits into a
> temporary table, and redirect to another program that displays a paged
> list of hits by reading from the table - in effect using the table as a
> queue. Since the paged display only shows the top 25 hits, there is no
> need to wait for all the query results.
> 
> So once more, my problem is that the redirect is not committed until the
> function returns. Any help much appreciated.
> 
> Tore
> 
> Alan Chaney wrote:
> > Tore
> > 
> > Your code below is written as though the 'out' was like writing data to 
> > a console. The processing in a servlet is part of a  request/response 
> > cycle, where the 'request' tells it what to do and the response is the 
> > reply.
> > 
> > Because of the nature of the request/response cycle you only get one 
> > chance at the reply. The javadocs for HttpServletResponse.sendRedirect 
> > make this clear.
> > 
> > "If the response has already been committed, this method throws an 
> > IllegalStateException. After using this method the response should be 
> > considered to be committed and should not be written to."
> > 
> > In other words, in one servlet request/response cycle you get exactly 
> > one chance to issue a 'sendRedirect'. If you think this through you'll 
> > see that this is how it has to be:
> > 
> > Browser sends request to servlet
> > Servlet process request and sendsRedirect
> > Browser display response.
> > 
> > Your problem is that you are trying to generate a second response 
> > without a correspondng request. The first response is for the 'top 25' 
> > and the second is for 'all the rest', but by then you've already 
> > committed the response.
> > 
> > To achieve what I think you are trying to achieve would require you to 
> > create some mechanism where the lucene query results are processed in a 
> > separate thread and your application makes TWO requests - one for the 
> > first set of results and then one for the final set of results.
> > 
> > There are far too many different ways to do this to detail here - I hope 
> > this helps
> > 
> > Regards
> > 
> > Alan Chaney
> > 
> > 
> > 
> > Tore Eriksson wrote:
> > > Hi everybody,
> > > 
> > > I have a problem with redirects in Tomcat 5.5.25. I am doing a Lucene
> > > search and would like to send a redirect after finding the top 25 hits,
> > > commit this response, and then continue processing the remaining hits.
> > > The relevant parts of the doPost() code are as below:
> > > 
> > > final int PARTIAL_HITS = 25;
> > > 
> > > for (int i = 0; i < hits.length(); i++) {
> > > 
> > >   Document doc = hits.doc(i);
> > >   String citation = doc.get("citation");
> > > 
> > >   /** Insert into table */
> > >   try {
> > >     insertId.setInt(1, java.lang.Integer.parseInt(citation));
> > >     insertId.executeUpdate();
> > >   }
> > >   catch (SQLException e) {
> > >     out.sendError(500, "Bad SQL insert: " + e);
> > >   }
> > >   catch (Exception e) {}
> > > 
> > >   if (i == PARTIAL_HITS) {
> > >     // Intermittant redirect
> > >     out.sendRedirect(resultUrl);
> > >   }
> > > }
> > > 
> > > insertId.close();
> > > 
> > > if (!out.isCommitted()) {
> > >   // Final redirect
> > >   out.sendRedirect(resultUrl);
> > > }
> > > 
> > > My problem is that the intermittant redirect is not committed until the
> > > function returns, which will take quite some time for some queries. I
> > > have tried HttpServletResponse.flushBuffer() and other possible
> > > variations. Any pointers would be most appreciated.
> > > 
> > > Tore
> 
> 
> _______________________________________________________________
> Tore Eriksson [tore.eriksson ad po.rd.taisho.co.jp]

_______________________________________________________________
Tore Eriksson [tore.eriksson at po.rd.taisho.co.jp]



---------------------------------------------------------------------
To start a new topic, e-mail: users@tomcat.apache.org
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: Committing sendRedirect()

Posted by Leon Rosenberg <ro...@googlemail.com>.
On Thu, Oct 23, 2008 at 2:12 AM, Tore Eriksson
<to...@po.rd.taisho.co.jp> wrote:
>> Tore Eriksson wrote:
>> > Hello everybody,
>> >
>> > As I found a solution to my problem, I thought I would share it in case
>> > someone else comes up against the same issue. The reason for the client
>> > not acting on the redirect is that sendRedirect does not send any
>> > Content-length header, and the client will then wait for an eventual
>> > Content body until the servlet finishes. This could be avoided if the
>> > sendRedirect would include "Content-length: 0" in its HTTP headers. I
>> > solved my problem by manually constructing the redirect on the
>> > HttpServletResponse object ('out' below).
>>
>> Why don't you just insert "return;" after the first redirect was called?
>>
>> p
>
> Becuse the doPost code have to keep on running and process more results after
> the redirect.

And thats why it doesn't work :-)

The "proper" or more common way of achieving your task is to start the
search in another thread/executor, monitor its progress, and return
from the initial thread/request as soon as the progress is sufficient,
letting the search thread finish his job in background.


The problem with your solution is, that you are thinking you can make
both at once: return from processing and continue processing. I can
imagine that even your "hack" may work under special circumstances it
is not guaranteed to work in another container, another version of
same container, proxied or behind http.
Imagine if you are running in a wrapped request, as long as the thread
will continue to execute, nothing will be send to client. Of course
you can hack everything, but sparing a threeliner for a new thread
just isn't worth it.


regards
Leon

---------------------------------------------------------------------
To start a new topic, e-mail: users@tomcat.apache.org
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: Committing sendRedirect()

Posted by Tore Eriksson <to...@po.rd.taisho.co.jp>.
> Tore Eriksson wrote:
> > Hello everybody,
> > 
> > As I found a solution to my problem, I thought I would share it in case
> > someone else comes up against the same issue. The reason for the client
> > not acting on the redirect is that sendRedirect does not send any
> > Content-length header, and the client will then wait for an eventual
> > Content body until the servlet finishes. This could be avoided if the
> > sendRedirect would include "Content-length: 0" in its HTTP headers. I
> > solved my problem by manually constructing the redirect on the
> > HttpServletResponse object ('out' below).
> 
> Why don't you just insert "return;" after the first redirect was called?
> 
> p

Becuse the doPost code have to keep on running and process more results after
the redirect.

> > Old code:
> > 
> > final int PARTIAL_HITS = 25;
> > 
> > for (int i = 0; i < hits.length(); i++) {
> > 
> >   /** Insert into table omitted */
> > 
> >   if (i == PARTIAL_HITS) {
> >     // Intermittant redirect, not acted on until doPost returns
> >     out.sendRedirect(resultUrl);
> 
>       return; // why not terminate the method call here?
> 
> >   }
> > }
> > 
> > if (!out.isCommitted()) {
> >   // Final redirect
> >   out.sendRedirect(resultUrl);
> > }
> > 
> > New code:
> > 
> > final int PARTIAL_HITS = 25;
> > 
> > for (int i = 0; i < hits.length(); i++) {
> > 
> >   /** Insert into table omitted */
> > 
> >   if (i == PARTIAL_HITS) {
> >     // Intermittant redirect, acted on immediately
> >     out.setHeader("Location", resultUrl);
> >     out.setStatus(303);
> >     out.setContentLength(0);
> >     out.flushBuffer();
> >   }
> > }
> > 
> > if (!out.isCommitted()) {
> >   // Final redirect (if case less than PARTIAL_HITS found)
> >   out.sendRedirect(resultUrl);
> > }
> > 

_______________________________________________________________
Tore Eriksson [tore.eriksson at po.rd.taisho.co.jp]



---------------------------------------------------------------------
To start a new topic, e-mail: users@tomcat.apache.org
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: Committing sendRedirect()

Posted by Christopher Schultz <ch...@christopherschultz.net>.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Tore,

Tore Eriksson wrote:
> The reason for the client
> not acting on the redirect is that sendRedirect does not send any
> Content-length header, and the client will then wait for an eventual
> Content body until the servlet finishes. This could be avoided if the
> sendRedirect would include "Content-length: 0" in its HTTP headers.

Although this technique works, it shouldn't be necessary. The
Content-Length header is not required by HTTP for server responses (or
the client requests for that matter). The client should accept this
situation and take appropriate action, rather than getting confused ;)

Nice to know that there was a solution, even if it is kind of a hack.

- -chris

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (MingW32)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iEYEARECAAYFAkj9QXcACgkQ9CaO5/Lv0PBLbQCeK1uytfY2eQ+TvY9d6HFD2xoo
yysAni+P+WHY76wPP3SEMf4utp9inemj
=BQbQ
-----END PGP SIGNATURE-----

---------------------------------------------------------------------
To start a new topic, e-mail: users@tomcat.apache.org
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: Committing sendRedirect()

Posted by Pid <p...@pidster.com>.
Tore Eriksson wrote:
> Hello everybody,
> 
> As I found a solution to my problem, I thought I would share it in case
> someone else comes up against the same issue. The reason for the client
> not acting on the redirect is that sendRedirect does not send any
> Content-length header, and the client will then wait for an eventual
> Content body until the servlet finishes. This could be avoided if the
> sendRedirect would include "Content-length: 0" in its HTTP headers. I
> solved my problem by manually constructing the redirect on the
> HttpServletResponse object ('out' below).

Why don't you just insert "return;" after the first redirect was called?

p

> Old code:
> 
> final int PARTIAL_HITS = 25;
> 
> for (int i = 0; i < hits.length(); i++) {
> 
>   /** Insert into table omitted */
> 
>   if (i == PARTIAL_HITS) {
>     // Intermittant redirect, not acted on until doPost returns
>     out.sendRedirect(resultUrl);

      return; // why not terminate the method call here?

>   }
> }
> 
> if (!out.isCommitted()) {
>   // Final redirect
>   out.sendRedirect(resultUrl);
> }
> 
> New code:
> 
> final int PARTIAL_HITS = 25;
> 
> for (int i = 0; i < hits.length(); i++) {
> 
>   /** Insert into table omitted */
> 
>   if (i == PARTIAL_HITS) {
>     // Intermittant redirect, acted on immediately
>     out.setHeader("Location", resultUrl);
>     out.setStatus(303);
>     out.setContentLength(0);
>     out.flushBuffer();
>   }
> }
> 
> if (!out.isCommitted()) {
>   // Final redirect (if case less than PARTIAL_HITS found)
>   out.sendRedirect(resultUrl);
> }
> 
>> Hello again,
>>
>> Thanks for the response, but it seems like my phrasing was a bit unclear.
>> The problem is not the second redirect - in fact there will be no
>> multiple redirects. The second redirect is only there for the case when
>> less than 25 hits are found and the first redirect is not called. The if
>> clause will prevent the program for trying to redirect twice.
>>
>> My problem is rather that the redirect is only commited - the response
>> is sent to the client - until the doPost method/thread finishes. I
>> expected to be able to redirect (once) in the middle of the loop. What I
>> am trying to accomplish is to do a query, enter the hits into a
>> temporary table, and redirect to another program that displays a paged
>> list of hits by reading from the table - in effect using the table as a
>> queue. Since the paged display only shows the top 25 hits, there is no
>> need to wait for all the query results.
>>
>> So once more, my problem is that the redirect is not committed until the
>> function returns. Any help much appreciated.
>>
>> Tore
>>
>> Alan Chaney wrote:
>>> Tore
>>>
>>> Your code below is written as though the 'out' was like writing data to 
>>> a console. The processing in a servlet is part of a  request/response 
>>> cycle, where the 'request' tells it what to do and the response is the 
>>> reply.
>>>
>>> Because of the nature of the request/response cycle you only get one 
>>> chance at the reply. The javadocs for HttpServletResponse.sendRedirect 
>>> make this clear.
>>>
>>> "If the response has already been committed, this method throws an 
>>> IllegalStateException. After using this method the response should be 
>>> considered to be committed and should not be written to."
>>>
>>> In other words, in one servlet request/response cycle you get exactly 
>>> one chance to issue a 'sendRedirect'. If you think this through you'll 
>>> see that this is how it has to be:
>>>
>>> Browser sends request to servlet
>>> Servlet process request and sendsRedirect
>>> Browser display response.
>>>
>>> Your problem is that you are trying to generate a second response 
>>> without a correspondng request. The first response is for the 'top 25' 
>>> and the second is for 'all the rest', but by then you've already 
>>> committed the response.
>>>
>>> To achieve what I think you are trying to achieve would require you to 
>>> create some mechanism where the lucene query results are processed in a 
>>> separate thread and your application makes TWO requests - one for the 
>>> first set of results and then one for the final set of results.
>>>
>>> There are far too many different ways to do this to detail here - I hope 
>>> this helps
>>>
>>> Regards
>>>
>>> Alan Chaney
>>>
>>>
>>>
>>> Tore Eriksson wrote:
>>>> Hi everybody,
>>>>
>>>> I have a problem with redirects in Tomcat 5.5.25. I am doing a Lucene
>>>> search and would like to send a redirect after finding the top 25 hits,
>>>> commit this response, and then continue processing the remaining hits.
>>>> The relevant parts of the doPost() code are as below:
>>>>
>>>> final int PARTIAL_HITS = 25;
>>>>
>>>> for (int i = 0; i < hits.length(); i++) {
>>>>
>>>>   Document doc = hits.doc(i);
>>>>   String citation = doc.get("citation");
>>>>
>>>>   /** Insert into table */
>>>>   try {
>>>>     insertId.setInt(1, java.lang.Integer.parseInt(citation));
>>>>     insertId.executeUpdate();
>>>>   }
>>>>   catch (SQLException e) {
>>>>     out.sendError(500, "Bad SQL insert: " + e);
>>>>   }
>>>>   catch (Exception e) {}
>>>>
>>>>   if (i == PARTIAL_HITS) {
>>>>     // Intermittant redirect
>>>>     out.sendRedirect(resultUrl);
>>>>   }
>>>> }
>>>>
>>>> insertId.close();
>>>>
>>>> if (!out.isCommitted()) {
>>>>   // Final redirect
>>>>   out.sendRedirect(resultUrl);
>>>> }
>>>>
>>>> My problem is that the intermittant redirect is not committed until the
>>>> function returns, which will take quite some time for some queries. I
>>>> have tried HttpServletResponse.flushBuffer() and other possible
>>>> variations. Any pointers would be most appreciated.
>>>>
>>>> Tore
>>
>> _______________________________________________________________
>> Tore Eriksson [tore.eriksson ad po.rd.taisho.co.jp]
> 
> _______________________________________________________________
> Tore Eriksson [tore.eriksson at po.rd.taisho.co.jp]
> 
> 
> 
> ---------------------------------------------------------------------
> To start a new topic, e-mail: users@tomcat.apache.org
> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
> For additional commands, e-mail: users-help@tomcat.apache.org
> 
> 


---------------------------------------------------------------------
To start a new topic, e-mail: users@tomcat.apache.org
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org