Path: blob/master/src/java.base/macosx/native/libnet/DefaultProxySelector.c
67760 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>29#ifdef TARGET_OS_IOS30#include <CFNetwork/CFNetwork.h>31#endif3233#include "jni.h"34#include "jni_util.h"35#include "jvm.h"36#include "jvm_md.h"3738#include "proxy_util.h"3940#include "sun_net_spi_DefaultProxySelector.h"414243/**44* For more information on how to use the APIs in "CFProxySupport.h" see:45* https://developer.apple.com/legacy/library/samplecode/CFProxySupportTool/Introduction/Intro.html46*/4748#define kResolveProxyRunLoopMode CFSTR("sun.net.spi.DefaultProxySelector")4950#define BUFFER_SIZE 10245152/* Callback for CFNetworkExecuteProxyAutoConfigurationURL. */53static void proxyUrlCallback(void * client, CFArrayRef proxies, CFErrorRef error) {54/* client is a pointer to a CFTypeRef and holds either proxies or an error. */55CFTypeRef* resultPtr = (CFTypeRef *)client;5657if (error != NULL) {58*resultPtr = CFRetain(error);59} else {60*resultPtr = CFRetain(proxies);61}62CFRunLoopStop(CFRunLoopGetCurrent());63}6465/*66* Returns a new array of proxies containing all the given non-PAC proxies as67* well as the results of executing all the given PAC-based proxies, for the68* specified URL. 'proxies' is a list that may contain both PAC and non-PAC69* proxies.70*/71static CFArrayRef createExpandedProxiesArray(CFArrayRef proxies, CFURLRef url) {7273CFIndex count;74CFIndex index;75CFMutableArrayRef expandedProxiesArray;7677expandedProxiesArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);78if (expandedProxiesArray == NULL)79return NULL;8081/* Iterate over the array of proxies */82count = CFArrayGetCount(proxies);83for (index = 0; index < count ; index++) {84CFDictionaryRef currentProxy;85CFStringRef proxyType;8687currentProxy = (CFDictionaryRef) CFArrayGetValueAtIndex(proxies, index);88if(currentProxy == NULL) {89CFRelease(expandedProxiesArray);90return NULL;91}92proxyType = (CFStringRef) CFDictionaryGetValue(currentProxy, kCFProxyTypeKey);93if (proxyType == NULL) {94CFRelease(expandedProxiesArray);95return NULL;96}9798if (!CFEqual(proxyType, kCFProxyTypeAutoConfigurationURL)) {99/* Non-PAC entry, just copy it to the new array */100CFArrayAppendValue(expandedProxiesArray, currentProxy);101} else {102/* PAC-based URL, execute its script append its results */103CFRunLoopSourceRef runLoop;104CFURLRef scriptURL;105CFTypeRef result = NULL;106CFStreamClientContext context = { 0, &result, NULL, NULL, NULL };107CFTimeInterval timeout = 5;108109scriptURL = CFDictionaryGetValue(currentProxy, kCFProxyAutoConfigurationURLKey);110111runLoop = CFNetworkExecuteProxyAutoConfigurationURL(scriptURL, url, proxyUrlCallback,112&context);113if (runLoop != NULL) {114/*115* Despite the fact that CFNetworkExecuteProxyAutoConfigurationURL has116* neither a "Create" nor a "Copy" in the name, we are required to117* release the return CFRunLoopSourceRef <rdar://problem/5533931>.118*/119CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoop, kResolveProxyRunLoopMode);120CFRunLoopRunInMode(kResolveProxyRunLoopMode, timeout, false);121CFRunLoopRemoveSource(CFRunLoopGetCurrent(), runLoop, kResolveProxyRunLoopMode);122123/*124* Once the runloop returns, there will be either an error result or125* a proxies array result. Do the appropriate thing with that result.126*/127if (result != NULL) {128if (CFGetTypeID(result) == CFArrayGetTypeID()) {129/*130* Append the new array from the PAC list - it contains131* only non-PAC entries.132*/133CFArrayAppendArray(expandedProxiesArray, result,134CFRangeMake(0, CFArrayGetCount(result)));135}136CFRelease(result);137}138CFRelease(runLoop);139}140}141}142return expandedProxiesArray;143}144145146/*147* Class: sun_net_spi_DefaultProxySelector148* Method: init149* Signature: ()Z150*/151JNIEXPORT jboolean JNICALL152Java_sun_net_spi_DefaultProxySelector_init(JNIEnv *env, jclass clazz) {153if (!initJavaClass(env)) {154return JNI_FALSE;155}156return JNI_TRUE;157}158159160/*161* Class: sun_net_spi_DefaultProxySelector162* Method: getSystemProxies163* Signature: ([Ljava/lang/String;Ljava/lang/String;)[Ljava/net/Proxy;164*/165JNIEXPORT jobjectArray JNICALL166Java_sun_net_spi_DefaultProxySelector_getSystemProxies(JNIEnv *env,167jobject this,168jstring proto,169jstring host)170{171CFDictionaryRef proxyDicRef = NULL;172CFURLRef urlRef = NULL;173bool proxyFound = false;174jobjectArray proxyArray = NULL;175const char *cproto;176const char *chost;177178/* Get system proxy settings */179proxyDicRef = CFNetworkCopySystemProxySettings();180if (proxyDicRef == NULL) {181return NULL;182}183184/* Create CFURLRef from proto and host */185cproto = (*env)->GetStringUTFChars(env, proto, NULL);186if (cproto != NULL) {187chost = (*env)->GetStringUTFChars(env, host, NULL);188if (chost != NULL) {189char* uri = NULL;190size_t protoLen = 0;191size_t hostLen = 0;192193protoLen = strlen(cproto);194hostLen = strlen(chost);195196/* Construct the uri, cproto + "://" + chost */197uri = malloc(protoLen + hostLen + 4);198if (uri != NULL) {199memcpy(uri, cproto, protoLen);200memcpy(uri + protoLen, "://", 3);201memcpy(uri + protoLen + 3, chost, hostLen + 1);202203urlRef = CFURLCreateWithBytes(NULL, (const UInt8 *) uri, strlen(uri),204kCFStringEncodingUTF8, NULL);205free(uri);206}207(*env)->ReleaseStringUTFChars(env, host, chost);208}209(*env)->ReleaseStringUTFChars(env, proto, cproto);210}211if (urlRef != NULL) {212CFArrayRef urlProxyArrayRef = CFNetworkCopyProxiesForURL(urlRef, proxyDicRef);213if (urlProxyArrayRef != NULL) {214CFIndex count;215CFIndex index;216217CFArrayRef expandedProxyArray = createExpandedProxiesArray(urlProxyArrayRef, urlRef);218CFRelease(urlProxyArrayRef);219220if (expandedProxyArray == NULL) {221CFRelease(urlRef);222CFRelease(proxyDicRef);223return NULL;224}225226count = CFArrayGetCount(expandedProxyArray);227228proxyArray = (*env)->NewObjectArray(env, count, proxy_class, NULL);229if (proxyArray != NULL || (*env)->ExceptionCheck(env)) {230/* Iterate over the expanded array of proxies */231for (index = 0; index < count ; index++) {232CFDictionaryRef currentProxy;233CFStringRef proxyType;234jobject proxy = NULL;235236currentProxy = (CFDictionaryRef) CFArrayGetValueAtIndex(expandedProxyArray,237index);238proxyType = (CFStringRef) CFDictionaryGetValue(currentProxy, kCFProxyTypeKey);239if (CFEqual(proxyType, kCFProxyTypeNone)) {240/* This entry states no proxy, therefore just add a NO_PROXY object. */241proxy = (*env)->GetStaticObjectField(env, proxy_class, pr_no_proxyID);242} else {243/*244* Create a proxy object for this entry.245* Differentiate between SOCKS and HTTP type.246*/247jfieldID typeID = ptype_httpID;248if (CFEqual(proxyType, kCFProxyTypeSOCKS)) {249typeID = ptype_socksID;250}251CFNumberRef portNumberRef = (CFNumberRef)CFDictionaryGetValue(currentProxy,252(const void*)kCFProxyPortNumberKey);253if (portNumberRef != NULL) {254int port = 0;255if (CFNumberGetValue(portNumberRef, kCFNumberSInt32Type, &port)) {256CFStringRef hostNameRef = (CFStringRef)CFDictionaryGetValue(257currentProxy, (const void*)kCFProxyHostNameKey);258if (hostNameRef != NULL) {259char hostNameBuffer[BUFFER_SIZE];260if (CFStringGetCString(hostNameRef, hostNameBuffer,261BUFFER_SIZE, kCFStringEncodingUTF8)) {262proxy = createProxy(env, typeID, &hostNameBuffer[0], port);263}264}265}266}267}268if (proxy == NULL || (*env)->ExceptionCheck(env)) {269proxyArray = NULL;270break;271}272(*env)->SetObjectArrayElement(env, proxyArray, index, proxy);273if ((*env)->ExceptionCheck(env)) {274proxyArray = NULL;275break;276}277}278}279CFRelease(expandedProxyArray);280}281CFRelease(urlRef);282}283CFRelease(proxyDicRef);284285return proxyArray;286}287288289