ソースを参照

commiting after migration

aeth 1 週間 前
コミット
0be8eaca40
5 ファイル変更185 行追加7 行削除
  1. 147 0
      cmd/http-proxy/http-proxy.go
  2. 3 1
      cmd/http-wokou/http-wokou.go
  3. 4 2
      pkg/client.go
  4. 30 4
      pkg/controller.go
  5. 1 0
      pkg/routing.go

+ 147 - 0
cmd/http-proxy/http-proxy.go

@@ -0,0 +1,147 @@
+package main
+
+import (
+	"fmt"
+	"io"
+	"log"
+	"net"
+	"net/http"
+	"strings"
+
+	"github.com/gin-gonic/gin"
+)
+
+const (
+	TUNNEL_PACKET = `HTTP/1.1 200 Connection Established\r\nProxy-agent: spit-wizard.void\r\n\r\n`
+)
+
+func main() {
+	r := gin.Default()
+	r.NoRoute(routeProxy) // NO Route is every Route!!!
+	r.Run(":8080")        // listen and serve on 0.0.0.0:8080
+}
+
+// Then I can process all routes
+func routeProxy(c *gin.Context) {
+	req := c.Request
+	go resolveReq(req) // just print basic info. Remember you can't proxy youself.
+
+	if req.Method == http.MethodConnect {
+		// create http tunnel process https
+		httpsProxy(c, req)
+	} else {
+		// process plain http
+		httpProxy(c, req)
+	}
+}
+
+func resolveReq(req *http.Request) {
+	fmt.Printf("Method: %s, Host: %s, URL: %s, Version: %s\n", req.Method, req.Host, req.URL.Path, req.Proto)
+	//fmt.Printf("%+v\n", req)
+}
+
+func httpProxy(c *gin.Context, req *http.Request) {
+	newReq, _ := http.NewRequest(req.Method, req.URL.String(), req.Body)
+	resp, err := http.DefaultClient.Do(newReq)
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer resp.Body.Close()
+
+	data, err := io.ReadAll(resp.Body)
+	if err != nil {
+		log.Fatal(err)
+	}
+	fmt.Printf("%s\n%s\n%s\n", req.Host, req.Method, req.RequestURI)
+	code := resp.StatusCode
+	c.Status(code) // change the status code, default is 404 !!!
+	for k, v := range resp.Header {
+		c.Header(k, strings.Join(v, ","))
+	}
+	c.Header("Server", "spit-wizard.void") // just change it, this is yours gin proxy.
+	c.Writer.Write(data)
+}
+
+func httpsProxy(c *gin.Context, req *http.Request) {
+	// established connect tunnel
+	c.Status(200)
+	c.Header("Server", "spit-wizard.void")
+	c.Writer.Write([]byte(TUNNEL_PACKET))
+	// c.Writer.Flush() // this may cause proble, but I don't know.
+
+	address := req.URL.Host // it contains the port
+	tunnelConn, err := net.Dial("tcp", address)
+	if err != nil {
+		log.Fatal(err)
+	}
+	//fmt.Printf("try to established Connect Tunnel to: %s has been successfully.\n", address)
+
+	// But next is a TCP communication, but the tcp conn is a non-export variable,
+	// so I can't get it, in the same, client's data is binary, so gin can't parse it.
+	// so I can't do anything!!!
+	// LOL, I find HTTP hijacker, it can make me take over the connection!!!
+	hj, ok := c.Writer.(http.Hijacker)
+	if !ok {
+		http.Error(c.Writer, "webserver doesn't support hijacking", http.StatusInternalServerError)
+		return
+	}
+	conn, bufrw, err := hj.Hijack()
+	if err != nil {
+		http.Error(c.Writer, err.Error(), http.StatusInternalServerError)
+		return
+	}
+	defer conn.Close()
+
+	// first read request, then write response.
+	// data flow direction:
+	// client <---> proxy <---> server
+
+	done := make(chan struct{})
+	go func() {
+
+		io.Copy(tunnelConn, bufrw)
+		/*
+			//	 this is my first write, but then I find other use io.Copy
+			log.Println("client --> proxy --> server")
+			data := make([]byte, 1024)
+			for {
+				log.Println("client --> proxy")
+				n, err := bufrw.Read(data)
+				if err != nil {
+					log.Printf("%v\n", err)
+					done <- struct{}{}
+				}
+				log.Println("proxy --> server")
+				tunnelConn.Write(data[:n])
+			}
+		*/
+	}()
+
+	go func() {
+
+		io.Copy(bufrw, tunnelConn)
+		/*
+			log.Println("server --> proxy --> client")
+			data := make([]byte, 1024)
+			for {
+				log.Println("server --> proxy")
+				for {
+					n, err := tunnelConn.Read(data)
+					if err != nil {
+						log.Printf("%v\n", err)
+						done <- struct{}{}
+					}
+					log.Println("proxy --> client")
+					bufrw.Write(data[:n])
+					if n < 1024 {
+						break
+					}
+				}
+				bufrw.Flush()
+			}
+		*/
+	}()
+
+	<-done
+	//fmt.Println("The Tunnel has closed.")
+}

