package webdevice import ( "net/http" "net/http/httptest" "net/url" "strings" "testing" "time" ) func TestRewriteLocation(t *testing.T) { t.Parallel() targetURL, _ := url.Parse("http://192.168.1.124:80") got := RewriteLocation("192.168.1.124", targetURL, "http://192.168.1.124/ISAPI/Security") if got != "/proxy/web/192.168.1.124/ISAPI/Security" { t.Fatalf("RewriteLocation() = %q", got) } } func TestRewriteSetCookie(t *testing.T) { t.Parallel() got := RewriteSetCookie("SID=1; Path=/; Domain=192.168.1.124; HttpOnly", "/proxy/web/192.168.1.124") if strings.Contains(strings.ToLower(got), "domain=") { t.Fatalf("RewriteSetCookie() kept domain: %q", got) } if !strings.Contains(got, "Path=/proxy/web/192.168.1.124/") { t.Fatalf("RewriteSetCookie() path = %q", got) } } func TestRewriteText(t *testing.T) { t.Parallel() targetURL, _ := url.Parse("http://192.168.1.124:80") body := `x` got := RewriteText(body, "/proxy/web/192.168.1.124", targetURL, "text/html") if !strings.Contains(got, `/proxy/web/192.168.1.124/doc/logo.png`) { t.Fatalf("rewritten body missing proxied relative URL: %s", got) } if !strings.Contains(got, `data-web-proxy-runtime`) { t.Fatalf("rewritten body missing runtime injection: %s", got) } } func TestProxyHTTPRejectsUnscannedIP(t *testing.T) { t.Parallel() svc := NewService() req := httptest.NewRequest(http.MethodGet, "http://portal/proxy/web/192.168.1.124/", nil) rec := httptest.NewRecorder() err := svc.ProxyHTTP(rec, req, "192.168.1.124", "/") if err != ErrTargetNotAllowed { t.Fatalf("ProxyHTTP() error = %v, want ErrTargetNotAllowed", err) } } func TestProxyHTTPServesAllowedTarget(t *testing.T) { t.Parallel() upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Location", "http://192.168.1.124/ISAPI/test") w.Header().Add("Set-Cookie", "SID=1; Path=/") w.Header().Set("Content-Type", "text/html") _, _ = w.Write([]byte(``)) })) defer upstream.Close() svc := NewService() svc.allowIP("192.168.1.124") svc.proxyTarget = func(ip string) string { return upstream.URL } req := httptest.NewRequest(http.MethodGet, "http://portal/proxy/web/192.168.1.124/", nil) rec := httptest.NewRecorder() if err := svc.ProxyHTTP(rec, req, "192.168.1.124", "/"); err != nil { t.Fatalf("ProxyHTTP() error = %v", err) } if rec.Code != http.StatusOK { t.Fatalf("status = %d body = %s", rec.Code, rec.Body.String()) } if got := rec.Header().Get("Location"); got != "http://192.168.1.124/ISAPI/test" { t.Fatalf("Location = %q", got) } if !strings.Contains(rec.Body.String(), "/proxy/web/192.168.1.124/doc/logo.png") { t.Fatalf("body = %s", rec.Body.String()) } } func TestProxyHTTPClosesUpstreamConnection(t *testing.T) { t.Parallel() closeSeen := make(chan bool, 1) upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { closeSeen <- r.Close w.Header().Set("Content-Type", "text/plain") _, _ = w.Write([]byte("ok")) })) defer upstream.Close() svc := NewService() svc.allowIP("192.168.1.124") svc.proxyTarget = func(ip string) string { return upstream.URL } req := httptest.NewRequest(http.MethodGet, "http://portal/proxy/web/192.168.1.124/", nil) rec := httptest.NewRecorder() if err := svc.ProxyHTTP(rec, req, "192.168.1.124", "/"); err != nil { t.Fatalf("ProxyHTTP() error = %v", err) } if rec.Code != http.StatusOK { t.Fatalf("status = %d body = %s", rec.Code, rec.Body.String()) } select { case got := <-closeSeen: if !got { t.Fatal("upstream request Close = false, want true") } case <-time.After(time.Second): t.Fatal("timed out waiting for upstream request") } } func TestSanitizeProxyRequestHeaderDropsLoginCookie(t *testing.T) { source := http.Header{} source.Set("User-Agent", "browser") source.Set("Cookie", "SID=1") source.Set("Referer", "http://10.8.0.18:13000/proxy/web/192.168.0.108/") source.Set("X-Forwarded-For", "10.8.0.1") loginHeader := sanitizeProxyRequestHeader(source, "/doc/page/login.asp") if got := loginHeader.Get("Cookie"); got != "" { t.Fatalf("login Cookie = %q, want empty", got) } if got := loginHeader.Get("Referer"); got != "" { t.Fatalf("login Referer = %q, want empty", got) } if got := loginHeader.Get("X-Forwarded-For"); got != "" { t.Fatalf("login X-Forwarded-For = %q, want empty", got) } apiHeader := sanitizeProxyRequestHeader(source, "/ISAPI/Security/userCheck") if got := apiHeader.Get("Cookie"); got != "SID=1" { t.Fatalf("api Cookie = %q, want SID=1", got) } }