blob: bc3b6508d3c69a2fc78475ac58bcb804d2935ff5 [file] [log] [blame]
/*
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
*/
package java.net.http;
import java.io.IOException;
import java.util.concurrent.CompletableFuture;
import static java.net.http.HttpClient.Version.HTTP_1_1;
/**
* Splits request so that headers and body can be sent separately with optional
* (multiple) responses in between (e.g. 100 Continue). Also request and
* response always sent/received in different calls.
*
* Synchronous and asynchronous versions of each method are provided.
*
* Separate implementations of this class exist for HTTP/1.1 and HTTP/2
* Http1Exchange (HTTP/1.1)
* Stream (HTTP/2)
*
* These implementation classes are where work is allocated to threads.
*/
abstract class ExchangeImpl {
final Exchange exchange;
ExchangeImpl(Exchange e) {
this.exchange = e;
}
/**
* Initiates a new exchange and assigns it to a connection if one exists
* already. connection usually null.
*/
static ExchangeImpl get(Exchange exchange, HttpConnection connection)
throws IOException, InterruptedException
{
HttpRequestImpl req = exchange.request();
if (req.version() == HTTP_1_1) {
return new Http1Exchange(exchange, connection);
} else {
Http2ClientImpl c2 = exchange.request().client().client2(); // TODO: improve
HttpRequestImpl request = exchange.request();
Http2Connection c = c2.getConnectionFor(request);
if (c == null) {
// no existing connection. Send request with HTTP 1 and then
// upgrade if successful
ExchangeImpl ex = new Http1Exchange(exchange, connection);
exchange.h2Upgrade();
return ex;
}
return c.createStream(exchange);
}
}
/* The following methods have separate HTTP/1.1 and HTTP/2 implementations */
/**
* Sends the request headers only. May block until all sent.
*/
abstract void sendHeadersOnly() throws IOException, InterruptedException;
/**
* Gets response headers by blocking if necessary. This may be an
* intermediate response (like 101) or a final response 200 etc.
*/
abstract HttpResponseImpl getResponse() throws IOException;
/**
* Sends a request body after request headers.
*/
abstract void sendBody() throws IOException, InterruptedException;
/**
* Sends the entire request (headers and body) blocking.
*/
abstract void sendRequest() throws IOException, InterruptedException;
/**
* Asynchronous version of sendHeaders().
*/
abstract CompletableFuture<Void> sendHeadersAsync();
/**
* Asynchronous version of getResponse(). Requires void parameter for
* CompletableFuture chaining.
*/
abstract CompletableFuture<HttpResponseImpl> getResponseAsync(Void v);
/**
* Asynchronous version of sendBody().
*/
abstract CompletableFuture<Void> sendBodyAsync();
/**
* Cancels a request. Not currently exposed through API.
*/
abstract void cancel();
/**
* Asynchronous version of sendRequest().
*/
abstract CompletableFuture<Void> sendRequestAsync();
abstract <T> T responseBody(HttpResponse.BodyProcessor<T> processor)
throws IOException;
/**
* Asynchronous version of responseBody().
*/
abstract <T> CompletableFuture<T>
responseBodyAsync(HttpResponse.BodyProcessor<T> processor);
}