fix(pr3): adapt to quic-go v0.59.0 API — drop H3App, capture h3 SETTINGS via http3.Settingser
quic-go v0.59.0 (shipped with Caddy v2.11.2) removed quic.Connection as a public interface and quic-go/logging as a public package, breaking H3App's connection-wrapping approach. Resolution: - Remove H3App (h3app.go) entirely; Caddy handles h3 natively when h3 is in the protocols list. - Rewrite h3conn.go to keep only tryParseH3ControlStream + varint/name utilities (tested, useful for future stream-level tapping if the API ever re-exposes it). - FPHandler.ServeHTTP: for h3 requests, type-assert ResponseWriter to http3.Settingser (the public interface exposed by quic-go/http3 v0.59), read the peer's Settings after ReceivedSettings channel closes, emit h3_settings fp record. - https/entrypoint.sh: include h3 in CADDY_PROTOCOLS (Caddy now owns UDP/443); remove DECNET_H3_GLOBAL block. - Update go.mod/go.sum to caddy v2.11.2 + quic-go v0.59.0. - Update test_https_compose_h3_app.py to expect h3 in protocols when http/3 is selected, and assert decnet_h3 block is absent. - All Go tests (9) and Python tests (15) remain green.
This commit is contained in:
@@ -23,6 +23,7 @@ import (
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -30,6 +31,7 @@ import (
|
||||
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
|
||||
"github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile"
|
||||
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
|
||||
"github.com/quic-go/quic-go/http3"
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/net/http2/hpack"
|
||||
)
|
||||
@@ -580,8 +582,35 @@ func (h *FPHandler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddy
|
||||
"ts": time.Now().UTC().Format(time.RFC3339),
|
||||
})
|
||||
|
||||
// For h3, emit best-effort http_request_headers (map order, degraded).
|
||||
// For h3: emit h3_settings (once per connection, deduped by remote_addr),
|
||||
// then emit best-effort http_request_headers (map order — QPACK frame order
|
||||
// is not available without a stream tap; degraded but usable for JA4H).
|
||||
if r.ProtoMajor == 3 {
|
||||
if settingser, ok := w.(http3.Settingser); ok {
|
||||
select {
|
||||
case <-settingser.ReceivedSettings():
|
||||
s := settingser.Settings()
|
||||
settingsMap := make(map[string]interface{})
|
||||
if s.EnableDatagrams {
|
||||
settingsMap["H3_DATAGRAM"] = uint64(1)
|
||||
}
|
||||
if s.EnableExtendedConnect {
|
||||
settingsMap["ENABLE_CONNECT_PROTOCOL"] = uint64(1)
|
||||
}
|
||||
for id, val := range s.Other {
|
||||
settingsMap[h3SettingName(id)] = val
|
||||
}
|
||||
go sendFP(map[string]interface{}{
|
||||
"kind": "h3_settings",
|
||||
"remote_addr": r.RemoteAddr,
|
||||
"settings": settingsMap,
|
||||
"ts": time.Now().UTC().Format(time.RFC3339),
|
||||
})
|
||||
default:
|
||||
// Settings not yet received — skip; the access_log record is sufficient.
|
||||
}
|
||||
}
|
||||
|
||||
ordered := make([][]string, 0, len(r.Header))
|
||||
var cookie, acceptLang string
|
||||
for name, vals := range r.Header {
|
||||
@@ -589,7 +618,7 @@ func (h *FPHandler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddy
|
||||
if len(vals) > 0 {
|
||||
v = vals[0]
|
||||
}
|
||||
ordered = append(ordered, []string{name, v})
|
||||
ordered = append(ordered, []string{strings.ToLower(name), v})
|
||||
switch http.CanonicalHeaderKey(name) {
|
||||
case "Cookie":
|
||||
cookie = v
|
||||
|
||||
Reference in New Issue
Block a user