Path: blob/master/src/java.base/macosx/native/libnet/DefaultProxySelector.c
41119 views
/*1* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.2* Copyright (c) 2017 SAP SE. All rights reserved.3* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.4*5* This code is free software; you can redistribute it and/or modify it6* under the terms of the GNU General Public License version 2 only, as7* published by the Free Software Foundation. Oracle designates this8* particular file as subject to the "Classpath" exception as provided9* by Oracle in the LICENSE file that accompanied this code.10*11* This code is distributed in the hope that it will be useful, but WITHOUT12* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or13* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License14* version 2 for more details (a copy is included in the LICENSE file that15* accompanied this code).16*17* You should have received a copy of the GNU General Public License version18* 2 along with this work; if not, write to the Free Software Foundation,19* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.20*21* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA22* or visit www.oracle.com if you need additional information or have any23* questions.24*/2526#include <string.h>27#include <CoreFoundation/CoreFoundation.h>28#include <CoreServices/CoreServices.h>2930#include "jni.h"31#include "jni_util.h"32#include "jvm.h"33#include "jvm_md.h"3435#include "proxy_util.h"3637#include "sun_net_spi_DefaultProxySelector.h"383940/**41* For more information on how to use the APIs in "CFProxySupport.h" see:42* https://developer.apple.com/legacy/library/samplecode/CFProxySupportTool/Introduction/Intro.html43*/4445#define kResolveProxyRunLoopMode CFSTR("sun.net.spi.DefaultProxySelector")4647#define BUFFER_SIZE 10244849/* Callback for CFNetworkExecuteProxyAutoConfigurationURL. */50static void proxyUrlCallback(void * client, CFArrayRef proxies, CFErrorRef error) {51/* client is a pointer to a CFTypeRef and holds either proxies or an error. */52CFTypeRef* resultPtr = (CFTypeRef *)client;5354if (error != NULL) {55*resultPtr = CFRetain(error);56} else {57*resultPtr = CFRetain(proxies);58}59CFRunLoopStop(CFRunLoopGetCurrent());60}6162/*63* Returns a new array of proxies containing all the given non-PAC proxies as64* well as the results of executing all the given PAC-based proxies, for the65* specified URL. 'proxies' is a list that may contain both PAC and non-PAC66* proxies.67*/68static CFArrayRef createExpandedProxiesArray(CFArrayRef proxies, CFURLRef url) {6970CFIndex count;71CFIndex index;72CFMutableArrayRef expandedProxiesArray;7374expandedProxiesArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);75if (expandedProxiesArray == NULL)76return NULL;7778/* Iterate over the array of proxies */79count = CFArrayGetCount(proxies);80for (index = 0; index < count ; index++) {81CFDictionaryRef currentProxy;82CFStringRef proxyType;8384currentProxy = (CFDictionaryRef) CFArrayGetValueAtIndex(proxies, index);85if(currentProxy == NULL) {86CFRelease(expandedProxiesArray);87return NULL;88}89proxyType = (CFStringRef) CFDictionaryGetValue(currentProxy, kCFProxyTypeKey);90if (proxyType == NULL) {91CFRelease(expandedProxiesArray);92return NULL;93}9495if (!CFEqual(proxyType, kCFProxyTypeAutoConfigurationURL)) {96/* Non-PAC entry, just copy it to the new array */97CFArrayAppendValue(expandedProxiesArray, currentProxy);98} else {99/* PAC-based URL, execute its script append its results */100CFRunLoopSourceRef runLoop;101CFURLRef scriptURL;102CFTypeRef result = NULL;103CFStreamClientContext context = { 0, &result, NULL, NULL, NULL };104CFTimeInterval timeout = 5;105106scriptURL = CFDictionaryGetValue(currentProxy, kCFProxyAutoConfigurationURLKey);107108runLoop = CFNetworkExecuteProxyAutoConfigurationURL(scriptURL, url, proxyUrlCallback,109&context);110if (runLoop != NULL) {111/*112* Despite the fact that CFNetworkExecuteProxyAutoConfigurationURL has113* neither a "Create" nor a "Copy" in the name, we are required to114* release the return CFRunLoopSourceRef <rdar://problem/5533931>.115*/116CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoop, kResolveProxyRunLoopMode);117CFRunLoopRunInMode(kResolveProxyRunLoopMode, timeout, false);118CFRunLoopRemoveSource(CFRunLoopGetCurrent(), runLoop, kResolveProxyRunLoopMode);119120/*121* Once the runloop returns, there will be either an error result or122* a proxies array result. Do the appropriate thing with that result.123*/124if (result != NULL) {125if (CFGetTypeID(result) == CFArrayGetTypeID()) {126/*127* Append the new array from the PAC list - it contains128* only non-PAC entries.129*/130CFArrayAppendArray(expandedProxiesArray, result,131CFRangeMake(0, CFArrayGetCount(result)));132}133CFRelease(result);134}135CFRelease(runLoop);136}137}138}139return expandedProxiesArray;140}141142143/*144* Class: sun_net_spi_DefaultProxySelector145* Method: init146* Signature: ()Z147*/148JNIEXPORT jboolean JNICALL149Java_sun_net_spi_DefaultProxySelector_init(JNIEnv *env, jclass clazz) {150if (!initJavaClass(env)) {151return JNI_FALSE;152}153return JNI_TRUE;154}155156157/*158* Class: sun_net_spi_DefaultProxySelector159* Method: getSystemProxies160* Signature: ([Ljava/lang/String;Ljava/lang/String;)[Ljava/net/Proxy;161*/162JNIEXPORT jobjectArray JNICALL163Java_sun_net_spi_DefaultProxySelector_getSystemProxies(JNIEnv *env,164jobject this,165jstring proto,166jstring host)167{168CFDictionaryRef proxyDicRef = NULL;169CFURLRef urlRef = NULL;170bool proxyFound = false;171jobjectArray proxyArray = NULL;172const char *cproto;173const char *chost;174175/* Get system proxy settings */176proxyDicRef = CFNetworkCopySystemProxySettings();177if (proxyDicRef == NULL) {178return NULL;179}180181/* Create CFURLRef from proto and host */182cproto = (*env)->GetStringUTFChars(env, proto, NULL);183if (cproto != NULL) {184chost = (*env)->GetStringUTFChars(env, host, NULL);185if (chost != NULL) {186char* uri = NULL;187size_t protoLen = 0;188size_t hostLen = 0;189190protoLen = strlen(cproto);191hostLen = strlen(chost);192193/* Construct the uri, cproto + "://" + chost */194uri = malloc(protoLen + hostLen + 4);195if (uri != NULL) {196memcpy(uri, cproto, protoLen);197memcpy(uri + protoLen, "://", 3);198memcpy(uri + protoLen + 3, chost, hostLen + 1);199200urlRef = CFURLCreateWithBytes(NULL, (const UInt8 *) uri, strlen(uri),201kCFStringEncodingUTF8, NULL);202free(uri);203}204(*env)->ReleaseStringUTFChars(env, host, chost);205}206(*env)->ReleaseStringUTFChars(env, proto, cproto);207}208if (urlRef != NULL) {209CFArrayRef urlProxyArrayRef = CFNetworkCopyProxiesForURL(urlRef, proxyDicRef);210if (urlProxyArrayRef != NULL) {211CFIndex count;212CFIndex index;213214CFArrayRef expandedProxyArray = createExpandedProxiesArray(urlProxyArrayRef, urlRef);215CFRelease(urlProxyArrayRef);216217if (expandedProxyArray == NULL) {218CFRelease(urlRef);219CFRelease(proxyDicRef);220return NULL;221}222223count = CFArrayGetCount(expandedProxyArray);224225proxyArray = (*env)->NewObjectArray(env, count, proxy_class, NULL);226if (proxyArray != NULL || (*env)->ExceptionCheck(env)) {227/* Iterate over the expanded array of proxies */228for (index = 0; index < count ; index++) {229CFDictionaryRef currentProxy;230CFStringRef proxyType;231jobject proxy = NULL;232233currentProxy = (CFDictionaryRef) CFArrayGetValueAtIndex(expandedProxyArray,234index);235proxyType = (CFStringRef) CFDictionaryGetValue(currentProxy, kCFProxyTypeKey);236if (CFEqual(proxyType, kCFProxyTypeNone)) {237/* This entry states no proxy, therefore just add a NO_PROXY object. */238proxy = (*env)->GetStaticObjectField(env, proxy_class, pr_no_proxyID);239} else {240/*241* Create a proxy object for this entry.242* Differentiate between SOCKS and HTTP type.243*/244jfieldID typeID = ptype_httpID;245if (CFEqual(proxyType, kCFProxyTypeSOCKS)) {246typeID = ptype_socksID;247}248CFNumberRef portNumberRef = (CFNumberRef)CFDictionaryGetValue(currentProxy,249(const void*)kCFProxyPortNumberKey);250if (portNumberRef != NULL) {251int port = 0;252if (CFNumberGetValue(portNumberRef, kCFNumberSInt32Type, &port)) {253CFStringRef hostNameRef = (CFStringRef)CFDictionaryGetValue(254currentProxy, (const void*)kCFProxyHostNameKey);255if (hostNameRef != NULL) {256char hostNameBuffer[BUFFER_SIZE];257if (CFStringGetCString(hostNameRef, hostNameBuffer,258BUFFER_SIZE, kCFStringEncodingUTF8)) {259proxy = createProxy(env, typeID, &hostNameBuffer[0], port);260}261}262}263}264}265if (proxy == NULL || (*env)->ExceptionCheck(env)) {266proxyArray = NULL;267break;268}269(*env)->SetObjectArrayElement(env, proxyArray, index, proxy);270if ((*env)->ExceptionCheck(env)) {271proxyArray = NULL;272break;273}274}275}276CFRelease(expandedProxyArray);277}278CFRelease(urlRef);279}280CFRelease(proxyDicRef);281282return proxyArray;283}284285286