You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@mina.apache.org by Julien Vermillard <jv...@archean.fr> on 2008/02/14 12:20:54 UTC

[Asyncweb] server API for commiting HTTPReponse in chunk

Hi,

I would like to have your comments about the Asyncweb server API

Actually you create your HttpResponse like that : 

MutableHttpResponse response = new DefaultHttpResponse();
response.setContent(myIoBuffer);
response.setHeader("Content-Type", "text/html");
response.setStatus(HttpResponseStatus.OK);

context.commitResponse(response);

I like this API, it's very simple to use. I would like to keep it
because it's *very* easy for anybody to make a simple HttpService for
serving few data, like RPC call or anything you want.

As Dave commented here http://jira.safehaus.org/browse/ASYNCWEB-21 it's
totally inefficient for serving large data and streaming is impossible.

I would like to propose a variation of Dave API idea : 

We keep "response.setContent(myIoBuffer);" because it will fit 70% of
the use cases :)

We add to MutableHttpResponse a Queue of IoBuffer you can fill like you
want for example : 

MutableHttpResponse response = new DefaultHttpResponse();
response.setStatus(HttpResponseStatus.OK);
response.addContent(buffer1);
response.addContent(buffer2);
response.addContent(buffer3);
response.commitResponse(response);

So you can add content in chunks in place of 1 big buffer, that won't
resolve the streaming problem, but it's convenient.

Now streaming : 

MutableHttpResponse response = new DefaultHttpResponse();

response.setStatus(HttpResponseStatus.OK);

// add a first chunk (optional)
response.addContent(buffer1);

PartialResponseListener listener = new PartialResponseListener() {
	public void queueEmpty(HTTPResponse response) {
		if(moreDataToSend) {
	                ...
        	        // add more data
			response.addContent(buffer);
		} else {
	                // streaming is done finish the response
        	       response.done();
		}
	}
};
response.commitPartialResponse(response, listener);

What I would like to discuss here is to find a good looking API doing
everything you can imagine about streaming (audio,commet,big
files,etc..) before looking at impementation

and of course with good names fitting picky Koreans :)

Julien

Re: [Asyncweb] server API for commiting HTTPReponse in chunk

Posted by Mike Heath <mh...@apache.org>.
이희승 (Trustin Lee) wrote:
> No, you are not late. :)
> 
> 2008-03-04 (화), 13:27 -0700, Mike Heath 쓰시길:
>> First off, sorry for the LATE response tot his thread.  My comments are
>> below inline.
>>
>> 이희승 (Trustin Lee) wrote:
>>> Adding commit(Partial)?Response method causes HttpResponse to keep a
>>> response to IoSession, which doesn't sound good to me.  What do you
>>> think about providing another setContent method with Queue<IoBuffer>?
>>>
>>> We could provide a special implementation of Queue that allows a user to
>>> stream a list of IoBuffers on demand.  The encoder will try to access
>>> the queue by calling poll() to get the newest chunk.
>>>
>>> Actually this proposal causes some changes in ProtocolCodecDecoder and
>>> MINA itself so it can understand Queue<IoBuffer>.  However, the encoder
>>> won't need to be changed at all.
>>>
>>> Another trickier part is decoding.  I prefer to have HttpRequest (or
>>> HttpResponse) to have a Queue<IoBuffer> as a content so the decoder can
>>> offer the newly received chunk there.
>>>
>>> On the other hand, Use of the Queue interface might be inadequate and we
>>> might need to introduce more specialized interface like the following:
>>>
>>> public interface IoBufferStream {
>>>     void offer(IoBuffer buf);
>>>
>>>     // Returns null on the end of the content.
>>>     // Returns an empty buffer if no chunk is ready yet.
>>>     IoBuffer poll();
>>>
>>>     // and some listener registration...
>>>     IoBufferStream addListener(IoBufferStreamListener listener);
>>>     IoBufferStream removeListener(IoBufferStreamListener listener);
>>> }
>>>
>>> By having MINA core providing a standardized interface for streaming a
>>> large list of buffer chunks will make more broad range of users happier
>>> rather than implementing such a feature in a certain protocol provider.
>>>
>>> WDYT?
>> Don't we already have the equivalent of an IoBufferStream with just
>> IoSession.write() and IoHandler.messageReceived()?  It seams like this
>> would add a lot of complication just to solve the problem of partial
>> HTTP responses from AsyncWeb server.  Also, wouldn't use a Queue require
>> the decode to block waiting for messages to send?
> 
> Just to make sure if I got your point.. what equivalent do we have in
> MINA core?
> 
>> That being said, I don't like the HttpResponse object holding the
>> IoSession either.  You also have to think about the HTTP client.  On the
>> client side it doesn't make any sense to have an addContent on an HTTP
>> response.
>>
>> I'm more inclined toward something like:
>>
>> public interface PartialResponse {
>>
>>   void write(Object message);
>>
>>   void done();
>>
>>   addListener(PartialWriteListener listener);
>>
>>   removeListener(PartialWriteListener listener);
>>
>> }
>>
>> public interface PartialWriteListener {
>>
>>   void onWriteCompletion(PartialResponse partialResponse, Object
>> writtenMessage);
>>
>> }
>>
>> You would then do something like:
>>
>> PartialResponse partial = response.commitPartialResponse(httpResponse);
>> partial.write(startofData);
>> partial.addListener(new PartialWriteListener() {
>>   void onWriteCompletiion(PartialResponse partialResponse, Object
>> writtenMessage) {
>>     if (noMoreData) {
>>       partialResponse.done();
>>     } else {
>>       partialResponse.write(moreData);
>>     }
>>   }
>> });
>>
>> Thoughts?
>>
>> Of course, we still have to incorporate exception handling if an
>> exception is thrown from the listener as Tuure pointed out and this
>> doesn't address the notion of setting a chunk size as David pointed out.
> 
> I think we are on the same page actually.  If you look into the
> IoBufferStream, it's identical to PartialResponse:
> 
> * IoBufferStream.offer() = PartialResponse.write()
> * IoBufferStream.poll() = PartialResponse.done() and some internal
> method?
> * and listener methods.
> 
> What differences do you think of?  

