8170868: DefaultProxySelector should use system defaults on Windows, MacOS and Gnome

Reviewed-by: chegar, simonis, clanger, stuefe, erikj
This commit is contained in:
Arno Zeller 2017-02-02 10:28:47 +01:00 committed by Christoph Langer
parent 64dd421a20
commit 4d92a188b2
10 changed files with 878 additions and 383 deletions

View File

@ -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 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBNET, \
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" \

View File

@ -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 @@ SUNWprivate_1.1 {
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;

View File

@ -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;
}

View File

@ -149,7 +149,7 @@ of proxies.</P>
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

View File

@ -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.Proxy;
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 @@ public class DefaultProxySelector extends ProxySelector {
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 @@ public class DefaultProxySelector extends ProxySelector {
* 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 @@ public class DefaultProxySelector extends ProxySelector {
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 @@ public class DefaultProxySelector extends ProxySelector {
* 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 @@ public class DefaultProxySelector extends ProxySelector {
/**
* 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 @@ public class DefaultProxySelector extends ProxySelector {
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 @@ public class DefaultProxySelector extends ProxySelector {
}
}
if (shouldNotUseProxyFor(nprop.pattern, urlhost)) {
return Proxy.NO_PROXY;
return null;
}
}
}
@ -311,22 +313,24 @@ public class DefaultProxySelector extends ProxySelector {
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 @@ public class DefaultProxySelector extends ProxySelector {
}
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

View File

@ -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;
}

View File

@ -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);

View File

@ -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 "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
#include "proxy_util.h"
#include "sun_net_spi_DefaultProxySelector.h"
/**
* These functions are used by the sun.net.spi.DefaultProxySelector class
@ -112,43 +108,11 @@ static g_network_address_get_hostname_func* g_network_address_get_hostname = NUL
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 @@ static int initGConf() {
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 @@ static jobject getProxyByGConf(JNIEnv *env, const char* cproto,
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 @@ static jobject getProxyByGConf(JNIEnv *env, const char* cproto,
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 @@ static int initGProxyResolver() {
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 @@ static jobject getProxyByGProxyResolver(JNIEnv *env, const char* cproto,
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 @@ static jobject getProxyByGProxyResolver(JNIEnv *env, const char* cproto,
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 @@ static jobject getProxyByGProxyResolver(JNIEnv *env, const char* cproto,
(*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 @@ Java_sun_net_spi_DefaultProxySelector_init(JNIEnv *env, jclass clazz) {
/*
* 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 @@ Java_sun_net_spi_DefaultProxySelector_getSystemProxy(JNIEnv *env,
jboolean isProtoCopy;
jboolean isHostCopy;
jobject proxy = NULL;
jobjectArray proxyArray = NULL;
cproto = (*env)->GetStringUTFChars(env, proto, &isProtoCopy);
@ -523,16 +496,15 @@ Java_sun_net_spi_DefaultProxySelector_getSystemProxy(JNIEnv *env,
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;
}

View File

@ -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 @@ static jfieldID ptype_socksID;
*/
JNIEXPORT jboolean JNICALL
Java_sun_net_spi_DefaultProxySelector_init(JNIEnv *env, jclass clazz) {
HKEY hKey;
LONG ret;
jclass cls;
/**
* 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);
/**
* 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.
/*
* Get one WinHTTP session handle to initialize the WinHTTP internal data
* structures. Keep and use only this one for the whole life time.
*/
return JNI_TRUE;
}
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;
}
return JNI_FALSE;
if (!initJavaClass(env)) {
return JNI_FALSE;
}
return JNI_TRUE;
}
#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;
/* 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;
}
}
/*
* 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;
/**
* 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);
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;
/**
* 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)&regserver, &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;
}
s = strtok_s(NULL, "; ", &ctx);
}
if (isCopy == JNI_TRUE)
(*env)->ReleaseStringUTFChars(env, host, urlhost);
}
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));
cproto = (*env)->GetStringUTFChars(env, proto, &isCopy);
if (cproto == NULL) {
if (!(*env)->ExceptionCheck(env))
lpHost = (*env)->GetStringChars(env, host, NULL);
if (lpHost == 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);
}
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;
}
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);
return NULL;
}
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;
}
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;
}
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;
}
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;
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;
}
}
}
}
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;
}

View File

@ -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;