+ 3 - 1
cmd/http-wokou/http-wokou.go

@@ -84,5 +84,7 @@ func main() {
 	e := gin.Default()
 	e.SetTrustedProxies(nil)
 	httpserver.RegisterRoutes(e, cfg)
-	e.Run(fmt.Sprintf("%s:%v", cfg.ListeningIp, cfg.HttpPort))
+	// e.Run(fmt.Sprintf("%s:%v", cfg.ListeningIp, cfg.HttpPort))
+	e.RunTLS(fmt.Sprintf("%s:%v", cfg.ListeningIp, cfg.HttpsPort), cfg.SslPemFile, cfg.SslKeyFile)
+
 }

+ 4 - 2
pkg/client.go

@@ -47,7 +47,7 @@ type ResponseCarrier struct {
 Generic site call to an upstream server
 */
 func (c *Controller) RequestGeneric(method string, host string, path string, hdrs *http.Header, body io.Reader) ResponseCarrier {
-	reqUrl := fmt.Sprintf("%s://%s%s", "http", host, path)
+	reqUrl := fmt.Sprintf("%s://%s%s", "https", host, path)
 	req, err := http.NewRequest(method, reqUrl, body)
 	if err != nil {
 		return ResponseCarrier{Data: nil, Headers: nil, StatusCode: 500, Error: err}
@@ -61,7 +61,9 @@ func (c *Controller) RequestGeneric(method string, host string, path string, hdr
 	if err != nil {
 		return ResponseCarrier{Data: nil, Headers: resp.Header, StatusCode: resp.StatusCode, Error: err}
 	}
-	bytes.ReplaceAll(b, []byte(c.Config.TargetDomain), []byte(c.Config.ProxyDomain))
+	fmt.Printf("%+v\n", resp.Header.Get("location"))
+
+	b = bytes.ReplaceAll(b, []byte(c.Config.TargetDomain), []byte(c.Config.ProxyDomain))
 
 	if c.Config.Caching {
 		if !strings.Contains(path, "?") {

+ 30 - 4
pkg/controller.go

@@ -28,6 +28,7 @@ package httpserver
 
 import (
 	"fmt"
+	"io"
 	"log"
 	"net/http"
 	"net/http/cookiejar"
@@ -120,14 +121,39 @@ func (c *Controller) HandleAny(ctx *gin.Context) {
 		log.Fatal(resp.Error, " failed to route the request: ", incomingPath, " to the target domain: ", ctx.Request.Host, " Error: ", resp.Error)
 	}
 	for k, v := range resp.Headers {
-		_, ok := NonmutableHeaders[k]
-		if !ok {
-			// ctx.Header(k, strings.ReplaceAll(v[0], c.Config.TargetDomain, c.Config.ProxyDomain))
-			ctx.Header(k, v[0])
+		//		_, ok := NonmutableHeaders[k]
+		//		if !ok {
+		for i := range v {
+			//ctx.Header(k, strings.ReplaceAll(v[i], c.Config.TargetDomain, c.Config.ProxyDomain))
+			ctx.Writer.Header().Add(k, v[i])
 		}
+		//		}
 	}
+	fmt.Printf("%+v\n", resp.Headers)
 	ctx.Header("access-control-allow-origin", c.Config.ProxyDomain)
 	ctx.Data(resp.StatusCode, resp.Headers.Get("content-type"), resp.Data)
 	return
 
 }
+
+func (c *Controller) HandleAnyRe(ctx *gin.Context) {
+	fmt.Printf("%s\n%s\n%s\n", ctx.Request.Method, ctx.Request.Host, ctx.Request.RequestURI)
+	resp, err := c.Client.Do(ctx.Request)
+	if err != nil {
+		ctx.Data(500, "text/html", []byte("Internal server error"))
+		return
+	}
+	defer resp.Body.Close()
+	b, err := io.ReadAll(resp.Body)
+	if err != nil {
+		ctx.Data(500, "text/html", []byte("Internal server error"))
+		return
+	}
+	for k, v := range resp.Header {
+		for i := range v {
+			ctx.Header(k, v[i])
+		}
+	}
+	ctx.Data(resp.StatusCode, resp.Header.Get("content-type"), b)
+
+}

+ 1 - 0
pkg/routing.go

@@ -51,5 +51,6 @@ func RegisterRoutes(e *gin.Engine, cfg HttpServerConfig) {
 	}(c)
 	web := e.Group("")
 	web.Any("/*ProxiedPath", c.HandleAny)
+	// web.Any("/*ProxiedPath", c.HandleAnyRe)
 
 }