mirror of
https://github.com/MengMengCode/VoCat.git
synced 2026-08-13 03:13:43 +08:00
73 lines
2.1 KiB
Go
73 lines
2.1 KiB
Go
package exportproxy
|
|
|
|
import (
|
|
"bufio"
|
|
"context"
|
|
"encoding/base64"
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
"net/http"
|
|
"strings"
|
|
)
|
|
|
|
func serveHTTP(client net.Conn, config Config, dialer *net.Dialer, resolver *net.Resolver) error {
|
|
reader := bufio.NewReader(client)
|
|
request, err := http.ReadRequest(reader)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if config.AuthEnabled && !httpAuthorized(request, config) {
|
|
_, _ = client.Write([]byte("HTTP/1.1 407 Proxy Authentication Required\r\nProxy-Authenticate: Basic realm=\"vocat-export-proxy\"\r\n\r\n"))
|
|
return errors.New("HTTP proxy authentication required")
|
|
}
|
|
if request.Method == http.MethodConnect {
|
|
ctx, cancel := context.WithTimeout(context.Background(), proxyTimeout)
|
|
target, err := dialTarget(ctx, request.URL.Host, dialer, resolver)
|
|
cancel()
|
|
if err != nil {
|
|
_, _ = fmt.Fprint(client, "HTTP/1.1 502 Bad Gateway\r\n\r\n")
|
|
return err
|
|
}
|
|
defer target.Close()
|
|
if _, err := client.Write([]byte("HTTP/1.1 200 Connection Established\r\n\r\n")); err != nil {
|
|
return err
|
|
}
|
|
if buffered := reader.Buffered(); buffered > 0 {
|
|
if value, err := reader.Peek(buffered); err == nil {
|
|
_, _ = target.Write(value)
|
|
_, _ = reader.Discard(buffered)
|
|
}
|
|
}
|
|
pipe(client, target)
|
|
return nil
|
|
}
|
|
|
|
request.Header.Del("Proxy-Authorization")
|
|
request.Header.Del("Proxy-Connection")
|
|
request.RequestURI = ""
|
|
transport := &http.Transport{
|
|
DialContext: func(ctx context.Context, _, address string) (net.Conn, error) {
|
|
return dialTarget(ctx, address, dialer, resolver)
|
|
},
|
|
DisableKeepAlives: true,
|
|
}
|
|
response, err := transport.RoundTrip(request)
|
|
if err != nil {
|
|
_, _ = fmt.Fprint(client, "HTTP/1.1 502 Bad Gateway\r\n\r\n")
|
|
return err
|
|
}
|
|
defer response.Body.Close()
|
|
return response.Write(client)
|
|
}
|
|
|
|
func httpAuthorized(request *http.Request, config Config) bool {
|
|
header := strings.TrimSpace(strings.TrimPrefix(request.Header.Get("Proxy-Authorization"), "Basic "))
|
|
decoded, err := base64.StdEncoding.DecodeString(header)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
parts := strings.SplitN(string(decoded), ":", 2)
|
|
return len(parts) == 2 && parts[0] == config.Username && parts[1] == config.Password
|
|
}
|