fix(http): resolve effective upstream authorities

This commit is contained in:
fhgffy 2026-10-14 00:28:06 +08:00
parent 487da737b9
commit 26ecfeffa7
2 changed files with 64 additions and 8 deletions

View File

@ -4,6 +4,7 @@ import (
"bufio" "bufio"
"bytes" "bytes"
"fmt" "fmt"
"net"
"net/textproto" "net/textproto"
"net/url" "net/url"
"strings" "strings"
@ -78,24 +79,19 @@ func parseRequest(r *bufio.Reader) (*request, error) {
uri = uri[7:] uri = uri[7:]
} }
tgt := u.Host
if !strings.Contains(tgt, ":") {
tgt += ":80"
}
req := &request{ req := &request{
method: method, method: method,
uri: uri, uri: uri,
proto: proto, proto: proto,
auth: auth, auth: auth,
header: header, header: header,
target: tgt,
} }
if u.IsAbs() { if u.IsAbs() {
req.absuri = u.String() req.absuri = u.String()
u.Scheme, u.Host = "", "" relative := *u
req.ruri = u.String() relative.Scheme, relative.Host = "", ""
req.ruri = relative.String()
} else { } else {
req.ruri = u.String() req.ruri = u.String()
base, err := url.Parse("http://" + header.Get("Host")) base, err := url.Parse("http://" + header.Get("Host"))
@ -106,6 +102,12 @@ func parseRequest(r *bufio.Reader) (*request, error) {
req.absuri = u.String() req.absuri = u.String()
} }
port := u.Port()
if port == "" {
port = "80"
}
req.target = net.JoinHostPort(u.Hostname(), port)
return req, nil return req, nil
} }

View File

@ -0,0 +1,54 @@
package http
import (
"bufio"
"strings"
"testing"
)
func TestParseRequestTarget(t *testing.T) {
for _, tt := range []struct {
name string
uri string
host string
target string
}{
{"absolute hostname", "http://example.com/path", "other.example", "example.com:80"},
{"absolute hostname port", "http://example.com:8080/path", "other.example", "example.com:8080"},
{"absolute IPv6", "http://[2001:db8::1]/path", "other.example", "[2001:db8::1]:80"},
{"absolute IPv6 port", "http://[2001:db8::1]:8080/path", "other.example", "[2001:db8::1]:8080"},
{"origin hostname", "/path", "example.com", "example.com:80"},
{"origin hostname port", "/path", "example.com:8080", "example.com:8080"},
{"origin IPv6", "/path", "[2001:db8::1]", "[2001:db8::1]:80"},
{"origin IPv6 port", "/path", "[2001:db8::1]:8080", "[2001:db8::1]:8080"},
} {
t.Run(tt.name, func(t *testing.T) {
raw := "GET " + tt.uri + " HTTP/1.1\r\nHost: " + tt.host + "\r\n\r\n"
req, err := parseRequest(bufio.NewReader(strings.NewReader(raw)))
if err != nil {
t.Fatal(err)
}
if req.target != tt.target {
t.Errorf("target = %q, want %q", req.target, tt.target)
}
if req.ruri != "/path" {
t.Errorf("relative URI = %q, want /path", req.ruri)
}
})
}
}
func TestParseConnectAuthority(t *testing.T) {
for _, authority := range []string{"example.com:443", "[2001:db8::1]:8443"} {
t.Run(authority, func(t *testing.T) {
raw := "CONNECT " + authority + " HTTP/1.1\r\nHost: other.example:8080\r\n\r\n"
req, err := parseRequest(bufio.NewReader(strings.NewReader(raw)))
if err != nil {
t.Fatal(err)
}
if req.uri != authority || req.target != authority {
t.Errorf("CONNECT uri=%q target=%q, want %q", req.uri, req.target, authority)
}
})
}
}