Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions .github/workflows/windows-proxy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,15 @@ jobs:
- name: Build probe helper
shell: pwsh
run: |
# Out-File does not create parent directories.
New-Item -ItemType Directory -Force -Path probe, probe/fetch, probe/bin | Out-Null
@'
package main

import (
"fmt"
"net/http"
"os"
"time"

"github.com/topcheer/ggcode/internal/util"
)
Expand All @@ -74,9 +75,10 @@ jobs:

import (
"fmt"
"io"
"net/http"
"os"
"io"
"time"

"github.com/topcheer/ggcode/internal/util"
)
Expand Down Expand Up @@ -141,16 +143,26 @@ jobs:
New-Item -ItemType Directory -Force -Path probe/www | Out-Null
$pac | Out-File -Encoding ascii probe/www/proxy.pac

# Serve the PAC script on 127.0.0.1:8099 -- AutoConfigURL points
# here and fetchPACScript GETs it, so something must listen.
$py = if (Get-Command python -ErrorAction SilentlyContinue) { 'python' } else { 'py' }
$server = Start-Process -FilePath $py -ArgumentList '-m','http.server','8099','--directory','probe/www' -PassThru -WindowStyle Hidden
$reg = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings"
Set-ItemProperty $reg AutoConfigURL "http://127.0.0.1:8099/proxy.pac"
try {
$up = $false
foreach ($i in 1..20) {
try { Invoke-WebRequest -NoProxy -UseBasicParsing http://127.0.0.1:8099/proxy.pac -TimeoutSec 2 | Out-Null; $up = $true; break } catch { Start-Sleep -Milliseconds 500 }
}
if (-not $up) { Write-Error "PAC server on :8099 did not come up"; exit 1 }
$out = & probe/bin/probe.exe
if ($out -notmatch '^PROXY http://127\.0\.0\.1:8888') { Write-Error "expected PAC-directed proxy, got: $out"; exit 1 }
Write-Host "layer3 OK: $out"
} finally {
Remove-ItemProperty $reg AutoConfigURL
if ($server -and -not $server.HasExited) { Stop-Process -Id $server.Id -Force }
}

- name: Table tests (all platforms)
shell: pwsh
run: go test -tags goolm -count=1 -run "PAC|SmartProxy" ./internal/util/
run: go test -tags goolm -count=1 -run "PAC|SmartProxy|Directive" ./internal/util/
41 changes: 37 additions & 4 deletions internal/util/sysproxy_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (

"github.com/mattn/go-ieproxy"
"github.com/saucelabs/forwarder/pac"
"golang.org/x/net/http/httpproxy"
)

// Windows system-proxy + PAC support (#761).
Expand Down Expand Up @@ -69,6 +70,35 @@ type pacState struct {
resultCache sync.Map
}

// staticSystemProxy resolves the registry static proxy (ProxyEnable /
// ProxyServer / ProxyOverride) for a single request, mirroring
// ieproxy's staticProxy but never consulting the auto-config entry.
// Returns (nil, nil) when the static proxy is disabled. Note: an
// autoDetect flag alone (WPAD, no AutoConfigURL) must NOT suppress the
// static proxy -- github runners boot with fAutoDetect=true, and the
// guard used to turn layer 2 into DIRECT there.
func staticSystemProxy(req *http.Request) (*url.URL, error) {
conf := ieproxy.GetConf()
if !conf.Static.Active || req.URL == nil {
return nil, nil
}
cfg := httpproxy.Config{
HTTPSProxy: protocolFallback(conf.Static.Protocols, "https"),
HTTPProxy: protocolFallback(conf.Static.Protocols, "http"),
NoProxy: conf.Static.NoProxy,
}
return cfg.ProxyFunc()(req.URL)
}

// protocolFallback returns the per-protocol static proxy, falling back to
// the protocol-less default entry ("http=...;https=..." vs "host:port").
func protocolFallback(m map[string]string, proto string) string {
if v, ok := m[proto]; ok {
return v
}
return m[""]
}

var thePAC pacState

func buildWindowsProxyFunc() func(*http.Request) (*url.URL, error) {
Expand All @@ -78,10 +108,13 @@ func buildWindowsProxyFunc() func(*http.Request) (*url.URL, error) {
return u, err
}

// 2. Static system proxy. ieproxy.GetProxyFunc reads the registry
// (ProxyEnable/ProxyServer/ProxyOverride) and handles per-protocol
// formats; it returns (nil, nil) for direct when disabled.
if u, err := ieproxy.GetProxyFunc()(req); err == nil && u != nil {
// 2. Static system proxy. Read the registry conf ourselves and
// build an httpproxy.Config only from the static entry. We must NOT
// use ieproxy.GetProxyFunc() here: when AutoConfig is active it
// resolves PAC itself via WinHTTP and returns scheme-less URLs
// (&url.URL{Host: ...}), which both short-circuits our own PAC
// engine below (dead code) and mis-handles SOCKS directives.
if u, err := staticSystemProxy(req); err == nil && u != nil {
return u, nil
}

Expand Down
Loading