Files
zonat/e2e/http_test.go
T

111 lines
3.0 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// HTTP 穿透测试:验证"隧道模式全用 tcp"成立——真实 HTTP 服务(含 keep-alive、
// 大 body)经纯 TCP 隧道完整可用,无需 zonat 的 http 反向代理模式。
package e2e
import (
"bytes"
"crypto/rand"
"encoding/json"
"io"
"net/http"
"net/http/httptest"
"strconv"
"testing"
"time"
"git.zeroonesoft.cn/golib/zonat/agent"
"git.zeroonesoft.cn/golib/zonat/internal/node"
)
func startHTTPServer(t *testing.T) *httptest.Server {
t.Helper()
mux := http.NewServeMux()
mux.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{"hello": "zonat", "via": "tcp-tunnel"})
})
mux.HandleFunc("/echo", func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "POST only", http.StatusMethodNotAllowed)
return
}
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
w.Write(body)
})
srv := httptest.NewServer(mux)
t.Cleanup(srv.Close)
return srv
}
// registerHTTP 把 httptest.Server 登记为一条隧道,返回公网端口
func registerHTTP(t *testing.T, n *node.Node, a *agent.Agent, srv *httptest.Server, id string) int {
t.Helper()
port, err := a.RegisterTunnel(buildTunnel(t, n, a, id, srv.Listener.Addr().String(), 0))
if err != nil {
t.Fatal(err)
}
return port
}
func TestHTTPGetPostThroughTunnel(t *testing.T) {
srv := startHTTPServer(t)
n, a := startEnv(t)
port := registerHTTP(t, n, a, srv, "http-tunnel")
base := "http://127.0.0.1:" + strconv.Itoa(port)
// GET
resp, err := http.Get(base + "/hello")
if err != nil {
t.Fatal(err)
}
var body map[string]string
if err := json.NewDecoder(resp.Body).Decode(&body); err != nil {
t.Fatal(err)
}
resp.Body.Close()
if resp.StatusCode != http.StatusOK || body["hello"] != "zonat" {
t.Fatalf("GET /hello 异常: status=%d body=%v", resp.StatusCode, body)
}
// POST 大 body(1MB,跨 smux 多帧)
payload := make([]byte, 1<<20)
if _, err := rand.Read(payload); err != nil {
t.Fatal(err)
}
resp2, err := http.Post(base+"/echo", "application/octet-stream", bytes.NewReader(payload))
if err != nil {
t.Fatal(err)
}
got, err := io.ReadAll(resp2.Body)
resp2.Body.Close()
if err != nil {
t.Fatal(err)
}
if resp2.StatusCode != http.StatusOK || !bytes.Equal(got, payload) {
t.Fatalf("POST /echo 异常: status=%d len(got)=%d", resp2.StatusCode, len(got))
}
}
func TestHTTPKeepAliveThroughTunnel(t *testing.T) {
srv := startHTTPServer(t)
n, a := startEnv(t)
port := registerHTTP(t, n, a, srv, "http-ka")
// 同一 client 复用 TCP 连接(keep-alive),10 次请求走同一条隧道流
client := &http.Client{Timeout: 10 * time.Second}
for i := 0; i < 10; i++ {
resp, err := client.Get("http://127.0.0.1:" + strconv.Itoa(port) + "/hello")
if err != nil {
t.Fatal(err)
}
resp.Body.Close()
if resp.StatusCode != http.StatusOK {
t.Fatalf("第 %d 次请求异常: %d", i+1, resp.StatusCode)
}
}
}