Http client API
Michael McMahon
michael.x.mcmahon at oracle.com
Wed Aug 15 09:06:55 PDT 2012
Mike. Thanks for the comments. I have commented on most of your points.
There are a few I'm not sure about, and maybe others will chime in.
- Michael.
On 08/08/2012 23:33, Mike Duigou wrote:
> General::
> - It's probably already been mentioned but having the classes in the httpclient package and most of them begin with "Http" seems redundant.
I think I'd agree if type names were always written as fully qualified
names,
or if it were possible to import partial package names
eg. import java.net.* and then refer to httpclient.Request or
httpclient.Response
but I don't think that is possible. Maybe we don't need a sub-package
for httpclient
but it is a convenient grouping from a readability point of view.
What do other folks think?
> - Package JavaDoc is missing for both packages.
right we need to add that
> - Is the SPI package needed for just one class?
I suspect not. We probably should just bring it into the main package.
> - I am unsure if sendRequest should be a method of Client or Request.
>
That question arose before and there seems to be two differing preferences.
We probably should enumerate the arguments for and against the two.
> HttpClientProvider::
>
> - HttpClientProvider JavaDoc uses inconsistent capitalization of HTTP.
>
> - createAsynchronousHttpClient() Since there's only one create method why bother to mention that it's "Asynchronous"?
>
> - It's not clear how loadFromExternal() is different from provider().
>
> - provider enumeration, request alternate providers?
Yes, the provider needs work. I agree with the above. Though I don't
know about the
necessity to provide multiple alternate providers.
>
>
> HttpClient::
>
> - There's no way to identify the source of the HttpClient(). ie. it is returned by provider() but there's no way to tell what you got. Would be useful for debugging to log to the file what provider you received.
I'm not sure I follow the comment above. Does it just relate to
implementation rather than the API?
> - HttpClient createClient() -- is this the same as HttpClientProvider.provider().createAsynchronousHttpClient()?
yes, and that needs to be documented.
> - There doesn't seem to be a way to be truly thread safe about changes to configuration other than to set all configuration options before sharing an HttpClient instance and then never changing the configuration. Is changing the configuration *after* sharing realistic or should perhaps configuration be immutable (perhaps using a Builder pattern for HttpClient instances, ie. createClient() becomes clientBuilder()). Seeing that the set methods return HttpClient (the same instance unfortunately) it looks like you are considering or have considered using a builder style construction.
Right. I agree (as others have suggested) a builder pattern for mutable
state is a good idea. The current behavior of returning
the same client instance was more about simply a "fluent" programming style.
> - Why expose the connection cache? Seems like just a good way to mess things up. Have you considered provider scope for connection cache? ie. all clients from the same provider share a cache?
The idea behind connection cache was to allow applications more control
over opening, closing and caching of TCP
connections. But, it's possibly not 100% right yet. I figured that its
scope would be at client level. If there were a higher
level notion of an application in Java SE, then it probably would be
associated at that level imo.
In what way do you think it would be easy to mess things up?
> - setProxy lacks proxy authentication features. (sorry, I just said that to annoy you. :-) )
Yes. Authentication is one missing piece of the puzzle. We want to
implement authentication
as a Filter, but it still needs a public API. But, it will be through
that API where proxy authentication
happens also.
> - Does the proxy default to system properties and respect the nonProxyHosts? ie:
> http.proxyHost (default:<none>)
> http.proxyPort (default: 80 if http.proxyHost specified)
> http.nonProxyHosts (default:<none>)
Currently no. Since this is a new API, I'm not sure about the benefit of
re-using the
legacy properties. Perhaps there could be value in allowing system proxy
settings to
be used.
> - Is the default cookie manager from CookieHandler.getDefault() or is there no default?
Currently no default, which means no special treatment of cookie headers,
which I think is reasonable
> - Default is not specified for setAllowPipeLineMode() Presumably it is "false"
right. we need to specify default is "false"
> - There's no discussion of pipeline mode and connection cache.
ok
> - sendHeaders/sendRequest : presumably it is an error to use an HttpRequest from a different HttpClient.
that was one reason why the sendXXX methods made sense on HttpRequest,
because otherwise
the possibility for sending a request on the wrong client has to be
considered.
So, we will have to specify that if we keep it as it is.
> - setResponseBodyBufferLimit - like timeout this is a default. Perhaps setDefaultResponseBodyBufferLimit (long I know).
>
> - What happens with sendHeaders when the request already has a body?
right. should have an @exception IllegalStateException
> - Impact of closing the OutputStream returned from sendHeaders(). chunked mode vs. non-chucked.
There could be an IOException if writing or closing the stream
in-appropriately. This should
be specified more explicitly in sendHeaders()
> - getResponse : java.util.concurrent.TimeoutException has a nice name but is an odd exception to be throwing. java.net.SocketTimeoutException seems more appropriate.
possibly, though the j.u.c.TimeoutException can be thrown when using a
Future<HttpResponse>
So, the idea was to use the same exception class for all timeouts. It's
an awkward choice though.
> - I'm curious why setUpgradeHandler() takes a class rather than an instance.
maybe Danny can comment on that.
> - getHttpsConfigurator() -- since a default is established before first invocation why not never return null. ie. implement the default behaviour in getHttpsConfigurator() and have the impl call getHttpsConfigurator().
good idea. It's always good to avoid nulls where possible.
> - I missed the "s" in setHttpsConfigurator until I looked at the method in more detail. It doesn't really stand out.
maybe setSSLConfigurator() and change HttpsConfigurator to SSLConfigurator?
> - getFilters() -- this is the only modify-in-place API. Kinda weird. I think having setFilters() would be better.
Do you mean getFilters() returns a copy and setFilters() would just set
the actual list? Whatever
works best with the builder model, I suppose is what we should do.
>
>
> HttpUpgradeHandler::
>
> - perhaps in the spi package?
>
> - Method or methods to identify the UpgradeHandler. ie. getName(), getProtocols.
>
>
>
> UpgradeConnection::
>
> - Perhaps "Upgrade**d**Connection"?
>
> - There's no way to get back the UpdgradeHandler or source client.
>
>
>
> SimpleConnectionClass::
>
> - Package private?
It was supposed to be usable directly by application code. So,
I don't think it could be package private.
>
>
> HttpRequest::
>
> - copy() vs clone()?
>
> - setFollowRedirects should get a default from HttpClient (or remove defaults for timeout and buffer limits). Asymmetry is annoying.
will probably add a default for follow redirects
> - setBody(Iterable<ByteBuffer>, boolean isRestartable) -- This seems heinous. Non-restartable Iterables should be avoided. I like the suggestion of additional setBody(Iterable<ByteBuffer>) method instead.
Ok. So, a setBody(Iterator<ByteBuffer>) then ?
> - setRequestURI() -- eliminate this unless there is a really good reason to keep it. Alternately, perhaps copy(URI) instead?
right. We need to clarify why that was put in there.
> - getMethod() -- missing.
ok
>
>
> HttpHeaders::
>
> - getValues() how about return empty result when there is no header of that name?
Right. The docs are inconsistent on that point. Empty list is what it
should be
> - getValues() -- the returned list is unmodifiable, correct?
Right.
> - contains() -- IAE for null.
ok
> - getFirstValue() -- IAE for null name. It has to consistently be either IAE or NPE.
ok
> - getAllHeaderNames() -- unmodifiable list, correct?
right
>
>
> HttpResponse::
>
> - getBodyAsBytes(byte[], int) - I would rather the return the number of bytes put into the buffer.
yes. Actually the number of bytes read needs to be returned somewhere.
It should return
an int or long
> - getBodyAsBytes(byte[], int) - Why would I ever want a max size less than the size of my byte buffer?
I originally wanted to implement the no-arg getBodyAsBytes() using the
other method.
Maybe it's better to replace them both with:
long getBodyAsBytes(byte[] buffer) - buffer can't be null, use entire
buffer, return # bytes read
byte[] getBodyAsBytes() - size limited by
HttpClient.getResponseBodyBufferLimit()
> - getBodyAsBytes -- Document handling for content-length> Integer.MAX_VALUE
dealt with implicitly from above change and the response body buffer
limit itself.
> - getBodyAsByteBuffers -- handling for not enough space in the array needs to be documented. Unused entries nulled out?
situation would only arise through ByteBuffer allocation failure, and
presumably OOM exception would be thrown.
Is it necessary to document this?
> - Perhaps maxlength -> maxBytes to be more clear?
>
> - getBodyAsByteBufferSource -- if the same iterator is always returned why not return the iterator rather than an iterable?
The idea was to allow for use of the foreach convenience. eg
Iterable<ByteBuffer> buffers = response.getBodyAsByteBufferSource();
for (ByteBuffer buffer : buffers) {
// handle data in buffer
}
This raises the same concern then about the Iterable being
non-restartable, which in this case
it clearly can't be. This is a "one-shot" streaming API. I notice that
the documentation for
Iterable is rather terse and doesn't say whether
this usage is encouraged or discouraged. So, I'm not sure now. The
question is if programmers would
really be confused by the fact that the Iterable can only be used to
return one Iterator instance.
>
>
> HttpConnectionCache.CachedConnection::
> - I would expect this to be abstract and that client providers would extend.
>
> - getCache() to return the client provider.
>
>
> On Aug 7 2012, at 16:09 , Michael McMahon wrote:
>
>> Hi,
>>
>> A new revision of the Http client API planned for jdk 8 can be viewed
>> at the following link
>>
>> http://cr.openjdk.java.net/~michaelm/httpclient/v0.3/
>>
>> We would like to review the api on this mailing list.
>> So, all comments are welcome.
>>
>> Thanks
>> Michael McMahon.
More information about the net-dev
mailing list