Import upstream version 0.0.6
Debian Janitor
2 years ago
0 | # These are supported funding model platforms | |
1 | ||
2 | github: mattn # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] | |
3 | patreon: # Replace with a single Patreon username | |
4 | open_collective: # Replace with a single Open Collective username | |
5 | ko_fi: # Replace with a single Ko-fi username | |
6 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel | |
7 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry | |
8 | liberapay: # Replace with a single Liberapay username | |
9 | issuehunt: # Replace with a single IssueHunt username | |
10 | otechie: # Replace with a single Otechie username | |
11 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] |
0 | name: CI | |
1 | ||
2 | on: | |
3 | push: | |
4 | branches: [master] | |
5 | pull_request: | |
6 | ||
7 | jobs: | |
8 | run-tests: | |
9 | name: Run test cases | |
10 | runs-on: ${{ matrix.os }} | |
11 | strategy: | |
12 | matrix: | |
13 | os: [ubuntu-latest, macos-latest, windows-latest] | |
14 | go: [1.17, 1.16] | |
15 | ||
16 | steps: | |
17 | - uses: actions/checkout@v2 | |
18 | ||
19 | - name: Set up Go | |
20 | uses: actions/setup-go@v2 | |
21 | with: | |
22 | go-version: ${{ matrix.go }} | |
23 | ||
24 | - name: Run tests | |
25 | run: go test -v ./... | |
26 |
0 | 0 | # ieproxy |
1 | 1 | |
2 | Go package to detect the proxy settings on Windows platform. | |
2 | Go package to detect the proxy settings on Windows platform, and MacOS. | |
3 | 3 | |
4 | The settings are initially attempted to be read from the [`WinHttpGetIEProxyConfigForCurrentUser` DLL call](https://docs.microsoft.com/en-us/windows/desktop/api/winhttp/nf-winhttp-winhttpgetieproxyconfigforcurrentuser), but falls back to the registry (`CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings`) in the event the DLL call fails. | |
4 | On Windows, the settings are initially attempted to be read from the [`WinHttpGetIEProxyConfigForCurrentUser` DLL call](https://docs.microsoft.com/en-us/windows/desktop/api/winhttp/nf-winhttp-winhttpgetieproxyconfigforcurrentuser), but falls back to the registry (`CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings`) in the event the DLL call fails. | |
5 | ||
6 | On MacOS, the settings are read from [`CFNetworkCopySystemProxySettings` method of CFNetwork](https://developer.apple.com/documentation/cfnetwork/1426754-cfnetworkcopysystemproxysettings?language=objc). | |
5 | 7 | |
6 | 8 | For more information, take a look at the [documentation](https://godoc.org/github.com/mattn/go-ieproxy) |
7 | 9 |
0 | // +build darwin | |
1 | ||
2 | package ieproxy | |
3 | ||
4 | import ( | |
5 | "net/http" | |
6 | "reflect" | |
7 | "testing" | |
8 | ) | |
9 | ||
10 | func TestPacfile(t *testing.T) { | |
11 | listener, err := listenAndServeWithClose("127.0.0.1:0", http.FileServer(http.Dir("pacfile_examples"))) | |
12 | serverBase := "http://" + listener.Addr().String() + "/" | |
13 | if err != nil { | |
14 | t.Fatal(err) | |
15 | } | |
16 | ||
17 | // test inactive proxy | |
18 | proxy := ProxyScriptConf{ | |
19 | Active: false, | |
20 | PreConfiguredURL: serverBase + "simple.pac", | |
21 | } | |
22 | out := proxy.FindProxyForURL("http://google.com") | |
23 | if out != "" { | |
24 | t.Error("Got: ", out, "Expected: ", "") | |
25 | } | |
26 | proxy.Active = true | |
27 | ||
28 | pacSet := []struct { | |
29 | pacfile string | |
30 | url string | |
31 | expected string | |
32 | }{ | |
33 | { | |
34 | "direct.pac", | |
35 | "http://google.com", | |
36 | "", | |
37 | }, | |
38 | { | |
39 | "404.pac", | |
40 | "http://google.com", | |
41 | "", | |
42 | }, | |
43 | { | |
44 | "simple.pac", | |
45 | "http://google.com", | |
46 | "127.0.0.1:8", | |
47 | }, | |
48 | { | |
49 | "multiple.pac", | |
50 | "http://google.com", | |
51 | "127.0.0.1:8081", | |
52 | }, | |
53 | { | |
54 | "except.pac", | |
55 | "http://imgur.com", | |
56 | "localhost:9999", | |
57 | }, | |
58 | { | |
59 | "except.pac", | |
60 | "http://example.com", | |
61 | "", | |
62 | }, | |
63 | } | |
64 | for _, p := range pacSet { | |
65 | proxy.PreConfiguredURL = serverBase + p.pacfile | |
66 | out := proxy.FindProxyForURL(p.url) | |
67 | if out != p.expected { | |
68 | t.Error("Got: ", out, "Expected: ", p.expected) | |
69 | } | |
70 | } | |
71 | listener.Close() | |
72 | } | |
73 | ||
74 | var multipleMap map[string]string | |
75 | ||
76 | func init() { | |
77 | multipleMap = make(map[string]string) | |
78 | multipleMap["http"] = "127.0.0.1" | |
79 | multipleMap["ftp"] = "128" | |
80 | } | |
81 | ||
82 | func TestOverrideEnv(t *testing.T) { | |
83 | var callStack []string | |
84 | pseudoSetEnv := func(key, value string) error { | |
85 | if value != "" { | |
86 | callStack = append(callStack, key) | |
87 | callStack = append(callStack, value) | |
88 | } | |
89 | return nil | |
90 | } | |
91 | overrideSet := []struct { | |
92 | in ProxyConf | |
93 | callStack []string | |
94 | }{ | |
95 | { | |
96 | callStack: []string{}, | |
97 | }, | |
98 | { | |
99 | in: ProxyConf{ | |
100 | Static: StaticProxyConf{ | |
101 | Active: true, | |
102 | Protocols: multipleMap, | |
103 | }, | |
104 | }, | |
105 | callStack: []string{"http_proxy", "127.0.0.1"}, | |
106 | }, | |
107 | { | |
108 | in: ProxyConf{ | |
109 | Static: StaticProxyConf{ | |
110 | Active: true, | |
111 | NoProxy: "example.com,microsoft.com", | |
112 | }, | |
113 | }, | |
114 | callStack: []string{"no_proxy", "example.com,microsoft.com"}, | |
115 | }, | |
116 | } | |
117 | for _, o := range overrideSet { | |
118 | callStack = []string{} | |
119 | overrideEnvWithStaticProxy(o.in, pseudoSetEnv) | |
120 | if !reflect.DeepEqual(o.callStack, callStack) { | |
121 | t.Error("Got: ", callStack, "Expected: ", o.callStack) | |
122 | } | |
123 | } | |
124 | } |
2 | 2 | go 1.14 |
3 | 3 | |
4 | 4 | require ( |
5 | golang.org/x/net v0.0.0-20191112182307-2180aed22343 | |
6 | golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea | |
7 | golang.org/x/text v0.3.2 // indirect | |
5 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 // indirect | |
6 | golang.org/x/net v0.0.0-20220107192237-5cfca573fb4d | |
7 | golang.org/x/sys v0.0.0-20220110181412-a018aaa089fe | |
8 | golang.org/x/text v0.3.7 // indirect | |
8 | 9 | ) |
0 | 0 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= |
1 | 1 | golang.org/x/net v0.0.0-20191112182307-2180aed22343 h1:00ohfJ4K98s3m6BGUoBd8nyfp4Yl0GoIKvw5abItTjI= |
2 | 2 | golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= |
3 | golang.org/x/net v0.0.0-20220107192237-5cfca573fb4d h1:62NvYBuaanGXR2ZOfwDFkhhl6X1DUgf8qg3GuQvxZsE= | |
4 | golang.org/x/net v0.0.0-20220107192237-5cfca573fb4d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= | |
3 | 5 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
4 | 6 | golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea h1:Mz1TMnfJDRJLk8S8OPCoJYgrsp/Se/2TBre2+vwX128= |
5 | 7 | golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
8 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |
9 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |
10 | golang.org/x/sys v0.0.0-20220110181412-a018aaa089fe h1:W8vbETX/n8S6EmY0Pu4Ix7VvpsJUESTwl0oCK8MJOgk= | |
11 | golang.org/x/sys v0.0.0-20220110181412-a018aaa089fe/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | |
12 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= | |
6 | 13 | golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= |
7 | 14 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |
8 | 15 | golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= |
9 | 16 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= |
17 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | |
18 | golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= | |
19 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= | |
10 | 20 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
35 | 35 | return getConf() |
36 | 36 | } |
37 | 37 | |
38 | // ReloadConf reloads the proxy configuration | |
39 | func ReloadConf() ProxyConf { | |
40 | return reloadConf() | |
41 | } | |
42 | ||
38 | 43 | // OverrideEnvWithStaticProxy writes new values to the |
39 | 44 | // `http_proxy`, `https_proxy` and `no_proxy` environment variables. |
40 | 45 | // The values are taken from the Windows Regedit (should be called in `init()` function - see example) |
0 | package ieproxy | |
1 | ||
2 | /* | |
3 | #cgo LDFLAGS: -framework CoreFoundation | |
4 | #cgo LDFLAGS: -framework CFNetwork | |
5 | #include <strings.h> | |
6 | #include <CFNetwork/CFProxySupport.h> | |
7 | */ | |
8 | import "C" | |
9 | ||
10 | import ( | |
11 | "fmt" | |
12 | "strings" | |
13 | "sync" | |
14 | "unsafe" | |
15 | ) | |
16 | ||
17 | var once sync.Once | |
18 | var darwinProxyConf ProxyConf | |
19 | ||
20 | // GetConf retrieves the proxy configuration from the Windows Regedit | |
21 | func getConf() ProxyConf { | |
22 | once.Do(writeConf) | |
23 | return darwinProxyConf | |
24 | } | |
25 | ||
26 | // reloadConf forces a reload of the proxy configuration. | |
27 | func reloadConf() ProxyConf { | |
28 | writeConf() | |
29 | return getConf() | |
30 | } | |
31 | ||
32 | func cfStringGetGoString(cfStr C.CFStringRef) string { | |
33 | retCString := (*C.char)(C.calloc(C.ulong(uint(128)), 1)) | |
34 | defer C.free(unsafe.Pointer(retCString)) | |
35 | ||
36 | C.CFStringGetCString(cfStr, retCString, C.long(128), C.kCFStringEncodingUTF8) | |
37 | return C.GoString(retCString) | |
38 | } | |
39 | ||
40 | func cfNumberGetGoInt(cfNum C.CFNumberRef) int { | |
41 | ret := 0 | |
42 | C.CFNumberGetValue(cfNum, C.kCFNumberIntType, unsafe.Pointer(&ret)) | |
43 | return ret | |
44 | } | |
45 | ||
46 | func cfArrayGetGoStrings(cfArray C.CFArrayRef) []string { | |
47 | var ret []string | |
48 | for i := 0; i < int(C.CFArrayGetCount(cfArray)); i++ { | |
49 | cfStr := C.CFStringRef(C.CFArrayGetValueAtIndex(cfArray, C.long(i))) | |
50 | if unsafe.Pointer(cfStr) != C.NULL { | |
51 | ret = append(ret, cfStringGetGoString(cfStr)) | |
52 | } | |
53 | } | |
54 | return ret | |
55 | } | |
56 | ||
57 | func writeConf() { | |
58 | cfDictProxy := C.CFDictionaryRef(C.CFNetworkCopySystemProxySettings()) | |
59 | defer C.CFRelease(C.CFTypeRef(cfDictProxy)) | |
60 | darwinProxyConf = ProxyConf{} | |
61 | ||
62 | cfNumHttpEnable := C.CFNumberRef(C.CFDictionaryGetValue(cfDictProxy, unsafe.Pointer(C.kCFNetworkProxiesHTTPEnable))) | |
63 | if unsafe.Pointer(cfNumHttpEnable) != C.NULL && cfNumberGetGoInt(cfNumHttpEnable) > 0 { | |
64 | darwinProxyConf.Static.Active = true | |
65 | if darwinProxyConf.Static.Protocols == nil { | |
66 | darwinProxyConf.Static.Protocols = make(map[string]string) | |
67 | } | |
68 | httpHost := C.CFStringRef(C.CFDictionaryGetValue(cfDictProxy, unsafe.Pointer(C.kCFNetworkProxiesHTTPProxy))) | |
69 | httpPort := C.CFNumberRef(C.CFDictionaryGetValue(cfDictProxy, unsafe.Pointer(C.kCFNetworkProxiesHTTPPort))) | |
70 | ||
71 | httpProxy := fmt.Sprintf("%s:%d", cfStringGetGoString(httpHost), cfNumberGetGoInt(httpPort)) | |
72 | darwinProxyConf.Static.Protocols["http"] = httpProxy | |
73 | } | |
74 | ||
75 | cfNumHttpsEnable := C.CFNumberRef(C.CFDictionaryGetValue(cfDictProxy, unsafe.Pointer(C.kCFNetworkProxiesHTTPSEnable))) | |
76 | if unsafe.Pointer(cfNumHttpsEnable) != C.NULL && cfNumberGetGoInt(cfNumHttpsEnable) > 0 { | |
77 | darwinProxyConf.Static.Active = true | |
78 | if darwinProxyConf.Static.Protocols == nil { | |
79 | darwinProxyConf.Static.Protocols = make(map[string]string) | |
80 | } | |
81 | httpsHost := C.CFStringRef(C.CFDictionaryGetValue(cfDictProxy, unsafe.Pointer(C.kCFNetworkProxiesHTTPSProxy))) | |
82 | httpsPort := C.CFNumberRef(C.CFDictionaryGetValue(cfDictProxy, unsafe.Pointer(C.kCFNetworkProxiesHTTPSPort))) | |
83 | ||
84 | httpProxy := fmt.Sprintf("%s:%d", cfStringGetGoString(httpsHost), cfNumberGetGoInt(httpsPort)) | |
85 | darwinProxyConf.Static.Protocols["https"] = httpProxy | |
86 | } | |
87 | ||
88 | if darwinProxyConf.Static.Active { | |
89 | cfArrayExceptionList := C.CFArrayRef(C.CFDictionaryGetValue(cfDictProxy, unsafe.Pointer(C.kCFNetworkProxiesExceptionsList))) | |
90 | if unsafe.Pointer(cfArrayExceptionList) != C.NULL { | |
91 | exceptionList := cfArrayGetGoStrings(cfArrayExceptionList) | |
92 | darwinProxyConf.Static.NoProxy = strings.Join(exceptionList, ",") | |
93 | } | |
94 | } | |
95 | ||
96 | cfNumPacEnable := C.CFNumberRef(C.CFDictionaryGetValue(cfDictProxy, unsafe.Pointer(C.kCFNetworkProxiesProxyAutoConfigEnable))) | |
97 | if unsafe.Pointer(cfNumPacEnable) != C.NULL && cfNumberGetGoInt(cfNumPacEnable) > 0 { | |
98 | cfStringPac := C.CFStringRef(C.CFDictionaryGetValue(cfDictProxy, unsafe.Pointer(C.kCFNetworkProxiesProxyAutoConfigURLString))) | |
99 | if unsafe.Pointer(cfStringPac) != C.NULL { | |
100 | pac := cfStringGetGoString(cfStringPac) | |
101 | darwinProxyConf.Automatic.PreConfiguredURL = pac | |
102 | darwinProxyConf.Automatic.Active = true | |
103 | } | |
104 | } | |
105 | } | |
106 | ||
107 | // OverrideEnvWithStaticProxy writes new values to the | |
108 | // http_proxy, https_proxy and no_proxy environment variables. | |
109 | // The values are taken from the MacOS System Preferences. | |
110 | func overrideEnvWithStaticProxy(conf ProxyConf, setenv envSetter) { | |
111 | if conf.Static.Active { | |
112 | for _, scheme := range []string{"http", "https"} { | |
113 | url := conf.Static.Protocols[scheme] | |
114 | if url != "" { | |
115 | setenv(scheme+"_proxy", url) | |
116 | } | |
117 | } | |
118 | if conf.Static.NoProxy != "" { | |
119 | setenv("no_proxy", conf.Static.NoProxy) | |
120 | } | |
121 | } | |
122 | } |
0 | // +build !windows | |
0 | // +build !windows,!darwin | |
1 | 1 | |
2 | 2 | package ieproxy |
3 | 3 | |
5 | 5 | return ProxyConf{} |
6 | 6 | } |
7 | 7 | |
8 | func reloadConf() ProxyConf { | |
9 | return getConf() | |
10 | } | |
11 | ||
8 | 12 | func overrideEnvWithStaticProxy(pc ProxyConf, setenv envSetter) { |
9 | 13 | } |
23 | 23 | return windowsProxyConf |
24 | 24 | } |
25 | 25 | |
26 | // reloadConf forces a reload of the proxy configuration from the Windows registry | |
27 | func reloadConf() ProxyConf { | |
28 | writeConf() | |
29 | return getConf() | |
30 | } | |
31 | ||
26 | 32 | func writeConf() { |
27 | 33 | proxy := "" |
28 | 34 | proxyByPass := "" |
41 | 47 | autoDetect = ieCfg.fAutoDetect |
42 | 48 | } |
43 | 49 | |
44 | // Try WinHTTP default proxy. | |
45 | if defaultCfg, err := getDefaultProxyConfiguration(); err == nil { | |
46 | defer globalFreeWrapper(defaultCfg.lpszProxy) | |
47 | defer globalFreeWrapper(defaultCfg.lpszProxyBypass) | |
48 | ||
49 | newProxy := StringFromUTF16Ptr(defaultCfg.lpszProxy) | |
50 | if proxy == "" { | |
51 | proxy = newProxy | |
52 | } | |
53 | ||
54 | newProxyByPass := StringFromUTF16Ptr(defaultCfg.lpszProxyBypass) | |
55 | if proxyByPass == "" { | |
56 | proxyByPass = newProxyByPass | |
50 | if proxy == "" && !autoDetect { | |
51 | // Try WinHTTP default proxy. | |
52 | if defaultCfg, err := getDefaultProxyConfiguration(); err == nil { | |
53 | defer globalFreeWrapper(defaultCfg.lpszProxy) | |
54 | defer globalFreeWrapper(defaultCfg.lpszProxyBypass) | |
55 | ||
56 | // Always set both of these (they are a pair, it doesn't make sense to set one here and keep the value of the other from above) | |
57 | proxy = StringFromUTF16Ptr(defaultCfg.lpszProxy) | |
58 | proxyByPass = StringFromUTF16Ptr(defaultCfg.lpszProxyBypass) | |
57 | 59 | } |
58 | 60 | } |
59 | 61 | |
167 | 169 | } |
168 | 170 | |
169 | 171 | func readRegedit() (values regeditValues, err error) { |
170 | k, err := registry.OpenKey(registry.CURRENT_USER, `Software\Microsoft\Windows\CurrentVersion\Internet Settings`, registry.QUERY_VALUE) | |
172 | var proxySettingsPerUser uint64 = 1 // 1 is the default value to consider current user | |
173 | k, err := registry.OpenKey(registry.LOCAL_MACHINE, `Software\Policies\Microsoft\Windows\CurrentVersion\Internet Settings`, registry.QUERY_VALUE) | |
174 | if err == nil { | |
175 | //We had used the below variable tempPrxUsrSettings, because the Golang method GetIntegerValue | |
176 | //sets the value to zero even it fails. | |
177 | tempPrxUsrSettings, _, err := k.GetIntegerValue("ProxySettingsPerUser") | |
178 | if err == nil { | |
179 | //consider the value of tempPrxUsrSettings if it is a success | |
180 | proxySettingsPerUser = tempPrxUsrSettings | |
181 | } | |
182 | k.Close() | |
183 | } | |
184 | ||
185 | var hkey registry.Key | |
186 | if proxySettingsPerUser == 0 { | |
187 | hkey = registry.LOCAL_MACHINE | |
188 | } else { | |
189 | hkey = registry.CURRENT_USER | |
190 | } | |
191 | ||
192 | k, err = registry.OpenKey(hkey, `Software\Microsoft\Windows\CurrentVersion\Internet Settings`, registry.QUERY_VALUE) | |
171 | 193 | if err != nil { |
172 | 194 | return |
173 | 195 | } |
0 | package ieproxy | |
1 | ||
2 | /* | |
3 | #cgo LDFLAGS: -framework CoreFoundation | |
4 | #cgo LDFLAGS: -framework CFNetwork | |
5 | #include <strings.h> | |
6 | #include <CFNetwork/CFProxySupport.h> | |
7 | ||
8 | #define STR_LEN 128 | |
9 | ||
10 | void proxyAutoConfCallback(void* client, CFArrayRef proxies, CFErrorRef error) { | |
11 | CFTypeRef* result_ptr = (CFTypeRef*)client; | |
12 | if (error != NULL) { | |
13 | *result_ptr = CFRetain(error); | |
14 | } else { | |
15 | *result_ptr = CFRetain(proxies); | |
16 | } | |
17 | CFRunLoopStop(CFRunLoopGetCurrent()); | |
18 | } | |
19 | ||
20 | int intCFNumber(CFNumberRef num) { | |
21 | int ret; | |
22 | CFNumberGetValue(num, kCFNumberIntType, &ret); | |
23 | return ret; | |
24 | } | |
25 | ||
26 | char* _getProxyUrlFromPac(char* pac, char* reqCs) { | |
27 | char* retCString = (char*)calloc(STR_LEN, sizeof(char)); | |
28 | ||
29 | CFStringRef reqStr = CFStringCreateWithCString(NULL, reqCs, kCFStringEncodingUTF8); | |
30 | CFStringRef pacStr = CFStringCreateWithCString(NULL, pac, kCFStringEncodingUTF8); | |
31 | CFURLRef pacUrl = CFURLCreateWithString(NULL, pacStr, NULL); | |
32 | CFURLRef reqUrl = CFURLCreateWithString(NULL, reqStr, NULL); | |
33 | ||
34 | CFTypeRef result = NULL; | |
35 | CFStreamClientContext context = { 0, &result, NULL, NULL, NULL }; | |
36 | CFRunLoopSourceRef runloop_src = CFNetworkExecuteProxyAutoConfigurationURL(pacUrl, reqUrl, proxyAutoConfCallback, &context); | |
37 | ||
38 | if (runloop_src) { | |
39 | const CFStringRef private_runloop_mode = CFSTR("go-ieproxy"); | |
40 | CFRunLoopAddSource(CFRunLoopGetCurrent(), runloop_src, private_runloop_mode); | |
41 | CFRunLoopRunInMode(private_runloop_mode, DBL_MAX, false); | |
42 | CFRunLoopRemoveSource(CFRunLoopGetCurrent(), runloop_src, kCFRunLoopCommonModes); | |
43 | ||
44 | if (CFGetTypeID(result) == CFArrayGetTypeID()) { | |
45 | CFArrayRef resultArray = (CFTypeRef)result; | |
46 | if (CFArrayGetCount(resultArray) > 0) { | |
47 | CFDictionaryRef pxy = (CFDictionaryRef)CFArrayGetValueAtIndex(resultArray, 0); | |
48 | CFStringRef pxyType = CFDictionaryGetValue(pxy, kCFProxyTypeKey); | |
49 | ||
50 | if (CFEqual(pxyType, kCFProxyTypeNone)) { | |
51 | // noop | |
52 | } | |
53 | ||
54 | if (CFEqual(pxyType, kCFProxyTypeHTTP)) { | |
55 | CFStringRef host = (CFStringRef)CFDictionaryGetValue(pxy, kCFProxyHostNameKey); | |
56 | CFNumberRef port = (CFNumberRef)CFDictionaryGetValue(pxy, kCFProxyPortNumberKey); | |
57 | ||
58 | char host_str[STR_LEN - 16]; | |
59 | CFStringGetCString(host, host_str, STR_LEN - 16, kCFStringEncodingUTF8); | |
60 | ||
61 | int port_int = 80; | |
62 | if (port) { | |
63 | CFNumberGetValue(port, kCFNumberIntType, &port_int); | |
64 | } | |
65 | ||
66 | sprintf(retCString, "%s:%d", host_str, port_int); | |
67 | } | |
68 | } | |
69 | } else { | |
70 | // error | |
71 | } | |
72 | } | |
73 | ||
74 | CFRelease(result); | |
75 | CFRelease(reqStr); | |
76 | CFRelease(reqUrl); | |
77 | CFRelease(pacStr); | |
78 | CFRelease(pacUrl); | |
79 | return retCString; | |
80 | } | |
81 | ||
82 | char* _getPacUrl() { | |
83 | char* retCString = (char*)calloc(STR_LEN, sizeof(char)); | |
84 | CFDictionaryRef proxyDict = CFNetworkCopySystemProxySettings(); | |
85 | CFNumberRef pacEnable = (CFNumberRef)CFDictionaryGetValue(proxyDict, kCFNetworkProxiesProxyAutoConfigEnable); | |
86 | ||
87 | if (pacEnable && intCFNumber(pacEnable)) { | |
88 | CFStringRef pacUrlStr = (CFStringRef)CFDictionaryGetValue(proxyDict, kCFNetworkProxiesProxyAutoConfigURLString); | |
89 | if (pacUrlStr) { | |
90 | CFStringGetCString(pacUrlStr, retCString, STR_LEN, kCFStringEncodingUTF8); | |
91 | } | |
92 | } | |
93 | ||
94 | CFRelease(proxyDict); | |
95 | return retCString; | |
96 | } | |
97 | ||
98 | */ | |
99 | import "C" | |
100 | import "unsafe" | |
101 | ||
102 | func (psc *ProxyScriptConf) findProxyForURL(URL string) string { | |
103 | if !psc.Active { | |
104 | return "" | |
105 | } | |
106 | proxy := getProxyForURL(psc.PreConfiguredURL, URL) | |
107 | return proxy | |
108 | } | |
109 | ||
110 | func getProxyForURL(pacFileURL, url string) string { | |
111 | if pacFileURL == "" { | |
112 | pacFileURL = getPacUrl() | |
113 | } | |
114 | if pacFileURL == "" { | |
115 | return "" | |
116 | } | |
117 | ||
118 | csUrl := C.CString(url) | |
119 | csPac := C.CString(pacFileURL) | |
120 | csRet := C._getProxyUrlFromPac(csPac, csUrl) | |
121 | ||
122 | defer C.free(unsafe.Pointer(csUrl)) | |
123 | defer C.free(unsafe.Pointer(csPac)) | |
124 | defer C.free(unsafe.Pointer(csRet)) | |
125 | ||
126 | return C.GoString(csRet) | |
127 | } | |
128 | ||
129 | func getPacUrl() string { | |
130 | csRet := C._getPacUrl() | |
131 | ||
132 | defer C.free(unsafe.Pointer(csRet)) | |
133 | return C.GoString(csRet) | |
134 | } |
0 | package ieproxy | |
1 | ||
2 | import ( | |
3 | "net/http" | |
4 | "net/url" | |
5 | ||
6 | "golang.org/x/net/http/httpproxy" | |
7 | ) | |
8 | ||
9 | func proxyMiddleman() func(req *http.Request) (i *url.URL, e error) { | |
10 | // Get the proxy configuration | |
11 | conf := GetConf() | |
12 | envCfg := httpproxy.FromEnvironment() | |
13 | ||
14 | if envCfg.HTTPProxy != "" || envCfg.HTTPSProxy != "" { | |
15 | // If the user manually specifies environment variables, prefer those over the MacOS config. | |
16 | return http.ProxyFromEnvironment | |
17 | } | |
18 | ||
19 | return func(req *http.Request) (i *url.URL, e error) { | |
20 | if conf.Automatic.Active { | |
21 | host := conf.Automatic.FindProxyForURL(req.URL.String()) | |
22 | if host != "" { | |
23 | return &url.URL{Host: host}, nil | |
24 | } | |
25 | } | |
26 | if conf.Static.Active { | |
27 | return staticProxy(conf, req) | |
28 | } | |
29 | // Should return no proxy; fallthrough. | |
30 | return http.ProxyFromEnvironment(req) | |
31 | } | |
32 | } | |
33 | ||
34 | func staticProxy(conf ProxyConf, req *http.Request) (i *url.URL, e error) { | |
35 | // If static proxy obtaining is specified | |
36 | proxy := httpproxy.Config{ | |
37 | HTTPSProxy: conf.Static.Protocols["https"], | |
38 | HTTPProxy: conf.Static.Protocols["http"], | |
39 | NoProxy: conf.Static.NoProxy, | |
40 | } | |
41 | return proxy.ProxyFunc()(req.URL) | |
42 | } |