In my example, calling PartialResponse.done() indicates that I'm done
sending a request.  This is telling AsyncWeb that it can now close the
IoSession or listen for another request.  In the case of chunked
encoding, it's also telling AsyncWeb to send the 'last-chunk' token.  If
chunked encoding is not being used, it tells AsyncWeb that it should
make sure I sent as much data as I said I would in 'Content-Length'.

IoBufferStream.poll() doesn't imply that to me but if that's what you
meant maybe we are talking about the same thing. :)

> However, my initial idea of integrating this interface tightly into the
> core is not good as you pointed out.  I'd rather want to provide this
> feature as a part of out-of-the-box filters.

I think a generic filter for doing this would be the best approach to
take and it would provide a valuable reusable component.

-Mike

Re: [Asyncweb] server API for commiting HTTPReponse in chunk

Posted by "이희승 (Trustin Lee)" <tr...@gmail.com>.
No, you are not late. :)

2008-03-04 (화), 13:27 -0700, Mike Heath 쓰시길:
> First off, sorry for the LATE response tot his thread.  My comments are
> below inline.
> 
> 이희승 (Trustin Lee) wrote:
> > Adding commit(Partial)?Response method causes HttpResponse to keep a
> > response to IoSession, which doesn't sound good to me.  What do you
> > think about providing another setContent method with Queue<IoBuffer>?
> >
> > We could provide a special implementation of Queue that allows a user to
> > stream a list of IoBuffers on demand.  The encoder will try to access
> > the queue by calling poll() to get the newest chunk.
> > 
> > Actually this proposal causes some changes in ProtocolCodecDecoder and
> > MINA itself so it can understand Queue<IoBuffer>.  However, the encoder
> > won't need to be changed at all.
> > 
> > Another trickier part is decoding.  I prefer to have HttpRequest (or
> > HttpResponse) to have a Queue<IoBuffer> as a content so the decoder can
> > offer the newly received chunk there.
> > 
> > On the other hand, Use of the Queue interface might be inadequate and we
> > might need to introduce more specialized interface like the following:
> > 
> > public interface IoBufferStream {
> >     void offer(IoBuffer buf);
> > 
> >     // Returns null on the end of the content.
> >     // Returns an empty buffer if no chunk is ready yet.
> >     IoBuffer poll();
> > 
> >     // and some listener registration...
> >     IoBufferStream addListener(IoBufferStreamListener listener);
> >     IoBufferStream removeListener(IoBufferStreamListener listener);
> > }
> > 
> > By having MINA core providing a standardized interface for streaming a
> > large list of buffer chunks will make more broad range of users happier
> > rather than implementing such a feature in a certain protocol provider.
> > 
> > WDYT?
> 
> Don't we already have the equivalent of an IoBufferStream with just
> IoSession.write() and IoHandler.messageReceived()?  It seams like this
> would add a lot of complication just to solve the problem of partial
> HTTP responses from AsyncWeb server.  Also, wouldn't use a Queue require
> the decode to block waiting for messages to send?

