< 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)&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); } ! 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 >