HTTP client API

Chris Hegarty chris.hegarty at oracle.com
Mon Nov 21 14:23:43 UTC 2016


Tobias,

If you look at the code in the sandbox [*], the notion of a default
client has been removed. Having global static default instances is
problematic. Http Clients are lightweight, easy to configure and
pass around, if that is what you want.

-Chris.

[*] hg clone http://hg.openjdk.java.net/jdk9/sandbox; cd sandbox
     bash common/bin/hgforest.sh update http-client-branch


On 21/11/16 11:28, Tobias Thierer wrote:
> Replying to my own first email in this thread to add another question /
> concern about flexibility of the HTTP Client API:
>
> Have you considered offering applications a way to globally replace the
> HTTP Client implementation with their own (e.g. via a method
> HttpClient.setDefault() to go with the existing method
> HttpClient.getDefault())?
> This feature seems to currently be missing from the API while even the
> old HttpURLConnection API supported this (via
> URL.setURLStreamHandlerFactory()
> <https://docs.oracle.com/javase/8/docs/api/java/net/URL.html#setURLStreamHandlerFactory-java.net.URLStreamHandlerFactory->).
>
> I'm aware that such global (process-wide) configuration options have
> disadvantages as well, but it would be consistent with other swappable
> Java APIs/SPIs such as SSLSocketFactory, XML parsers, CookieHandler,
> etc.  The advantage would be that applications / application frameworks
> could swap out the HttpClient implementation used by lower level
> libraries / applications that they're bundling in binary form - e.g. to
> globally provide a fake implementation to use during testing, instrument
> HTTP Client usage (e.g. log all URLs accessed or count the number of
> bytes transferred), to adhere to requirements in some corporate
> networks, or to otherwise decouple the version/implementation of the
> HTTP Client from the platform / OpenJDK version. What's your view?
>
> Tobias
>
>
> On Mon, Oct 24, 2016 at 8:33 PM, Tobias Thierer <tobiast at google.com
> <mailto:tobiast at google.com>> wrote:
>
>     Hi Michael and others -
>
>
>     Thanks for publishing the latest HTTP client API docs
>     <http://cr.openjdk.java.net/~michaelm/httpclient/api/>(already
>     slightly outdated again), as well as for publishing the current
>     draft code in the sandbox repository!
>
>
>     Below is some concrete feedback, questions and brainstorming on how to
>
>     (a) increase the usefulness or
>
>     (b) decrease the semantic weight
>
>     of the API. Note that most of this is driven only by inspection of
>     the API and some brief exploration of the implementation code, not
>     (yet) by a substantial effort to write proof of concept client
>     applications. I’d love if I could help make this API as useful to
>     applications as possible, so I’d appreciate your feedback on how I
>     can best do that and what the principles were that guided your
>     design choices.
>
>
>     1.) The HttpRequest.BodyProcessor
>     <http://cr.openjdk.java.net/~michaelm/httpclient/api/java/net/http/HttpRequest.BodyProcessor.html>and
>     HttpResponse.BodyProcessor
>     <http://cr.openjdk.java.net/~michaelm/httpclient/api/java/net/http/HttpResponse.BodyProcessor.html>abstractions
>     seem particularly hard to grasp / have a high semantics weight.
>
>       *
>
>         What purpose does the abstraction of a BodyProcessoraim to
>         fulfill beyond what the (simpler) abstraction of a Bodycould be?
>
>           o
>
>             Instead of describing the abstraction as a “processor” of
>             ByteBuffers / Java objects, wouldn’t it be simpler to say to
>             say that request / response bodiesare ByteBuffer / Java
>             object sources/ sinks? What is the advantage of the
>             Publisher<ByteBuffer> / Subscriber<ByteBuffer> API over
>             plain old InputStream / OutputStream based APIs?
>
>           o
>
>             The term “processor” and the description of “converting
>             incoming buffers of data to some user-defined object type T”
>             is especially confusing (increases the semantic weight of
>             the abstraction) given that there is an implementation that
>             discards all data
>             <http://cr.openjdk.java.net/~michaelm/httpclient/api/java/net/http/HttpResponse.BodyProcessor.html#discard-U->(and
>             its generic type is called Urather than T). A BodyProcessor
>             that has no input but generates the digits of Pi is also
>             conceivable. Perhaps call these BodySource / BodySink,
>             ByteBufferPublisher / ByteBufferSubscriber, or just Body?
>
>           o
>
>             The fact that you felt the need to introduce an abstraction
>             HttpResponse.BodyHandler whose name is similar to but whose
>             semantics are different from HttpResponse.BodyProcessor is
>             another indication that these concepts could be clarified
>             and named better.
>
>           o
>
>             To explore how well the abstractions “fit”, I played with
>             some draft code implementing the API on top of another one;
>             one thing I found particularly challenging was the control
>             flow progression:
>             HttpClient.send(request, bodyHandler)
>             -> bodyProcessor = bodyHandler.apply(); // called by the library
>             -> bodyProcessor.onSubscribe() / onNext()
>             because it is push based and forces an application to
>             relinquish control to the library rather than pulling data
>             out of the library.
>             Perhaps the Response BodyHandler abstraction could be
>             eliminated altogether? For example, wouldn’t it be
>             sufficient to abort downloading the body once an application
>             thread has a chance to look at the Response object? Perhaps
>             once a buffer is full, the download of the further response
>             body could be delayed until a client asks for it?
>
>           o
>
>             What’s the purpose of HttpRequest.bodyProcessor()’s return
>             type being an Optional<BodyProcessor> (rather than
>             BodyProcessor)? Why can’t this default to an empty body?
>
>           o
>
>             Naming inconsistency: HttpRequest.BodyProcessor.fromFile()
>             vs. HttpResponse.BodyProcessor.asFile(). How about calling
>             all of these of(), or alternatively renaming asFile() ->
>             toFile() or toPath()?
>
>           o
>
>             asByteArrayConsumer(Consumer<Optional<byte[]>> consumer):
>             Why is this an Optional? What logic decides whether an empty
>             response body will be represented as a present byte[0] or an
>             absent value?
>
>
>     2.) HttpHeaders: I love that there is a type for this abstraction! But:
>
>       *
>
>         Why is the type an interface rather than a concrete, final
>         class? Since this is a pure value type, there doesn’t seem to be
>         much point in allowing alternative implementations?
>
>       *
>
>         The documentation should probably specify what the methods do
>         when nameis not valid (according to RFC 7230 section 3.2?), or
>         is null.
>
>       *
>
>         Do the methods other than map() really pull their weight
>         (provide enough value relative to the semantic API weight that
>         they introduce)?
>
>           o
>
>             firstValueAsLong() looks particularly suspect: why would
>             anyone care particularly about long values? Especiallysince
>             the current implementation seems to throw
>             NumberFormatException rather than returning an empty Optional?
>
>
>     3.) Redirect
>
>       *
>
>         Stupid question: Should Redirect.SAME_PROTOCOL be called
>         SAME_SCHEME (“scheme” is what the “http” part is called in a
>         URL)? I’m not sure which one is better.
>
>       *
>
>         I haven’t made up my mind about whether the existing choices are
>         the right ones / sufficient. Perhaps if this class used the
>         typesafe enum pattern from Effective Java 1st edition rather
>         than being an actual enum, the API would maintain the option in
>         a future version to allow client-configured Redirect policies,
>         allowing Redirect for URLs as long as they are within the same
>         host/domain?
>
>
>     4.) HttpClient.Version:
>
>       *
>
>         Why does a HttpClient need to commit to using one HTTP version
>         or the other? What if an application wants to use HTTP/2 for
>         those servers that support it, but fall back to HTTP/1.1 for
>         those that don’t?
>
>
>     5.) CookieManager
>
>       *
>
>         Is there a common interface we could add without making the API
>         much more complex to allow us both RFC 2965 (outdated,
>         implemented by CookieManager) and RFC 6265 (new, real world,
>         actually used) cookies? Needs prototyping. I think it’s likely
>         we’ll be able to do something similar to OkHttp’s CookieJar
>         <https://square.github.io/okhttp/3.x/okhttp/okhttp3/CookieJar.html>which
>         can be adapted to RFC 2965 - not 100%, but close enough that
>         most implementations of CookieManager could be reused by the new
>         HTTP API, while still taking advantage of RFC 6265 cookies.
>
>
>     6.) HttpClient.Executor
>
>       * The documentation isn’t very clear about what tasks run on this
>         executor and how a client can control HTTP traffic through a
>         custom Executor instance. What power does the current executor()
>         API provide to clients? Perhaps it would be simpler to omit this
>         API altogether until the correct API becomes clearer?
>
>
>     Thanks!
>
>     Tobias
>
>


More information about the net-dev mailing list