Just to make sure if I got your point.. what equivalent do we have in
MINA core?

> That being said, I don't like the HttpResponse object holding the
> IoSession either.  You also have to think about the HTTP client.  On the
> client side it doesn't make any sense to have an addContent on an HTTP
> response.
> 
> I'm more inclined toward something like:
> 
> public interface PartialResponse {
> 
>   void write(Object message);
> 
>   void done();
> 
>   addListener(PartialWriteListener listener);
> 
>   removeListener(PartialWriteListener listener);
> 
> }
> 
> public interface PartialWriteListener {
> 
>   void onWriteCompletion(PartialResponse partialResponse, Object
> writtenMessage);
> 
> }
> 
> You would then do something like:
> 
> PartialResponse partial = response.commitPartialResponse(httpResponse);
> partial.write(startofData);
> partial.addListener(new PartialWriteListener() {
>   void onWriteCompletiion(PartialResponse partialResponse, Object
> writtenMessage) {
>     if (noMoreData) {
>       partialResponse.done();
>     } else {
>       partialResponse.write(moreData);
>     }
>   }
> });
> 
> Thoughts?
> 
> Of course, we still have to incorporate exception handling if an
> exception is thrown from the listener as Tuure pointed out and this
> doesn't address the notion of setting a chunk size as David pointed out.

I think we are on the same page actually.  If you look into the
IoBufferStream, it's identical to PartialResponse:

* IoBufferStream.offer() = PartialResponse.write()
* IoBufferStream.poll() = PartialResponse.done() and some internal
method?
* and listener methods.

What differences do you think of?  

However, my initial idea of integrating this interface tightly into the
core is not good as you pointed out.  I'd rather want to provide this
feature as a part of out-of-the-box filters.

Cheers,
-- 
Trustin Lee - Principal Software Engineer, JBoss, Red Hat
--
what we call human nature is actually human habit
--
http://gleamynode.net/

Re: [Asyncweb] server API for commiting HTTPReponse in chunk

Posted by Mike Heath <mh...@apache.org>.
First off, sorry for the LATE response tot his thread.  My comments are
below inline.

이희승 (Trustin Lee) wrote:
> Adding commit(Partial)?Response method causes HttpResponse to keep a
> response to IoSession, which doesn't sound good to me.  What do you
> think about providing another setContent method with Queue<IoBuffer>?
>
> We could provide a special implementation of Queue that allows a user to
> stream a list of IoBuffers on demand.  The encoder will try to access
> the queue by calling poll() to get the newest chunk.
> 
> Actually this proposal causes some changes in ProtocolCodecDecoder and
> MINA itself so it can understand Queue<IoBuffer>.  However, the encoder
> won't need to be changed at all.
> 
> Another trickier part is decoding.  I prefer to have HttpRequest (or
> HttpResponse) to have a Queue<IoBuffer> as a content so the decoder can
> offer the newly received chunk there.
> 
> On the other hand, Use of the Queue interface might be inadequate and we
> might need to introduce more specialized interface like the following:
> 
> public interface IoBufferStream {
>     void offer(IoBuffer buf);
> 
>     // Returns null on the end of the content.
>     // Returns an empty buffer if no chunk is ready yet.
>     IoBuffer poll();
> 
>     // and some listener registration...
>     IoBufferStream addListener(IoBufferStreamListener listener);
>     IoBufferStream removeListener(IoBufferStreamListener listener);
> }
> 
> By having MINA core providing a standardized interface for streaming a
> large list of buffer chunks will make more broad range of users happier
> rather than implementing such a feature in a certain protocol provider.
> 
> WDYT?

Don't we already have the equivalent of an IoBufferStream with just
IoSession.write() and IoHandler.messageReceived()?  It seams like this
would add a lot of complication just to solve the problem of partial
HTTP responses from AsyncWeb server.  Also, wouldn't use a Queue require
the decode to block waiting for messages to send?

That being said, I don't like the HttpResponse object holding the
IoSession either.  You also have to think about the HTTP client.  On the
client side it doesn't make any sense to have an addContent on an HTTP
response.

I'm more inclined toward something like:

public interface PartialResponse {

  void write(Object message);

  void done();

  addListener(PartialWriteListener listener);

  removeListener(PartialWriteListener listener);

}

public interface PartialWriteListener {

  void onWriteCompletion(PartialResponse partialResponse, Object
writtenMessage);

}

