Path: blob/master/src/java.base/windows/native/libnet/DefaultProxySelector.c
67723 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;106107/*108* The proxy server list contains one or more of the following strings109* separated by semicolons or whitespace:110* ([<scheme>=][<scheme>"://"]<server>[":"<port>])111*/112current_proxy = wcstok_s(win_proxy, separators, &context);113while (current_proxy != NULL) {114LPWSTR pport;115LPWSTR phost;116int portVal = 0;117list_item *proxy = NULL;118wchar_t* pos = NULL;119120/* Filter based on the scheme, if there is one */121pos = wcschr(current_proxy, L'=');122if (pos) {123*pos = L'\0';124if (wcscmp(current_proxy, pproto) != 0) {125current_proxy = wcstok_s(NULL, separators, &context);126continue;127}128current_proxy = pos + 1;129}130131/* Let's check for a scheme and ignore it. */132if ((phost = wcsstr(current_proxy, L"://")) != NULL) {133phost += 3;134} else {135phost = current_proxy;136}137138/* Get the port */139pport = wcschr(phost, L':');140if (pport != NULL) {141*pport = 0;142pport++;143swscanf(pport, L"%d", &portVal);144}145146proxy = (list_item *)malloc(sizeof(list_item));147if (proxy != NULL) {148proxy->next = NULL;149proxy->port = portVal;150proxy->host = _wcsdup(phost);151152if (proxy->host != NULL) {153if (*head == NULL) {154*head = proxy; /* first elem */155}156if (current != NULL) {157current->next = proxy;158}159current = proxy;160nr_elems++;161} else {162free(proxy); /* cleanup */163}164}165/* goto next proxy if available... */166current_proxy = wcstok_s(NULL, separators, &context);167}168return nr_elems;169}170171172173/*174* Class: sun_net_spi_DefaultProxySelector175* Method: getSystemProxies176* Signature: ([Ljava/lang/String;Ljava/lang/String;)[Ljava/net/Proxy;177*/178JNIEXPORT jobjectArray JNICALL179Java_sun_net_spi_DefaultProxySelector_getSystemProxies(JNIEnv *env,180jobject this,181jstring proto,182jstring host)183{184jobjectArray proxy_array = NULL;185jobject type_proxy = NULL;186LPCWSTR lpProto;187LPCWSTR lpHost;188list_item *head = NULL;189190BOOL use_auto_proxy = FALSE;191WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ie_proxy_config;192WINHTTP_AUTOPROXY_OPTIONS auto_proxy_options;193WINHTTP_PROXY_INFO proxy_info;194LPWSTR win_proxy = NULL;195LPWSTR win_bypass_proxy = NULL;196197memset(&ie_proxy_config, 0, sizeof(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG));198memset(&auto_proxy_options, 0, sizeof(WINHTTP_AUTOPROXY_OPTIONS));199memset(&proxy_info, 0, sizeof(WINHTTP_PROXY_INFO));200201lpHost = (*env)->GetStringChars(env, host, NULL);202if (lpHost == NULL) {203if (!(*env)->ExceptionCheck(env))204JNU_ThrowOutOfMemoryError(env, NULL);205return NULL;206}207208lpProto = (*env)->GetStringChars(env, proto, NULL);209if (lpProto == NULL) {210(*env)->ReleaseStringChars(env, host, lpHost);211if (!(*env)->ExceptionCheck(env))212JNU_ThrowOutOfMemoryError(env, NULL);213return NULL;214}215216if (WinHttpGetIEProxyConfigForCurrentUser(&ie_proxy_config) == FALSE) {217/* cleanup and exit */218(*env)->ReleaseStringChars(env, host, lpHost);219(*env)->ReleaseStringChars(env, proto, lpProto);220return NULL;221}222223if (ie_proxy_config.fAutoDetect) {224/* Windows uses WPAD */225auto_proxy_options.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP |226WINHTTP_AUTO_DETECT_TYPE_DNS_A;227auto_proxy_options.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT;228auto_proxy_options.fAutoLogonIfChallenged = TRUE;229use_auto_proxy = TRUE;230} else if (ie_proxy_config.lpszAutoConfigUrl != NULL) {231/* Windows uses PAC file */232auto_proxy_options.lpszAutoConfigUrl = ie_proxy_config.lpszAutoConfigUrl;233auto_proxy_options.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL;234use_auto_proxy = TRUE;235} else if (ie_proxy_config.lpszProxy != NULL) {236/* Windows uses manually entered proxy. */237use_auto_proxy = FALSE;238win_bypass_proxy = ie_proxy_config.lpszProxyBypass;239win_proxy = ie_proxy_config.lpszProxy;240}241242if (use_auto_proxy) {243WCHAR url[MAX_STR_LEN];244/* Create url for WinHttpGetProxyForUrl */245_snwprintf(url, sizeof(url) - 1, L"%s://%s", lpProto, lpHost);246/* Get proxy for URL from Windows */247use_auto_proxy = WinHttpGetProxyForUrl(session, &url[0], &auto_proxy_options, &proxy_info);248if (use_auto_proxy) {249win_proxy = proxy_info.lpszProxy;250win_bypass_proxy = proxy_info.lpszProxyBypass;251}252}253254/* Check the bypass entry. */255if (NULL != win_bypass_proxy) {256/*257* From MSDN:258* The proxy bypass list contains one or more server names separated by259* semicolons or whitespace. The proxy bypass list can also contain the260* string "<local>" to indicate that all local intranet sites are261* bypassed. Local intranet sites are considered to be all servers that262* do not contain a period in their name.263*/264wchar_t *context = NULL;265LPWSTR s = wcstok_s(win_bypass_proxy, L"; ", &context);266267while (s != NULL) {268size_t maxlen = wcslen(s);269if (wcsncmp(s, lpHost, maxlen) == 0) {270/*271* The URL host name matches with one of the prefixes, use a272* direct connection.273*/274goto noproxy;275}276if (wcsncmp(s, L"<local>", maxlen) == 0) {277/*278* All local intranet sites are bypassed - Microsoft consider all279* servers that do not contain a period in their name to be local.280*/281if (wcschr(lpHost, '.') == NULL) {282goto noproxy;283}284}285s = wcstok_s(NULL, L"; ", &context);286}287}288289if (win_proxy != NULL) {290int defport = 0;291int nr_elems = 0;292293/* Set the default port value & proxy type from protocol. */294if ((wcscmp(lpProto, L"http") == 0) ||295(wcscmp(lpProto, L"ftp") == 0))296defport = 80;297if (wcscmp(lpProto, L"https") == 0)298defport = 443;299if (wcscmp(lpProto, L"socks") == 0) {300defport = 1080;301type_proxy = (*env)->GetStaticObjectField(env, ptype_class, ptype_socksID);302} else {303type_proxy = (*env)->GetStaticObjectField(env, ptype_class, ptype_httpID);304}305if (type_proxy == NULL || (*env)->ExceptionCheck(env)) {306goto noproxy;307}308309nr_elems = createProxyList(win_proxy, lpProto, &head);310if (nr_elems != 0 && head != NULL) {311int index = 0;312list_item *current = head;313proxy_array = (*env)->NewObjectArray(env, nr_elems, proxy_class, NULL);314if (proxy_array == NULL || (*env)->ExceptionCheck(env)) {315goto noproxy;316}317while (current != NULL && index < nr_elems) {318jstring jhost;319jobject isa;320jobject proxy;321322if (current->host != NULL && proxy_array != NULL) {323/* Let's create the appropriate Proxy object then. */324if (current->port == 0) {325current->port = defport;326}327jhost = (*env)->NewString(env, current->host, (jsize)wcslen(current->host));328if (jhost == NULL || (*env)->ExceptionCheck(env)) {329proxy_array = NULL;330}331isa = (*env)->CallStaticObjectMethod(env, isaddr_class,332isaddr_createUnresolvedID, jhost,333current->port);334if (isa == NULL || (*env)->ExceptionCheck(env)) {335proxy_array = NULL;336}337proxy = (*env)->NewObject(env, proxy_class, proxy_ctrID, type_proxy, isa);338if (proxy == NULL || (*env)->ExceptionCheck(env)) {339proxy_array = NULL;340}341(*env)->SetObjectArrayElement(env, proxy_array, index, proxy);342if ((*env)->ExceptionCheck(env)) {343proxy_array = NULL;344}345index++;346}347current = current->next;348}349}350}351352noproxy:353if (head != NULL) {354freeList(head);355}356if (proxy_info.lpszProxy != NULL)357GlobalFree(proxy_info.lpszProxy);358if (proxy_info.lpszProxyBypass != NULL)359GlobalFree(proxy_info.lpszProxyBypass);360if (ie_proxy_config.lpszAutoConfigUrl != NULL)361GlobalFree(ie_proxy_config.lpszAutoConfigUrl);362if (ie_proxy_config.lpszProxy != NULL)363GlobalFree(ie_proxy_config.lpszProxy);364if (ie_proxy_config.lpszProxyBypass != NULL)365GlobalFree(ie_proxy_config.lpszProxyBypass);366if (lpHost != NULL)367(*env)->ReleaseStringChars(env, host, lpHost);368if (lpProto != NULL)369(*env)->ReleaseStringChars(env, proto, lpProto);370371return proxy_array;372}373374375