mirror of
https://github.com/TecharoHQ/anubis.git
synced 2026-04-29 03:22:42 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 29afb6f517 |
@@ -341,6 +341,7 @@ xff
|
|||||||
XForwarded
|
XForwarded
|
||||||
XNG
|
XNG
|
||||||
XOB
|
XOB
|
||||||
|
XOriginal
|
||||||
XReal
|
XReal
|
||||||
yae
|
yae
|
||||||
YAMLTo
|
YAMLTo
|
||||||
|
|||||||
@@ -21,24 +21,6 @@ const (
|
|||||||
querySeparatorLength = 1 // Length of "?" for query strings
|
querySeparatorLength = 1 // Length of "?" for query strings
|
||||||
)
|
)
|
||||||
|
|
||||||
// unixRoundTripper wraps an http.Transport to handle Unix socket requests properly
|
|
||||||
// by ensuring the URL scheme is set to "http" to avoid TLS issues.
|
|
||||||
// Based on the UnixRoundTripper implementation in lib/http.go
|
|
||||||
type unixRoundTripper struct {
|
|
||||||
Transport *http.Transport
|
|
||||||
}
|
|
||||||
|
|
||||||
// RoundTrip implements the http.RoundTripper interface
|
|
||||||
func (t *unixRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
|
||||||
req = req.Clone(req.Context())
|
|
||||||
if req.Host == "" {
|
|
||||||
req.Host = "localhost"
|
|
||||||
}
|
|
||||||
req.URL.Host = req.Host
|
|
||||||
req.URL.Scheme = "http" // Ensure HTTP scheme to avoid "server gave HTTP response to HTTPS client" error
|
|
||||||
return t.Transport.RoundTrip(req)
|
|
||||||
}
|
|
||||||
|
|
||||||
type OGTagCache struct {
|
type OGTagCache struct {
|
||||||
cache store.JSON[map[string]string]
|
cache store.JSON[map[string]string]
|
||||||
targetURL *url.URL
|
targetURL *url.URL
|
||||||
@@ -87,12 +69,11 @@ func NewOGTagCache(target string, conf config.OpenGraph, backend store.Interface
|
|||||||
// Configure custom transport for Unix sockets
|
// Configure custom transport for Unix sockets
|
||||||
if parsedTargetURL.Scheme == "unix" {
|
if parsedTargetURL.Scheme == "unix" {
|
||||||
socketPath := parsedTargetURL.Path // For unix scheme, path is the socket path
|
socketPath := parsedTargetURL.Path // For unix scheme, path is the socket path
|
||||||
transport := &http.Transport{
|
client.Transport = &http.Transport{
|
||||||
DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
|
DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
|
||||||
return net.Dial("unix", socketPath)
|
return net.Dial("unix", socketPath)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
client.Transport = &unixRoundTripper{Transport: transport}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return &OGTagCache{
|
return &OGTagCache{
|
||||||
|
|||||||
@@ -99,16 +99,16 @@ func TestNewOGTagCache_UnixSocket(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if the client transport is configured for Unix sockets
|
// Check if the client transport is configured for Unix sockets
|
||||||
roundTripper, ok := cache.client.Transport.(*unixRoundTripper)
|
transport, ok := cache.client.Transport.(*http.Transport)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Fatalf("expected client transport to be *unixRoundTripper, got %T", cache.client.Transport)
|
t.Fatalf("expected client transport to be *http.Transport, got %T", cache.client.Transport)
|
||||||
}
|
}
|
||||||
if roundTripper.Transport.DialContext == nil {
|
if transport.DialContext == nil {
|
||||||
t.Fatal("expected client transport DialContext to be non-nil for unix socket")
|
t.Fatal("expected client transport DialContext to be non-nil for unix socket")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempt a dummy dial to see if it uses the correct path (optional, more involved check)
|
// Attempt a dummy dial to see if it uses the correct path (optional, more involved check)
|
||||||
dummyConn, err := roundTripper.Transport.DialContext(context.Background(), "", "")
|
dummyConn, err := transport.DialContext(context.Background(), "", "")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
dummyConn.Close()
|
dummyConn.Close()
|
||||||
t.Log("DialContext seems functional, but couldn't verify path without a listener")
|
t.Log("DialContext seems functional, but couldn't verify path without a listener")
|
||||||
|
|||||||
@@ -1,98 +0,0 @@
|
|||||||
package ogtags
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/TecharoHQ/anubis/lib/policy/config"
|
|
||||||
"github.com/TecharoHQ/anubis/lib/store/memory"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TestUnixSocketHTTPSFix tests that the fix prevents "http: server gave HTTP response to HTTPS client" errors
|
|
||||||
// when using Unix socket targets with HTTPS input URLs
|
|
||||||
func TestUnixSocketHTTPSFix(t *testing.T) {
|
|
||||||
tempDir := t.TempDir()
|
|
||||||
socketPath := filepath.Join(tempDir, "test.sock")
|
|
||||||
|
|
||||||
// Create a simple HTTP server listening on the Unix socket
|
|
||||||
server := &http.Server{
|
|
||||||
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
// Verify that the request comes in with HTTP (not HTTPS)
|
|
||||||
if r.URL.Scheme != "" && r.URL.Scheme != "http" {
|
|
||||||
t.Errorf("Unexpected scheme in request: %s (expected 'http' or empty)", r.URL.Scheme)
|
|
||||||
}
|
|
||||||
if r.TLS != nil {
|
|
||||||
t.Errorf("Request has TLS information when it shouldn't for Unix socket")
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "text/html")
|
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
w.Write([]byte(`<html><head><meta property="og:title" content="Test Title"></head></html>`))
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
|
|
||||||
// Listen on Unix socket
|
|
||||||
listener, err := net.Listen("unix", socketPath)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to create Unix socket listener: %v", err)
|
|
||||||
}
|
|
||||||
defer os.Remove(socketPath)
|
|
||||||
defer listener.Close()
|
|
||||||
|
|
||||||
// Start the server
|
|
||||||
go func() {
|
|
||||||
server.Serve(listener)
|
|
||||||
}()
|
|
||||||
defer server.Close()
|
|
||||||
|
|
||||||
// Wait a bit for server to start
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
|
|
||||||
// Create OGTagCache with Unix socket target
|
|
||||||
target := "unix://" + socketPath
|
|
||||||
cache := NewOGTagCache(target, config.OpenGraph{
|
|
||||||
Enabled: true,
|
|
||||||
TimeToLive: time.Minute,
|
|
||||||
}, memory.New(t.Context()))
|
|
||||||
|
|
||||||
// Test cases that previously might have caused the "HTTP response to HTTPS client" error
|
|
||||||
testCases := []struct {
|
|
||||||
name string
|
|
||||||
url string
|
|
||||||
}{
|
|
||||||
{"HTTPS URL", "https://example.com/test"},
|
|
||||||
{"HTTPS with port", "https://example.com:443/test"},
|
|
||||||
{"HTTPS with query", "https://example.com/test?param=value"},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
|
||||||
inputURL, _ := url.Parse(tc.url)
|
|
||||||
|
|
||||||
// This should succeed without the "server gave HTTP response to HTTPS client" error
|
|
||||||
ogTags, err := cache.GetOGTags(context.Background(), inputURL, "example.com")
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
if strings.Contains(err.Error(), "server gave HTTP response to HTTPS client") {
|
|
||||||
t.Errorf("Fix did not work: still getting HTTPS/HTTP error: %v", err)
|
|
||||||
} else {
|
|
||||||
// Other errors are acceptable for this test
|
|
||||||
t.Logf("Got non-HTTPS error (acceptable): %v", err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Success case
|
|
||||||
if ogTags["og:title"] != "Test Title" {
|
|
||||||
t.Errorf("Expected og:title 'Test Title', got: %v", ogTags["og:title"])
|
|
||||||
}
|
|
||||||
t.Logf("Success: got expected og:title = %s", ogTags["og:title"])
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user