< prev index next >
src/java.base/windows/native/libnet/DefaultProxySelector.c
Print this page
rev 16207 : 8170868: DefaultProxySelector should use system defaults on Windows, MacOS and Gnome
Contributed-by: arno.zeller@sap.com
*** 1,7 ****
/*
! * Copyright (c) 2004, 2010, 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
--- 1,7 ----
/*
! * 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
*** 22,284 ****
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include <windows.h>
#include "jni.h"
#include "jni_util.h"
#include "jvm.h"
! #include "jlong.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.
*/
! 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;
/*
* Class: sun_net_spi_DefaultProxySelector
* Method: init
* Signature: ()Z
*/
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.
*/
! return JNI_TRUE;
! }
! return JNI_FALSE;
}
#define MAX_STR_LEN 1024
/*
! * Class: sun_net_spi_DefaultProxySelector
! * Method: getSystemProxy
! * 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)
! {
! 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;
!
! /**
! * 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);
!
! /**
! * 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;
}
- s = strtok_s(NULL, "; ", &ctx);
- }
- if (isCopy == JNI_TRUE)
- (*env)->ReleaseStringUTFChars(env, host, urlhost);
}
! 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);
}
- 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);
}
- }
noproxy:
! no_proxy = (*env)->GetStaticObjectField(env, proxy_class, pr_no_proxyID);
! return no_proxy;
}
--- 22,376 ----
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include <windows.h>
+ #include <Winhttp.h>
+
#include "jni.h"
#include "jni_util.h"
#include "jvm.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 WinHTTP functions to get the system settings.
*/
! /* Keep one static session for all requests. */
! static HINTERNET session = NULL;
/*
* Class: sun_net_spi_DefaultProxySelector
* Method: init
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL
Java_sun_net_spi_DefaultProxySelector_init(JNIEnv *env, jclass clazz) {
!
! /*
! * Get one WinHTTP session handle to initialize the WinHTTP internal data structures
! * We 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;
}
+
#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: 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)
+ {
+ 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;
+ }
! 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, we have to use a direct
! * connection.
! */
! goto noproxy;
! }
! if (wcsncmp(s, L"<local>", maxlen) == 0) {
! /*
! * All local intranet sites are bypassed - Microsoft considers 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 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:
! 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;
}
< prev index next >