8170868: DefaultProxySelector should use system defaults on Windows, MacOS and Gnome
Reviewed-by: chegar, simonis, clanger, stuefe, erikj
Contributed-by: arno.zeller@sap.com
--- a/jdk/make/lib/NetworkingLibraries.gmk Wed Feb 01 23:33:39 2017 +0300
+++ b/jdk/make/lib/NetworkingLibraries.gmk Thu Feb 02 10:28:47 2017 +0100
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2017, 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
@@ -44,8 +44,9 @@
LIBS_linux := $(LIBDL) -lpthread, \
LIBS_solaris := -lnsl -lsocket $(LIBDL) -lc, \
LIBS_aix := $(LIBDL),\
- LIBS_windows := ws2_32.lib jvm.lib secur32.lib iphlpapi.lib \
+ LIBS_windows := ws2_32.lib jvm.lib secur32.lib iphlpapi.lib winhttp.lib \
delayimp.lib $(WIN_JAVA_LIB) advapi32.lib, \
+ LIBS_macosx := -framework CoreFoundation -framework CoreServices, \
VERSIONINFO_RESOURCE := $(GLOBAL_VERSION_INFO_RESOURCE), \
RC_FLAGS := $(RC_FLAGS) \
-D "JDK_FNAME=net.dll" \
--- a/jdk/make/mapfiles/libnet/mapfile-vers Wed Feb 01 23:33:39 2017 +0300
+++ b/jdk/make/mapfiles/libnet/mapfile-vers Thu Feb 02 10:28:47 2017 +0100
@@ -1,5 +1,5 @@
#
-# Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 1997, 2017, 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
@@ -97,7 +97,7 @@
Java_sun_net_sdp_SdpSupport_convert0;
Java_sun_net_sdp_SdpSupport_create0;
Java_sun_net_spi_DefaultProxySelector_init;
- Java_sun_net_spi_DefaultProxySelector_getSystemProxy;
+ Java_sun_net_spi_DefaultProxySelector_getSystemProxies;
NET_SockaddrToInetAddress;
NET_SockaddrEqualsInetAddress;
NET_InetAddressToSockaddr;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/macosx/native/libnet/DefaultProxySelector.c Thu Feb 02 10:28:47 2017 +0100
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017 SAP SE. 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
+ * questions.
+ */
+
+#include <string.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreServices/CoreServices.h>
+
+#include "jni.h"
+#include "jni_util.h"
+#include "jvm.h"
+#include "jvm_md.h"
+
+#include "proxy_util.h"
+
+#include "sun_net_spi_DefaultProxySelector.h"
+
+
+/**
+ * For more information on how to use the APIs in "CFProxySupport.h" see:
+ * https://developer.apple.com/legacy/library/samplecode/CFProxySupportTool/Introduction/Intro.html
+ */
+
+#define kResolveProxyRunLoopMode CFSTR("sun.net.spi.DefaultProxySelector")
+
+#define BUFFER_SIZE 1024
+
+/* Callback for CFNetworkExecuteProxyAutoConfigurationURL. */
+static void proxyUrlCallback(void * client, CFArrayRef proxies, CFErrorRef error) {
+ /* client is a pointer to a CFTypeRef and holds either proxies or an error. */
+ CFTypeRef* resultPtr = (CFTypeRef *)client;
+
+ if (error != NULL) {
+ *resultPtr = CFRetain(error);
+ } else {
+ *resultPtr = CFRetain(proxies);
+ }
+ CFRunLoopStop(CFRunLoopGetCurrent());
+}
+
+/*
+ * Returns a new array of proxies containing all the given non-PAC proxies as
+ * well as the results of executing all the given PAC-based proxies, for the
+ * specified URL. 'proxies' is a list that may contain both PAC and non-PAC
+ * proxies.
+ */
+static CFArrayRef createExpandedProxiesArray(CFArrayRef proxies, CFURLRef url) {
+
+ CFIndex count;
+ CFIndex index;
+ CFMutableArrayRef expandedProxiesArray;
+
+ expandedProxiesArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ if (expandedProxiesArray == NULL)
+ return NULL;
+
+ /* Iterate over the array of proxies */
+ count = CFArrayGetCount(proxies);
+ for (index = 0; index < count ; index++) {
+ CFDictionaryRef currentProxy;
+ CFStringRef proxyType;
+
+ currentProxy = (CFDictionaryRef) CFArrayGetValueAtIndex(proxies, index);
+ if(currentProxy == NULL) {
+ CFRelease(expandedProxiesArray);
+ return NULL;
+ }
+ proxyType = (CFStringRef) CFDictionaryGetValue(currentProxy, kCFProxyTypeKey);
+ if (proxyType == NULL) {
+ CFRelease(expandedProxiesArray);
+ return NULL;
+ }
+
+ if (!CFEqual(proxyType, kCFProxyTypeAutoConfigurationURL)) {
+ /* Non-PAC entry, just copy it to the new array */
+ CFArrayAppendValue(expandedProxiesArray, currentProxy);
+ } else {
+ /* PAC-based URL, execute its script append its results */
+ CFRunLoopSourceRef runLoop;
+ CFURLRef scriptURL;
+ CFTypeRef result = NULL;
+ CFStreamClientContext context = { 0, &result, NULL, NULL, NULL };
+ CFTimeInterval timeout = 5;
+
+ scriptURL = CFDictionaryGetValue(currentProxy, kCFProxyAutoConfigurationURLKey);
+
+ runLoop = CFNetworkExecuteProxyAutoConfigurationURL(scriptURL, url, proxyUrlCallback,
+ &context);
+ if (runLoop != NULL) {
+ /*
+ * Despite the fact that CFNetworkExecuteProxyAutoConfigurationURL has
+ * neither a "Create" nor a "Copy" in the name, we are required to
+ * release the return CFRunLoopSourceRef <rdar://problem/5533931>.
+ */
+ CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoop, kResolveProxyRunLoopMode);
+ CFRunLoopRunInMode(kResolveProxyRunLoopMode, timeout, false);
+ CFRunLoopRemoveSource(CFRunLoopGetCurrent(), runLoop, kResolveProxyRunLoopMode);
+
+ /*
+ * Once the runloop returns, there will be either an error result or
+ * a proxies array result. Do the appropriate thing with that result.
+ */
+ if (result != NULL) {
+ if (CFGetTypeID(result) == CFArrayGetTypeID()) {
+ /*
+ * Append the new array from the PAC list - it contains
+ * only non-PAC entries.
+ */
+ CFArrayAppendArray(expandedProxiesArray, result,
+ CFRangeMake(0, CFArrayGetCount(result)));
+ }
+ CFRelease(result);
+ }
+ CFRelease(runLoop);
+ }
+ }
+ }
+ return expandedProxiesArray;
+}
+
+
+/*
+ * Class: sun_net_spi_DefaultProxySelector
+ * Method: init
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL
+Java_sun_net_spi_DefaultProxySelector_init(JNIEnv *env, jclass clazz) {
+ if (!initJavaClass(env)) {
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+}
+
+
+/*
+ * Class: sun_net_spi_DefaultProxySelector
+ * Method: getSystemProxies
+ * Signature: ([Ljava/lang/String;Ljava/lang/String;)[Ljava/net/Proxy;
+ */
+JNIEXPORT jobjectArray JNICALL
+Java_sun_net_spi_DefaultProxySelector_getSystemProxies(JNIEnv *env,
+ jobject this,
+ jstring proto,
+ jstring host)
+{
+ CFDictionaryRef proxyDicRef = NULL;
+ CFURLRef urlRef = NULL;
+ bool proxyFound = false;
+ jobjectArray proxyArray = NULL;
+ const char *cproto;
+ const char *chost;
+
+ /* Get system proxy settings */
+ proxyDicRef = CFNetworkCopySystemProxySettings();
+ if (proxyDicRef == NULL) {
+ return NULL;
+ }
+
+ /* Create CFURLRef from proto and host */
+ cproto = (*env)->GetStringUTFChars(env, proto, NULL);
+ if (cproto != NULL) {
+ chost = (*env)->GetStringUTFChars(env, host, NULL);
+ if (chost != NULL) {
+ char* uri = NULL;
+ size_t protoLen = 0;
+ size_t hostLen = 0;
+
+ protoLen = strlen(cproto);
+ hostLen = strlen(chost);
+
+ /* Construct the uri, cproto + "://" + chost */
+ uri = malloc(protoLen + hostLen + 4);
+ if (uri != NULL) {
+ memcpy(uri, cproto, protoLen);
+ memcpy(uri + protoLen, "://", 3);
+ memcpy(uri + protoLen + 3, chost, hostLen + 1);
+
+ urlRef = CFURLCreateWithBytes(NULL, (const UInt8 *) uri, strlen(uri),
+ kCFStringEncodingUTF8, NULL);
+ free(uri);
+ }
+ (*env)->ReleaseStringUTFChars(env, host, chost);
+ }
+ (*env)->ReleaseStringUTFChars(env, proto, cproto);
+ }
+ if (urlRef != NULL) {
+ CFArrayRef urlProxyArrayRef = CFNetworkCopyProxiesForURL(urlRef, proxyDicRef);
+ if (urlProxyArrayRef != NULL) {
+ CFIndex count;
+ CFIndex index;
+
+ CFArrayRef expandedProxyArray = createExpandedProxiesArray(urlProxyArrayRef, urlRef);
+ CFRelease(urlProxyArrayRef);
+
+ if (expandedProxyArray == NULL) {
+ CFRelease(urlRef);
+ CFRelease(proxyDicRef);
+ return NULL;
+ }
+
+ count = CFArrayGetCount(expandedProxyArray);
+
+ proxyArray = (*env)->NewObjectArray(env, count, proxy_class, NULL);
+ if (proxyArray != NULL || (*env)->ExceptionCheck(env)) {
+ /* Iterate over the expanded array of proxies */
+ for (index = 0; index < count ; index++) {
+ CFDictionaryRef currentProxy;
+ CFStringRef proxyType;
+ jobject proxy = NULL;
+
+ currentProxy = (CFDictionaryRef) CFArrayGetValueAtIndex(expandedProxyArray,
+ index);
+ proxyType = (CFStringRef) CFDictionaryGetValue(currentProxy, kCFProxyTypeKey);
+ if (CFEqual(proxyType, kCFProxyTypeNone)) {
+ /* This entry states no proxy, therefore just add a NO_PROXY object. */
+ proxy = (*env)->GetStaticObjectField(env, proxy_class, pr_no_proxyID);
+ } else {
+ /*
+ * Create a proxy object for this entry.
+ * Differentiate between SOCKS and HTTP type.
+ */
+ jfieldID typeID = ptype_httpID;
+ if (CFEqual(proxyType, kCFProxyTypeSOCKS)) {
+ typeID = ptype_socksID;
+ }
+ CFNumberRef portNumberRef = (CFNumberRef)CFDictionaryGetValue(currentProxy,
+ (const void*)kCFProxyPortNumberKey);
+ if (portNumberRef != NULL) {
+ int port = 0;
+ if (CFNumberGetValue(portNumberRef, kCFNumberSInt32Type, &port)) {
+ CFStringRef hostNameRef = (CFStringRef)CFDictionaryGetValue(
+ currentProxy, (const void*)kCFProxyHostNameKey);
+ if (hostNameRef != NULL) {
+ char hostNameBuffer[BUFFER_SIZE];
+ if (CFStringGetCString(hostNameRef, hostNameBuffer,
+ BUFFER_SIZE, kCFStringEncodingUTF8)) {
+ proxy = createProxy(env, typeID, &hostNameBuffer[0], port);
+ }
+ }
+ }
+ }
+ }
+ if (proxy == NULL || (*env)->ExceptionCheck(env)) {
+ proxyArray = NULL;
+ break;
+ }
+ (*env)->SetObjectArrayElement(env, proxyArray, index, proxy);
+ if ((*env)->ExceptionCheck(env)) {
+ proxyArray = NULL;
+ break;
+ }
+ }
+ }
+ CFRelease(expandedProxyArray);
+ }
+ CFRelease(urlRef);
+ }
+ CFRelease(proxyDicRef);
+
+ return proxyArray;
+}
--- a/jdk/src/java.base/share/classes/java/net/doc-files/net-properties.html Wed Feb 01 23:33:39 2017 +0300
+++ b/jdk/src/java.base/share/classes/java/net/doc-files/net-properties.html Thu Feb 02 10:28:47 2017 +0100
@@ -149,7 +149,7 @@
the <B>user.name</B> property will be used with no password.</P>
</UL>
<LI><P><B>java.net.useSystemProxies</B> (default: false)<BR>
- On recent Windows systems and on Gnome 2.x systems it is possible to
+ On Windows systems, macOS systems and on Gnome systems it is possible to
tell the java.net stack, setting this property to <B>true</B>, to use
the system proxy settings (both these systems let you set proxies
globally through their user interface). Note that this property is
--- a/jdk/src/java.base/share/classes/sun/net/spi/DefaultProxySelector.java Wed Feb 01 23:33:39 2017 +0300
+++ b/jdk/src/java.base/share/classes/sun/net/spi/DefaultProxySelector.java Thu Feb 02 10:28:47 2017 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2017, 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
@@ -30,16 +30,19 @@
import java.net.ProxySelector;
import java.net.SocketAddress;
import java.net.URI;
-import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.io.IOException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.StringJoiner;
import java.util.regex.Pattern;
+import java.util.stream.Stream;
import sun.net.NetProperties;
import sun.net.SocksProxy;
import static java.util.regex.Pattern.quote;
+import static java.util.stream.Collectors.collectingAndThen;
+import static java.util.stream.Collectors.toList;
/**
* Supports proxy settings using system properties This proxy selector
@@ -87,6 +90,8 @@
private static boolean hasSystemProxies = false;
+ private static final List<Proxy> NO_PROXY_LIST = List.of(Proxy.NO_PROXY);
+
static {
final String key = "java.net.useSystemProxies";
Boolean b = AccessController.doPrivileged(
@@ -149,8 +154,9 @@
* select() method. Where all the hard work is done.
* Build a list of proxies depending on URI.
* Since we're only providing compatibility with the system properties
- * from previous releases (see list above), that list will always
- * contain 1 single proxy, default being NO_PROXY.
+ * from previous releases (see list above), that list will typically
+ * contain one single proxy, default being NO_PROXY.
+ * If we can get a system proxy it might contain more entries.
*/
public java.util.List<Proxy> select(URI uri) {
if (uri == null) {
@@ -185,7 +191,6 @@
if (protocol == null || host == null) {
throw new IllegalArgumentException("protocol = "+protocol+" host = "+host);
}
- List<Proxy> proxyl = new ArrayList<Proxy>(1);
NonProxyInfo pinfo = null;
@@ -214,9 +219,9 @@
* System properties it does help having only 1 call to doPrivileged.
* Be mindful what you do in here though!
*/
- Proxy p = AccessController.doPrivileged(
- new PrivilegedAction<Proxy>() {
- public Proxy run() {
+ Proxy[] proxyArray = AccessController.doPrivileged(
+ new PrivilegedAction<Proxy[]>() {
+ public Proxy[] run() {
int i, j;
String phost = null;
int pport = 0;
@@ -239,8 +244,8 @@
/**
* No system property defined for that
* protocol. Let's check System Proxy
- * settings (Gnome & Windows) if we were
- * instructed to.
+ * settings (Gnome, MacOsX & Windows) if
+ * we were instructed to.
*/
if (hasSystemProxies) {
String sproto;
@@ -248,12 +253,9 @@
sproto = "socks";
else
sproto = proto;
- Proxy sproxy = getSystemProxy(sproto, urlhost);
- if (sproxy != null) {
- return sproxy;
- }
+ return getSystemProxies(sproto, urlhost);
}
- return Proxy.NO_PROXY;
+ return null;
}
// If a Proxy Host is defined for that protocol
// Let's get the NonProxyHosts property
@@ -281,7 +283,7 @@
}
}
if (shouldNotUseProxyFor(nprop.pattern, urlhost)) {
- return Proxy.NO_PROXY;
+ return null;
}
}
}
@@ -311,22 +313,24 @@
saddr = InetSocketAddress.createUnresolved(phost, pport);
// Socks is *always* the last on the list.
if (j == (props[i].length - 1)) {
- return SocksProxy.create(saddr, socksProxyVersion());
- } else {
- return new Proxy(Proxy.Type.HTTP, saddr);
+ return new Proxy[] {SocksProxy.create(saddr, socksProxyVersion())};
}
+ return new Proxy[] {new Proxy(Proxy.Type.HTTP, saddr)};
}
}
- return Proxy.NO_PROXY;
+ return null;
}});
- proxyl.add(p);
- /*
- * If no specific property was set for that URI, we should be
- * returning an iterator to an empty List.
- */
- return proxyl;
+ if (proxyArray != null) {
+ // Remove duplicate entries, while preserving order.
+ return Stream.of(proxyArray).distinct().collect(
+ collectingAndThen(toList(), Collections::unmodifiableList));
+ }
+
+ // If no specific proxy was found, return a standard list containing
+ // only one NO_PROXY entry.
+ return NO_PROXY_LIST;
}
public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
@@ -354,7 +358,7 @@
}
private static native boolean init();
- private synchronized native Proxy getSystemProxy(String protocol, String host);
+ private synchronized native Proxy[] getSystemProxies(String protocol, String host);
/**
* @return {@code true} if given this pattern for non-proxy hosts and this
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/native/libnet/proxy_util.c Thu Feb 02 10:28:47 2017 +0100
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2017, 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
+ * questions.
+ */
+
+#include "jni.h"
+#include "jni_util.h"
+
+#include "proxy_util.h"
+
+jclass proxy_class;
+jclass isaddr_class;
+jclass ptype_class;
+jmethodID isaddr_createUnresolvedID;
+jmethodID proxy_ctrID;
+jfieldID pr_no_proxyID;
+jfieldID ptype_httpID;
+jfieldID ptype_socksID;
+
+int initJavaClass(JNIEnv *env) {
+ jclass proxy_cls = NULL;
+ jclass ptype_cls = NULL;
+ jclass isaddr_cls = NULL;
+
+ // Proxy initialization
+ proxy_cls = (*env)->FindClass(env,"java/net/Proxy");
+ CHECK_NULL_RETURN(proxy_cls, 0);
+ proxy_class = (*env)->NewGlobalRef(env, proxy_cls);
+ CHECK_NULL_RETURN(proxy_class, 0);
+ proxy_ctrID = (*env)->GetMethodID(env, proxy_class, "<init>",
+ "(Ljava/net/Proxy$Type;Ljava/net/SocketAddress;)V");
+ CHECK_NULL_RETURN(proxy_ctrID, 0);
+
+ // Proxy$Type initialization
+ ptype_cls = (*env)->FindClass(env,"java/net/Proxy$Type");
+ CHECK_NULL_RETURN(ptype_cls, 0);
+ ptype_class = (*env)->NewGlobalRef(env, ptype_cls);
+ CHECK_NULL_RETURN(ptype_class, 0);
+ ptype_httpID = (*env)->GetStaticFieldID(env, ptype_class, "HTTP",
+ "Ljava/net/Proxy$Type;");
+ CHECK_NULL_RETURN(ptype_httpID, 0);
+ ptype_socksID = (*env)->GetStaticFieldID(env, ptype_class, "SOCKS",
+ "Ljava/net/Proxy$Type;");
+ CHECK_NULL_RETURN(ptype_socksID, 0);
+
+ // NO_PROXY
+ pr_no_proxyID = (*env)->GetStaticFieldID(env, proxy_class, "NO_PROXY",
+ "Ljava/net/Proxy;");
+ CHECK_NULL_RETURN(pr_no_proxyID, 0);
+
+ // InetSocketAddress initialization
+ isaddr_cls = (*env)->FindClass(env, "java/net/InetSocketAddress");
+ CHECK_NULL_RETURN(isaddr_cls, 0);
+ isaddr_class = (*env)->NewGlobalRef(env, isaddr_cls);
+ CHECK_NULL_RETURN(isaddr_class, 0);
+ isaddr_createUnresolvedID = (*env)->GetStaticMethodID(env, isaddr_class,
+ "createUnresolved",
+ "(Ljava/lang/String;I)Ljava/net/InetSocketAddress;");
+
+ return isaddr_createUnresolvedID != NULL ? 1 : 0;
+}
+
+jobject createProxy(JNIEnv *env, jfieldID ptype_ID, const char* phost, unsigned short pport) {
+ jobject jProxy = NULL;
+ jobject type_proxy = NULL;
+ type_proxy = (*env)->GetStaticObjectField(env, ptype_class, ptype_ID);
+ if (type_proxy) {
+ jstring jhost = NULL;
+ jhost = (*env)->NewStringUTF(env, phost);
+ if (jhost) {
+ jobject isa = NULL;
+ isa = (*env)->CallStaticObjectMethod(env, isaddr_class,
+ isaddr_createUnresolvedID, jhost, pport);
+ if (isa) {
+ jProxy = (*env)->NewObject(env, proxy_class, proxy_ctrID,
+ type_proxy, isa);
+ }
+ }
+ }
+ return jProxy;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/native/libnet/proxy_util.h Thu Feb 02 10:28:47 2017 +0100
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2017, 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
+ * questions.
+ */
+
+extern jclass proxy_class;
+extern jclass isaddr_class;
+extern jclass ptype_class;
+extern jmethodID isaddr_createUnresolvedID;
+extern jmethodID proxy_ctrID;
+extern jfieldID pr_no_proxyID;
+extern jfieldID ptype_httpID;
+extern jfieldID ptype_socksID;
+
+int initJavaClass(JNIEnv *env);
+
+jobject createProxy(JNIEnv *env, jfieldID ptype_ID, const char* phost, unsigned short pport);
--- a/jdk/src/java.base/unix/native/libnet/DefaultProxySelector.c Wed Feb 01 23:33:39 2017 +0300
+++ b/jdk/src/java.base/unix/native/libnet/DefaultProxySelector.c Thu Feb 02 10:28:47 2017 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2017, 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,24 +23,20 @@
* questions.
*/
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
#include "jni.h"
#include "jni_util.h"
#include "jvm.h"
#include "jvm_md.h"
-#include "jlong.h"
+
+#include "proxy_util.h"
+
#include "sun_net_spi_DefaultProxySelector.h"
-#include <dlfcn.h>
-#include <stdio.h>
-#include <stdlib.h>
-#if defined(__linux__) || defined(_ALLBSD_SOURCE)
-#include <string.h>
-#else
-#include <strings.h>
-#endif
-#ifndef CHECK_NULL_RETURN
-#define CHECK_NULL_RETURN(x, y) if ((x) == NULL) return y;
-#endif
/**
* These functions are used by the sun.net.spi.DefaultProxySelector class
@@ -112,43 +108,11 @@
static g_network_address_get_port_func* g_network_address_get_port = NULL;
static g_strfreev_func* g_strfreev = NULL;
-
-static jclass proxy_class;
-static jclass isaddr_class;
-static jclass ptype_class;
-static jmethodID isaddr_createUnresolvedID;
-static jmethodID proxy_ctrID;
-static jfieldID ptype_httpID;
-static jfieldID ptype_socksID;
-
-
static void* gconf_client = NULL;
static int use_gproxyResolver = 0;
static int use_gconf = 0;
-static jobject createProxy(JNIEnv *env, jfieldID ptype_ID,
- const char* phost, unsigned short pport)
-{
- jobject jProxy = NULL;
- jobject type_proxy = NULL;
- type_proxy = (*env)->GetStaticObjectField(env, ptype_class, ptype_ID);
- if (type_proxy) {
- jstring jhost = NULL;
- jhost = (*env)->NewStringUTF(env, phost);
- if (jhost) {
- jobject isa = NULL;
- isa = (*env)->CallStaticObjectMethod(env, isaddr_class,
- isaddr_createUnresolvedID, jhost, pport);
- if (isa) {
- jProxy = (*env)->NewObject(env, proxy_class, proxy_ctrID,
- type_proxy, isa);
- }
- }
- }
- return jProxy;
-}
-
static int initGConf() {
/**
* Let's try to load GConf-2 library
@@ -196,18 +160,18 @@
return 0;
}
-static jobject getProxyByGConf(JNIEnv *env, const char* cproto,
- const char* chost)
+static jobjectArray getProxyByGConf(JNIEnv *env, const char* cproto,
+ const char* chost)
{
char *phost = NULL;
char *mode = NULL;
int pport = 0;
int use_proxy = 0;
int use_same_proxy = 0;
- jobject proxy = NULL;
+ jobjectArray proxy_array = NULL;
jfieldID ptype_ID = ptype_httpID;
- // We only check manual proxy configurations
+ /* We only check manual proxy configurations */
mode = (*my_get_string_func)(gconf_client, "/system/proxy/mode", NULL);
if (mode && !strcasecmp(mode, "manual")) {
/*
@@ -293,7 +257,7 @@
char *s;
/**
- * check for the exclude list (aka "No Proxy For" list).
+ * Check for the exclude list (aka "No Proxy For" list).
* It's a list of comma separated suffixes (e.g. domain name).
*/
noproxyfor = (*my_get_string_func)(gconf_client, "/system/proxy/no_proxy_for", NULL);
@@ -313,11 +277,25 @@
s = strtok_r(NULL, ", ", tmpbuf);
}
}
- if (use_proxy)
+ if (use_proxy) {
+ jobject proxy = NULL;
+ /* create a proxy array with one element. */
+ proxy_array = (*env)->NewObjectArray(env, 1, proxy_class, NULL);
+ if (proxy_array == NULL || (*env)->ExceptionCheck(env)) {
+ return NULL;
+ }
proxy = createProxy(env, ptype_ID, phost, pport);
+ if (proxy == NULL || (*env)->ExceptionCheck(env)) {
+ return NULL;
+ }
+ (*env)->SetObjectArrayElement(env, proxy_array, 0, proxy);
+ if ((*env)->ExceptionCheck(env)) {
+ return NULL;
+ }
+ }
}
- return proxy;
+ return proxy_array;
}
static int initGProxyResolver() {
@@ -371,8 +349,8 @@
return 1;
}
-static jobject getProxyByGProxyResolver(JNIEnv *env, const char* cproto,
- const char* chost)
+static jobjectArray getProxyByGProxyResolver(JNIEnv *env, const char *cproto,
+ const char *chost)
{
GProxyResolver* resolver = NULL;
char** proxies = NULL;
@@ -382,19 +360,19 @@
size_t hostLen = 0;
char* uri = NULL;
- jobject jProxy = NULL;
+ jobjectArray proxy_array = NULL;
resolver = (*g_proxy_resolver_get_default)();
if (resolver == NULL) {
return NULL;
}
- // Construct the uri, cproto + "://" + chost
+ /* Construct the uri, cproto + "://" + chost */
protoLen = strlen(cproto);
hostLen = strlen(chost);
uri = malloc(protoLen + hostLen + 4);
if (!uri) {
- // Out of memory
+ /* Out of memory */
return NULL;
}
memcpy(uri, cproto, protoLen);
@@ -414,22 +392,56 @@
if (proxies) {
if (!error) {
int i;
- for(i = 0; proxies[i] && !jProxy; i++) {
- if (strcmp(proxies[i], "direct://")) {
- GSocketConnectable* conn =
- (*g_network_address_parse_uri)(proxies[i], 0,
- &error);
- if (conn && !error) {
- const char* phost = NULL;
- unsigned short pport = 0;
- phost = (*g_network_address_get_hostname)(conn);
- pport = (*g_network_address_get_port)(conn);
- if (phost && pport > 0) {
- jfieldID ptype_ID = ptype_httpID;
- if (!strncmp(proxies[i], "socks", 5))
- ptype_ID = ptype_socksID;
+ int nr_proxies = 0;
+ char** p = proxies;
+ /* count the elements in the null terminated string vector. */
+ while (*p) {
+ nr_proxies++;
+ p++;
+ }
+ /* create a proxy array that has to be filled. */
+ proxy_array = (*env)->NewObjectArray(env, nr_proxies, proxy_class, NULL);
+ if (proxy_array != NULL && !(*env)->ExceptionCheck(env)) {
+ for (i = 0; proxies[i]; i++) {
+ if (strncmp(proxies[i], "direct://", 9)) {
+ GSocketConnectable* conn =
+ (*g_network_address_parse_uri)(proxies[i], 0,
+ &error);
+ if (conn && !error) {
+ const char *phost = NULL;
+ unsigned short pport = 0;
+ phost = (*g_network_address_get_hostname)(conn);
+ pport = (*g_network_address_get_port)(conn);
+ if (phost && pport > 0) {
+ jobject proxy = NULL;
+ jfieldID ptype_ID = ptype_httpID;
+ if (!strncmp(proxies[i], "socks", 5))
+ ptype_ID = ptype_socksID;
- jProxy = createProxy(env, ptype_ID, phost, pport);
+ proxy = createProxy(env, ptype_ID, phost, pport);
+ if (proxy == NULL || (*env)->ExceptionCheck(env)) {
+ proxy_array = NULL;
+ break;
+ }
+ (*env)->SetObjectArrayElement(env, proxy_array, i, proxy);
+ if ((*env)->ExceptionCheck(env)) {
+ proxy_array = NULL;
+ break;
+ }
+ }
+ }
+ } else {
+ /* direct connection - no proxy */
+ jobject proxy = (*env)->GetStaticObjectField(env, proxy_class,
+ pr_no_proxyID);
+ if (proxy == NULL || (*env)->ExceptionCheck(env)) {
+ proxy_array = NULL;
+ break;
+ }
+ (*env)->SetObjectArrayElement(env, proxy_array, i, proxy);
+ if ((*env)->ExceptionCheck(env)) {
+ proxy_array = NULL;
+ break;
}
}
}
@@ -438,48 +450,9 @@
(*g_strfreev)(proxies);
}
- return jProxy;
+ return proxy_array;
}
-static int initJavaClass(JNIEnv *env) {
- jclass proxy_cls = NULL;
- jclass ptype_cls = NULL;
- jclass isaddr_cls = NULL;
-
- // Proxy initialization
- proxy_cls = (*env)->FindClass(env,"java/net/Proxy");
- CHECK_NULL_RETURN(proxy_cls, 0);
- proxy_class = (*env)->NewGlobalRef(env, proxy_cls);
- CHECK_NULL_RETURN(proxy_class, 0);
- proxy_ctrID = (*env)->GetMethodID(env, proxy_class, "<init>",
- "(Ljava/net/Proxy$Type;Ljava/net/SocketAddress;)V");
- CHECK_NULL_RETURN(proxy_ctrID, 0);
-
- // Proxy$Type initialization
- ptype_cls = (*env)->FindClass(env,"java/net/Proxy$Type");
- CHECK_NULL_RETURN(ptype_cls, 0);
- ptype_class = (*env)->NewGlobalRef(env, ptype_cls);
- CHECK_NULL_RETURN(ptype_class, 0);
- ptype_httpID = (*env)->GetStaticFieldID(env, ptype_class, "HTTP",
- "Ljava/net/Proxy$Type;");
- CHECK_NULL_RETURN(ptype_httpID, 0);
- ptype_socksID = (*env)->GetStaticFieldID(env, ptype_class, "SOCKS",
- "Ljava/net/Proxy$Type;");
- CHECK_NULL_RETURN(ptype_socksID, 0);
-
- // InetSocketAddress initialization
- isaddr_cls = (*env)->FindClass(env, "java/net/InetSocketAddress");
- CHECK_NULL_RETURN(isaddr_cls, 0);
- isaddr_class = (*env)->NewGlobalRef(env, isaddr_cls);
- CHECK_NULL_RETURN(isaddr_class, 0);
- isaddr_createUnresolvedID = (*env)->GetStaticMethodID(env, isaddr_class,
- "createUnresolved",
- "(Ljava/lang/String;I)Ljava/net/InetSocketAddress;");
-
- return isaddr_createUnresolvedID != NULL ? 1 : 0;
-}
-
-
/*
* Class: sun_net_spi_DefaultProxySelector
* Method: init
@@ -500,14 +473,14 @@
/*
* Class: sun_net_spi_DefaultProxySelector
- * Method: getSystemProxy
- * Signature: ([Ljava/lang/String;Ljava/lang/String;)Ljava/net/Proxy;
+ * Method: getSystemProxies
+ * Signature: ([Ljava/lang/String;Ljava/lang/String;)[Ljava/net/Proxy;
*/
-JNIEXPORT jobject JNICALL
-Java_sun_net_spi_DefaultProxySelector_getSystemProxy(JNIEnv *env,
- jobject this,
- jstring proto,
- jstring host)
+JNIEXPORT jobjectArray JNICALL
+Java_sun_net_spi_DefaultProxySelector_getSystemProxies(JNIEnv *env,
+ jobject this,
+ jstring proto,
+ jstring host)
{
const char* cproto;
const char* chost;
@@ -515,7 +488,7 @@
jboolean isProtoCopy;
jboolean isHostCopy;
- jobject proxy = NULL;
+ jobjectArray proxyArray = NULL;
cproto = (*env)->GetStringUTFChars(env, proto, &isProtoCopy);
@@ -523,16 +496,15 @@
chost = (*env)->GetStringUTFChars(env, host, &isHostCopy);
if (chost != NULL) {
if (use_gproxyResolver)
- proxy = getProxyByGProxyResolver(env, cproto, chost);
+ proxyArray = getProxyByGProxyResolver(env, cproto, chost);
else if (use_gconf)
- proxy = getProxyByGConf(env, cproto, chost);
-
+ proxyArray = getProxyByGConf(env, cproto, chost);
if (isHostCopy == JNI_TRUE)
(*env)->ReleaseStringUTFChars(env, host, chost);
}
if (isProtoCopy == JNI_TRUE)
(*env)->ReleaseStringUTFChars(env, proto, cproto);
}
- return proxy;
+ return proxyArray;
}
--- a/jdk/src/java.base/windows/native/libnet/DefaultProxySelector.c Wed Feb 01 23:33:39 2017 +0300
+++ b/jdk/src/java.base/windows/native/libnet/DefaultProxySelector.c Thu Feb 02 10:28:47 2017 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2017, 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,26 +24,24 @@
*/
#include <windows.h>
+#include <Winhttp.h>
+
#include "jni.h"
#include "jni_util.h"
#include "jvm.h"
-#include "jlong.h"
+
+#include "proxy_util.h"
+
#include "sun_net_spi_DefaultProxySelector.h"
-/**
+/*
* These functions are used by the sun.net.spi.DefaultProxySelector class
* to access some platform specific settings.
- * This is the Windows code using the registry settings.
+ * On Windows use WinHTTP functions to get the system settings.
*/
-static jclass proxy_class;
-static jclass isaddr_class;
-static jclass ptype_class;
-static jmethodID isaddr_createUnresolvedID;
-static jmethodID proxy_ctrID;
-static jfieldID pr_no_proxyID;
-static jfieldID ptype_httpID;
-static jfieldID ptype_socksID;
+/* Keep one static session for all requests. */
+static HINTERNET session = NULL;
/*
* Class: sun_net_spi_DefaultProxySelector
@@ -52,233 +50,327 @@
*/
JNIEXPORT jboolean JNICALL
Java_sun_net_spi_DefaultProxySelector_init(JNIEnv *env, jclass clazz) {
- HKEY hKey;
- LONG ret;
- jclass cls;
+
+ /*
+ * Get one WinHTTP session handle to initialize the WinHTTP internal data
+ * structures. Keep and use only this one for the whole life time.
+ */
+ session = WinHttpOpen(L"Only used internal", /* we need no real agent string here */
+ WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
+ WINHTTP_NO_PROXY_NAME,
+ WINHTTP_NO_PROXY_BYPASS,
+ 0);
+ if (session == NULL) {
+ return JNI_FALSE;
+ }
+
+ if (!initJavaClass(env)) {
+ return JNI_FALSE;
+ }
+
+ return JNI_TRUE;
+}
- /**
- * Get all the method & field IDs for later use.
- */
- cls = (*env)->FindClass(env,"java/net/Proxy");
- CHECK_NULL_RETURN(cls, JNI_FALSE);
- proxy_class = (*env)->NewGlobalRef(env, cls);
- CHECK_NULL_RETURN(proxy_class, JNI_FALSE);
- cls = (*env)->FindClass(env,"java/net/Proxy$Type");
- CHECK_NULL_RETURN(cls, JNI_FALSE);
- ptype_class = (*env)->NewGlobalRef(env, cls);
- CHECK_NULL_RETURN(ptype_class, JNI_FALSE);
- cls = (*env)->FindClass(env, "java/net/InetSocketAddress");
- CHECK_NULL_RETURN(cls, JNI_FALSE);
- isaddr_class = (*env)->NewGlobalRef(env, cls);
- CHECK_NULL_RETURN(isaddr_class, JNI_FALSE);
- proxy_ctrID = (*env)->GetMethodID(env, proxy_class, "<init>",
- "(Ljava/net/Proxy$Type;Ljava/net/SocketAddress;)V");
- CHECK_NULL_RETURN(proxy_ctrID, JNI_FALSE);
- pr_no_proxyID = (*env)->GetStaticFieldID(env, proxy_class, "NO_PROXY", "Ljava/net/Proxy;");
- CHECK_NULL_RETURN(pr_no_proxyID, JNI_FALSE);
- ptype_httpID = (*env)->GetStaticFieldID(env, ptype_class, "HTTP", "Ljava/net/Proxy$Type;");
- CHECK_NULL_RETURN(ptype_httpID, JNI_FALSE);
- ptype_socksID = (*env)->GetStaticFieldID(env, ptype_class, "SOCKS", "Ljava/net/Proxy$Type;");
- CHECK_NULL_RETURN(ptype_socksID, JNI_FALSE);
- isaddr_createUnresolvedID = (*env)->GetStaticMethodID(env, isaddr_class, "createUnresolved",
- "(Ljava/lang/String;I)Ljava/net/InetSocketAddress;");
- CHECK_NULL_RETURN(isaddr_createUnresolvedID, JNI_FALSE);
+
+#define MAX_STR_LEN 1024
+
+/* A linked list element for a proxy */
+typedef struct list_item {
+ wchar_t *host;
+ int port;
+ struct list_item *next;
+} list_item;
- /**
- * Let's see if we can find the proper Registry entry.
- */
- ret = RegOpenKeyEx(HKEY_CURRENT_USER,
- "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings",
- 0, KEY_READ, (PHKEY)&hKey);
- if (ret == ERROR_SUCCESS) {
- RegCloseKey(hKey);
- /**
- * It worked, we can probably rely on it then.
- */
- return JNI_TRUE;
- }
-
- return JNI_FALSE;
+/* Free the linked list */
+static void freeList(list_item *head) {
+ list_item *next = NULL;
+ list_item *current = head;
+ while (current != NULL) {
+ next = current->next;
+ free(current->host);
+ free(current);
+ current = next;
+ }
}
-#define MAX_STR_LEN 1024
+
+/*
+ * Creates a linked list of list_item elements that has to be freed later on.
+ * Returns the size of the array as int.
+ */
+static int createProxyList(LPWSTR win_proxy, const WCHAR *pproto, list_item **head) {
+ static const wchar_t separators[] = L"\t\r\n ;";
+ list_item *current = NULL;
+ int nr_elems = 0;
+ wchar_t *context = NULL;
+ wchar_t *current_proxy = NULL;
+ BOOL error = FALSE;
+
+ /*
+ * The proxy server list contains one or more of the following strings
+ * separated by semicolons or whitespace:
+ * ([<scheme>=][<scheme>"://"]<server>[":"<port>])
+ */
+ current_proxy = wcstok_s(win_proxy, separators, &context);
+ while (current_proxy != NULL) {
+ LPWSTR pport;
+ LPWSTR phost;
+ int portVal = 0;
+ wchar_t *next_proxy = NULL;
+ list_item *proxy = NULL;
+ wchar_t* pos = NULL;
+
+ /* Filter based on the scheme, if there is one */
+ pos = wcschr(current_proxy, L'=');
+ if (pos) {
+ *pos = L'\0';
+ if (wcscmp(current_proxy, pproto) != 0) {
+ current_proxy = wcstok_s(NULL, separators, &context);
+ continue;
+ }
+ current_proxy = pos + 1;
+ }
+
+ /* Let's check for a scheme and ignore it. */
+ if ((phost = wcsstr(current_proxy, L"://")) != NULL) {
+ phost += 3;
+ } else {
+ phost = current_proxy;
+ }
+
+ /* Get the port */
+ pport = wcschr(phost, L':');
+ if (pport != NULL) {
+ *pport = 0;
+ pport++;
+ swscanf(pport, L"%d", &portVal);
+ }
+
+ proxy = (list_item *)malloc(sizeof(list_item));
+ if (proxy != NULL) {
+ proxy->next = NULL;
+ proxy->port = portVal;
+ proxy->host = _wcsdup(phost);
+
+ if (proxy->host != NULL) {
+ if (*head == NULL) {
+ *head = proxy; /* first elem */
+ }
+ if (current != NULL) {
+ current->next = proxy;
+ }
+ current = proxy;
+ nr_elems++;
+ } else {
+ free(proxy); /* cleanup */
+ }
+ }
+ /* goto next proxy if available... */
+ current_proxy = wcstok_s(NULL, separators, &context);
+ }
+ return nr_elems;
+}
+
+
/*
* Class: sun_net_spi_DefaultProxySelector
- * Method: getSystemProxy
- * Signature: ([Ljava/lang/String;Ljava/lang/String;)Ljava/net/Proxy;
+ * Method: getSystemProxies
+ * Signature: ([Ljava/lang/String;Ljava/lang/String;)[Ljava/net/Proxy;
*/
-JNIEXPORT jobject JNICALL
-Java_sun_net_spi_DefaultProxySelector_getSystemProxy(JNIEnv *env,
- jobject this,
- jstring proto,
- jstring host)
+JNIEXPORT jobjectArray JNICALL
+Java_sun_net_spi_DefaultProxySelector_getSystemProxies(JNIEnv *env,
+ jobject this,
+ jstring proto,
+ jstring host)
{
- jobject isa = NULL;
- jobject proxy = NULL;
- jobject type_proxy = NULL;
- jobject no_proxy = NULL;
- jboolean isCopy;
- HKEY hKey;
- LONG ret;
- const char* cproto;
- const char* urlhost;
- char pproto[MAX_STR_LEN];
- char regserver[MAX_STR_LEN];
- char override[MAX_STR_LEN];
- char *s, *s2;
- char *ctx = NULL;
- int pport = 0;
- int defport = 0;
- char *phost;
+ jobjectArray proxy_array = NULL;
+ jobject type_proxy = NULL;
+ LPCWSTR lpProto;
+ LPCWSTR lpHost;
+ list_item *head = NULL;
+
+ BOOL use_auto_proxy = FALSE;
+ WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ie_proxy_config;
+ WINHTTP_AUTOPROXY_OPTIONS auto_proxy_options;
+ WINHTTP_PROXY_INFO proxy_info;
+ LPWSTR win_proxy = NULL;
+ LPWSTR win_bypass_proxy = NULL;
+
+ memset(&ie_proxy_config, 0, sizeof(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG));
+ memset(&auto_proxy_options, 0, sizeof(WINHTTP_AUTOPROXY_OPTIONS));
+ memset(&proxy_info, 0, sizeof(WINHTTP_PROXY_INFO));
+
+ lpHost = (*env)->GetStringChars(env, host, NULL);
+ if (lpHost == NULL) {
+ if (!(*env)->ExceptionCheck(env))
+ JNU_ThrowOutOfMemoryError(env, NULL);
+ return NULL;
+ }
- /**
- * Let's open the Registry entry. We'll check a few values in it:
- *
- * - ProxyEnable: 0 means no proxy, 1 means use the proxy
- * - ProxyServer: a string that can take 2 forms:
- * "server[:port]"
- * or
- * "protocol1=server[:port][;protocol2=server[:port]]..."
- * - ProxyOverride: a string containing a list of prefixes for hostnames.
- * e.g.: hoth;localhost;<local>
- */
- ret = RegOpenKeyEx(HKEY_CURRENT_USER,
- "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings",
- 0, KEY_READ, (PHKEY)&hKey);
- if (ret == ERROR_SUCCESS) {
- DWORD dwLen;
- DWORD dwProxyEnabled;
- ULONG ulType;
- dwLen = sizeof(dwProxyEnabled);
+ lpProto = (*env)->GetStringChars(env, proto, NULL);
+ if (lpProto == NULL) {
+ (*env)->ReleaseStringChars(env, host, lpHost);
+ if (!(*env)->ExceptionCheck(env))
+ JNU_ThrowOutOfMemoryError(env, NULL);
+ return NULL;
+ }
+
+ if (WinHttpGetIEProxyConfigForCurrentUser(&ie_proxy_config) == FALSE) {
+ /* cleanup and exit */
+ (*env)->ReleaseStringChars(env, host, lpHost);
+ (*env)->ReleaseStringChars(env, proto, lpProto);
+ return NULL;
+ }
+
+ if (ie_proxy_config.fAutoDetect) {
+ /* Windows uses WPAD */
+ auto_proxy_options.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP |
+ WINHTTP_AUTO_DETECT_TYPE_DNS_A;
+ auto_proxy_options.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT;
+ auto_proxy_options.fAutoLogonIfChallenged = TRUE;
+ use_auto_proxy = TRUE;
+ } else if (ie_proxy_config.lpszAutoConfigUrl != NULL) {
+ /* Windows uses PAC file */
+ auto_proxy_options.lpszAutoConfigUrl = ie_proxy_config.lpszAutoConfigUrl;
+ auto_proxy_options.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL;
+ use_auto_proxy = TRUE;
+ } else if (ie_proxy_config.lpszProxy != NULL) {
+ /* Windows uses manually entered proxy. */
+ use_auto_proxy = FALSE;
+ win_bypass_proxy = ie_proxy_config.lpszProxyBypass;
+ win_proxy = ie_proxy_config.lpszProxy;
+ }
- /**
- * Let's see if the proxy settings are to be used.
- */
- ret = RegQueryValueEx(hKey, "ProxyEnable", NULL, &ulType,
- (LPBYTE)&dwProxyEnabled, &dwLen);
- if ((ret == ERROR_SUCCESS) && (dwProxyEnabled > 0)) {
- /*
- * Yes, ProxyEnable == 1
- */
- dwLen = sizeof(override);
- override[0] = 0;
- ret = RegQueryValueEx(hKey, "ProxyOverride", NULL, &ulType,
- (LPBYTE)&override, &dwLen);
- dwLen = sizeof(regserver);
- regserver[0] = 0;
- ret = RegQueryValueEx(hKey, "ProxyServer", NULL, &ulType,
- (LPBYTE)®server, &dwLen);
- RegCloseKey(hKey);
- if (ret == ERROR_SUCCESS) {
- if (strlen(override) > 0) {
- /**
- * we did get ProxyServer and may have an override.
- * So let's check the override list first, by walking down the list
- * The semicolons (;) separated entries have to be matched with the
- * the beginning of the hostname.
- */
- s = strtok_s(override, "; ", &ctx);
- urlhost = (*env)->GetStringUTFChars(env, host, &isCopy);
- if (urlhost == NULL) {
- if (!(*env)->ExceptionCheck(env))
- JNU_ThrowOutOfMemoryError(env, NULL);
- return NULL;
- }
- while (s != NULL) {
- if (strncmp(s, urlhost, strlen(s)) == 0) {
- /**
- * the URL host name matches with one of the prefixes,
- * therefore we have to use a direct connection.
- */
- if (isCopy == JNI_TRUE)
- (*env)->ReleaseStringUTFChars(env, host, urlhost);
- goto noproxy;
+ if (use_auto_proxy) {
+ WCHAR url[MAX_STR_LEN];
+ /* Create url for WinHttpGetProxyForUrl */
+ _snwprintf(url, sizeof(url) - 1, L"%s://%s", lpProto, lpHost);
+ /* Get proxy for URL from Windows */
+ use_auto_proxy = WinHttpGetProxyForUrl(session, &url[0], &auto_proxy_options, &proxy_info);
+ if (use_auto_proxy) {
+ win_proxy = proxy_info.lpszProxy;
+ win_bypass_proxy = proxy_info.lpszProxyBypass;
+ }
+ }
+
+ /* Check the bypass entry. */
+ if (NULL != win_bypass_proxy) {
+ /*
+ * From MSDN:
+ * The proxy bypass list contains one or more server names separated by
+ * semicolons or whitespace. The proxy bypass list can also contain the
+ * string "<local>" to indicate that all local intranet sites are
+ * bypassed. Local intranet sites are considered to be all servers that
+ * do not contain a period in their name.
+ */
+ wchar_t *context = NULL;
+ LPWSTR s = wcstok_s(win_bypass_proxy, L"; ", &context);
+
+ while (s != NULL) {
+ size_t maxlen = wcslen(s);
+ if (wcsncmp(s, lpHost, maxlen) == 0) {
+ /*
+ * The URL host name matches with one of the prefixes, use a
+ * direct connection.
+ */
+ goto noproxy;
}
- s = strtok_s(NULL, "; ", &ctx);
- }
- if (isCopy == JNI_TRUE)
- (*env)->ReleaseStringUTFChars(env, host, urlhost);
+ if (wcsncmp(s, L"<local>", maxlen) == 0) {
+ /*
+ * All local intranet sites are bypassed - Microsoft consider all
+ * servers that do not contain a period in their name to be local.
+ */
+ if (wcschr(lpHost, '.') == NULL) {
+ goto noproxy;
+ }
+ }
+ s = wcstok_s(NULL, L"; ", &context);
+ }
+ }
+
+ if (win_proxy != NULL) {
+ wchar_t *context = NULL;
+ int defport = 0;
+ int nr_elems = 0;
+
+ /* Set the default port value & proxy type from protocol. */
+ if ((wcscmp(lpProto, L"http") == 0) ||
+ (wcscmp(lpProto, L"ftp") == 0) ||
+ (wcscmp(lpProto, L"gopher") == 0))
+ defport = 80;
+ if (wcscmp(lpProto, L"https") == 0)
+ defport = 443;
+ if (wcscmp(lpProto, L"socks") == 0) {
+ defport = 1080;
+ type_proxy = (*env)->GetStaticObjectField(env, ptype_class, ptype_socksID);
+ } else {
+ type_proxy = (*env)->GetStaticObjectField(env, ptype_class, ptype_httpID);
+ }
+ if (type_proxy == NULL || (*env)->ExceptionCheck(env)) {
+ goto noproxy;
}
- cproto = (*env)->GetStringUTFChars(env, proto, &isCopy);
- if (cproto == NULL) {
- if (!(*env)->ExceptionCheck(env))
- JNU_ThrowOutOfMemoryError(env, NULL);
- return NULL;
- }
-
- /*
- * Set default port value & proxy type from protocol.
- */
- if ((strcmp(cproto, "http") == 0) ||
- (strcmp(cproto, "ftp") == 0) ||
- (strcmp(cproto, "gopher") == 0))
- defport = 80;
- if (strcmp(cproto, "https") == 0)
- defport = 443;
- if (strcmp(cproto, "socks") == 0) {
- defport = 1080;
- type_proxy = (*env)->GetStaticObjectField(env, ptype_class, ptype_socksID);
- } else {
- type_proxy = (*env)->GetStaticObjectField(env, ptype_class, ptype_httpID);
- }
+ nr_elems = createProxyList(win_proxy, lpProto, &head);
+ if (nr_elems != 0 && head != NULL) {
+ int index = 0;
+ proxy_array = (*env)->NewObjectArray(env, nr_elems, proxy_class, NULL);
+ if (proxy_array == NULL || (*env)->ExceptionCheck(env)) {
+ goto noproxy;
+ }
+ while (head != NULL && index < nr_elems) {
+ jstring jhost;
+ jobject isa;
+ jobject proxy;
- sprintf(pproto,"%s=", cproto);
- if (isCopy == JNI_TRUE)
- (*env)->ReleaseStringUTFChars(env, proto, cproto);
- /**
- * Let's check the protocol specific form first.
- */
- if ((s = strstr(regserver, pproto)) != NULL) {
- s += strlen(pproto);
- } else {
- /**
- * If we couldn't find *this* protocol but the string is in the
- * protocol specific format, then don't use proxy
- */
- if (strchr(regserver, '=') != NULL)
- goto noproxy;
- s = regserver;
+ if (head->host != NULL && proxy_array != NULL) {
+ /* Let's create the appropriate Proxy object then. */
+ if (head->port == 0) {
+ head->port = defport;
+ }
+ jhost = (*env)->NewString(env, head->host, (jsize)wcslen(head->host));
+ if (jhost == NULL || (*env)->ExceptionCheck(env)) {
+ proxy_array = NULL;
+ }
+ isa = (*env)->CallStaticObjectMethod(env, isaddr_class,
+ isaddr_createUnresolvedID, jhost,
+ head->port);
+ if (isa == NULL || (*env)->ExceptionCheck(env)) {
+ proxy_array = NULL;
+ }
+ proxy = (*env)->NewObject(env, proxy_class, proxy_ctrID, type_proxy, isa);
+ if (proxy == NULL || (*env)->ExceptionCheck(env)) {
+ proxy_array = NULL;
+ }
+ (*env)->SetObjectArrayElement(env, proxy_array, index, proxy);
+ if ((*env)->ExceptionCheck(env)) {
+ proxy_array = NULL;
+ }
+ index++;
+ }
+ head = head->next;
+ }
}
- s2 = strchr(s, ';');
- if (s2 != NULL)
- *s2 = 0;
-
- /**
- * Is there a port specified?
- */
- s2 = strchr(s, ':');
- if (s2 != NULL) {
- *s2 = 0;
- s2++;
- sscanf(s2, "%d", &pport);
- }
- phost = s;
-
- if (phost != NULL) {
- /**
- * Let's create the appropriate Proxy object then.
- */
- jstring jhost;
- if (pport == 0)
- pport = defport;
- jhost = (*env)->NewStringUTF(env, phost);
- CHECK_NULL_RETURN(jhost, NULL);
- isa = (*env)->CallStaticObjectMethod(env, isaddr_class, isaddr_createUnresolvedID, jhost, pport);
- CHECK_NULL_RETURN(isa, NULL);
- proxy = (*env)->NewObject(env, proxy_class, proxy_ctrID, type_proxy, isa);
- return proxy;
- }
- }
- } else {
- /* ProxyEnable == 0 or Query failed */
- /* close the handle to the registry key */
- RegCloseKey(hKey);
}
- }
noproxy:
- no_proxy = (*env)->GetStaticObjectField(env, proxy_class, pr_no_proxyID);
- return no_proxy;
+ if (head != NULL) {
+ freeList(head);
+ }
+ if (proxy_info.lpszProxy != NULL)
+ GlobalFree(proxy_info.lpszProxy);
+ if (proxy_info.lpszProxyBypass != NULL)
+ GlobalFree(proxy_info.lpszProxyBypass);
+ if (ie_proxy_config.lpszAutoConfigUrl != NULL)
+ GlobalFree(ie_proxy_config.lpszAutoConfigUrl);
+ if (ie_proxy_config.lpszProxy != NULL)
+ GlobalFree(ie_proxy_config.lpszProxy);
+ if (ie_proxy_config.lpszProxyBypass != NULL)
+ GlobalFree(ie_proxy_config.lpszProxyBypass);
+ if (lpHost != NULL)
+ (*env)->ReleaseStringChars(env, host, lpHost);
+ if (lpProto != NULL)
+ (*env)->ReleaseStringChars(env, proto, lpProto);
+
+ return proxy_array;
}
--- a/jdk/test/java/net/ProxySelector/SystemProxies.java Wed Feb 01 23:33:39 2017 +0300
+++ b/jdk/test/java/net/ProxySelector/SystemProxies.java Thu Feb 02 10:28:47 2017 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2017, 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
@@ -22,9 +22,13 @@
*/
/*
- * This is a manual test to determine the proxies set on the system for various
- * protocols. See bug 6912868.
+ * @test
+ * @bug 6912868 8170868
+ * @summary Basic test to provide some coverage of system proxy code. Will
+ * always pass. Should be run manually for specific systems to inspect output.
+ * @run main/othervm -Djava.net.useSystemProxies=true SystemProxies
*/
+
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.URI;