Golang中http服务器在处理hijacked连接时Io.copy挂起问题

Golang中http服务器在处理hijacked连接时Io.copy挂起问题 由于被劫持的连接没有上下文,很难预测连接是否已关闭。我添加了一个计数器来测量由io.copy持有的连接数量,结果显示即使客户端断开连接且超时触发后,部分连接仍会长时间保持。

package main

import (
	"context"
	"fmt"
	"github.com/gadelkareem/go-helpers"
	"io"
	"net"
	"net/http"
	"sync"
	"sync/atomic"
	"time"
)

const Timeout = 5 * time.Second

var counter int64

func main() {
	go func() {
		for range time.Tick(Timeout) {
			fmt.Printf("%d requests being processed\n", atomic.LoadInt64(&counter))
		}
	}()

	s := &http.Server{
		Addr:    ":8888",
		Handler: http.HandlerFunc(Serve),
	}
	s.ListenAndServe()
}

func Serve(w http.ResponseWriter, r *http.Request) {

	atomic.AddInt64(&counter, 1)

	if r.Method == http.MethodConnect {
		// HTTPS
		hij, ok := w.(http.Hijacker)
		if !ok {
			return
		}

		hj, bufrw, err := hij.Hijack()
		h.PanicOnError(err)
		bufrw.WriteString("HTTP/1.0 200 OK\r\n\r\n")
		bufrw.Flush()

		target, err := net.DialTimeout("tcp", r.URL.Host, Timeout)
		h.PanicOnError(err)

		// Not sure if this is needed since we add a context timeout
		// Just leaving it for the example
		dl := time.Now().Add(Timeout)
		err = hj.SetDeadline(dl)
		h.PanicOnError(err)
		err = target.SetDeadline(dl)
		h.PanicOnError(err)

		var wg sync.WaitGroup
		ctx, cancel := context.WithTimeout(r.Context(), Timeout)
		defer cancel()
		go func() {
			for {
				select {
				case <-ctx.Done():
					hj.Close()
					target.Close()
					println("context canceled")
					return
				}
			}
		}()
		targetTCP, _ := target.(*net.TCPConn)
		hjTCP, _ := hj.(*net.TCPConn)
		wg.Add(2)
		go copyAndClose(targetTCP, hjTCP, &wg)
		go copyAndClose(hjTCP, targetTCP, &wg)
		wg.Wait()
	} else {
		//ignore HTTP for this example
	}

	atomic.AddInt64(&counter, -1)

	return
}

func copyAndClose(dst, src *net.TCPConn, wg *sync.WaitGroup) {
	io.Copy(dst, src)
	dst.CloseWrite()
	src.CloseRead()
	wg.Done()
}

你可以在此处复现代码:https://gist.github.com/gadelkareem/3484fe05747f9fcc55b408cf23e92484

这段代码是否存在问题,或者这可能是一个潜在的bug?


更多关于Golang中http服务器在处理hijacked连接时Io.copy挂起问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang中http服务器在处理hijacked连接时Io.copy挂起问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


没关系,那是计数器递减前不可劫持连接的返回值

回到顶部