You are viewing a plain text version of this content. The canonical link for it is here.
Posted to httpclient-users@hc.apache.org by Daniel Feist <df...@gmail.com> on 2014/09/16 01:59:55 UTC

Implementing a simple non-blocking echo server

Hi,

I'm struggling to implement a simple echo server using http components
aysnc api (HttpAsyncRequestHandler, HttpAsyncResponseProducer,
HttpAsyncRequestConsumer) without using: "response.setEntity(new
InputStreamEntity(requestEntity.getContent(),..,..)".

This is my attempt:

http://pastebin.com/Tbz0rxDH

It seems to work for small http bodies, but as soon as the body size is
larger than the buffer it hangs.

Anything obvious i'm doing wrong?

thanks,
Dan

Re: Implementing a simple non-blocking echo server

Posted by Oleg Kalnichevski <ol...@apache.org>.
On Tue, 2014-09-16 at 13:49 +0100, Daniel Feist wrote:
> Hi,
> 
> Jetty uses a default output buffer of 64KB, although the echo
> implementation I referenced works beyond this buffer size too.  When the
> internal buffer is full it writes to response channel, only closing (and
> flushing?) the channel once the request has been fully read and processed
> and response written.
> 
> Forgetting Jetty now, playing around more with HttpCore I see this
> behaviour when debugging my implementation.  Is this right?
> 
> - When the buffer size is smaller that the request body I'm using IoCtrl to
> suspend input and request output.
> - Because the ContentDecoder is not completed AsyncHttpHandler#handle is
> never called and my HttpAsyncResponseProducer never submitted (using
>  httpexchange.submitResponse).
> - As such, when org.apache.http.nio.protocol.HttpAsyncService#responseReady
> is called there is no HttpAsyncResponseProducer available.
> - Because there is not HttpAsyncResponseProducer available, the buffer is
> never read and IoCtrl.requestInput is never called to continue reading the
> body.
> 
> I know what i'm trying to implement to learn httpcore may seem kind of
> artificial, but i'm struggling to make sense of this behaviour in the
> implementation.  Or is it simply that this is deliberate because handling
> the request and processing the response makes no sense at all until the
> request body has been fully read?  

Yes, it is deliberate and is based on a conscious design decision.
Nothing, however, stops you from tweaking HttpAsyncService to support
out of sync responses at the expense of compatibility with blocking HTTP
clients.

> 
> Ignoring what i've been playing with, what is the best, most efficient way,
> of implementing a AsyncEchoHandler with httpcore?
> 

I would probably opt to just truncate request content after a certain
limit. 

However if your main goal is learning rather than some practical
application I would recommend taking your chances with building a custom
protocol handler using HttpAsyncService as your starting point.

Hope this helps

Oleg



---------------------------------------------------------------------
To unsubscribe, e-mail: httpclient-users-unsubscribe@hc.apache.org
For additional commands, e-mail: httpclient-users-help@hc.apache.org


Re: Implementing a simple non-blocking echo server

Posted by Daniel Feist <df...@gmail.com>.
Hi,

Jetty uses a default output buffer of 64KB, although the echo
implementation I referenced works beyond this buffer size too.  When the
internal buffer is full it writes to response channel, only closing (and
flushing?) the channel once the request has been fully read and processed
and response written.

Forgetting Jetty now, playing around more with HttpCore I see this
behaviour when debugging my implementation.  Is this right?

- When the buffer size is smaller that the request body I'm using IoCtrl to
suspend input and request output.
- Because the ContentDecoder is not completed AsyncHttpHandler#handle is
never called and my HttpAsyncResponseProducer never submitted (using
 httpexchange.submitResponse).
- As such, when org.apache.http.nio.protocol.HttpAsyncService#responseReady
is called there is no HttpAsyncResponseProducer available.
- Because there is not HttpAsyncResponseProducer available, the buffer is
never read and IoCtrl.requestInput is never called to continue reading the
body.

I know what i'm trying to implement to learn httpcore may seem kind of
artificial, but i'm struggling to make sense of this behaviour in the
implementation.  Or is it simply that this is deliberate because handling
the request and processing the response makes no sense at all until the
request body has been fully read?  Am i

Ignoring what i've been playing with, what is the best, most efficient way,
of implementing a AsyncEchoHandler with httpcore?

thanks!


On Tue, Sep 16, 2014 at 12:25 PM, Oleg Kalnichevski <ol...@apache.org>
wrote:

> On Tue, 2014-09-16 at 11:34 +0100, Daniel Feist wrote:
> > Hi,
> >
> > This makes sense yes.  I thought it might be related to this, but at the
> > same time I'm unsure why the jetty implementation works.  (see
> > http://pastebin.com/1Ennis2m)
> >
> > Potentially because writing to the ServletOutputStream isn't writing
> > directly to the channel as the httpcore ContentEncoder is?
>
> Exactly. Jetty's internal buffer might simply be dynamically expandable.
> Generally servlet engines always buffer content in memory at least to a
> certain threshold simply because servlet APIs make it very easy to do
> stuff like writing out response content and then setting a response
> header or a response status.
>
> Oleg
>
> >
> > On Tue, Sep 16, 2014 at 10:33 AM, Oleg Kalnichevski <ol...@apache.org>
> > wrote:
> >
> > > On Tue, 2014-09-16 at 00:59 +0100, Daniel Feist wrote:
> > > > Hi,
> > > >
> > > > I'm struggling to implement a simple echo server using http
> components
> > > > aysnc api (HttpAsyncRequestHandler, HttpAsyncResponseProducer,
> > > > HttpAsyncRequestConsumer) without using: "response.setEntity(new
> > > > InputStreamEntity(requestEntity.getContent(),..,..)".
> > > >
> > > > This is my attempt:
> > > >
> > > > http://pastebin.com/Tbz0rxDH
> > > >
> > > > It seems to work for small http bodies, but as soon as the body size
> is
> > > > larger than the buffer it hangs.
> > > >
> > > > Anything obvious i'm doing wrong?
> > > >
> > > > thanks,
> > > > Dan
> > >
> > > Dan
> > >
> > > I think what is happening is this. Echoer content handler allocates a
> > > fixed buffer of 2048 bytes. When the buffer fills up the content
> handler
> > > suspends input. However, HTTP/1.1 is not a full duplex protocol! Well
> > > behaved protocol handler is not going to submit a response until the
> > > incoming request has been fully consumed. So, in your case the content
> > > buffer will never get flushed and the content handler will get stuck
> > > forever.
> > >
> > > One can naturally implement so called 'out of sync' response scheme
> > > whereby the server can send a response prematurely. It is subject to
> > > discussion as to whether 'out of sync' response scheme is actually
> > > legal. Many HTTP clients cannot handle out of sync responses
> gracefully.
> > > (Apache HttpClient, for instance). For compatibility sake the default
> > > protocol handler in HttpCore never responds out of sequence.
> > >
> > > Hope this helps
> > >
> > > Oleg
> > >
> > >
> > > ---------------------------------------------------------------------
> > > To unsubscribe, e-mail: httpclient-users-unsubscribe@hc.apache.org
> > > For additional commands, e-mail: httpclient-users-help@hc.apache.org
> > >
> > >
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: httpclient-users-unsubscribe@hc.apache.org
> For additional commands, e-mail: httpclient-users-help@hc.apache.org
>
>

Re: Implementing a simple non-blocking echo server

Posted by Oleg Kalnichevski <ol...@apache.org>.
On Tue, 2014-09-16 at 11:34 +0100, Daniel Feist wrote:
> Hi,
> 
> This makes sense yes.  I thought it might be related to this, but at the
> same time I'm unsure why the jetty implementation works.  (see
> http://pastebin.com/1Ennis2m)
> 
> Potentially because writing to the ServletOutputStream isn't writing
> directly to the channel as the httpcore ContentEncoder is?

Exactly. Jetty's internal buffer might simply be dynamically expandable.
Generally servlet engines always buffer content in memory at least to a
certain threshold simply because servlet APIs make it very easy to do
stuff like writing out response content and then setting a response
header or a response status.  

Oleg

> 
> On Tue, Sep 16, 2014 at 10:33 AM, Oleg Kalnichevski <ol...@apache.org>
> wrote:
> 
> > On Tue, 2014-09-16 at 00:59 +0100, Daniel Feist wrote:
> > > Hi,
> > >
> > > I'm struggling to implement a simple echo server using http components
> > > aysnc api (HttpAsyncRequestHandler, HttpAsyncResponseProducer,
> > > HttpAsyncRequestConsumer) without using: "response.setEntity(new
> > > InputStreamEntity(requestEntity.getContent(),..,..)".
> > >
> > > This is my attempt:
> > >
> > > http://pastebin.com/Tbz0rxDH
> > >
> > > It seems to work for small http bodies, but as soon as the body size is
> > > larger than the buffer it hangs.
> > >
> > > Anything obvious i'm doing wrong?
> > >
> > > thanks,
> > > Dan
> >
> > Dan
> >
> > I think what is happening is this. Echoer content handler allocates a
> > fixed buffer of 2048 bytes. When the buffer fills up the content handler
> > suspends input. However, HTTP/1.1 is not a full duplex protocol! Well
> > behaved protocol handler is not going to submit a response until the
> > incoming request has been fully consumed. So, in your case the content
> > buffer will never get flushed and the content handler will get stuck
> > forever.
> >
> > One can naturally implement so called 'out of sync' response scheme
> > whereby the server can send a response prematurely. It is subject to
> > discussion as to whether 'out of sync' response scheme is actually
> > legal. Many HTTP clients cannot handle out of sync responses gracefully.
> > (Apache HttpClient, for instance). For compatibility sake the default
> > protocol handler in HttpCore never responds out of sequence.
> >
> > Hope this helps
> >
> > Oleg
> >
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: httpclient-users-unsubscribe@hc.apache.org
> > For additional commands, e-mail: httpclient-users-help@hc.apache.org
> >
> >



