Files
2026-03-22 17:37:40 +08:00

95 lines
1.8 KiB
Go

// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build plus
package http3
import (
"context"
"errors"
"fmt"
"github.com/quic-go/quic-go"
http3quic "github.com/quic-go/quic-go/http3"
"log"
"net"
"net/http"
)
type Server struct {
Addr string
Handler http.Handler
ConnState func(conn net.Conn, state http.ConnState)
ConnContext ContextFunc
rawServer *http3quic.Server
isClosed bool
listener Listener
}
func (this *Server) Serve(listener Listener) error {
if listener == nil {
return errors.New("listener must not be nil")
}
this.listener = listener
this.rawServer = &http3quic.Server{
Addr: this.Addr,
Handler: this.Handler,
}
for {
conn, err := listener.Accept(context.Background(), this.ConnContext)
if err != nil {
if this.isClosed {
return nil
}
continue
}
go func() {
defer func() {
if r := recover(); r != nil {
log.Println(fmt.Sprintf("[HTTP3]goroutine panic: %v", r))
}
}()
// 通知ConnState
if this.ConnState != nil {
netConn, isNetConn := conn.(net.Conn)
if isNetConn {
this.ConnState(netConn, http.StateNew)
this.ConnState(netConn, http.StateActive)
}
}
_ = this.rawServer.ServeQUICConn(conn)
// 关闭连接
_ = conn.CloseWithError(quic.ApplicationErrorCode(quic.NoError), "")
// 通知ConnState
if this.ConnState != nil {
netConn, isNetConn := conn.(net.Conn)
if isNetConn {
this.ConnState(netConn, http.StateClosed)
}
}
}()
}
}
func (this *Server) SetQuicHeaders(headers http.Header) {
if this.isClosed {
return
}
headers.Set("Alt-Svc", `h3="`+this.Addr+`"; ma=2592000,h3-29="`+this.Addr+`"; ma=2592000`)
}
func (this *Server) Close() error {
this.isClosed = true
_ = this.listener.Close()
return this.rawServer.Close()
}