You would then do something like:

PartialResponse partial = response.commitPartialResponse(httpResponse);
partial.write(startofData);
partial.addListener(new PartialWriteListener() {
  void onWriteCompletiion(PartialResponse partialResponse, Object
writtenMessage) {
    if (noMoreData) {
      partialResponse.done();
    } else {
      partialResponse.write(moreData);
    }
  }
});

Thoughts?

Of course, we still have to incorporate exception handling if an
exception is thrown from the listener as Tuure pointed out and this
doesn't address the notion of setting a chunk size as David pointed out.

-Mike

> 
> 2008-02-14 (목), 12:20 +0100, Julien Vermillard 쓰시길:
>> Hi,
>>
>> I would like to have your comments about the Asyncweb server API
>>
>> Actually you create your HttpResponse like that : 
>>
>> MutableHttpResponse response = new DefaultHttpResponse();
>> response.setContent(myIoBuffer);
>> response.setHeader("Content-Type", "text/html");
>> response.setStatus(HttpResponseStatus.OK);
>>
>> context.commitResponse(response);
>>
>> I like this API, it's very simple to use. I would like to keep it
>> because it's *very* easy for anybody to make a simple HttpService for
>> serving few data, like RPC call or anything you want.
>>
>> As Dave commented here http://jira.safehaus.org/browse/ASYNCWEB-21 it's
>> totally inefficient for serving large data and streaming is impossible.
>>
>> I would like to propose a variation of Dave API idea : 
>>
>> We keep "response.setContent(myIoBuffer);" because it will fit 70% of
>> the use cases :)
>>
>> We add to MutableHttpResponse a Queue of IoBuffer you can fill like you
>> want for example : 
>>
>> MutableHttpResponse response = new DefaultHttpResponse();
>> response.setStatus(HttpResponseStatus.OK);
>> response.addContent(buffer1);
>> response.addContent(buffer2);
>> response.addContent(buffer3);
>> response.commitResponse(response);
>>
>> So you can add content in chunks in place of 1 big buffer, that won't
>> resolve the streaming problem, but it's convenient.
>>
>> Now streaming : 
>>
>> MutableHttpResponse response = new DefaultHttpResponse();
>>
>> response.setStatus(HttpResponseStatus.OK);
>>
>> // add a first chunk (optional)
>> response.addContent(buffer1);
>>
>> PartialResponseListener listener = new PartialResponseListener() {
>> 	public void queueEmpty(HTTPResponse response) {
>> 		if(moreDataToSend) {
>> 	                ...
>>         	        // add more data
>> 			response.addContent(buffer);
>> 		} else {
>> 	                // streaming is done finish the response
>>         	       response.done();
>> 		}
>> 	}
>> };
>> response.commitPartialResponse(response, listener);
>>
>> What I would like to discuss here is to find a good looking API doing
>> everything you can imagine about streaming (audio,commet,big
>> files,etc..) before looking at impementation
>>
>> and of course with good names fitting picky Koreans :)
>>
>> Julien


Re: [Asyncweb] server API for commiting HTTPReponse in chunk

Posted by "이희승 (Trustin Lee)" <tr...@gmail.com>.
Adding commit(Partial)?Response method causes HttpResponse to keep a
response to IoSession, which doesn't sound good to me.  What do you
think about providing another setContent method with Queue<IoBuffer>?

We could provide a special implementation of Queue that allows a user to
stream a list of IoBuffers on demand.  The encoder will try to access
the queue by calling poll() to get the newest chunk.

Actually this proposal causes some changes in ProtocolCodecDecoder and
MINA itself so it can understand Queue<IoBuffer>.  However, the encoder
won't need to be changed at all.

Another trickier part is decoding.  I prefer to have HttpRequest (or
HttpResponse) to have a Queue<IoBuffer> as a content so the decoder can
offer the newly received chunk there.

On the other hand, Use of the Queue interface might be inadequate and we
might need to introduce more specialized interface like the following:

public interface IoBufferStream {
    void offer(IoBuffer buf);

    // Returns null on the end of the content.
    // Returns an empty buffer if no chunk is ready yet.
    IoBuffer poll();

    // and some listener registration...
    IoBufferStream addListener(IoBufferStreamListener listener);
    IoBufferStream removeListener(IoBufferStreamListener listener);
}

By having MINA core providing a standardized interface for streaming a
large list of buffer chunks will make more broad range of users happier
rather than implementing such a feature in a certain protocol provider.

WDYT?