---------------------------------------------------------------------
To unsubscribe, e-mail: httpclient-users-unsubscribe@hc.apache.org
For additional commands, e-mail: httpclient-users-help@hc.apache.org


Re: Implementing a simple non-blocking echo server

Posted by Daniel Feist <df...@gmail.com>.
Hi,

This makes sense yes.  I thought it might be related to this, but at the
same time I'm unsure why the jetty implementation works.  (see
http://pastebin.com/1Ennis2m)

Potentially because writing to the ServletOutputStream isn't writing
directly to the channel as the httpcore ContentEncoder is?

On Tue, Sep 16, 2014 at 10:33 AM, Oleg Kalnichevski <ol...@apache.org>
wrote:

> On Tue, 2014-09-16 at 00:59 +0100, Daniel Feist wrote:
> > Hi,
> >
> > I'm struggling to implement a simple echo server using http components
> > aysnc api (HttpAsyncRequestHandler, HttpAsyncResponseProducer,
> > HttpAsyncRequestConsumer) without using: "response.setEntity(new
> > InputStreamEntity(requestEntity.getContent(),..,..)".
> >
> > This is my attempt:
> >
> > http://pastebin.com/Tbz0rxDH
> >
> > It seems to work for small http bodies, but as soon as the body size is
> > larger than the buffer it hangs.
> >
> > Anything obvious i'm doing wrong?
> >
> > thanks,
> > Dan
>
> Dan
>
> I think what is happening is this. Echoer content handler allocates a
> fixed buffer of 2048 bytes. When the buffer fills up the content handler
> suspends input. However, HTTP/1.1 is not a full duplex protocol! Well
> behaved protocol handler is not going to submit a response until the
> incoming request has been fully consumed. So, in your case the content
> buffer will never get flushed and the content handler will get stuck
> forever.
>
> One can naturally implement so called 'out of sync' response scheme
> whereby the server can send a response prematurely. It is subject to
> discussion as to whether 'out of sync' response scheme is actually
> legal. Many HTTP clients cannot handle out of sync responses gracefully.
> (Apache HttpClient, for instance). For compatibility sake the default
> protocol handler in HttpCore never responds out of sequence.
>
> Hope this helps
>
> Oleg
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: httpclient-users-unsubscribe@hc.apache.org
> For additional commands, e-mail: httpclient-users-help@hc.apache.org
>
>

Re: Implementing a simple non-blocking echo server

Posted by Oleg Kalnichevski <ol...@apache.org>.
On Tue, 2014-09-16 at 00:59 +0100, Daniel Feist wrote:
> Hi,
> 
> I'm struggling to implement a simple echo server using http components
> aysnc api (HttpAsyncRequestHandler, HttpAsyncResponseProducer,
> HttpAsyncRequestConsumer) without using: "response.setEntity(new
> InputStreamEntity(requestEntity.getContent(),..,..)".
> 
> This is my attempt:
> 
> http://pastebin.com/Tbz0rxDH
> 
> It seems to work for small http bodies, but as soon as the body size is
> larger than the buffer it hangs.
> 
> Anything obvious i'm doing wrong?
> 
> thanks,
> Dan

Dan

I think what is happening is this. Echoer content handler allocates a
fixed buffer of 2048 bytes. When the buffer fills up the content handler
suspends input. However, HTTP/1.1 is not a full duplex protocol! Well
behaved protocol handler is not going to submit a response until the
incoming request has been fully consumed. So, in your case the content
buffer will never get flushed and the content handler will get stuck
forever.

One can naturally implement so called 'out of sync' response scheme
whereby the server can send a response prematurely. It is subject to
discussion as to whether 'out of sync' response scheme is actually
legal. Many HTTP clients cannot handle out of sync responses gracefully.
(Apache HttpClient, for instance). For compatibility sake the default
protocol handler in HttpCore never responds out of sequence.

Hope this helps

Oleg


---------------------------------------------------------------------
To unsubscribe, e-mail: httpclient-users-unsubscribe@hc.apache.org
For additional commands, e-mail: httpclient-users-help@hc.apache.org


Re: Implementing a simple non-blocking echo server

Posted by Daniel Feist <df...@gmail.com>.
For reference, this is what I'm trying to achieve with httpcore,
implemented (and working) with the jetty and servlet api.

http://pastebin.com/1Ennis2m

Dan

On Tue, Sep 16, 2014 at 12:59 AM, Daniel Feist <df...@gmail.com> wrote:

> Hi,
>
> I'm struggling to implement a simple echo server using http components
> aysnc api (HttpAsyncRequestHandler, HttpAsyncResponseProducer,
> HttpAsyncRequestConsumer) without using: "response.setEntity(new
> InputStreamEntity(requestEntity.getContent(),..,..)".
>
> This is my attempt:
>
> http://pastebin.com/Tbz0rxDH
>
> It seems to work for small http bodies, but as soon as the body size is
> larger than the buffer it hangs.
>
> Anything obvious i'm doing wrong?
>
> thanks,
> Dan
>
>
>