This commit is contained in:
unknown
2026-02-04 20:27:13 +08:00
commit 3b042d1dad
9410 changed files with 1488147 additions and 0 deletions

View File

@@ -0,0 +1,43 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build plus
package http3
import (
"context"
"github.com/quic-go/quic-go"
"net"
"time"
)
type Conn interface {
SetParentConn(parentConn Conn)
SetNotifier(notifier Notifier)
AcceptStream(ctx context.Context) (quic.Stream, error)
AcceptUniStream(ctx context.Context) (quic.ReceiveStream, error)
OpenStream() (quic.Stream, error)
OpenStreamSync(ctx context.Context) (quic.Stream, error)
OpenUniStream() (quic.SendStream, error)
OpenUniStreamSync(ctx context.Context) (quic.SendStream, error)
LocalAddr() net.Addr
RemoteAddr() net.Addr
CloseWithError(errCode quic.ApplicationErrorCode, errMsg string) error
Context() context.Context
ConnectionState() quic.ConnectionState
SendDatagram(b []byte) error
ReceiveDatagram(ctx context.Context) ([]byte, error)
HandshakeComplete() <-chan struct{}
NextConnection() quic.Connection
notifier() (notifier Notifier)
callContextFunc(ctx context.Context) context.Context
// net.Conn
Read(b []byte) (n int, err error)
Write(b []byte) (n int, err error)
Close() error
SetDeadline(t time.Time) error
SetReadDeadline(t time.Time) error
SetWriteDeadline(t time.Time) error
}

View File

@@ -0,0 +1,187 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build plus
package http3
import (
"context"
"github.com/quic-go/quic-go"
"net"
"sync"
"time"
)
type ContextFunc func(ctx context.Context, conn net.Conn) context.Context
type BasicConn struct {
rawConn quic.EarlyConnection
parentConn Conn
ctxFunc ContextFunc
connNotifier Notifier
closeOnce *sync.Once
}
func NewConn(rawConn quic.EarlyConnection, ctxFunc ContextFunc) *BasicConn {
return &BasicConn{
rawConn: rawConn,
ctxFunc: ctxFunc,
closeOnce: &sync.Once{},
}
}
func (this *BasicConn) callContextFunc(ctx context.Context) context.Context {
if this.ctxFunc != nil {
if this.parentConn != nil {
return this.ctxFunc(ctx, this.parentConn)
}
return this.ctxFunc(ctx, this)
}
return ctx
}
func (this *BasicConn) SetParentConn(parentConn Conn) {
this.parentConn = parentConn
}
func (this *BasicConn) SetNotifier(notifier Notifier) {
this.connNotifier = notifier
}
func (this *BasicConn) notifier() (Notifier Notifier) {
return this.connNotifier
}
func (this *BasicConn) AcceptStream(ctx context.Context) (quic.Stream, error) {
stream, err := this.rawConn.AcceptStream(ctx)
if err != nil {
return stream, err
}
return NewStream(stream, this), nil
}
func (this *BasicConn) AcceptUniStream(ctx context.Context) (quic.ReceiveStream, error) {
stream, err := this.rawConn.AcceptUniStream(ctx)
if err != nil {
return stream, err
}
return NewReceiveStream(stream, this), nil
}
func (this *BasicConn) OpenStream() (quic.Stream, error) {
stream, err := this.rawConn.OpenStream()
if err != nil {
return stream, err
}
return NewStream(stream, this), nil
}
func (this *BasicConn) OpenStreamSync(ctx context.Context) (quic.Stream, error) {
stream, err := this.rawConn.OpenStreamSync(ctx)
if err != nil {
return stream, err
}
return NewStream(stream, this), nil
}
func (this *BasicConn) OpenUniStream() (quic.SendStream, error) {
stream, err := this.rawConn.OpenUniStream()
if err != nil {
return stream, err
}
return NewSendStream(stream, this), nil
}
func (this *BasicConn) OpenUniStreamSync(ctx context.Context) (quic.SendStream, error) {
stream, err := this.rawConn.OpenUniStreamSync(ctx)
if err != nil {
return stream, err
}
return NewSendStream(stream, this), nil
}
func (this *BasicConn) LocalAddr() net.Addr {
return this.rawConn.LocalAddr()
}
func (this *BasicConn) RemoteAddr() net.Addr {
return this.rawConn.RemoteAddr()
}
func (this *BasicConn) CloseWithError(errCode quic.ApplicationErrorCode, errMsg string) error {
err := this.rawConn.CloseWithError(errCode, errMsg)
if this.connNotifier != nil {
this.closeOnce.Do(func() {
this.connNotifier.Close()
})
}
return err
}
func (this *BasicConn) Context() context.Context {
return this.rawConn.Context()
}
func (this *BasicConn) ConnectionState() quic.ConnectionState {
return this.rawConn.ConnectionState()
}
func (this *BasicConn) SendDatagram(b []byte) error {
return this.rawConn.SendDatagram(b)
}
func (this *BasicConn) ReceiveDatagram(ctx context.Context) ([]byte, error) {
data, err := this.rawConn.ReceiveDatagram(ctx)
return data, err
}
func (this *BasicConn) HandshakeComplete() <-chan struct{} {
return this.rawConn.HandshakeComplete()
}
func (this *BasicConn) NextConnection() quic.Connection {
return this.rawConn.NextConnection()
}
/** implement net.Conn **/
func (this *BasicConn) Read(b []byte) (n int, err error) {
_ = b
// do nothing
return
}
func (this *BasicConn) Write(b []byte) (n int, err error) {
_ = b
// do nothing
return
}
func (this *BasicConn) Close() error {
return this.CloseWithError(quic.ApplicationErrorCode(quic.NoError), "")
}
func (this *BasicConn) SetDeadline(t time.Time) error {
_ = t
// do nothing
return nil
}
func (this *BasicConn) SetReadDeadline(t time.Time) error {
_ = t
// do nothing
return nil
}
func (this *BasicConn) SetWriteDeadline(t time.Time) error {
_ = t
// do nothing
return nil
}

