HTTP/3 Server side support
All checks were successful
CI / build (push) Successful in 4m31s

This commit is contained in:
Fijxu 2024-11-04 10:48:00 -03:00
parent 78ae56be37
commit bdb1afbf61
Signed by: Fijxu
GPG key ID: 32C1DDF333EDA6A4

87
main.go
View file

@ -1,6 +1,7 @@
package main package main
import ( import (
"crypto/tls"
"encoding/json" "encoding/json"
"flag" "flag"
"fmt" "fmt"
@ -16,6 +17,7 @@ import (
"time" "time"
"github.com/conduitio/bwlimit" "github.com/conduitio/bwlimit"
"github.com/quic-go/quic-go"
"github.com/quic-go/quic-go/http3" "github.com/quic-go/quic-go/http3"
) )
@ -58,7 +60,6 @@ var h2client = &http.Client{
}, },
} }
// https://github.com/lucas-clemente/quic-go/issues/2836
var client *http.Client var client *http.Client
// Same user agent as Invidious // Same user agent as Invidious
@ -93,6 +94,8 @@ var ipv6_only = false
var version string var version string
var h3s bool
type statusJson struct { type statusJson struct {
Version string `json:"version"` Version string `json:"version"`
RequestCount int64 `json:"requestCount"` RequestCount int64 `json:"requestCount"`
@ -169,13 +172,20 @@ func beforeAll(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) { return func(w http.ResponseWriter, req *http.Request) {
defer panicHandler(w) defer panicHandler(w)
if h3s {
w.Header().Set("Alt-Svc", "h3=\":8443\"; ma=86400")
}
if req.Method == "OPTIONS" {
w.WriteHeader(http.StatusOK)
return
}
if req.Method != "GET" && req.Method != "HEAD" { if req.Method != "GET" && req.Method != "HEAD" {
io.WriteString(w, "Only GET and HEAD requests are allowed.") io.WriteString(w, "Only GET and HEAD requests are allowed.")
return return
} }
atomic.AddInt64(&stats_.RequestCount, 1)
// To look like more like a browser // To look like more like a browser
req.Header.Add("Origin", "https://www.youtube.com") req.Header.Add("Origin", "https://www.youtube.com")
req.Header.Add("Referer", "https://www.youtube.com/") req.Header.Add("Referer", "https://www.youtube.com/")
@ -184,11 +194,7 @@ func beforeAll(next http.HandlerFunc) http.HandlerFunc {
w.Header().Set("Access-Control-Allow-Headers", "*") w.Header().Set("Access-Control-Allow-Headers", "*")
w.Header().Set("Access-Control-Max-Age", "1728000") w.Header().Set("Access-Control-Max-Age", "1728000")
if req.Method == "OPTIONS" { atomic.AddInt64(&stats_.RequestCount, 1)
w.WriteHeader(http.StatusOK)
return
}
next(w, req) next(w, req)
} }
} }
@ -197,15 +203,23 @@ func main() {
var sock string var sock string
var host string var host string
var port string var port string
var tls_cert string var tls_cert string
var tls_key string var tls_key string
var ipv6 bool
var https bool
var h3c bool
path_prefix = os.Getenv("PREFIX_PATH") ua = os.Getenv("USER_AGENT")
ipv6_only = os.Getenv("IPV6_ONLY") == "1" https = os.Getenv("HTTPS") == "1"
h3c = os.Getenv("H3C") == "1"
h3s = os.Getenv("H3S") == "1"
ipv6 = os.Getenv("IPV6_ONLY") == "1"
var https = flag.Bool("https", false, "Use built-in https server (recommended)") flag.BoolVar(&https, "https", false, "Use built-in https server (recommended)")
var h3 = flag.Bool("h3", false, "Use HTTP/3 for requests (high CPU usage)") flag.BoolVar(&h3s, "h3c", false, "Use HTTP/3 for client requests (high CPU usage)")
var ipv6 = flag.Bool("ipv6_only", false, "Only use ipv6 for requests") flag.BoolVar(&h3s, "h3s", true, "Use HTTP/3 for server requests")
flag.BoolVar(&ipv6_only, "ipv6_only", false, "Only use ipv6 for requests")
flag.StringVar(&tls_cert, "tls-cert", "", "TLS Certificate path") flag.StringVar(&tls_cert, "tls-cert", "", "TLS Certificate path")
flag.StringVar(&tls_key, "tls-key", "", "TLS Certificate Key path") flag.StringVar(&tls_key, "tls-key", "", "TLS Certificate Key path")
flag.StringVar(&sock, "s", "/tmp/http-ytproxy.sock", "Specify a socket name") flag.StringVar(&sock, "s", "/tmp/http-ytproxy.sock", "Specify a socket name")
@ -213,25 +227,25 @@ func main() {
flag.StringVar(&host, "l", "0.0.0.0", "Specify a listen address") flag.StringVar(&host, "l", "0.0.0.0", "Specify a listen address")
flag.Parse() flag.Parse()
if *h3 { if h3c {
client = h3client client = h3client
} else { } else {
client = h2client client = h2client
} }
if *https { if https {
if len(tls_cert) <= 0 { if len(tls_cert) <= 0 {
fmt.Println("tls-cert argument is missing") fmt.Println("tls-cert argument is missing, you need a TLS certificate for HTTPS")
fmt.Println("You need a TLS certificate for HTTPS") os.Exit(1)
} }
if len(tls_key) <= 0 { if len(tls_key) <= 0 {
fmt.Println("tls-key argument is missing") fmt.Println("tls-key argument is missing, you need a TLS key for HTTPS")
fmt.Println("You need a TLS key for HTTPS") os.Exit(1)
} }
} }
ipv6_only = *ipv6 ipv6_only = ipv6
mux := http.NewServeMux() mux := http.NewServeMux()
@ -262,11 +276,25 @@ func main() {
) )
ln = bwlimit.NewListener(ln, writeLimit, readLimit) ln = bwlimit.NewListener(ln, writeLimit, readLimit)
// srvDialer := bwlimit.NewDialer(&net.Dialer{}, writeLimit, readLimit)
srv := &http.Server{ srv := &http.Server{
Handler: mux,
ReadTimeout: 5 * time.Second, ReadTimeout: 5 * time.Second,
WriteTimeout: 1 * time.Hour, WriteTimeout: 1 * time.Hour,
Handler: mux, }
srvh3 := &http3.Server{
Handler: mux,
EnableDatagrams: false, // https://quic.video/blog/never-use-datagrams/ (Read it)
IdleTimeout: 120 * time.Second,
TLSConfig: http3.ConfigureTLSConfig(&tls.Config{}),
QUICConfig: &quic.Config{
// KeepAlivePeriod: 10 * time.Second,
MaxIncomingStreams: 256, // I'm not sure if this is correct.
MaxIncomingUniStreams: 256, // Same as above
},
Addr: host + ":" + port,
} }
syscall.Unlink(sock) syscall.Unlink(sock)
@ -289,11 +317,22 @@ func main() {
go srv.Serve(socket_listener) go srv.Serve(socket_listener)
fmt.Println("Unix socket listening at:", string(sock)) fmt.Println("Unix socket listening at:", string(sock))
if *https { if https {
fmt.Println("Serving HTTPS at port", string(port)) fmt.Println("Serving HTTPS at port", string(port))
if err := srv.ServeTLS(ln, tls_cert, tls_key); err != nil { go func() {
log.Fatal(err) if err := srv.ServeTLS(ln, tls_cert, tls_key); err != nil {
log.Fatal(err)
}
}()
if h3s {
fmt.Println("Serving HTTPS via QUIC at port", string(port))
go func() {
if err := srvh3.ListenAndServeTLS(tls_cert, tls_key); err != nil {
log.Fatal(err)
}
}()
} }
select {}
} else { } else {
fmt.Println("Serving HTTP at port", string(port)) fmt.Println("Serving HTTP at port", string(port))
if err := srv.Serve(ln); err != nil { if err := srv.Serve(ln); err != nil {