Initial commit (code only without large binaries)
This commit is contained in:
43
EdgeNode/internal/http3/conn.go
Normal file
43
EdgeNode/internal/http3/conn.go
Normal 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
|
||||
}
|
||||
187
EdgeNode/internal/http3/conn_basic.go
Normal file
187
EdgeNode/internal/http3/conn_basic.go
Normal 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
|
||||
}
|
||||
16
EdgeNode/internal/http3/listener.go
Normal file
16
EdgeNode/internal/http3/listener.go
Normal 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
|
||||
}
|
||||
47
EdgeNode/internal/http3/listener_basic.go
Normal file
47
EdgeNode/internal/http3/listener_basic.go
Normal 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
|
||||
}
|
||||
10
EdgeNode/internal/http3/notifier.go
Normal file
10
EdgeNode/internal/http3/notifier.go
Normal 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()
|
||||
}
|
||||
86
EdgeNode/internal/http3/server.go
Normal file
86
EdgeNode/internal/http3/server.go
Normal 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()
|
||||
}
|
||||
86
EdgeNode/internal/http3/stream.go
Normal file
86
EdgeNode/internal/http3/stream.go
Normal 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()
|
||||
}
|
||||
47
EdgeNode/internal/http3/stream_receive.go
Normal file
47
EdgeNode/internal/http3/stream_receive.go
Normal 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
|
||||
}
|
||||
60
EdgeNode/internal/http3/stream_send.go
Normal file
60
EdgeNode/internal/http3/stream_send.go
Normal 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()
|
||||
}
|
||||
Reference in New Issue
Block a user