2008-02-14 (목), 12:20 +0100, Julien Vermillard 쓰시길:
> Hi,
> 
> I would like to have your comments about the Asyncweb server API
> 
> Actually you create your HttpResponse like that : 
> 
> MutableHttpResponse response = new DefaultHttpResponse();
> response.setContent(myIoBuffer);
> response.setHeader("Content-Type", "text/html");
> response.setStatus(HttpResponseStatus.OK);
> 
> context.commitResponse(response);
> 
> I like this API, it's very simple to use. I would like to keep it
> because it's *very* easy for anybody to make a simple HttpService for
> serving few data, like RPC call or anything you want.
> 
> As Dave commented here http://jira.safehaus.org/browse/ASYNCWEB-21 it's
> totally inefficient for serving large data and streaming is impossible.
> 
> I would like to propose a variation of Dave API idea : 
> 
> We keep "response.setContent(myIoBuffer);" because it will fit 70% of
> the use cases :)
> 
> We add to MutableHttpResponse a Queue of IoBuffer you can fill like you
> want for example : 
> 
> MutableHttpResponse response = new DefaultHttpResponse();
> response.setStatus(HttpResponseStatus.OK);
> response.addContent(buffer1);
> response.addContent(buffer2);
> response.addContent(buffer3);
> response.commitResponse(response);
> 
> So you can add content in chunks in place of 1 big buffer, that won't
> resolve the streaming problem, but it's convenient.
> 
> Now streaming : 
> 
> MutableHttpResponse response = new DefaultHttpResponse();
> 
> response.setStatus(HttpResponseStatus.OK);
> 
> // add a first chunk (optional)
> response.addContent(buffer1);
> 
> PartialResponseListener listener = new PartialResponseListener() {
> 	public void queueEmpty(HTTPResponse response) {
> 		if(moreDataToSend) {
> 	                ...
>         	        // add more data
> 			response.addContent(buffer);
> 		} else {
> 	                // streaming is done finish the response
>         	       response.done();
> 		}
> 	}
> };
> response.commitPartialResponse(response, listener);
> 
> What I would like to discuss here is to find a good looking API doing
> everything you can imagine about streaming (audio,commet,big
> files,etc..) before looking at impementation
> 
> and of course with good names fitting picky Koreans :)
> 
> Julien
-- 
Trustin Lee - Principal Software Engineer, JBoss, Red Hat
--
what we call human nature is actually human habit
--
http://gleamynode.net/

Re: [Asyncweb] server API for commiting HTTPReponse in chunk

Posted by Tuure Laurinolli <tu...@indagon.com>.
Julien Vermillard wrote:
<snip non-streaming parts>

> Now streaming : 
> 
> MutableHttpResponse response = new DefaultHttpResponse();
> 
> response.setStatus(HttpResponseStatus.OK);
> 
> // add a first chunk (optional)
> response.addContent(buffer1);
> 
> PartialResponseListener listener = new PartialResponseListener() {
> 	public void queueEmpty(HTTPResponse response) {
> 		if(moreDataToSend) {
> 	                ...
>         	        // add more data
> 			response.addContent(buffer);
> 		} else {
> 	                // streaming is done finish the response
>         	       response.done();
> 		}
> 	}
> };
> response.commitPartialResponse(response, listener);

Who will handle errors when sending a part of the response fails? The 
current commitResponse()-API doesn't seem to expose errors very well either.

Also, what should queueEmpty() do if there is currently no more content 
to be added to the queue, but more content will still be produced at a 
later time? I guess this can be handled with a NullListener that does 
nothing when the queue is emptied, and just adding content to the 
response from the producer whenever new content becomes available.

> What I would like to discuss here is to find a good looking API doing
> everything you can imagine about streaming (audio,commet,big
> files,etc..) before looking at impementation

I hope the questions above help other's thinking :)

Re: [Asyncweb] server API for commiting HTTPReponse in chunk

Posted by "David M. Lloyd" <da...@redhat.com>.
Julien Vermillard wrote:
> Hi,
> 
> I would like to have your comments about the Asyncweb server API
[...]
> So you can add content in chunks in place of 1 big buffer, that won't
> resolve the streaming problem, but it's convenient.
> 
> Now streaming : 
[...]
 > PartialResponseListener listener = new PartialResponseListener() {
[...]

Looks good to me.  I might suggest that in addition, there should be 
some method that would allow you to signify the content-length ahead of 
time, or to indicate that chunked encoding will be used.  And there 
should be a level of checking to make sure that you don't overflow the 
content length, if it was given.

But I like this idea.

- DML