HTTP 2 client API

Michael McMahon michael.x.mcmahon at oracle.com
Sun Aug 2 08:22:21 UTC 2015


Actually, thinking about this again. There is an obviously better way of
notifying request completion, by just de-coupling the send and the receive
explicitly, while still keeping a way to do both together.
1. 2. and 3. below would be replaced with the following:

(HttpRequest)

void send() -> blocks until send completed
CF<Void> sendAsync() -> starts send. CF completes when send is completed

HttpResponse response() -> blocks for response
CF<HttpResponse> responseAsync() -> CF completes when response received

To maintain the fluent program style, response() would call send() if 
not already
called, and responseAsync() will call sendAsync() if not already called.
sendAsync() and responseAsync() if called repeatedly, just return the 
same CF instance
as when called the first time. This maintains equivalence between the 
blocking
and asynchronous variants of each operation.

Cancellation would then be reasonable in the async case, where the 
CF<HttpResponse>
completes before the CF of the request, indicating a likely error. It's 
probably a minority
use-case, but I think it's good for the API not to preclude it.

- Michael.

On 01/08/15 10:23, Michael McMahon wrote:
> Here is what I propose on some of the issues you raised yesterday:
>
> 1. make it clear that HttpRequest.send() blocks until entire request 
> is sent
>     and the response headers received.
>
> 2. Add a new method to HttpRequest
>     /**
>      * Notifies when this request has been completely sent. If the 
> request is
>      * sent asynchronously then its response may be received before a
>      * potentially large request body has been fully sent. If the request
>      * was already sent when this method is called, then the returned
>      * {@code CompletableFuture} will be already completed. If an error
>      * occurs when sending the request, the returned CompletableFuture
>      * completes exceptionally.
>      *
>      * @return a {@code CompletableFuture<Void>}
>      */
>     public abstract CompletableFuture<Void> sentAsync();
>
>     So, to create the exact same behavior as HttpRequest.send() you would
>     have to wait on both the CFs returned from HttpRequest.sendAsync() 
> and
>     HttpRequest.sentAsync().
>
> 3. Having done that makes me wonder if send() and sendAsync() should be
>     renamed response() and responseAsync(). It seems to be more 
> consistent
>     with the rest of the API. And sendAsync() sounds too similar to 
> sentAsync()
>
> 4. Add a new method to HttpRequest
>     /**
>      * Cancels this request and its response. Any pending asynchronous
>      * operations associated with the request or its response will 
> complete
>      * exceptionally.
>      */
>     public abstract void cancel();
>
>
> 5. Rename HttpResponse.responseCode() to statusCode()
>
> I'm not proposing to add any direct timeout control, since CF already 
> provides
> timed waits and with the addition of cancel() above, I don't see a 
> need for further
> methods.
>
> - Michael
>
> On 31/07/15 18:22, Simone Bordet wrote:
>> Hi,
>>
>> On Fri, Jul 31, 2015 at 6:33 PM, Michael McMahon
>> <michael.x.mcmahon at oracle.com> wrote:
>>> Well, it needs co-operation between the producer and the consumer
>>> obviously. But, the onResponseBodyChunk() method could write to a queue
>>> and block if it reaches a certain size. The onRequestBodyChunk() would
>>> read off the data and send it on. When the queue reaches a lower 
>>> limit it
>>> notifies the producer to continue. It's not asynchronous, but is 
>>> possible
>>> and I'm not sure we're aiming at this type of application.
>> Sure, it's possible to implement it in a blocking way with the 
>> current APIs.
>> But the whole world is moving to asynchronous APIs, so... :)
>>
>>> Having said that, this is an area we planned to look at again, after 
>>> the
>>> initial putback.
>> Great! Please notify this list when you have a further revision to 
>> review.
>>
>>> Strangely, Future.cancel() doesn't specify any such restriction, but
>>> CompletableFuture.cancel() does. In theory, one could sub-class
>>> CompletableFuture and implement cancellation behavior that way,
>>> but the intent does seem to be that cancellation should come from 
>>> outside
>>> and just be reported through this class. And considering the point 
>>> above
>>> about stopping runaway request sends then maybe an explicit
>>> cancellation API would be useful.
>> Right. Just remember that in my experience, supporting abort() would
>> complicate the implementation a lot, but I guess it's just an
>> implementation detail.
>>
>>>> IMHO the API is confusing, I prefer just doing builder.header("Foo",
>>>> "foovalue").header("Bar", "barvalue").
>>>
>>> the parameters have to be specified in pairs
>>> with (header name first, then value) * n
>> Right, but you cannot enforce that, so the API is brittle, hence my 
>> dislike :)
>>
>> Thanks !
>>
>



More information about the net-dev mailing list