提交 b2c42206 编写于 作者: C chegar
上级 2bd60f0d
......@@ -89,6 +89,7 @@ PLATFORM_MODULES += \
#
PLATFORM_MODULES += \
java.net.http \
java.scripting \
java.security.jgss \
java.smartcardio \
......@@ -102,7 +103,6 @@ PLATFORM_MODULES += \
jdk.crypto.ec \
jdk.dynalink \
jdk.httpserver \
jdk.incubator.httpclient \
jdk.internal.vm.compiler.management \
jdk.jsobject \
jdk.localedata \
......@@ -145,7 +145,6 @@ DOCS_MODULES += \
jdk.editpad \
jdk.hotspot.agent \
jdk.httpserver \
jdk.incubator.httpclient \
jdk.jartool \
jdk.javadoc \
jdk.jcmd \
......
......@@ -36,9 +36,9 @@ import sun.security.util.SecurityConstants;
* handler. The HTTP state management mechanism specifies a way to
* create a stateful session with HTTP requests and responses.
*
* <p>A system-wide CookieHandler that to used by the HTTP protocol
* handler can be registered by doing a
* CookieHandler.setDefault(CookieHandler). The currently registered
* <p> A system-wide CookieHandler to be used by the {@linkplain
* HttpURLConnection HTTP URL stream protocol handler} can be registered by
* doing a CookieHandler.setDefault(CookieHandler). The currently registered
* CookieHandler can be retrieved by calling
* CookieHandler.getDefault().
*
......
......@@ -156,7 +156,7 @@ of proxies.</P>
checked only once at startup.</P>
</UL>
<a id="MiscHTTP"></a>
<H2>Misc HTTP properties</H2>
<H2>Misc HTTP URL stream protocol handler properties</H2>
<UL>
<LI><P><B>http.agent</B> (default: &ldquo;Java/&lt;version&gt;&rdquo;)<BR>
Defines the string sent in the User-Agent request header in http
......
......@@ -121,8 +121,8 @@
* underlying protocol handlers like http or https.</li>
* <li>{@link java.net.HttpURLConnection} is a subclass of URLConnection
* and provides some additional functionalities specific to the
* HTTP protocol. This API has been superceded by the newer
HTTP client API described in the previous section.</li>
* HTTP protocol. This API has been superseded by the newer
* {@linkplain java.net.http HTTP Client API}.</li>
* </ul>
* <p>The recommended usage is to use {@link java.net.URI} to identify
* resources, then convert it into a {@link java.net.URL} when it is time to
......
......@@ -171,7 +171,7 @@ module java.base {
jdk.attach,
jdk.charsets,
jdk.compiler,
jdk.incubator.httpclient,
java.net.http,
jdk.jdeps,
jdk.jlink,
jdk.jshell,
......@@ -204,12 +204,11 @@ module java.base {
jdk.internal.jvmstat;
exports jdk.internal.vm.annotation to
jdk.unsupported,
jdk.internal.vm.ci,
jdk.incubator.httpclient;
jdk.internal.vm.ci;
exports jdk.internal.util.jar to
jdk.jartool;
exports sun.net to
jdk.incubator.httpclient,
java.net.http,
jdk.naming.dns;
exports sun.net.ext to
jdk.net;
......@@ -219,10 +218,10 @@ module java.base {
exports sun.net.util to
java.desktop,
jdk.jconsole,
jdk.incubator.httpclient;
java.net.http;
exports sun.net.www to
java.desktop,
jdk.incubator.httpclient,
java.net.http,
jdk.jartool;
exports sun.net.www.protocol.http to
java.security.jgss;
......
......@@ -14,6 +14,23 @@ grant codeBase "jrt:/java.compiler" {
};
grant codeBase "jrt:/java.net.http" {
permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
permission java.net.SocketPermission "*","connect,resolve";
permission java.net.URLPermission "http:*","*:*";
permission java.net.URLPermission "https:*","*:*";
permission java.net.URLPermission "ws:*","*:*";
permission java.net.URLPermission "wss:*","*:*";
permission java.net.URLPermission "socket:*","CONNECT"; // proxy
// For request/response body processors, fromFile, asFile
permission java.io.FilePermission "<<ALL FILES>>","read,write,delete";
permission java.util.PropertyPermission "*","read";
permission java.net.NetPermission "getProxySelector";
};
grant codeBase "jrt:/java.scripting" {
permission java.security.AllPermission;
};
......
/*
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2018, 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
......@@ -23,7 +23,7 @@
* questions.
*/
package jdk.incubator.http;
package java.net.http;
import java.util.List;
import java.util.Map;
......@@ -35,15 +35,19 @@ import static java.util.Objects.requireNonNull;
/**
* A read-only view of a set of HTTP headers.
* {@Incubating}
*
* <p> An {@code HttpHeaders} is not created directly, but rather returned from
* an {@link HttpResponse HttpResponse}. Specific HTTP headers can be set for
* {@linkplain HttpRequest requests} through the one of the request builder's
* {@link HttpRequest.Builder#header(String, String) headers} methods.
*
* <p> The methods of this class ( that accept a String header name ), and the
* Map returned by the {@linkplain #map() map} method, operate without regard to
* Map returned by the {@link #map() map} method, operate without regard to
* case when retrieving the header value.
*
* <p> HttpHeaders instances are immutable.
* <p> {@code HttpHeaders} instances are immutable.
*
* @since 9
* @since 11
*/
public abstract class HttpHeaders {
......@@ -139,7 +143,7 @@ public abstract class HttpHeaders {
* Computes a hash code for this HTTP headers instance.
*
* <p> The hash code is based upon the components of the HTTP headers
* {@linkplain #map() map}, and satisfies the general contract of the
* {@link #map() map}, and satisfies the general contract of the
* {@link Object#hashCode Object.hashCode} method.
*
* @return the hash-code value for this HTTP headers
......@@ -156,7 +160,7 @@ public abstract class HttpHeaders {
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(super.toString()).append(" ");
sb.append(super.toString()).append(" { ");
sb.append(map());
sb.append(" }");
return sb.toString();
......
/*
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2018, 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
......@@ -23,18 +23,25 @@
* questions.
*/
package jdk.incubator.http;
package java.net.http;
import java.io.IOException;
/**
* Thrown when a response is not received within a specified time period.
* {@Incubating}
*
* @since 11
*/
public class HttpTimeoutException extends IOException {
private static final long serialVersionUID = 981344271622632951L;
/**
* Constructs an {@code HttpTimeoutException} with the given detail message.
*
* @param message
* The detail message; can be {@code null}
*/
public HttpTimeoutException(String message) {
super(message);
}
......
/*
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2018, 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
......@@ -23,15 +23,14 @@
* questions.
*/
package jdk.incubator.http;
package java.net.http;
import java.io.IOException;
/**
* An exception used to signal the opening handshake failed.
* {@Incubating}
*
* @since 9
* @since 11
*/
public final class WebSocketHandshakeException extends IOException {
......@@ -39,6 +38,13 @@ public final class WebSocketHandshakeException extends IOException {
private final transient HttpResponse<?> response;
/**
* Constructs a {@code WebSocketHandshakeException} with the given
* {@code HttpResponse}.
*
* @param response
* the {@code HttpResponse} that resulted in the handshake failure
*/
public WebSocketHandshakeException(HttpResponse<?> response) {
this.response = response;
}
......@@ -47,7 +53,7 @@ public final class WebSocketHandshakeException extends IOException {
* Returns the server's counterpart of the opening handshake.
*
* <p> The value may be unavailable ({@code null}) if this exception has
* been serialized and then read back in.
* been serialized and then deserialized.
*
* @return server response
*/
......
/*
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2018, 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
......@@ -24,37 +24,42 @@
*/
/**
* <h2>High level HTTP and WebSocket API</h2>
* {@Incubating}
* <h2>HTTP Client and WebSocket APIs</h2>
*
* <p> Provides high-level client interfaces to HTTP (versions 1.1 and 2) and
* WebSocket. The main types defined are:
* low-level client interfaces to WebSocket. The main types defined are:
*
* <ul>
* <li>{@link jdk.incubator.http.HttpClient}</li>
* <li>{@link jdk.incubator.http.HttpRequest}</li>
* <li>{@link jdk.incubator.http.HttpResponse}</li>
* <li>{@link jdk.incubator.http.WebSocket}</li>
* <li>{@link java.net.http.HttpClient}</li>
* <li>{@link java.net.http.HttpRequest}</li>
* <li>{@link java.net.http.HttpResponse}</li>
* <li>{@link java.net.http.WebSocket}</li>
* </ul>
*
* <p> The API functions asynchronously (using {@link java.util.concurrent.CompletableFuture})
* and work is done on the threads supplied by the client's {@link java.util.concurrent.Executor}
* where practical.
* <p> The protocol-specific requirements are defined in the
* <a href="https://tools.ietf.org/html/rfc7540">Hypertext Transfer Protocol
* Version 2 (HTTP/2)</a>, the <a href="https://tools.ietf.org/html/rfc2616">
* Hypertext Transfer Protocol (HTTP/1.1)</a>, and
* <a href="https://tools.ietf.org/html/rfc6455">The WebSocket Protocol</a>.
*
* <p> {@code HttpClient} also provides a simple synchronous mode, where all
* work may be done on the calling thread.
* <p> Asynchronous tasks and dependent actions of returned {@link
* java.util.concurrent.CompletableFuture} instances are executed on the threads
* supplied by the client's {@link java.util.concurrent.Executor}, where
* practical.
*
* <p> {@code CompletableFuture}s returned by this API will throw {@link java.lang.UnsupportedOperationException}
* for their {@link java.util.concurrent.CompletableFuture#obtrudeValue(Object) obtrudeValue}
* and {@link java.util.concurrent.CompletableFuture#obtrudeException(Throwable) obtrudeException}
* methods. Invoking the {@link java.util.concurrent.CompletableFuture#cancel cancel}
* method on a {@code CompletableFuture} returned by this API will not interrupt
* the underlying operation, but may be useful to complete, exceptionally,
* dependent stages that have not already completed.
* <p> {@code CompletableFuture}s returned by this API will throw {@link
* java.lang.UnsupportedOperationException} for their {@link
* java.util.concurrent.CompletableFuture#obtrudeValue(Object) obtrudeValue}
* and {@link java.util.concurrent.CompletableFuture#obtrudeException(Throwable)
* obtrudeException} methods. Invoking the {@link
* java.util.concurrent.CompletableFuture#cancel cancel} method on a {@code
* CompletableFuture} returned by this API will not interrupt the underlying
* operation, but may be useful to complete, exceptionally, dependent stages
* that have not already completed.
*
* <p> Unless otherwise stated, {@code null} parameter values will cause methods
* of all classes in this package to throw {@code NullPointerException}.
*
* @since 9
* @since 11
*/
package jdk.incubator.http;
package java.net.http;
/*
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2018, 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
......@@ -23,25 +23,21 @@
* questions.
*/
package jdk.incubator.http;
package jdk.internal.net.http;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import javax.net.ssl.SNIHostName;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLEngineResult;
import javax.net.ssl.SSLParameters;
import jdk.incubator.http.internal.common.SSLTube;
import jdk.incubator.http.internal.common.Log;
import jdk.incubator.http.internal.common.Utils;
import jdk.internal.net.http.common.SSLTube;
import jdk.internal.net.http.common.Log;
import jdk.internal.net.http.common.Utils;
import static jdk.internal.net.http.common.Utils.ServerName;
/**
* Asynchronous version of SSLConnection.
......@@ -67,16 +63,20 @@ abstract class AbstractAsyncSSLConnection extends HttpConnection
protected final String serverName;
protected final SSLParameters sslParameters;
// Setting this property disables HTTPS hostname verification. Use with care.
private static final boolean disableHostnameVerification
= Utils.isHostnameVerificationDisabled();
AbstractAsyncSSLConnection(InetSocketAddress addr,
HttpClientImpl client,
String serverName,
ServerName serverName, int port,
String[] alpn) {
super(addr, client);
this.serverName = serverName;
this.serverName = serverName.getName();
SSLContext context = client.theSSLContext();
sslParameters = createSSLParameters(client, serverName, alpn);
Log.logParams(sslParameters);
engine = createEngine(context, sslParameters);
engine = createEngine(context, serverName.getName(), port, sslParameters);
}
abstract HttpConnection plainConnection();
......@@ -90,10 +90,12 @@ abstract class AbstractAsyncSSLConnection extends HttpConnection
final SSLEngine getEngine() { return engine; }
private static SSLParameters createSSLParameters(HttpClientImpl client,
String serverName,
ServerName serverName,
String[] alpn) {
SSLParameters sslp = client.sslParameters();
SSLParameters sslParameters = Utils.copySSLParameters(sslp);
if (!disableHostnameVerification)
sslParameters.setEndpointIdentificationAlgorithm("HTTPS");
if (alpn != null) {
Log.logSSL("AbstractAsyncSSLConnection: Setting application protocols: {0}",
Arrays.toString(alpn));
......@@ -101,15 +103,18 @@ abstract class AbstractAsyncSSLConnection extends HttpConnection
} else {
Log.logSSL("AbstractAsyncSSLConnection: no applications set!");
}
if (serverName != null) {
sslParameters.setServerNames(List.of(new SNIHostName(serverName)));
if (!serverName.isLiteral()) {
String name = serverName.getName();
if (name != null && name.length() > 0) {
sslParameters.setServerNames(List.of(new SNIHostName(name)));
}
}
return sslParameters;
}
private static SSLEngine createEngine(SSLContext context,
private static SSLEngine createEngine(SSLContext context, String serverName, int port,
SSLParameters sslParameters) {
SSLEngine engine = context.createSSLEngine();
SSLEngine engine = context.createSSLEngine(serverName, port);
engine.setUseClientMode(true);
engine.setSSLParameters(sslParameters);
return engine;
......@@ -120,69 +125,4 @@ abstract class AbstractAsyncSSLConnection extends HttpConnection
return true;
}
// Support for WebSocket/RawChannelImpl which unfortunately
// still depends on synchronous read/writes.
// It should be removed when RawChannelImpl moves to using asynchronous APIs.
static final class SSLConnectionChannel extends DetachedConnectionChannel {
final DetachedConnectionChannel delegate;
final SSLDelegate sslDelegate;
SSLConnectionChannel(DetachedConnectionChannel delegate, SSLDelegate sslDelegate) {
this.delegate = delegate;
this.sslDelegate = sslDelegate;
}
SocketChannel channel() {
return delegate.channel();
}
@Override
ByteBuffer read() throws IOException {
SSLDelegate.WrapperResult r = sslDelegate.recvData(ByteBuffer.allocate(8192));
// TODO: check for closure
int n = r.result.bytesProduced();
if (n > 0) {
return r.buf;
} else if (n == 0) {
return Utils.EMPTY_BYTEBUFFER;
} else {
return null;
}
}
@Override
long write(ByteBuffer[] buffers, int start, int number) throws IOException {
long l = SSLDelegate.countBytes(buffers, start, number);
SSLDelegate.WrapperResult r = sslDelegate.sendData(buffers, start, number);
if (r.result.getStatus() == SSLEngineResult.Status.CLOSED) {
if (l > 0) {
throw new IOException("SSLHttpConnection closed");
}
}
return l;
}
@Override
public void shutdownInput() throws IOException {
delegate.shutdownInput();
}
@Override
public void shutdownOutput() throws IOException {
delegate.shutdownOutput();
}
@Override
public void close() {
delegate.close();
}
}
// Support for WebSocket/RawChannelImpl which unfortunately
// still depends on synchronous read/writes.
// It should be removed when RawChannelImpl moves to using asynchronous APIs.
@Override
DetachedConnectionChannel detachChannel() {
assert client() != null;
DetachedConnectionChannel detachedChannel = plainConnection().detachChannel();
SSLDelegate sslDelegate = new SSLDelegate(engine,
detachedChannel.channel());
return new SSLConnectionChannel(detachedChannel, sslDelegate);
}
}
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2018, 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
......@@ -23,14 +23,13 @@
* questions.
*/
package jdk.incubator.http;
package jdk.internal.net.http;
import java.util.concurrent.Flow;
import jdk.incubator.http.internal.common.Demand;
import jdk.internal.net.http.common.Demand;
/**
* A {@link Flow.Subscription} wrapping a {@link Demand} instance.
*
*/
abstract class AbstractSubscription implements Flow.Subscription {
......@@ -41,5 +40,4 @@ abstract class AbstractSubscription implements Flow.Subscription {
* @return the subscription's demand.
*/
protected Demand demand() { return demand; }
}
/*
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2018, 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
......@@ -23,7 +23,7 @@
* questions.
*/
package jdk.incubator.http;
package jdk.internal.net.http;
import java.io.IOException;
import java.nio.channels.SelectableChannel;
......
/*
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2018, 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
......@@ -23,16 +23,13 @@
* questions.
*/
package jdk.incubator.http;
package jdk.internal.net.http;
import java.io.IOException;
import java.lang.System.Logger.Level;
import java.net.InetSocketAddress;
import java.nio.channels.SocketChannel;
import java.util.concurrent.CompletableFuture;
import jdk.incubator.http.internal.common.SSLTube;
import jdk.incubator.http.internal.common.Utils;
import jdk.internal.net.http.common.SSLTube;
import jdk.internal.net.http.common.Utils;
/**
* Asynchronous version of SSLConnection.
......@@ -46,7 +43,7 @@ class AsyncSSLConnection extends AbstractAsyncSSLConnection {
AsyncSSLConnection(InetSocketAddress addr,
HttpClientImpl client,
String[] alpn) {
super(addr, client, Utils.getServerName(addr), alpn);
super(addr, client, Utils.getServerName(addr), addr.getPort(), alpn);
plainConnection = new PlainHttpConnection(addr, client);
writePublisher = new PlainHttpPublisher();
}
......@@ -96,18 +93,6 @@ class AsyncSSLConnection extends AbstractAsyncSSLConnection {
plainConnection.close();
}
@Override
void shutdownInput() throws IOException {
debug.log(Level.DEBUG, "plainConnection.channel().shutdownInput()");
plainConnection.channel().shutdownInput();
}
@Override
void shutdownOutput() throws IOException {
debug.log(Level.DEBUG, "plainConnection.channel().shutdownOutput()");
plainConnection.channel().shutdownOutput();
}
@Override
SSLTube getConnectionFlow() {
return flow;
......
/*
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2018, 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
......@@ -23,15 +23,14 @@
* questions.
*/
package jdk.incubator.http;
package jdk.internal.net.http;
import java.io.IOException;
import java.lang.System.Logger.Level;
import java.net.InetSocketAddress;
import java.nio.channels.SocketChannel;
import java.util.concurrent.CompletableFuture;
import jdk.incubator.http.internal.common.SSLTube;
import jdk.incubator.http.internal.common.Utils;
import java.net.http.HttpHeaders;
import jdk.internal.net.http.common.SSLTube;
import jdk.internal.net.http.common.Utils;
/**
* An SSL tunnel built on a Plain (CONNECT) TCP tunnel.
......@@ -45,23 +44,24 @@ class AsyncSSLTunnelConnection extends AbstractAsyncSSLConnection {
AsyncSSLTunnelConnection(InetSocketAddress addr,
HttpClientImpl client,
String[] alpn,
InetSocketAddress proxy)
InetSocketAddress proxy,
HttpHeaders proxyHeaders)
{
super(addr, client, Utils.getServerName(addr), alpn);
this.plainConnection = new PlainTunnelingConnection(addr, proxy, client);
super(addr, client, Utils.getServerName(addr), addr.getPort(), alpn);
this.plainConnection = new PlainTunnelingConnection(addr, proxy, client, proxyHeaders);
this.writePublisher = new PlainHttpPublisher();
}
@Override
public CompletableFuture<Void> connectAsync() {
debug.log(Level.DEBUG, "Connecting plain tunnel connection");
if (debug.on()) debug.log("Connecting plain tunnel connection");
// This will connect the PlainHttpConnection flow, so that
// its HttpSubscriber and HttpPublisher are subscribed to the
// SocketTube
return plainConnection
.connectAsync()
.thenApply( unused -> {
debug.log(Level.DEBUG, "creating SSLTube");
if (debug.on()) debug.log("creating SSLTube");
// create the SSLTube wrapping the SocketTube, with the given engine
flow = new SSLTube(engine,
client().theExecutor(),
......@@ -69,6 +69,9 @@ class AsyncSSLTunnelConnection extends AbstractAsyncSSLConnection {
return null;} );
}
@Override
boolean isTunnel() { return true; }
@Override
boolean connected() {
return plainConnection.connected(); // && sslDelegate.connected();
......@@ -97,16 +100,6 @@ class AsyncSSLTunnelConnection extends AbstractAsyncSSLConnection {
plainConnection.close();
}
@Override
void shutdownInput() throws IOException {
plainConnection.channel().shutdownInput();
}
@Override
void shutdownOutput() throws IOException {
plainConnection.channel().shutdownOutput();
}
@Override
SocketChannel channel() {
return plainConnection.channel();
......
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2018, 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
......@@ -23,7 +23,7 @@
* questions.
*/
package jdk.incubator.http;
package jdk.internal.net.http;
import java.io.IOException;
import java.nio.channels.SelectableChannel;
......
/*
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2018, 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
......@@ -23,18 +23,23 @@
* questions.
*/
package jdk.incubator.http;
package jdk.internal.net.http;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.PasswordAuthentication;
import java.net.URI;
import java.net.InetSocketAddress;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Base64;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.WeakHashMap;
import jdk.incubator.http.internal.common.Utils;
import java.net.http.HttpHeaders;
import jdk.internal.net.http.common.Log;
import jdk.internal.net.http.common.Utils;
import static java.net.Authenticator.RequestorType.PROXY;
import static java.net.Authenticator.RequestorType.SERVER;
import static java.nio.charset.StandardCharsets.ISO_8859_1;
......@@ -43,7 +48,7 @@ import static java.nio.charset.StandardCharsets.ISO_8859_1;
* Implementation of Http Basic authentication.
*/
class AuthenticationFilter implements HeaderFilter {
volatile MultiExchange<?,?> exchange;
volatile MultiExchange<?> exchange;
private static final Base64.Encoder encoder = Base64.getEncoder();
static final int DEFAULT_RETRY_LIMIT = 3;
......@@ -54,6 +59,10 @@ class AuthenticationFilter implements HeaderFilter {
static final int UNAUTHORIZED = 401;
static final int PROXY_UNAUTHORIZED = 407;
private static final List<String> BASIC_DUMMY =
List.of("Basic " + Base64.getEncoder()
.encodeToString("o:o".getBytes(ISO_8859_1)));
// A public no-arg constructor is required by FilterFactory
public AuthenticationFilter() {}
......@@ -72,19 +81,46 @@ class AuthenticationFilter implements HeaderFilter {
String realm = parser.findValue("realm");
java.net.Authenticator.RequestorType rtype = proxy ? PROXY : SERVER;
URL url = toURL(uri, req.method(), proxy);
String host;
int port;
String protocol;
InetSocketAddress proxyAddress;
if (proxy && (proxyAddress = req.proxy()) != null) {
// request sent to server through proxy
proxyAddress = req.proxy();
host = proxyAddress.getHostString();
port = proxyAddress.getPort();
protocol = "http"; // we don't support https connection to proxy
} else {
// direct connection to server or proxy
host = uri.getHost();
port = uri.getPort();
protocol = uri.getScheme();
}
// needs to be instance method in Authenticator
return auth.requestPasswordAuthenticationInstance(uri.getHost(),
return auth.requestPasswordAuthenticationInstance(host,
null,
uri.getPort(),
uri.getScheme(),
port,
protocol,
realm,
authscheme,
uri.toURL(),
url,
rtype
);
}
private URL toURL(URI uri, String method, boolean proxy)
throws MalformedURLException
{
if (proxy && "CONNECT".equalsIgnoreCase(method)
&& "socket".equalsIgnoreCase(uri.getScheme())) {
return null; // proxy tunneling
}
return uri.toURL();
}
private URI getProxyURI(HttpRequestImpl r) {
InetSocketAddress proxy = r.proxy();
if (proxy == null) {
......@@ -99,7 +135,7 @@ class AuthenticationFilter implements HeaderFilter {
null,
proxy.getHostString(),
proxy.getPort(),
null,
"/",
null,
null);
} catch (URISyntaxException e) {
......@@ -108,7 +144,7 @@ class AuthenticationFilter implements HeaderFilter {
}
@Override
public void request(HttpRequestImpl r, MultiExchange<?,?> e) throws IOException {
public void request(HttpRequestImpl r, MultiExchange<?> e) throws IOException {
// use preemptive authentication if an entry exists.
Cache cache = getCache(e);
this.exchange = e;
......@@ -144,6 +180,21 @@ class AuthenticationFilter implements HeaderFilter {
sb.append(pw.getUserName()).append(':').append(pw.getPassword());
String s = encoder.encodeToString(sb.toString().getBytes(ISO_8859_1));
String value = "Basic " + s;
if (proxy) {
if (r.isConnect()) {
if (!Utils.PROXY_TUNNEL_FILTER
.test(hdrname, List.of(value))) {
Log.logError("{0} disabled", hdrname);
return;
}
} else if (r.proxy() != null) {
if (!Utils.PROXY_FILTER
.test(hdrname, List.of(value))) {
Log.logError("{0} disabled", hdrname);
return;
}
}
}
r.setSystemHeader(hdrname, value);
}
......@@ -200,7 +251,10 @@ class AuthenticationFilter implements HeaderFilter {
}
if (exchange.proxyauth != null && !exchange.proxyauth.fromcache) {
AuthInfo au = exchange.proxyauth;
cache.store(au.scheme, req.uri(), false, au.credentials);
URI proxyURI = getProxyURI(req);
if (proxyURI != null) {
cache.store(au.scheme, proxyURI, true, au.credentials);
}
}
return null;
}
......@@ -219,8 +273,27 @@ class AuthenticationFilter implements HeaderFilter {
return null; // error gets returned to app
}
if (proxy) {
if (r.isConnectResponse) {
if (!Utils.PROXY_TUNNEL_FILTER
.test("Proxy-Authorization", BASIC_DUMMY)) {
Log.logError("{0} disabled", "Proxy-Authorization");
return null;
}
} else if (req.proxy() != null) {
if (!Utils.PROXY_FILTER
.test("Proxy-Authorization", BASIC_DUMMY)) {
Log.logError("{0} disabled", "Proxy-Authorization");
return null;
}
}
}
AuthInfo au = proxy ? exchange.proxyauth : exchange.serverauth;
if (au == null) {
// if no authenticator, let the user deal with 407/401
if (!exchange.client().authenticator().isPresent()) return null;
PasswordAuthentication pw = getCredentials(authval, proxy, req);
if (pw == null) {
throw new IOException("No credentials provided");
......@@ -232,6 +305,7 @@ class AuthenticationFilter implements HeaderFilter {
} else {
exchange.serverauth = au;
}
req = HttpRequestImpl.newInstanceForAuthentication(req);
addBasicCredentials(req, proxy, pw);
return req;
} else if (au.retries > retry_limit) {
......@@ -242,6 +316,10 @@ class AuthenticationFilter implements HeaderFilter {
if (au.fromcache) {
cache.remove(au.cacheEntry);
}
// if no authenticator, let the user deal with 407/401
if (!exchange.client().authenticator().isPresent()) return null;
// try again
PasswordAuthentication pw = getCredentials(authval, proxy, req);
if (pw == null) {
......@@ -253,6 +331,7 @@ class AuthenticationFilter implements HeaderFilter {
} else {
exchange.serverauth = au;
}
req = HttpRequestImpl.newInstanceForAuthentication(req);
addBasicCredentials(req, proxy, au.credentials);
au.retries++;
return req;
......@@ -260,10 +339,10 @@ class AuthenticationFilter implements HeaderFilter {
}
// Use a WeakHashMap to make it possible for the HttpClient to
// be garbaged collected when no longer referenced.
// be garbage collected when no longer referenced.
static final WeakHashMap<HttpClientImpl,Cache> caches = new WeakHashMap<>();
static synchronized Cache getCache(MultiExchange<?,?> exchange) {
static synchronized Cache getCache(MultiExchange<?> exchange) {
HttpClientImpl client = exchange.client();
Cache c = caches.get(client);
if (c == null) {
......@@ -276,9 +355,11 @@ class AuthenticationFilter implements HeaderFilter {
// Note: Make sure that Cache and CacheEntry do not keep any strong
// reference to the HttpClient: it would prevent the client being
// GC'ed when no longer referenced.
static class Cache {
static final class Cache {
final LinkedList<CacheEntry> entries = new LinkedList<>();
Cache() {}
synchronized CacheEntry get(URI uri, boolean proxy) {
for (CacheEntry entry : entries) {
if (entry.equalsKey(uri, proxy)) {
......@@ -309,7 +390,26 @@ class AuthenticationFilter implements HeaderFilter {
}
}
static class CacheEntry {
static URI normalize(URI uri, boolean isPrimaryKey) {
String path = uri.getPath();
if (path == null || path.isEmpty()) {
// make sure the URI has a path, ignore query and fragment
try {
return new URI(uri.getScheme(), uri.getAuthority(), "/", null, null);
} catch (URISyntaxException e) {
throw new InternalError(e);
}
} else if (isPrimaryKey || !"/".equals(path)) {
// remove extraneous components and normalize path
return uri.resolve(".");
} else {
// path == "/" and the URI is not used to store
// the primary key in the cache: nothing to do.
return uri;
}
}
static final class CacheEntry {
final String root;
final String scheme;
final boolean proxy;
......@@ -320,7 +420,7 @@ class AuthenticationFilter implements HeaderFilter {
boolean proxy,
PasswordAuthentication value) {
this.scheme = authscheme;
this.root = uri.resolve(".").toString(); // remove extraneous components
this.root = normalize(uri, true).toString(); // remove extraneous components
this.proxy = proxy;
this.value = value;
}
......@@ -333,7 +433,7 @@ class AuthenticationFilter implements HeaderFilter {
if (this.proxy != proxy) {
return false;
}
String other = uri.toString();
String other = String.valueOf(normalize(uri, false));
return other.startsWith(root);
}
}
......
/*
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2018, 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
......@@ -23,21 +23,22 @@
* questions.
*/
package jdk.incubator.http;
package jdk.internal.net.http;
import java.util.LinkedList;
import java.util.List;
class FilterFactory {
// Strictly-ordered list of filters.
final LinkedList<Class<? extends HeaderFilter>> filterClasses = new LinkedList<>();
public void addFilter(Class<? extends HeaderFilter> type) {
filterClasses.add(type);
}
List<HeaderFilter> getFilterChain() {
List<HeaderFilter> l = new LinkedList<>();
LinkedList<HeaderFilter> getFilterChain() {
LinkedList<HeaderFilter> l = new LinkedList<>();
for (Class<? extends HeaderFilter> clazz : filterClasses) {
try {
// Requires a public no arg constructor.
......
/*
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2018, 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
......@@ -23,7 +23,7 @@
* questions.
*/
package jdk.incubator.http;
package jdk.internal.net.http;
import java.io.IOException;
......@@ -34,7 +34,7 @@ import java.io.IOException;
*/
interface HeaderFilter {
void request(HttpRequestImpl r, MultiExchange<?,?> e) throws IOException;
void request(HttpRequestImpl r, MultiExchange<?> e) throws IOException;
/**
* Returns null if response ok to be given to user. Non null is a request
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册