src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/HttpRequestImpl.java
branchhttp-client-branch
changeset 55763 634d8e14c172
parent 47216 71c04702a3d5
child 55764 34d7cc00f87a
equal deleted inserted replaced
55762:e947a3a50a95 55763:634d8e14c172
    31 import java.io.IOException;
    31 import java.io.IOException;
    32 import java.net.InetSocketAddress;
    32 import java.net.InetSocketAddress;
    33 import java.net.ProxySelector;
    33 import java.net.ProxySelector;
    34 import java.net.URI;
    34 import java.net.URI;
    35 import java.security.AccessControlContext;
    35 import java.security.AccessControlContext;
       
    36 import java.security.AccessController;
       
    37 import java.security.PrivilegedAction;
    36 import java.time.Duration;
    38 import java.time.Duration;
    37 import java.util.Locale;
    39 import java.util.Locale;
    38 import java.util.Optional;
    40 import java.util.Optional;
    39 
    41 
    40 import static jdk.incubator.http.internal.common.Utils.ALLOWED_HEADERS;
    42 import static jdk.incubator.http.internal.common.Utils.ALLOWED_HEADERS;
    44     private final HttpHeaders userHeaders;
    46     private final HttpHeaders userHeaders;
    45     private final HttpHeadersImpl systemHeaders;
    47     private final HttpHeadersImpl systemHeaders;
    46     private final URI uri;
    48     private final URI uri;
    47     private InetSocketAddress authority; // only used when URI not specified
    49     private InetSocketAddress authority; // only used when URI not specified
    48     private final String method;
    50     private final String method;
    49     final BodyProcessor requestProcessor;
    51     final BodyPublisher requestPublisher;
    50     final boolean secure;
    52     final boolean secure;
    51     final boolean expectContinue;
    53     final boolean expectContinue;
    52     private boolean isWebSocket;
    54     private boolean isWebSocket;
    53     private AccessControlContext acc;
    55     private AccessControlContext acc;
    54     private final Duration duration;
    56     private final Duration timeout;  // may be null
    55     private final Optional<HttpClient.Version> version;
    57     private final Optional<HttpClient.Version> version;
    56 
    58 
    57     /**
    59     /**
    58      * Creates an HttpRequestImpl from the given builder.
    60      * Creates an HttpRequestImpl from the given builder.
    59      */
    61      */
    60     public HttpRequestImpl(HttpRequestBuilderImpl builder) {
    62     public HttpRequestImpl(HttpRequestBuilderImpl builder) {
    61         String method = builder.method();
    63         String method = builder.method();
    62         this.method = method == null? "GET" : method;
    64         this.method = method == null ? "GET" : method;
    63         this.userHeaders = ImmutableHeaders.of(builder.headers().map(), ALLOWED_HEADERS);
    65         this.userHeaders = ImmutableHeaders.of(builder.headers().map(), ALLOWED_HEADERS);
    64         this.systemHeaders = new HttpHeadersImpl();
    66         this.systemHeaders = new HttpHeadersImpl();
    65         this.uri = builder.uri();
    67         this.uri = builder.uri();
       
    68         assert uri != null;
    66         this.expectContinue = builder.expectContinue();
    69         this.expectContinue = builder.expectContinue();
    67         this.secure = uri.getScheme().toLowerCase(Locale.US).equals("https");
    70         this.secure = uri.getScheme().toLowerCase(Locale.US).equals("https");
    68         if (builder.body() == null) {
    71         this.requestPublisher = builder.bodyPublisher();  // may be null
    69             this.requestProcessor = HttpRequest.noBody();
    72         this.timeout = builder.timeout();
    70         } else {
       
    71             this.requestProcessor = builder.body();
       
    72         }
       
    73         this.duration = builder.duration();
       
    74         this.version = builder.version();
    73         this.version = builder.version();
    75     }
    74     }
    76 
    75 
    77     /**
    76     /**
    78      * Creates an HttpRequestImpl from the given request.
    77      * Creates an HttpRequestImpl from the given request.
    79      */
    78      */
    80     public HttpRequestImpl(HttpRequest request) {
    79     public HttpRequestImpl(HttpRequest request, AccessControlContext acc) {
    81         String method = request.method();
    80         String method = request.method();
    82         this.method = method == null? "GET" : method;
    81         this.method = method == null ? "GET" : method;
    83         this.userHeaders = request.headers();
    82         this.userHeaders = request.headers();
    84         if (request instanceof HttpRequestImpl) {
    83         if (request instanceof HttpRequestImpl) {
    85             this.systemHeaders = ((HttpRequestImpl) request).systemHeaders;
    84             this.systemHeaders = ((HttpRequestImpl) request).systemHeaders;
    86             this.isWebSocket = ((HttpRequestImpl) request).isWebSocket;
    85             this.isWebSocket = ((HttpRequestImpl) request).isWebSocket;
    87         } else {
    86         } else {
    88             this.systemHeaders = new HttpHeadersImpl();
    87             this.systemHeaders = new HttpHeadersImpl();
    89         }
    88         }
    90         this.uri = request.uri();
    89         this.uri = request.uri();
    91         this.expectContinue = request.expectContinue();
    90         this.expectContinue = request.expectContinue();
    92         this.secure = uri.getScheme().toLowerCase(Locale.US).equals("https");
    91         this.secure = uri.getScheme().toLowerCase(Locale.US).equals("https");
    93         if (!request.bodyProcessor().isPresent()) {
    92         this.requestPublisher = request.bodyPublisher().orElse(null);
    94             this.requestProcessor = HttpRequest.noBody();
    93         if (acc != null && requestPublisher instanceof RequestPublishers.FilePublisher) {
    95         } else {
    94             // Restricts the file publisher with the senders ACC, if any
    96             this.requestProcessor = request.bodyProcessor().get();
    95             ((RequestPublishers.FilePublisher)requestPublisher).setAccessControlContext(acc);
    97         }
    96         }
    98         this.duration = request.duration();
    97         this.timeout = request.timeout().orElse(null);
    99         this.version = request.version();
    98         this.version = request.version();
   100     }
    99     }
   101 
   100 
   102     /** Creates a HttpRequestImpl using fields of an existing request impl. */
   101     /** Creates a HttpRequestImpl using fields of an existing request impl. */
   103     public HttpRequestImpl(URI uri,
   102     public HttpRequestImpl(URI uri,
   108         this.isWebSocket = other.isWebSocket;
   107         this.isWebSocket = other.isWebSocket;
   109         this.systemHeaders = other.systemHeaders;
   108         this.systemHeaders = other.systemHeaders;
   110         this.uri = uri;
   109         this.uri = uri;
   111         this.expectContinue = other.expectContinue;
   110         this.expectContinue = other.expectContinue;
   112         this.secure = uri.getScheme().toLowerCase(Locale.US).equals("https");
   111         this.secure = uri.getScheme().toLowerCase(Locale.US).equals("https");
   113         this.requestProcessor = other.requestProcessor;
   112         this.requestPublisher = other.requestPublisher;  // may be null
   114         this.acc = other.acc;
   113         this.acc = other.acc;
   115         this.duration = other.duration;
   114         this.timeout = other.timeout;
   116         this.version = other.version();
   115         this.version = other.version();
   117     }
   116     }
   118 
   117 
   119     /* used for creating CONNECT requests  */
   118     /* used for creating CONNECT requests  */
   120     HttpRequestImpl(String method, HttpClientImpl client,
   119     HttpRequestImpl(String method, InetSocketAddress authority) {
   121                     InetSocketAddress authority) {
       
   122         // TODO: isWebSocket flag is not specified, but the assumption is that
   120         // TODO: isWebSocket flag is not specified, but the assumption is that
   123         // such a request will never be made on a connection that will be returned
   121         // such a request will never be made on a connection that will be returned
   124         // to the connection pool (we might need to revisit this constructor later)
   122         // to the connection pool (we might need to revisit this constructor later)
   125         this.method = method;
   123         this.method = method;
   126         this.systemHeaders = new HttpHeadersImpl();
   124         this.systemHeaders = new HttpHeadersImpl();
   127         this.userHeaders = ImmutableHeaders.empty();
   125         this.userHeaders = ImmutableHeaders.empty();
   128         this.uri = URI.create("socket://" + authority.getHostString() + ":" + Integer.toString(authority.getPort()) + "/");
   126         this.uri = URI.create("socket://" + authority.getHostString() + ":"
   129         this.requestProcessor = HttpRequest.noBody();
   127                               + Integer.toString(authority.getPort()) + "/");
       
   128         this.requestPublisher = null;
   130         this.authority = authority;
   129         this.authority = authority;
   131         this.secure = false;
   130         this.secure = false;
   132         this.expectContinue = false;
   131         this.expectContinue = false;
   133         this.duration = null;
   132         this.timeout = null;
   134         this.version = Optional.of(client.version());
   133         // The CONNECT request sent for tunneling is only used in two cases:
       
   134         //   1. websocket, which only supports HTTP/1.1
       
   135         //   2. SSL tunneling through a HTTP/1.1 proxy
       
   136         // In either case we do not want to upgrade the connection to the proxy.
       
   137         // What we want to possibly upgrade is the tunneled connection to the
       
   138         // target server (so not the CONNECT request itself)
       
   139         this.version = Optional.of(HttpClient.Version.HTTP_1_1);
   135     }
   140     }
   136 
   141 
   137     /**
   142     /**
   138      * Creates a HttpRequestImpl from the given set of Headers and the associated
   143      * Creates a HttpRequestImpl from the given set of Headers and the associated
   139      * "parent" request. Fields not taken from the headers are taken from the
   144      * "parent" request. Fields not taken from the headers are taken from the
   164 
   169 
   165         this.userHeaders = ImmutableHeaders.of(headers.map(), ALLOWED_HEADERS);
   170         this.userHeaders = ImmutableHeaders.of(headers.map(), ALLOWED_HEADERS);
   166         this.systemHeaders = parent.systemHeaders;
   171         this.systemHeaders = parent.systemHeaders;
   167         this.expectContinue = parent.expectContinue;
   172         this.expectContinue = parent.expectContinue;
   168         this.secure = parent.secure;
   173         this.secure = parent.secure;
   169         this.requestProcessor = parent.requestProcessor;
   174         this.requestPublisher = parent.requestPublisher;
   170         this.acc = parent.acc;
   175         this.acc = parent.acc;
   171         this.duration = parent.duration;
   176         this.timeout = parent.timeout;
   172         this.version = parent.version;
   177         this.version = parent.version;
   173     }
   178     }
   174 
   179 
   175     @Override
   180     @Override
   176     public String toString() {
   181     public String toString() {
   193     @Override
   198     @Override
   194     public boolean expectContinue() { return expectContinue; }
   199     public boolean expectContinue() { return expectContinue; }
   195 
   200 
   196     InetSocketAddress proxy(HttpClientImpl client) {
   201     InetSocketAddress proxy(HttpClientImpl client) {
   197         ProxySelector ps = client.proxy().orElse(null);
   202         ProxySelector ps = client.proxy().orElse(null);
   198         if (ps == null) {
       
   199             ps = client.proxy().orElse(null);
       
   200         }
       
   201         if (ps == null || method.equalsIgnoreCase("CONNECT")) {
   203         if (ps == null || method.equalsIgnoreCase("CONNECT")) {
   202             return null;
   204             return null;
   203         }
   205         }
   204         return (InetSocketAddress)ps.select(uri).get(0).address();
   206         return (InetSocketAddress)ps.select(uri).get(0).address();
   205     }
   207     }
   213 
   215 
   214     boolean isWebSocket() {
   216     boolean isWebSocket() {
   215         return isWebSocket;
   217         return isWebSocket;
   216     }
   218     }
   217 
   219 
   218 //    /** Returns the follow-redirects setting for this request. */
   220     @Override
   219 //    @Override
   221     public Optional<BodyPublisher> bodyPublisher() {
   220 //    public jdk.incubator.http.HttpClient.Redirect followRedirects() {
   222         return requestPublisher == null ? Optional.empty()
   221 //        return followRedirects;
   223                                         : Optional.of(requestPublisher);
   222 //    }
       
   223 
       
   224     @Override
       
   225     public Optional<BodyProcessor> bodyProcessor() {
       
   226         return Optional.of(requestProcessor);
       
   227     }
   224     }
   228 
   225 
   229     /**
   226     /**
   230      * Returns the request method for this request. If not set explicitly,
   227      * Returns the request method for this request. If not set explicitly,
   231      * the default method for any request is "GET".
   228      * the default method for any request is "GET".
   235 
   232 
   236     @Override
   233     @Override
   237     public URI uri() { return uri; }
   234     public URI uri() { return uri; }
   238 
   235 
   239     @Override
   236     @Override
   240     public Duration duration() {
   237     public Optional<Duration> timeout() {
   241         return duration;
   238         return timeout == null ? Optional.empty() : Optional.of(timeout);
   242     }
   239     }
   243 
       
   244 //    HttpClientImpl client() {
       
   245 //        return client;
       
   246 //    }
       
   247 
   240 
   248     HttpHeaders getUserHeaders() { return userHeaders; }
   241     HttpHeaders getUserHeaders() { return userHeaders; }
   249 
   242 
   250     HttpHeadersImpl getSystemHeaders() { return systemHeaders; }
   243     HttpHeadersImpl getSystemHeaders() { return systemHeaders; }
   251 
   244 
   259     @Override
   252     @Override
   260     public void setSystemHeader(String name, String value) {
   253     public void setSystemHeader(String name, String value) {
   261         systemHeaders.setHeader(name, value);
   254         systemHeaders.setHeader(name, value);
   262     }
   255     }
   263 
   256 
   264 //    @Override
   257     InetSocketAddress getAddress(HttpClientImpl client) {
   265 //    public <T> HttpResponse<T>
       
   266 //    response(HttpResponse.BodyHandler<T> responseHandler)
       
   267 //        throws IOException, InterruptedException
       
   268 //    {
       
   269 //        if (!sent.compareAndSet(false, true)) {
       
   270 //            throw new IllegalStateException("request already sent");
       
   271 //        }
       
   272 //        MultiExchange<Void,T> mex = new MultiExchange<>(this, responseHandler);
       
   273 //        return mex.response();
       
   274 //    }
       
   275 //
       
   276 //    @Override
       
   277 //    public <T> CompletableFuture<HttpResponse<T>>
       
   278 //    responseAsync(HttpResponse.BodyHandler<T> responseHandler)
       
   279 //    {
       
   280 //        if (!sent.compareAndSet(false, true)) {
       
   281 //            throw new IllegalStateException("request already sent");
       
   282 //        }
       
   283 //        MultiExchange<Void,T> mex = new MultiExchange<>(this, responseHandler);
       
   284 //        return mex.responseAsync(null)
       
   285 //                  .thenApply((HttpResponseImpl<T> b) -> (HttpResponse<T>) b);
       
   286 //    }
       
   287 //
       
   288 //    @Override
       
   289 //    public <U, T> CompletableFuture<U>
       
   290 //    multiResponseAsync(HttpResponse.MultiProcessor<U, T> responseHandler)
       
   291 //    {
       
   292 //        if (!sent.compareAndSet(false, true)) {
       
   293 //            throw new IllegalStateException("request already sent");
       
   294 //        }
       
   295 //        MultiExchange<U,T> mex = new MultiExchange<>(this, responseHandler);
       
   296 //        return mex.multiResponseAsync();
       
   297 //    }
       
   298 
       
   299     public InetSocketAddress getAddress(HttpClientImpl client) {
       
   300         URI uri = uri();
   258         URI uri = uri();
   301         if (uri == null) {
   259         if (uri == null) {
   302             return authority();
   260             return authority();
   303         }
   261         }
   304         int port = uri.getPort();
   262         int p = uri.getPort();
   305         if (port == -1) {
   263         if (p == -1) {
   306             if (uri.getScheme().equalsIgnoreCase("https")) {
   264             if (uri.getScheme().equalsIgnoreCase("https")) {
   307                 port = 443;
   265                 p = 443;
   308             } else {
   266             } else {
   309                 port = 80;
   267                 p = 80;
   310             }
   268             }
   311         }
   269         }
   312         String host = uri.getHost();
   270         final String host = uri.getHost();
       
   271         final int port = p;
   313         if (proxy(client) == null) {
   272         if (proxy(client) == null) {
   314             return new InetSocketAddress(host, port);
   273             PrivilegedAction<InetSocketAddress> pa = () -> new InetSocketAddress(host, port);
       
   274             return AccessController.doPrivileged(pa);
   315         } else {
   275         } else {
   316             return InetSocketAddress.createUnresolved(host, port);
   276             return InetSocketAddress.createUnresolved(host, port);
   317         }
   277         }
   318     }
   278     }
   319 }
   279 }