View File

@@ -0,0 +1,16 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build plus
package http3
import (
"context"
"github.com/quic-go/quic-go"
"net"
)
type Listener interface {
Addr() net.Addr
Accept(ctx context.Context, ctxFunc ContextFunc) (quic.EarlyConnection, error)
Close() error
}

View File

@@ -0,0 +1,47 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build plus
package http3
import (
"context"
"crypto/tls"
"github.com/quic-go/quic-go"
http3quic "github.com/quic-go/quic-go/http3"
"net"
)
type BasicListener struct {
rawListener http3quic.QUICEarlyListener
}
func Listen(addr string, tlsConfig *tls.Config) (Listener, error) {
listener, err := quic.ListenAddrEarly(addr, http3quic.ConfigureTLSConfig(tlsConfig), &quic.Config{
Allow0RTT: true,
})
if err != nil {
return nil, err
}
return NewBasicListener(listener), nil
}
func NewBasicListener(rawListener http3quic.QUICEarlyListener) Listener {
return &BasicListener{rawListener: rawListener}
}
func (this *BasicListener) Close() error {
return this.rawListener.Close()
}
func (this *BasicListener) Addr() net.Addr {
return this.rawListener.Addr()
}
func (this *BasicListener) Accept(ctx context.Context, ctxFunc ContextFunc) (quic.EarlyConnection, error) {
conn, err := this.rawListener.Accept(ctx)
if err != nil {
return nil, err
}
return NewConn(conn, ctxFunc), nil
}

View File

@@ -0,0 +1,10 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build plus
package http3
type Notifier interface {
ReadBytes(size int)
WriteBytes(size int)
Close()
}

View File

@@ -0,0 +1,86 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build plus
package http3
import (
"context"
"errors"
"github.com/quic-go/quic-go"
http3quic "github.com/quic-go/quic-go/http3"
"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() {
// 通知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()
}

View File

