Path: blob/master/src/java.base/windows/native/libnet/DefaultProxySelector.c
41119 views
/*1* Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#include <windows.h>26#include <Winhttp.h>2728#include "jni.h"29#include "jni_util.h"30#include "jvm.h"3132#include "proxy_util.h"3334#include "sun_net_spi_DefaultProxySelector.h"3536/*37* These functions are used by the sun.net.spi.DefaultProxySelector class38* to access some platform specific settings.39* On Windows use WinHTTP functions to get the system settings.40*/4142/* Keep one static session for all requests. */43static HINTERNET session = NULL;4445/*46* Class: sun_net_spi_DefaultProxySelector47* Method: init48* Signature: ()Z49*/50JNIEXPORT jboolean JNICALL51Java_sun_net_spi_DefaultProxySelector_init(JNIEnv *env, jclass clazz) {5253/*54* Get one WinHTTP session handle to initialize the WinHTTP internal data55* structures. Keep and use only this one for the whole life time.56*/57session = WinHttpOpen(L"Only used internal", /* we need no real agent string here */58WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,59WINHTTP_NO_PROXY_NAME,60WINHTTP_NO_PROXY_BYPASS,610);62if (session == NULL) {63return JNI_FALSE;64}6566if (!initJavaClass(env)) {67return JNI_FALSE;68}6970return JNI_TRUE;71}727374#define MAX_STR_LEN 10247576/* A linked list element for a proxy */77typedef struct list_item {78wchar_t *host;79int port;80struct list_item *next;81} list_item;8283/* Free the linked list */84static void freeList(list_item *head) {85list_item *next = NULL;86list_item *current = head;87while (current != NULL) {88next = current->next;89free(current->host);90free(current);91current = next;92}93}949596/*97* Creates a linked list of list_item elements that has to be freed later on.98* Returns the size of the array as int.99*/100static int createProxyList(LPWSTR win_proxy, const WCHAR *pproto, list_item **head) {101static const wchar_t separators[] = L"\t\r\n ;";102list_item *current = NULL;103int nr_elems = 0;104wchar_t *context = NULL;105wchar_t *current_proxy = NULL;106BOOL error = FALSE;107108/*109* The proxy server list contains one or more of the following strings110* separated by semicolons or whitespace:111* ([<scheme>=][<scheme>"://"]<server>[":"<port>])112*/113current_proxy = wcstok_s(win_proxy, separators, &context);114while (current_proxy != NULL) {115LPWSTR pport;116LPWSTR phost;117int portVal = 0;118wchar_t *next_proxy = NULL;119list_item *proxy = NULL;120wchar_t* pos = NULL;121122/* Filter based on the scheme, if there is one */123pos = wcschr(current_proxy, L'=');124if (pos) {125*pos = L'\0';126if (wcscmp(current_proxy, pproto) != 0) {127current_proxy = wcstok_s(NULL, separators, &context);128continue;129}130current_proxy = pos + 1;131}132133/* Let's check for a scheme and ignore it. */134if ((phost = wcsstr(current_proxy, L"://")) != NULL) {135phost += 3;136} else {137phost = current_proxy;138}139140/* Get the port */141pport = wcschr(phost, L':');142if (pport != NULL) {143*pport = 0;144pport++;145swscanf(pport, L"%d", &portVal);146}147148proxy = (list_item *)malloc(sizeof(list_item));149if (proxy != NULL) {150proxy->next = NULL;151proxy->port = portVal;152proxy->host = _wcsdup(phost);153154if (proxy->host != NULL) {155if (*head == NULL) {156*head = proxy; /* first elem */157}158if (current != NULL) {159current->next = proxy;160}161current = proxy;162nr_elems++;163} else {164free(proxy); /* cleanup */165}166}167/* goto next proxy if available... */168current_proxy = wcstok_s(NULL, separators, &context);169}170return nr_elems;171}172173174175/*176* Class: sun_net_spi_DefaultProxySelector177* Method: getSystemProxies178* Signature: ([Ljava/lang/String;Ljava/lang/String;)[Ljava/net/Proxy;179*/180JNIEXPORT jobjectArray JNICALL181Java_sun_net_spi_DefaultProxySelector_getSystemProxies(JNIEnv *env,182jobject this,183jstring proto,184jstring host)185{186jobjectArray proxy_array = NULL;187jobject type_proxy = NULL;188LPCWSTR lpProto;189LPCWSTR lpHost;190list_item *head = NULL;191192BOOL use_auto_proxy = FALSE;193WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ie_proxy_config;194WINHTTP_AUTOPROXY_OPTIONS auto_proxy_options;195WINHTTP_PROXY_INFO proxy_info;196LPWSTR win_proxy = NULL;197LPWSTR win_bypass_proxy = NULL;198199memset(&ie_proxy_config, 0, sizeof(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG));200memset(&auto_proxy_options, 0, sizeof(WINHTTP_AUTOPROXY_OPTIONS));201memset(&proxy_info, 0, sizeof(WINHTTP_PROXY_INFO));202203lpHost = (*env)->GetStringChars(env, host, NULL);204if (lpHost == NULL) {205if (!(*env)->ExceptionCheck(env))206JNU_ThrowOutOfMemoryError(env, NULL);207return NULL;208}209210lpProto = (*env)->GetStringChars(env, proto, NULL);211if (lpProto == NULL) {212(*env)->ReleaseStringChars(env, host, lpHost);213if (!(*env)->ExceptionCheck(env))214JNU_ThrowOutOfMemoryError(env, NULL);215return NULL;216}217218if (WinHttpGetIEProxyConfigForCurrentUser(&ie_proxy_config) == FALSE) {219/* cleanup and exit */220(*env)->ReleaseStringChars(env, host, lpHost);221(*env)->ReleaseStringChars(env, proto, lpProto);222return NULL;223}224225if (ie_proxy_config.fAutoDetect) {226/* Windows uses WPAD */227auto_proxy_options.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP |228WINHTTP_AUTO_DETECT_TYPE_DNS_A;229auto_proxy_options.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT;230auto_proxy_options.fAutoLogonIfChallenged = TRUE;231use_auto_proxy = TRUE;232} else if (ie_proxy_config.lpszAutoConfigUrl != NULL) {233/* Windows uses PAC file */234auto_proxy_options.lpszAutoConfigUrl = ie_proxy_config.lpszAutoConfigUrl;235auto_proxy_options.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL;236use_auto_proxy = TRUE;237} else if (ie_proxy_config.lpszProxy != NULL) {238/* Windows uses manually entered proxy. */239use_auto_proxy = FALSE;240win_bypass_proxy = ie_proxy_config.lpszProxyBypass;241win_proxy = ie_proxy_config.lpszProxy;242}243244if (use_auto_proxy) {245WCHAR url[MAX_STR_LEN];246/* Create url for WinHttpGetProxyForUrl */247_snwprintf(url, sizeof(url) - 1, L"%s://%s", lpProto, lpHost);248/* Get proxy for URL from Windows */249use_auto_proxy = WinHttpGetProxyForUrl(session, &url[0], &auto_proxy_options, &proxy_info);250if (use_auto_proxy) {251win_proxy = proxy_info.lpszProxy;252win_bypass_proxy = proxy_info.lpszProxyBypass;253}254}255256/* Check the bypass entry. */257if (NULL != win_bypass_proxy) {258/*259* From MSDN:260* The proxy bypass list contains one or more server names separated by261* semicolons or whitespace. The proxy bypass list can also contain the262* string "<local>" to indicate that all local intranet sites are263* bypassed. Local intranet sites are considered to be all servers that264* do not contain a period in their name.265*/266wchar_t *context = NULL;267LPWSTR s = wcstok_s(win_bypass_proxy, L"; ", &context);268269while (s != NULL) {270size_t maxlen = wcslen(s);271if (wcsncmp(s, lpHost, maxlen) == 0) {272/*273* The URL host name matches with one of the prefixes, use a274* direct connection.275*/276goto noproxy;277}278if (wcsncmp(s, L"<local>", maxlen) == 0) {279/*280* All local intranet sites are bypassed - Microsoft consider all281* servers that do not contain a period in their name to be local.282*/283if (wcschr(lpHost, '.') == NULL) {284goto noproxy;285}286}287s = wcstok_s(NULL, L"; ", &context);288}289}290291if (win_proxy != NULL) {292wchar_t *context = NULL;293int defport = 0;294int nr_elems = 0;295296/* Set the default port value & proxy type from protocol. */297if ((wcscmp(lpProto, L"http") == 0) ||298(wcscmp(lpProto, L"ftp") == 0))299defport = 80;300if (wcscmp(lpProto, L"https") == 0)301defport = 443;302if (wcscmp(lpProto, L"socks") == 0) {303defport = 1080;304type_proxy = (*env)->GetStaticObjectField(env, ptype_class, ptype_socksID);305} else {306type_proxy = (*env)->GetStaticObjectField(env, ptype_class, ptype_httpID);307}308if (type_proxy == NULL || (*env)->ExceptionCheck(env)) {309goto noproxy;310}311312nr_elems = createProxyList(win_proxy, lpProto, &head);313if (nr_elems != 0 && head != NULL) {314int index = 0;315proxy_array = (*env)->NewObjectArray(env, nr_elems, proxy_class, NULL);316if (proxy_array == NULL || (*env)->ExceptionCheck(env)) {317goto noproxy;318}319while (head != NULL && index < nr_elems) {320jstring jhost;321jobject isa;322jobject proxy;323324if (head->host != NULL && proxy_array != NULL) {325/* Let's create the appropriate Proxy object then. */326if (head->port == 0) {327head->port = defport;328}329jhost = (*env)->NewString(env, head->host, (jsize)wcslen(head->host));330if (jhost == NULL || (*env)->ExceptionCheck(env)) {331proxy_array = NULL;332}333isa = (*env)->CallStaticObjectMethod(env, isaddr_class,334isaddr_createUnresolvedID, jhost,335head->port);336if (isa == NULL || (*env)->ExceptionCheck(env)) {337proxy_array = NULL;338}339proxy = (*env)->NewObject(env, proxy_class, proxy_ctrID, type_proxy, isa);340if (proxy == NULL || (*env)->ExceptionCheck(env)) {341proxy_array = NULL;342}343(*env)->SetObjectArrayElement(env, proxy_array, index, proxy);344if ((*env)->ExceptionCheck(env)) {345proxy_array = NULL;346}347index++;348}349head = head->next;350}351}352}353354noproxy:355if (head != NULL) {356freeList(head);357}358if (proxy_info.lpszProxy != NULL)359GlobalFree(proxy_info.lpszProxy);360if (proxy_info.lpszProxyBypass != NULL)361GlobalFree(proxy_info.lpszProxyBypass);362if (ie_proxy_config.lpszAutoConfigUrl != NULL)363GlobalFree(ie_proxy_config.lpszAutoConfigUrl);364if (ie_proxy_config.lpszProxy != NULL)365GlobalFree(ie_proxy_config.lpszProxy);366if (ie_proxy_config.lpszProxyBypass != NULL)367GlobalFree(ie_proxy_config.lpszProxyBypass);368if (lpHost != NULL)369(*env)->ReleaseStringChars(env, host, lpHost);370if (lpProto != NULL)371(*env)->ReleaseStringChars(env, proto, lpProto);372373return proxy_array;374}375376377