@@ -0,0 +1,86 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build plus
package http3
import (
"context"
"github.com/quic-go/quic-go"
"time"
)
type Stream struct {
rawStream quic.Stream
conn Conn
}
func NewStream(rawStream quic.Stream, conn Conn) quic.Stream {
return &Stream{
rawStream: rawStream,
conn: conn,
}
}
func (this *Stream) SetDeadline(t time.Time) error {
return this.rawStream.SetDeadline(t)
}
func (this *Stream) StreamID() quic.StreamID {
return this.rawStream.StreamID()
}
func (this *Stream) CancelRead(errorCode quic.StreamErrorCode) {
this.rawStream.CancelRead(errorCode)
}
func (this *Stream) SetReadDeadline(t time.Time) error {
return this.rawStream.SetReadDeadline(t)
}
func (this *Stream) Read(p []byte) (n int, err error) {
n, err = this.rawStream.Read(p)
// notify
if n > 0 && this.conn != nil {
var notifier = this.conn.notifier()
if notifier != nil {
notifier.ReadBytes(n)
}
}
return
}
func (this *Stream) CancelWrite(errorCode quic.StreamErrorCode) {
this.rawStream.CancelWrite(errorCode)
}
func (this *Stream) Context() context.Context {
var ctx = this.rawStream.Context()
if this.conn != nil {
ctx = this.conn.callContextFunc(ctx)
}
return ctx
}
func (this *Stream) SetWriteDeadline(t time.Time) error {
return this.rawStream.SetWriteDeadline(t)
}
func (this *Stream) Write(p []byte) (n int, err error) {
n, err = this.rawStream.Write(p)
// notify
if n > 0 && this.conn != nil {
var notifier = this.conn.notifier()
if notifier != nil {
notifier.WriteBytes(n)
}
}
return
}
func (this *Stream) Close() error {
return this.rawStream.Close()
}

View File

@@ -0,0 +1,47 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build plus
package http3
import (
"github.com/quic-go/quic-go"
"time"
)
type ReceiveStream struct {
rawReceiveStream quic.ReceiveStream
conn Conn
}
func NewReceiveStream(rawReceiveStream quic.ReceiveStream, conn Conn) *ReceiveStream {
return &ReceiveStream{
rawReceiveStream: rawReceiveStream,
conn: conn,
}
}
func (this *ReceiveStream) StreamID() quic.StreamID {
return this.rawReceiveStream.StreamID()
}
func (this *ReceiveStream) CancelRead(errorCode quic.StreamErrorCode) {
this.rawReceiveStream.CancelRead(errorCode)
}
func (this *ReceiveStream) SetReadDeadline(t time.Time) error {
return this.rawReceiveStream.SetReadDeadline(t)
}
func (this *ReceiveStream) Read(p []byte) (n int, err error) {
n, err = this.rawReceiveStream.Read(p)
// notify
if n > 0 && this.conn != nil {
var notifier = this.conn.notifier()
if notifier != nil {
notifier.ReadBytes(n)
}
}
return
}

View File

@@ -0,0 +1,60 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build plus
package http3
import (
"context"
"github.com/quic-go/quic-go"
"time"
)
type SendStream struct {
rawSendStream quic.SendStream
conn Conn
}
func NewSendStream(rawSendStream quic.SendStream, conn Conn) *SendStream {
return &SendStream{
rawSendStream: rawSendStream,
conn: conn,
}
}
func (this *SendStream) StreamID() quic.StreamID {
return this.rawSendStream.StreamID()
}
func (this *SendStream) CancelWrite(errorCode quic.StreamErrorCode) {
this.rawSendStream.CancelWrite(errorCode)
}
func (this *SendStream) Context() context.Context {
var ctx = this.rawSendStream.Context()
if this.conn != nil {
ctx = this.conn.callContextFunc(ctx)
}
return ctx
}
func (this *SendStream) SetWriteDeadline(t time.Time) error {
return this.rawSendStream.SetWriteDeadline(t)
}
func (this *SendStream) Write(p []byte) (n int, err error) {
n, err = this.rawSendStream.Write(p)
// notify
if n > 0 && this.conn != nil {
var notifier = this.conn.notifier()
if notifier != nil {
notifier.WriteBytes(n)
}
}
return
}
func (this *SendStream) Close() error {
return this.rawSendStream.Close()
}