forked from quic-go/quic-go
qlog: implement a minimal jsontext-like JSON encoder (#5353)
* qlog: use fork of encoding/json/jsontext instead of unmaintained gojay * implement a minimal jsontext-compatible encoder * qlogtext: improve fuzz test * qlog: simplify JSON encoding error handling * qlog: make use of jsontext.Bool
This commit is contained in:
2
go.mod
2
go.mod
@@ -3,7 +3,6 @@ module github.com/quic-go/quic-go
|
||||
go 1.24
|
||||
|
||||
require (
|
||||
github.com/francoispqt/gojay v1.2.13
|
||||
github.com/prometheus/client_golang v1.19.1
|
||||
github.com/quic-go/qpack v0.5.1
|
||||
github.com/stretchr/testify v1.9.0
|
||||
@@ -19,6 +18,7 @@ require (
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/kr/text v0.1.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_model v0.5.0 // indirect
|
||||
github.com/prometheus/common v0.48.0 // indirect
|
||||
|
||||
157
go.sum
157
go.sum
@@ -1,209 +1,52 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo=
|
||||
dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU=
|
||||
dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU=
|
||||
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
|
||||
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
|
||||
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
|
||||
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk=
|
||||
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
|
||||
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
|
||||
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
|
||||
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
|
||||
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
|
||||
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
|
||||
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
|
||||
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
|
||||
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
|
||||
github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
|
||||
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
||||
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
||||
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
|
||||
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
|
||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
|
||||
github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
|
||||
github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0=
|
||||
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
|
||||
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
|
||||
github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw=
|
||||
github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI=
|
||||
github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU=
|
||||
github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag=
|
||||
github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg=
|
||||
github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw=
|
||||
github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y=
|
||||
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
|
||||
github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q=
|
||||
github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ=
|
||||
github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I=
|
||||
github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0=
|
||||
github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=
|
||||
github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk=
|
||||
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
|
||||
github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
|
||||
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
|
||||
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
|
||||
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
|
||||
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
|
||||
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
|
||||
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
|
||||
go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
|
||||
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
|
||||
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
|
||||
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
|
||||
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ=
|
||||
golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
|
||||
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
|
||||
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
|
||||
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
|
||||
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg=
|
||||
golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
|
||||
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
|
||||
google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
|
||||
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
|
||||
|
||||
@@ -9,8 +9,6 @@ import (
|
||||
"github.com/quic-go/quic-go/internal/utils"
|
||||
"github.com/quic-go/quic-go/internal/wire"
|
||||
"github.com/quic-go/quic-go/logging"
|
||||
|
||||
"github.com/francoispqt/gojay"
|
||||
)
|
||||
|
||||
type connectionTracer struct {
|
||||
@@ -255,7 +253,7 @@ func (t *connectionTracer) SentShortHeaderPacket(
|
||||
}
|
||||
|
||||
func (t *connectionTracer) sentPacket(
|
||||
hdr gojay.MarshalerJSONObject,
|
||||
hdr jsontextEncoder,
|
||||
size, payloadLen logging.ByteCount,
|
||||
ecn logging.ECN,
|
||||
ack *logging.AckFrame,
|
||||
|
||||
728
qlog/event.go
728
qlog/event.go
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,8 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/francoispqt/gojay"
|
||||
"github.com/quic-go/quic-go/qlog/jsontext"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@@ -14,17 +15,27 @@ type mevent struct{}
|
||||
|
||||
var _ eventDetails = mevent{}
|
||||
|
||||
func (mevent) Name() string { return "foobar:mevent" }
|
||||
func (mevent) IsNil() bool { return false }
|
||||
func (mevent) MarshalJSONObject(enc *gojay.Encoder) { enc.StringKey("event", "details") }
|
||||
func (mevent) Name() string { return "foobar:mevent" }
|
||||
func (mevent) Encode(enc *jsontext.Encoder) error {
|
||||
if err := enc.WriteToken(jsontext.BeginObject); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := enc.WriteToken(jsontext.String("event")); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := enc.WriteToken(jsontext.String("details")); err != nil {
|
||||
return err
|
||||
}
|
||||
return enc.WriteToken(jsontext.EndObject)
|
||||
}
|
||||
|
||||
func TestEventMarshaling(t *testing.T) {
|
||||
buf := &bytes.Buffer{}
|
||||
enc := gojay.NewEncoder(buf)
|
||||
err := enc.Encode(event{
|
||||
enc := jsontext.NewEncoder(buf)
|
||||
err := (event{
|
||||
RelativeTime: 1337 * time.Microsecond,
|
||||
eventDetails: mevent{},
|
||||
})
|
||||
}).Encode(enc)
|
||||
require.NoError(t, err)
|
||||
|
||||
var decoded map[string]any
|
||||
|
||||
442
qlog/frame.go
442
qlog/frame.go
@@ -5,246 +5,416 @@ import (
|
||||
|
||||
"github.com/quic-go/quic-go/internal/wire"
|
||||
"github.com/quic-go/quic-go/logging"
|
||||
|
||||
"github.com/francoispqt/gojay"
|
||||
"github.com/quic-go/quic-go/qlog/jsontext"
|
||||
)
|
||||
|
||||
type frame struct {
|
||||
Frame logging.Frame
|
||||
}
|
||||
|
||||
var _ gojay.MarshalerJSONObject = frame{}
|
||||
|
||||
var _ gojay.MarshalerJSONArray = frames{}
|
||||
|
||||
func (f frame) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
func (f frame) Encode(enc *jsontext.Encoder) error {
|
||||
switch frame := f.Frame.(type) {
|
||||
case *logging.PingFrame:
|
||||
marshalPingFrame(enc, frame)
|
||||
return encodePingFrame(enc, frame)
|
||||
case *logging.AckFrame:
|
||||
marshalAckFrame(enc, frame)
|
||||
return encodeAckFrame(enc, frame)
|
||||
case *logging.ResetStreamFrame:
|
||||
marshalResetStreamFrame(enc, frame)
|
||||
return encodeResetStreamFrame(enc, frame)
|
||||
case *logging.StopSendingFrame:
|
||||
marshalStopSendingFrame(enc, frame)
|
||||
return encodeStopSendingFrame(enc, frame)
|
||||
case *logging.CryptoFrame:
|
||||
marshalCryptoFrame(enc, frame)
|
||||
return encodeCryptoFrame(enc, frame)
|
||||
case *logging.NewTokenFrame:
|
||||
marshalNewTokenFrame(enc, frame)
|
||||
return encodeNewTokenFrame(enc, frame)
|
||||
case *logging.StreamFrame:
|
||||
marshalStreamFrame(enc, frame)
|
||||
return encodeStreamFrame(enc, frame)
|
||||
case *logging.MaxDataFrame:
|
||||
marshalMaxDataFrame(enc, frame)
|
||||
return encodeMaxDataFrame(enc, frame)
|
||||
case *logging.MaxStreamDataFrame:
|
||||
marshalMaxStreamDataFrame(enc, frame)
|
||||
return encodeMaxStreamDataFrame(enc, frame)
|
||||
case *logging.MaxStreamsFrame:
|
||||
marshalMaxStreamsFrame(enc, frame)
|
||||
return encodeMaxStreamsFrame(enc, frame)
|
||||
case *logging.DataBlockedFrame:
|
||||
marshalDataBlockedFrame(enc, frame)
|
||||
return encodeDataBlockedFrame(enc, frame)
|
||||
case *logging.StreamDataBlockedFrame:
|
||||
marshalStreamDataBlockedFrame(enc, frame)
|
||||
return encodeStreamDataBlockedFrame(enc, frame)
|
||||
case *logging.StreamsBlockedFrame:
|
||||
marshalStreamsBlockedFrame(enc, frame)
|
||||
return encodeStreamsBlockedFrame(enc, frame)
|
||||
case *logging.NewConnectionIDFrame:
|
||||
marshalNewConnectionIDFrame(enc, frame)
|
||||
return encodeNewConnectionIDFrame(enc, frame)
|
||||
case *logging.RetireConnectionIDFrame:
|
||||
marshalRetireConnectionIDFrame(enc, frame)
|
||||
return encodeRetireConnectionIDFrame(enc, frame)
|
||||
case *logging.PathChallengeFrame:
|
||||
marshalPathChallengeFrame(enc, frame)
|
||||
return encodePathChallengeFrame(enc, frame)
|
||||
case *logging.PathResponseFrame:
|
||||
marshalPathResponseFrame(enc, frame)
|
||||
return encodePathResponseFrame(enc, frame)
|
||||
case *logging.ConnectionCloseFrame:
|
||||
marshalConnectionCloseFrame(enc, frame)
|
||||
return encodeConnectionCloseFrame(enc, frame)
|
||||
case *logging.HandshakeDoneFrame:
|
||||
marshalHandshakeDoneFrame(enc, frame)
|
||||
return encodeHandshakeDoneFrame(enc, frame)
|
||||
case *logging.DatagramFrame:
|
||||
marshalDatagramFrame(enc, frame)
|
||||
return encodeDatagramFrame(enc, frame)
|
||||
case *logging.AckFrequencyFrame:
|
||||
marshalAckFrequencyFrame(enc, frame)
|
||||
return encodeAckFrequencyFrame(enc, frame)
|
||||
case *logging.ImmediateAckFrame:
|
||||
marshalImmediateAckFrame(enc, frame)
|
||||
return encodeImmediateAckFrame(enc, frame)
|
||||
default:
|
||||
panic("unknown frame type")
|
||||
}
|
||||
}
|
||||
|
||||
func (f frame) IsNil() bool { return false }
|
||||
|
||||
type frames []frame
|
||||
|
||||
func (fs frames) IsNil() bool { return fs == nil }
|
||||
func (fs frames) MarshalJSONArray(enc *gojay.Encoder) {
|
||||
func (fs frames) Encode(enc *jsontext.Encoder) error {
|
||||
h := encoderHelper{enc: enc}
|
||||
h.WriteToken(jsontext.BeginArray)
|
||||
for _, f := range fs {
|
||||
enc.Object(f)
|
||||
if err := f.Encode(enc); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
h.WriteToken(jsontext.EndArray)
|
||||
return h.err
|
||||
}
|
||||
|
||||
func marshalPingFrame(enc *gojay.Encoder, _ *wire.PingFrame) {
|
||||
enc.StringKey("frame_type", "ping")
|
||||
func encodePingFrame(enc *jsontext.Encoder, _ *logging.PingFrame) error {
|
||||
h := encoderHelper{enc: enc}
|
||||
h.WriteToken(jsontext.BeginObject)
|
||||
h.WriteToken(jsontext.String("frame_type"))
|
||||
h.WriteToken(jsontext.String("ping"))
|
||||
h.WriteToken(jsontext.EndObject)
|
||||
return h.err
|
||||
}
|
||||
|
||||
type ackRanges []wire.AckRange
|
||||
|
||||
func (ars ackRanges) MarshalJSONArray(enc *gojay.Encoder) {
|
||||
func (ars ackRanges) Encode(enc *jsontext.Encoder) error {
|
||||
h := encoderHelper{enc: enc}
|
||||
h.WriteToken(jsontext.BeginArray)
|
||||
for _, r := range ars {
|
||||
enc.Array(ackRange(r))
|
||||
if err := ackRange(r).Encode(enc); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
h.WriteToken(jsontext.EndArray)
|
||||
return h.err
|
||||
}
|
||||
|
||||
func (ars ackRanges) IsNil() bool { return false }
|
||||
|
||||
type ackRange wire.AckRange
|
||||
|
||||
func (ar ackRange) MarshalJSONArray(enc *gojay.Encoder) {
|
||||
enc.AddInt64(int64(ar.Smallest))
|
||||
func (ar ackRange) Encode(enc *jsontext.Encoder) error {
|
||||
h := encoderHelper{enc: enc}
|
||||
h.WriteToken(jsontext.BeginArray)
|
||||
h.WriteToken(jsontext.Int(int64(ar.Smallest)))
|
||||
if ar.Smallest != ar.Largest {
|
||||
enc.AddInt64(int64(ar.Largest))
|
||||
h.WriteToken(jsontext.Int(int64(ar.Largest)))
|
||||
}
|
||||
h.WriteToken(jsontext.EndArray)
|
||||
return h.err
|
||||
}
|
||||
|
||||
func (ar ackRange) IsNil() bool { return false }
|
||||
|
||||
func marshalAckFrame(enc *gojay.Encoder, f *logging.AckFrame) {
|
||||
enc.StringKey("frame_type", "ack")
|
||||
enc.FloatKeyOmitEmpty("ack_delay", milliseconds(f.DelayTime))
|
||||
enc.ArrayKey("acked_ranges", ackRanges(f.AckRanges))
|
||||
if hasECN := f.ECT0 > 0 || f.ECT1 > 0 || f.ECNCE > 0; hasECN {
|
||||
enc.Uint64Key("ect0", f.ECT0)
|
||||
enc.Uint64Key("ect1", f.ECT1)
|
||||
enc.Uint64Key("ce", f.ECNCE)
|
||||
func encodeAckFrame(enc *jsontext.Encoder, f *logging.AckFrame) error {
|
||||
h := encoderHelper{enc: enc}
|
||||
h.WriteToken(jsontext.BeginObject)
|
||||
h.WriteToken(jsontext.String("frame_type"))
|
||||
h.WriteToken(jsontext.String("ack"))
|
||||
if f.DelayTime != 0 {
|
||||
h.WriteToken(jsontext.String("ack_delay"))
|
||||
h.WriteToken(jsontext.Float(milliseconds(f.DelayTime)))
|
||||
}
|
||||
h.WriteToken(jsontext.String("acked_ranges"))
|
||||
if err := ackRanges(f.AckRanges).Encode(enc); err != nil {
|
||||
return err
|
||||
}
|
||||
hasECN := f.ECT0 > 0 || f.ECT1 > 0 || f.ECNCE > 0
|
||||
if hasECN {
|
||||
h.WriteToken(jsontext.String("ect0"))
|
||||
h.WriteToken(jsontext.Uint(f.ECT0))
|
||||
h.WriteToken(jsontext.String("ect1"))
|
||||
h.WriteToken(jsontext.Uint(f.ECT1))
|
||||
h.WriteToken(jsontext.String("ce"))
|
||||
h.WriteToken(jsontext.Uint(f.ECNCE))
|
||||
}
|
||||
h.WriteToken(jsontext.EndObject)
|
||||
return h.err
|
||||
}
|
||||
|
||||
func marshalResetStreamFrame(enc *gojay.Encoder, f *logging.ResetStreamFrame) {
|
||||
func encodeResetStreamFrame(enc *jsontext.Encoder, f *logging.ResetStreamFrame) error {
|
||||
h := encoderHelper{enc: enc}
|
||||
h.WriteToken(jsontext.BeginObject)
|
||||
h.WriteToken(jsontext.String("frame_type"))
|
||||
if f.ReliableSize > 0 {
|
||||
enc.StringKey("frame_type", "reset_stream_at")
|
||||
h.WriteToken(jsontext.String("reset_stream_at"))
|
||||
} else {
|
||||
enc.StringKey("frame_type", "reset_stream")
|
||||
h.WriteToken(jsontext.String("reset_stream"))
|
||||
}
|
||||
enc.Int64Key("stream_id", int64(f.StreamID))
|
||||
enc.Int64Key("error_code", int64(f.ErrorCode))
|
||||
enc.Int64Key("final_size", int64(f.FinalSize))
|
||||
h.WriteToken(jsontext.String("stream_id"))
|
||||
h.WriteToken(jsontext.Uint(uint64(f.StreamID)))
|
||||
h.WriteToken(jsontext.String("error_code"))
|
||||
h.WriteToken(jsontext.Uint(uint64(f.ErrorCode)))
|
||||
h.WriteToken(jsontext.String("final_size"))
|
||||
h.WriteToken(jsontext.Uint(uint64(f.FinalSize)))
|
||||
if f.ReliableSize > 0 {
|
||||
enc.Int64Key("reliable_size", int64(f.ReliableSize))
|
||||
h.WriteToken(jsontext.String("reliable_size"))
|
||||
h.WriteToken(jsontext.Uint(uint64(f.ReliableSize)))
|
||||
}
|
||||
h.WriteToken(jsontext.EndObject)
|
||||
return h.err
|
||||
}
|
||||
|
||||
func marshalStopSendingFrame(enc *gojay.Encoder, f *logging.StopSendingFrame) {
|
||||
enc.StringKey("frame_type", "stop_sending")
|
||||
enc.Int64Key("stream_id", int64(f.StreamID))
|
||||
enc.Int64Key("error_code", int64(f.ErrorCode))
|
||||
func encodeStopSendingFrame(enc *jsontext.Encoder, f *logging.StopSendingFrame) error {
|
||||
h := encoderHelper{enc: enc}
|
||||
h.WriteToken(jsontext.BeginObject)
|
||||
h.WriteToken(jsontext.String("frame_type"))
|
||||
h.WriteToken(jsontext.String("stop_sending"))
|
||||
h.WriteToken(jsontext.String("stream_id"))
|
||||
h.WriteToken(jsontext.Uint(uint64(f.StreamID)))
|
||||
h.WriteToken(jsontext.String("error_code"))
|
||||
h.WriteToken(jsontext.Uint(uint64(f.ErrorCode)))
|
||||
h.WriteToken(jsontext.EndObject)
|
||||
return h.err
|
||||
}
|
||||
|
||||
func marshalCryptoFrame(enc *gojay.Encoder, f *logging.CryptoFrame) {
|
||||
enc.StringKey("frame_type", "crypto")
|
||||
enc.Int64Key("offset", int64(f.Offset))
|
||||
enc.Int64Key("length", int64(f.Length))
|
||||
func encodeCryptoFrame(enc *jsontext.Encoder, f *logging.CryptoFrame) error {
|
||||
h := encoderHelper{enc: enc}
|
||||
h.WriteToken(jsontext.BeginObject)
|
||||
h.WriteToken(jsontext.String("frame_type"))
|
||||
h.WriteToken(jsontext.String("crypto"))
|
||||
h.WriteToken(jsontext.String("offset"))
|
||||
h.WriteToken(jsontext.Uint(uint64(f.Offset)))
|
||||
h.WriteToken(jsontext.String("length"))
|
||||
h.WriteToken(jsontext.Uint(uint64(f.Length)))
|
||||
h.WriteToken(jsontext.EndObject)
|
||||
return h.err
|
||||
}
|
||||
|
||||
func marshalNewTokenFrame(enc *gojay.Encoder, f *logging.NewTokenFrame) {
|
||||
enc.StringKey("frame_type", "new_token")
|
||||
enc.ObjectKey("token", &token{Raw: f.Token})
|
||||
func encodeNewTokenFrame(enc *jsontext.Encoder, f *logging.NewTokenFrame) error {
|
||||
h := encoderHelper{enc: enc}
|
||||
h.WriteToken(jsontext.BeginObject)
|
||||
h.WriteToken(jsontext.String("frame_type"))
|
||||
h.WriteToken(jsontext.String("new_token"))
|
||||
h.WriteToken(jsontext.String("token"))
|
||||
if err := (token{Raw: f.Token}).Encode(enc); err != nil {
|
||||
return err
|
||||
}
|
||||
h.WriteToken(jsontext.EndObject)
|
||||
return h.err
|
||||
}
|
||||
|
||||
func marshalStreamFrame(enc *gojay.Encoder, f *logging.StreamFrame) {
|
||||
enc.StringKey("frame_type", "stream")
|
||||
enc.Int64Key("stream_id", int64(f.StreamID))
|
||||
enc.Int64Key("offset", int64(f.Offset))
|
||||
enc.IntKey("length", int(f.Length))
|
||||
enc.BoolKeyOmitEmpty("fin", f.Fin)
|
||||
func encodeStreamFrame(enc *jsontext.Encoder, f *logging.StreamFrame) error {
|
||||
h := encoderHelper{enc: enc}
|
||||
h.WriteToken(jsontext.BeginObject)
|
||||
h.WriteToken(jsontext.String("frame_type"))
|
||||
h.WriteToken(jsontext.String("stream"))
|
||||
h.WriteToken(jsontext.String("stream_id"))
|
||||
h.WriteToken(jsontext.Uint(uint64(f.StreamID)))
|
||||
h.WriteToken(jsontext.String("offset"))
|
||||
h.WriteToken(jsontext.Uint(uint64(f.Offset)))
|
||||
h.WriteToken(jsontext.String("length"))
|
||||
h.WriteToken(jsontext.Uint(uint64(f.Length)))
|
||||
if f.Fin {
|
||||
h.WriteToken(jsontext.String("fin"))
|
||||
h.WriteToken(jsontext.True)
|
||||
}
|
||||
h.WriteToken(jsontext.EndObject)
|
||||
return h.err
|
||||
}
|
||||
|
||||
func marshalMaxDataFrame(enc *gojay.Encoder, f *logging.MaxDataFrame) {
|
||||
enc.StringKey("frame_type", "max_data")
|
||||
enc.Int64Key("maximum", int64(f.MaximumData))
|
||||
func encodeMaxDataFrame(enc *jsontext.Encoder, f *logging.MaxDataFrame) error {
|
||||
h := encoderHelper{enc: enc}
|
||||
h.WriteToken(jsontext.BeginObject)
|
||||
h.WriteToken(jsontext.String("frame_type"))
|
||||
h.WriteToken(jsontext.String("max_data"))
|
||||
h.WriteToken(jsontext.String("maximum"))
|
||||
h.WriteToken(jsontext.Uint(uint64(f.MaximumData)))
|
||||
h.WriteToken(jsontext.EndObject)
|
||||
return h.err
|
||||
}
|
||||
|
||||
func marshalMaxStreamDataFrame(enc *gojay.Encoder, f *logging.MaxStreamDataFrame) {
|
||||
enc.StringKey("frame_type", "max_stream_data")
|
||||
enc.Int64Key("stream_id", int64(f.StreamID))
|
||||
enc.Int64Key("maximum", int64(f.MaximumStreamData))
|
||||
func encodeMaxStreamDataFrame(enc *jsontext.Encoder, f *logging.MaxStreamDataFrame) error {
|
||||
h := encoderHelper{enc: enc}
|
||||
h.WriteToken(jsontext.BeginObject)
|
||||
h.WriteToken(jsontext.String("frame_type"))
|
||||
h.WriteToken(jsontext.String("max_stream_data"))
|
||||
h.WriteToken(jsontext.String("stream_id"))
|
||||
h.WriteToken(jsontext.Uint(uint64(f.StreamID)))
|
||||
h.WriteToken(jsontext.String("maximum"))
|
||||
h.WriteToken(jsontext.Uint(uint64(f.MaximumStreamData)))
|
||||
h.WriteToken(jsontext.EndObject)
|
||||
return h.err
|
||||
}
|
||||
|
||||
func marshalMaxStreamsFrame(enc *gojay.Encoder, f *logging.MaxStreamsFrame) {
|
||||
enc.StringKey("frame_type", "max_streams")
|
||||
enc.StringKey("stream_type", streamType(f.Type).String())
|
||||
enc.Int64Key("maximum", int64(f.MaxStreamNum))
|
||||
func encodeMaxStreamsFrame(enc *jsontext.Encoder, f *logging.MaxStreamsFrame) error {
|
||||
h := encoderHelper{enc: enc}
|
||||
h.WriteToken(jsontext.BeginObject)
|
||||
h.WriteToken(jsontext.String("frame_type"))
|
||||
h.WriteToken(jsontext.String("max_streams"))
|
||||
h.WriteToken(jsontext.String("stream_type"))
|
||||
h.WriteToken(jsontext.String(streamType(f.Type).String()))
|
||||
h.WriteToken(jsontext.String("maximum"))
|
||||
h.WriteToken(jsontext.Uint(uint64(f.MaxStreamNum)))
|
||||
h.WriteToken(jsontext.EndObject)
|
||||
return h.err
|
||||
}
|
||||
|
||||
func marshalDataBlockedFrame(enc *gojay.Encoder, f *logging.DataBlockedFrame) {
|
||||
enc.StringKey("frame_type", "data_blocked")
|
||||
enc.Int64Key("limit", int64(f.MaximumData))
|
||||
func encodeDataBlockedFrame(enc *jsontext.Encoder, f *logging.DataBlockedFrame) error {
|
||||
h := encoderHelper{enc: enc}
|
||||
h.WriteToken(jsontext.BeginObject)
|
||||
h.WriteToken(jsontext.String("frame_type"))
|
||||
h.WriteToken(jsontext.String("data_blocked"))
|
||||
h.WriteToken(jsontext.String("limit"))
|
||||
h.WriteToken(jsontext.Uint(uint64(f.MaximumData)))
|
||||
h.WriteToken(jsontext.EndObject)
|
||||
return h.err
|
||||
}
|
||||
|
||||
func marshalStreamDataBlockedFrame(enc *gojay.Encoder, f *logging.StreamDataBlockedFrame) {
|
||||
enc.StringKey("frame_type", "stream_data_blocked")
|
||||
enc.Int64Key("stream_id", int64(f.StreamID))
|
||||
enc.Int64Key("limit", int64(f.MaximumStreamData))
|
||||
func encodeStreamDataBlockedFrame(enc *jsontext.Encoder, f *logging.StreamDataBlockedFrame) error {
|
||||
h := encoderHelper{enc: enc}
|
||||
h.WriteToken(jsontext.BeginObject)
|
||||
h.WriteToken(jsontext.String("frame_type"))
|
||||
h.WriteToken(jsontext.String("stream_data_blocked"))
|
||||
h.WriteToken(jsontext.String("stream_id"))
|
||||
h.WriteToken(jsontext.Uint(uint64(f.StreamID)))
|
||||
h.WriteToken(jsontext.String("limit"))
|
||||
h.WriteToken(jsontext.Uint(uint64(f.MaximumStreamData)))
|
||||
h.WriteToken(jsontext.EndObject)
|
||||
return h.err
|
||||
}
|
||||
|
||||
func marshalStreamsBlockedFrame(enc *gojay.Encoder, f *logging.StreamsBlockedFrame) {
|
||||
enc.StringKey("frame_type", "streams_blocked")
|
||||
enc.StringKey("stream_type", streamType(f.Type).String())
|
||||
enc.Int64Key("limit", int64(f.StreamLimit))
|
||||
func encodeStreamsBlockedFrame(enc *jsontext.Encoder, f *logging.StreamsBlockedFrame) error {
|
||||
h := encoderHelper{enc: enc}
|
||||
h.WriteToken(jsontext.BeginObject)
|
||||
h.WriteToken(jsontext.String("frame_type"))
|
||||
h.WriteToken(jsontext.String("streams_blocked"))
|
||||
h.WriteToken(jsontext.String("stream_type"))
|
||||
h.WriteToken(jsontext.String(streamType(f.Type).String()))
|
||||
h.WriteToken(jsontext.String("limit"))
|
||||
h.WriteToken(jsontext.Uint(uint64(f.StreamLimit)))
|
||||
h.WriteToken(jsontext.EndObject)
|
||||
return h.err
|
||||
}
|
||||
|
||||
func marshalNewConnectionIDFrame(enc *gojay.Encoder, f *logging.NewConnectionIDFrame) {
|
||||
enc.StringKey("frame_type", "new_connection_id")
|
||||
enc.Int64Key("sequence_number", int64(f.SequenceNumber))
|
||||
enc.Int64Key("retire_prior_to", int64(f.RetirePriorTo))
|
||||
enc.IntKey("length", f.ConnectionID.Len())
|
||||
enc.StringKey("connection_id", f.ConnectionID.String())
|
||||
enc.StringKey("stateless_reset_token", fmt.Sprintf("%x", f.StatelessResetToken))
|
||||
func encodeNewConnectionIDFrame(enc *jsontext.Encoder, f *logging.NewConnectionIDFrame) error {
|
||||
h := encoderHelper{enc: enc}
|
||||
h.WriteToken(jsontext.BeginObject)
|
||||
h.WriteToken(jsontext.String("frame_type"))
|
||||
h.WriteToken(jsontext.String("new_connection_id"))
|
||||
h.WriteToken(jsontext.String("sequence_number"))
|
||||
h.WriteToken(jsontext.Uint(f.SequenceNumber))
|
||||
h.WriteToken(jsontext.String("retire_prior_to"))
|
||||
h.WriteToken(jsontext.Uint(f.RetirePriorTo))
|
||||
h.WriteToken(jsontext.String("length"))
|
||||
h.WriteToken(jsontext.Int(int64(f.ConnectionID.Len())))
|
||||
h.WriteToken(jsontext.String("connection_id"))
|
||||
h.WriteToken(jsontext.String(f.ConnectionID.String()))
|
||||
h.WriteToken(jsontext.String("stateless_reset_token"))
|
||||
h.WriteToken(jsontext.String(fmt.Sprintf("%x", f.StatelessResetToken)))
|
||||
h.WriteToken(jsontext.EndObject)
|
||||
return h.err
|
||||
}
|
||||
|
||||
func marshalRetireConnectionIDFrame(enc *gojay.Encoder, f *logging.RetireConnectionIDFrame) {
|
||||
enc.StringKey("frame_type", "retire_connection_id")
|
||||
enc.Int64Key("sequence_number", int64(f.SequenceNumber))
|
||||
func encodeRetireConnectionIDFrame(enc *jsontext.Encoder, f *logging.RetireConnectionIDFrame) error {
|
||||
h := encoderHelper{enc: enc}
|
||||
h.WriteToken(jsontext.BeginObject)
|
||||
h.WriteToken(jsontext.String("frame_type"))
|
||||
h.WriteToken(jsontext.String("retire_connection_id"))
|
||||
h.WriteToken(jsontext.String("sequence_number"))
|
||||
h.WriteToken(jsontext.Uint(f.SequenceNumber))
|
||||
h.WriteToken(jsontext.EndObject)
|
||||
return h.err
|
||||
}
|
||||
|
||||
func marshalPathChallengeFrame(enc *gojay.Encoder, f *logging.PathChallengeFrame) {
|
||||
enc.StringKey("frame_type", "path_challenge")
|
||||
enc.StringKey("data", fmt.Sprintf("%x", f.Data[:]))
|
||||
func encodePathChallengeFrame(enc *jsontext.Encoder, f *logging.PathChallengeFrame) error {
|
||||
h := encoderHelper{enc: enc}
|
||||
h.WriteToken(jsontext.BeginObject)
|
||||
h.WriteToken(jsontext.String("frame_type"))
|
||||
h.WriteToken(jsontext.String("path_challenge"))
|
||||
h.WriteToken(jsontext.String("data"))
|
||||
h.WriteToken(jsontext.String(fmt.Sprintf("%x", f.Data[:])))
|
||||
h.WriteToken(jsontext.EndObject)
|
||||
return h.err
|
||||
}
|
||||
|
||||
func marshalPathResponseFrame(enc *gojay.Encoder, f *logging.PathResponseFrame) {
|
||||
enc.StringKey("frame_type", "path_response")
|
||||
enc.StringKey("data", fmt.Sprintf("%x", f.Data[:]))
|
||||
func encodePathResponseFrame(enc *jsontext.Encoder, f *logging.PathResponseFrame) error {
|
||||
h := encoderHelper{enc: enc}
|
||||
h.WriteToken(jsontext.BeginObject)
|
||||
h.WriteToken(jsontext.String("frame_type"))
|
||||
h.WriteToken(jsontext.String("path_response"))
|
||||
h.WriteToken(jsontext.String("data"))
|
||||
h.WriteToken(jsontext.String(fmt.Sprintf("%x", f.Data[:])))
|
||||
h.WriteToken(jsontext.EndObject)
|
||||
return h.err
|
||||
}
|
||||
|
||||
func marshalConnectionCloseFrame(enc *gojay.Encoder, f *logging.ConnectionCloseFrame) {
|
||||
func encodeConnectionCloseFrame(enc *jsontext.Encoder, f *logging.ConnectionCloseFrame) error {
|
||||
h := encoderHelper{enc: enc}
|
||||
h.WriteToken(jsontext.BeginObject)
|
||||
h.WriteToken(jsontext.String("frame_type"))
|
||||
h.WriteToken(jsontext.String("connection_close"))
|
||||
h.WriteToken(jsontext.String("error_space"))
|
||||
errorSpace := "transport"
|
||||
if f.IsApplicationError {
|
||||
errorSpace = "application"
|
||||
}
|
||||
enc.StringKey("frame_type", "connection_close")
|
||||
enc.StringKey("error_space", errorSpace)
|
||||
if errName := transportError(f.ErrorCode).String(); len(errName) > 0 {
|
||||
enc.StringKey("error_code", errName)
|
||||
h.WriteToken(jsontext.String(errorSpace))
|
||||
errName := transportError(f.ErrorCode).String()
|
||||
if len(errName) > 0 {
|
||||
h.WriteToken(jsontext.String("error_code"))
|
||||
h.WriteToken(jsontext.String(errName))
|
||||
} else {
|
||||
enc.Uint64Key("error_code", f.ErrorCode)
|
||||
h.WriteToken(jsontext.String("error_code"))
|
||||
h.WriteToken(jsontext.Uint(f.ErrorCode))
|
||||
}
|
||||
enc.Uint64Key("raw_error_code", f.ErrorCode)
|
||||
enc.StringKey("reason", f.ReasonPhrase)
|
||||
h.WriteToken(jsontext.String("raw_error_code"))
|
||||
h.WriteToken(jsontext.Uint(f.ErrorCode))
|
||||
h.WriteToken(jsontext.String("reason"))
|
||||
h.WriteToken(jsontext.String(f.ReasonPhrase))
|
||||
h.WriteToken(jsontext.EndObject)
|
||||
return h.err
|
||||
}
|
||||
|
||||
func marshalHandshakeDoneFrame(enc *gojay.Encoder, _ *logging.HandshakeDoneFrame) {
|
||||
enc.StringKey("frame_type", "handshake_done")
|
||||
func encodeHandshakeDoneFrame(enc *jsontext.Encoder, _ *logging.HandshakeDoneFrame) error {
|
||||
h := encoderHelper{enc: enc}
|
||||
h.WriteToken(jsontext.BeginObject)
|
||||
h.WriteToken(jsontext.String("frame_type"))
|
||||
h.WriteToken(jsontext.String("handshake_done"))
|
||||
h.WriteToken(jsontext.EndObject)
|
||||
return h.err
|
||||
}
|
||||
|
||||
func marshalDatagramFrame(enc *gojay.Encoder, f *logging.DatagramFrame) {
|
||||
enc.StringKey("frame_type", "datagram")
|
||||
enc.Int64Key("length", int64(f.Length))
|
||||
func encodeDatagramFrame(enc *jsontext.Encoder, f *logging.DatagramFrame) error {
|
||||
h := encoderHelper{enc: enc}
|
||||
h.WriteToken(jsontext.BeginObject)
|
||||
h.WriteToken(jsontext.String("frame_type"))
|
||||
h.WriteToken(jsontext.String("datagram"))
|
||||
h.WriteToken(jsontext.String("length"))
|
||||
h.WriteToken(jsontext.Uint(uint64(f.Length)))
|
||||
h.WriteToken(jsontext.EndObject)
|
||||
return h.err
|
||||
}
|
||||
|
||||
func marshalAckFrequencyFrame(enc *gojay.Encoder, f *logging.AckFrequencyFrame) {
|
||||
enc.StringKey("frame_type", "ack_frequency")
|
||||
enc.Uint64Key("sequence_number", f.SequenceNumber)
|
||||
enc.Uint64Key("ack_eliciting_threshold", f.AckElicitingThreshold)
|
||||
enc.Float64Key("request_max_ack_delay", milliseconds(f.RequestMaxAckDelay))
|
||||
enc.Uint64Key("reordering_threshold", uint64(f.ReorderingThreshold))
|
||||
func encodeAckFrequencyFrame(enc *jsontext.Encoder, f *logging.AckFrequencyFrame) error {
|
||||
h := encoderHelper{enc: enc}
|
||||
h.WriteToken(jsontext.BeginObject)
|
||||
h.WriteToken(jsontext.String("frame_type"))
|
||||
h.WriteToken(jsontext.String("ack_frequency"))
|
||||
h.WriteToken(jsontext.String("sequence_number"))
|
||||
h.WriteToken(jsontext.Uint(f.SequenceNumber))
|
||||
h.WriteToken(jsontext.String("ack_eliciting_threshold"))
|
||||
h.WriteToken(jsontext.Uint(f.AckElicitingThreshold))
|
||||
h.WriteToken(jsontext.String("request_max_ack_delay"))
|
||||
h.WriteToken(jsontext.Float(milliseconds(f.RequestMaxAckDelay)))
|
||||
h.WriteToken(jsontext.String("reordering_threshold"))
|
||||
h.WriteToken(jsontext.Uint(uint64(f.ReorderingThreshold)))
|
||||
h.WriteToken(jsontext.EndObject)
|
||||
return h.err
|
||||
}
|
||||
|
||||
func marshalImmediateAckFrame(enc *gojay.Encoder, _ *logging.ImmediateAckFrame) {
|
||||
enc.StringKey("frame_type", "immediate_ack")
|
||||
func encodeImmediateAckFrame(enc *jsontext.Encoder, _ *logging.ImmediateAckFrame) error {
|
||||
h := encoderHelper{enc: enc}
|
||||
h.WriteToken(jsontext.BeginObject)
|
||||
h.WriteToken(jsontext.String("frame_type"))
|
||||
h.WriteToken(jsontext.String("immediate_ack"))
|
||||
h.WriteToken(jsontext.EndObject)
|
||||
return h.err
|
||||
}
|
||||
|
||||
@@ -6,17 +6,19 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/francoispqt/gojay"
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
"github.com/quic-go/quic-go/internal/qerr"
|
||||
"github.com/quic-go/quic-go/logging"
|
||||
|
||||
"github.com/quic-go/quic-go/qlog/jsontext"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func check(t *testing.T, f logging.Frame, expected map[string]any) {
|
||||
buf := &bytes.Buffer{}
|
||||
enc := gojay.NewEncoder(buf)
|
||||
err := enc.Encode(frame{Frame: f})
|
||||
enc := jsontext.NewEncoder(buf)
|
||||
err := (frame{Frame: f}).Encode(enc)
|
||||
require.NoError(t, err)
|
||||
data := buf.Bytes()
|
||||
require.True(t, json.Valid(data))
|
||||
|
||||
@@ -30,6 +30,8 @@ func unmarshal(data []byte, v any) error {
|
||||
}
|
||||
|
||||
func checkEncoding(t *testing.T, data []byte, expected map[string]any) {
|
||||
t.Helper()
|
||||
|
||||
m := make(map[string]any)
|
||||
require.NoError(t, json.Unmarshal(data, &m))
|
||||
require.Len(t, m, len(expected))
|
||||
@@ -68,6 +70,8 @@ type entry struct {
|
||||
}
|
||||
|
||||
func exportAndParse(t *testing.T, buf *bytes.Buffer) []entry {
|
||||
t.Helper()
|
||||
|
||||
m := make(map[string]any)
|
||||
line, err := buf.ReadBytes('\n')
|
||||
require.NoError(t, err)
|
||||
@@ -100,6 +104,8 @@ func exportAndParse(t *testing.T, buf *bytes.Buffer) []entry {
|
||||
}
|
||||
|
||||
func exportAndParseSingle(t *testing.T, buf *bytes.Buffer) entry {
|
||||
t.Helper()
|
||||
|
||||
entries := exportAndParse(t, buf)
|
||||
require.Len(t, entries, 1)
|
||||
return entries[0]
|
||||
|
||||
314
qlog/jsontext/encoder.go
Normal file
314
qlog/jsontext/encoder.go
Normal file
@@ -0,0 +1,314 @@
|
||||
// Package jsontext provides a fast JSON encoder providing only the necessary features
|
||||
// for qlog encoding. No efforts are made to add any features beyond qlog's requirements.
|
||||
//
|
||||
// The API aims to be compatible with the standard library's encoding/json/jsontext package.
|
||||
package jsontext
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type kind uint8
|
||||
|
||||
const (
|
||||
kindString kind = iota
|
||||
kindInt
|
||||
kindUint
|
||||
kindFloat
|
||||
kindBool
|
||||
kindObjectStart
|
||||
kindObjectEnd
|
||||
kindArrayStart
|
||||
kindArrayEnd
|
||||
)
|
||||
|
||||
// Token represents a JSON token.
|
||||
type Token struct {
|
||||
kind kind
|
||||
str string
|
||||
i64 int64
|
||||
u64 uint64
|
||||
f64 float64
|
||||
b bool
|
||||
}
|
||||
|
||||
// String creates a string token.
|
||||
func String(s string) Token {
|
||||
return Token{kind: kindString, str: s}
|
||||
}
|
||||
|
||||
// Int creates an int token.
|
||||
func Int(i int64) Token {
|
||||
return Token{kind: kindInt, i64: i}
|
||||
}
|
||||
|
||||
// Uint creates a uint token.
|
||||
func Uint(u uint64) Token {
|
||||
return Token{kind: kindUint, u64: u}
|
||||
}
|
||||
|
||||
// Float creates a float token.
|
||||
func Float(f float64) Token {
|
||||
return Token{kind: kindFloat, f64: f}
|
||||
}
|
||||
|
||||
// Bool creates a bool token.
|
||||
func Bool(b bool) Token {
|
||||
return Token{kind: kindBool, b: b}
|
||||
}
|
||||
|
||||
// BeginObject is the begin object token.
|
||||
var BeginObject Token = Token{kind: kindObjectStart}
|
||||
|
||||
// EndObject is the end object token.
|
||||
var EndObject Token = Token{kind: kindObjectEnd}
|
||||
|
||||
// BeginArray is the begin array token.
|
||||
var BeginArray Token = Token{kind: kindArrayStart}
|
||||
|
||||
// EndArray is the end array token.
|
||||
var EndArray Token = Token{kind: kindArrayEnd}
|
||||
|
||||
// True is a true token.
|
||||
var True Token = Bool(true)
|
||||
|
||||
// False is a false token.
|
||||
var False Token = Bool(false)
|
||||
|
||||
var hexDigits = [16]byte{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}
|
||||
|
||||
var (
|
||||
commaByte = []byte(",")
|
||||
quoteByte = []byte(`"`)
|
||||
colonByte = []byte(":")
|
||||
trueByte = []byte("true")
|
||||
falseByte = []byte("false")
|
||||
openObjectByte = []byte("{")
|
||||
closeObjectByte = []byte("}")
|
||||
openArrayByte = []byte("[")
|
||||
closeArrayByte = []byte("]")
|
||||
newlineByte = []byte("\n")
|
||||
escapeQuote = []byte(`\"`)
|
||||
escapeBackslash = []byte(`\\`)
|
||||
escapeBackspace = []byte(`\b`)
|
||||
escapeFormfeed = []byte(`\f`)
|
||||
escapeNewline = []byte(`\n`)
|
||||
escapeCarriage = []byte(`\r`)
|
||||
escapeTab = []byte(`\t`)
|
||||
escapeUnicode = []byte(`\u00`)
|
||||
)
|
||||
|
||||
type context struct {
|
||||
isObject bool
|
||||
needsComma bool
|
||||
expectKey bool
|
||||
}
|
||||
|
||||
// Encoder encodes JSON to an io.Writer.
|
||||
type Encoder struct {
|
||||
w io.Writer
|
||||
buf [64]byte // scratch buffer for number formatting
|
||||
stack []context
|
||||
}
|
||||
|
||||
// NewEncoder creates a new Encoder.
|
||||
func NewEncoder(w io.Writer) *Encoder {
|
||||
stack := make([]context, 0, 8)
|
||||
stack = append(stack, context{isObject: false, needsComma: false, expectKey: false})
|
||||
return &Encoder{
|
||||
w: w,
|
||||
stack: stack,
|
||||
}
|
||||
}
|
||||
|
||||
// WriteToken writes a token to the encoder.
|
||||
func (e *Encoder) WriteToken(t Token) error {
|
||||
if len(e.stack) == 0 {
|
||||
return fmt.Errorf("empty stack")
|
||||
}
|
||||
curr := &e.stack[len(e.stack)-1]
|
||||
isClosing := t.kind == kindObjectEnd || t.kind == kindArrayEnd
|
||||
if !isClosing && curr.needsComma {
|
||||
if _, err := e.w.Write(commaByte); err != nil {
|
||||
return err
|
||||
}
|
||||
curr.needsComma = false
|
||||
}
|
||||
var err error
|
||||
switch t.kind {
|
||||
case kindString:
|
||||
data := stringToBytes(t.str)
|
||||
needsEscape := false
|
||||
for _, b := range data {
|
||||
if b == '"' || b == '\\' || b < 0x20 {
|
||||
needsEscape = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !needsEscape {
|
||||
if _, err = e.w.Write(quoteByte); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = e.w.Write(data); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = e.w.Write(quoteByte); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if _, err = e.w.Write(quoteByte); err != nil {
|
||||
return err
|
||||
}
|
||||
for i := 0; i < len(t.str); i++ {
|
||||
c := t.str[i]
|
||||
switch c {
|
||||
case '"':
|
||||
if _, err = e.w.Write(escapeQuote); err != nil {
|
||||
return err
|
||||
}
|
||||
case '\\':
|
||||
if _, err = e.w.Write(escapeBackslash); err != nil {
|
||||
return err
|
||||
}
|
||||
case '\b':
|
||||
if _, err = e.w.Write(escapeBackspace); err != nil {
|
||||
return err
|
||||
}
|
||||
case '\f':
|
||||
if _, err = e.w.Write(escapeFormfeed); err != nil {
|
||||
return err
|
||||
}
|
||||
case '\n':
|
||||
if _, err = e.w.Write(escapeNewline); err != nil {
|
||||
return err
|
||||
}
|
||||
case '\r':
|
||||
if _, err = e.w.Write(escapeCarriage); err != nil {
|
||||
return err
|
||||
}
|
||||
case '\t':
|
||||
if _, err = e.w.Write(escapeTab); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
if c < 0x20 {
|
||||
if _, err = e.w.Write(escapeUnicode); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = e.w.Write([]byte{hexDigits[c>>4], hexDigits[c&0xf]}); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if _, err = e.w.Write([]byte{c}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if _, err = e.w.Write(quoteByte); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if curr.isObject {
|
||||
if curr.expectKey {
|
||||
// key
|
||||
if _, err = e.w.Write(colonByte); err != nil {
|
||||
return err
|
||||
}
|
||||
curr.expectKey = false
|
||||
return nil // do not call afterValue for keys
|
||||
} else {
|
||||
// value
|
||||
e.afterValue()
|
||||
}
|
||||
} else {
|
||||
e.afterValue()
|
||||
}
|
||||
case kindInt:
|
||||
b := strconv.AppendInt(e.buf[:0], t.i64, 10)
|
||||
if _, err = e.w.Write(b); err != nil {
|
||||
return err
|
||||
}
|
||||
e.afterValue()
|
||||
case kindUint:
|
||||
b := strconv.AppendUint(e.buf[:0], t.u64, 10)
|
||||
if _, err = e.w.Write(b); err != nil {
|
||||
return err
|
||||
}
|
||||
e.afterValue()
|
||||
case kindFloat:
|
||||
b := strconv.AppendFloat(e.buf[:0], t.f64, 'g', -1, 64)
|
||||
if _, err = e.w.Write(b); err != nil {
|
||||
return err
|
||||
}
|
||||
e.afterValue()
|
||||
case kindBool:
|
||||
if t.b {
|
||||
if _, err = e.w.Write(trueByte); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if _, err = e.w.Write(falseByte); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
e.afterValue()
|
||||
case kindObjectStart:
|
||||
if _, err = e.w.Write(openObjectByte); err != nil {
|
||||
return err
|
||||
}
|
||||
e.stack = append(e.stack, context{isObject: true, needsComma: false, expectKey: true})
|
||||
return nil
|
||||
case kindObjectEnd:
|
||||
if _, err = e.w.Write(closeObjectByte); err != nil {
|
||||
return err
|
||||
}
|
||||
e.stack = e.stack[:len(e.stack)-1]
|
||||
e.afterValue()
|
||||
if len(e.stack) == 1 {
|
||||
if _, err = e.w.Write(newlineByte); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
case kindArrayStart:
|
||||
if _, err = e.w.Write(openArrayByte); err != nil {
|
||||
return err
|
||||
}
|
||||
e.stack = append(e.stack, context{isObject: false, needsComma: false, expectKey: false})
|
||||
return nil
|
||||
case kindArrayEnd:
|
||||
if _, err = e.w.Write(closeArrayByte); err != nil {
|
||||
return err
|
||||
}
|
||||
e.stack = e.stack[:len(e.stack)-1]
|
||||
e.afterValue()
|
||||
if len(e.stack) == 1 {
|
||||
if _, err = e.w.Write(newlineByte); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("unknown token kind")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// afterValue updates the state after encoding a value
|
||||
func (e *Encoder) afterValue() {
|
||||
if len(e.stack) > 1 {
|
||||
curr := &e.stack[len(e.stack)-1]
|
||||
curr.needsComma = true
|
||||
if curr.isObject {
|
||||
curr.expectKey = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func stringToBytes(s string) []byte {
|
||||
return unsafe.Slice(unsafe.StringData(s), len(s))
|
||||
}
|
||||
383
qlog/jsontext/encoder_test.go
Normal file
383
qlog/jsontext/encoder_test.go
Normal file
@@ -0,0 +1,383 @@
|
||||
package jsontext_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/quic-go/quic-go/qlog/jsontext"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestEncoderSimpleObject(t *testing.T) {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
enc := jsontext.NewEncoder(buf)
|
||||
enc.WriteToken(jsontext.BeginObject)
|
||||
enc.WriteToken(jsontext.String("foo"))
|
||||
enc.WriteToken(jsontext.String("bar"))
|
||||
enc.WriteToken(jsontext.String("foo2"))
|
||||
enc.WriteToken(jsontext.String("bar2"))
|
||||
enc.WriteToken(jsontext.EndObject)
|
||||
output := buf.String()
|
||||
|
||||
var got map[string]string
|
||||
require.NoError(t, json.Unmarshal([]byte(output), &got))
|
||||
require.Equal(t, map[string]string{"foo": "bar", "foo2": "bar2"}, got)
|
||||
}
|
||||
|
||||
func TestEncoderArrayInts(t *testing.T) {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
enc := jsontext.NewEncoder(buf)
|
||||
enc.WriteToken(jsontext.BeginArray)
|
||||
enc.WriteToken(jsontext.Int(1))
|
||||
enc.WriteToken(jsontext.Int(2))
|
||||
enc.WriteToken(jsontext.Int(3))
|
||||
enc.WriteToken(jsontext.EndArray)
|
||||
output := buf.String()
|
||||
|
||||
var got []int
|
||||
require.NoError(t, json.Unmarshal([]byte(output), &got))
|
||||
require.Equal(t, []int{1, 2, 3}, got)
|
||||
}
|
||||
|
||||
func TestEncoderArrayStrings(t *testing.T) {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
enc := jsontext.NewEncoder(buf)
|
||||
enc.WriteToken(jsontext.BeginArray)
|
||||
enc.WriteToken(jsontext.String("one"))
|
||||
enc.WriteToken(jsontext.String("two"))
|
||||
enc.WriteToken(jsontext.EndArray)
|
||||
output := buf.String()
|
||||
|
||||
var got []string
|
||||
err := json.Unmarshal([]byte(output), &got)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, []string{"one", "two"}, got)
|
||||
}
|
||||
|
||||
func TestEncoderNestedObject(t *testing.T) {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
enc := jsontext.NewEncoder(buf)
|
||||
enc.WriteToken(jsontext.BeginObject)
|
||||
enc.WriteToken(jsontext.String("outer"))
|
||||
enc.WriteToken(jsontext.BeginObject)
|
||||
enc.WriteToken(jsontext.String("inner"))
|
||||
enc.WriteToken(jsontext.String("value"))
|
||||
enc.WriteToken(jsontext.EndObject)
|
||||
enc.WriteToken(jsontext.EndObject)
|
||||
output := buf.String()
|
||||
|
||||
var got map[string]map[string]string
|
||||
require.NoError(t, json.Unmarshal([]byte(output), &got))
|
||||
require.Equal(t, map[string]map[string]string{"outer": {"inner": "value"}}, got)
|
||||
}
|
||||
|
||||
func TestEncoderNumbersAndBool(t *testing.T) {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
enc := jsontext.NewEncoder(buf)
|
||||
enc.WriteToken(jsontext.BeginObject)
|
||||
enc.WriteToken(jsontext.String("int"))
|
||||
enc.WriteToken(jsontext.Int(42))
|
||||
enc.WriteToken(jsontext.String("uint"))
|
||||
enc.WriteToken(jsontext.Uint(100))
|
||||
enc.WriteToken(jsontext.String("float"))
|
||||
enc.WriteToken(jsontext.Float(3.14))
|
||||
enc.WriteToken(jsontext.String("true"))
|
||||
enc.WriteToken(jsontext.True)
|
||||
enc.WriteToken(jsontext.String("false"))
|
||||
enc.WriteToken(jsontext.False)
|
||||
enc.WriteToken(jsontext.EndObject)
|
||||
output := buf.String()
|
||||
|
||||
var got map[string]any
|
||||
require.NoError(t, json.Unmarshal([]byte(output), &got))
|
||||
require.Equal(t, map[string]any{
|
||||
"int": float64(42), // json.Unmarshal decodes numbers as float64
|
||||
"uint": float64(100),
|
||||
"float": 3.14,
|
||||
"true": true,
|
||||
"false": false,
|
||||
}, got)
|
||||
}
|
||||
|
||||
func TestEncoderEmptyObject(t *testing.T) {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
enc := jsontext.NewEncoder(buf)
|
||||
enc.WriteToken(jsontext.BeginObject)
|
||||
enc.WriteToken(jsontext.EndObject)
|
||||
output := buf.String()
|
||||
|
||||
var got map[string]any
|
||||
require.NoError(t, json.Unmarshal([]byte(output), &got))
|
||||
require.Equal(t, map[string]any{}, got)
|
||||
}
|
||||
|
||||
func TestEncoderEmptyArray(t *testing.T) {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
enc := jsontext.NewEncoder(buf)
|
||||
enc.WriteToken(jsontext.BeginArray)
|
||||
enc.WriteToken(jsontext.EndArray)
|
||||
output := buf.String()
|
||||
|
||||
var got []any
|
||||
require.NoError(t, json.Unmarshal([]byte(output), &got))
|
||||
require.Equal(t, []any{}, got)
|
||||
}
|
||||
|
||||
func TestEncoderEscapedStrings(t *testing.T) {
|
||||
t.Run("no escapes", func(t *testing.T) {
|
||||
testEncoderEscapedStrings(t, "simplekey", "simplevalue")
|
||||
})
|
||||
|
||||
t.Run("basic escapes", func(t *testing.T) {
|
||||
key := `key"\/`
|
||||
value := `value"\/`
|
||||
testEncoderEscapedStrings(t, key, value)
|
||||
})
|
||||
|
||||
t.Run("control characters", func(t *testing.T) {
|
||||
key := "key\b\f\n\r\t"
|
||||
value := "value\b\f\n\r\t"
|
||||
testEncoderEscapedStrings(t, key, value)
|
||||
})
|
||||
|
||||
t.Run("unicode low", func(t *testing.T) {
|
||||
key := "key\u0007\u001f"
|
||||
value := "value\u0007\u001f"
|
||||
testEncoderEscapedStrings(t, key, value)
|
||||
})
|
||||
|
||||
t.Run("mixed all", func(t *testing.T) {
|
||||
key := `key"\\\/\b\f\n\r\t\u0007\u001f`
|
||||
value := `value"\\\/\b\f\n\r\t\u0007\u001f`
|
||||
testEncoderEscapedStrings(t, key, value)
|
||||
})
|
||||
}
|
||||
|
||||
func testEncoderEscapedStrings(t *testing.T, key, value string) {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
enc := jsontext.NewEncoder(buf)
|
||||
enc.WriteToken(jsontext.BeginObject)
|
||||
enc.WriteToken(jsontext.String(key))
|
||||
enc.WriteToken(jsontext.String(value))
|
||||
enc.WriteToken(jsontext.EndObject)
|
||||
output := buf.String()
|
||||
|
||||
var got map[string]string
|
||||
err := json.Unmarshal([]byte(output), &got)
|
||||
require.NoError(t, err)
|
||||
expected := map[string]string{key: value}
|
||||
require.Equal(t, expected, got)
|
||||
}
|
||||
|
||||
func encodeValue(t testing.TB, enc *jsontext.Encoder, v any) (isSupported bool) {
|
||||
t.Helper()
|
||||
|
||||
switch val := v.(type) {
|
||||
case map[string]any:
|
||||
require.NoError(t, enc.WriteToken(jsontext.BeginObject))
|
||||
for k, vv := range val {
|
||||
require.NoError(t, enc.WriteToken(jsontext.String(k)))
|
||||
if !encodeValue(t, enc, vv) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
require.NoError(t, enc.WriteToken(jsontext.EndObject))
|
||||
return true
|
||||
case []any:
|
||||
require.NoError(t, enc.WriteToken(jsontext.BeginArray))
|
||||
for _, vv := range val {
|
||||
if !encodeValue(t, enc, vv) {
|
||||
return false // Propagate unsupported if any nested value fails
|
||||
}
|
||||
}
|
||||
require.NoError(t, enc.WriteToken(jsontext.EndArray))
|
||||
return true
|
||||
case string:
|
||||
require.NoError(t, enc.WriteToken(jsontext.String(val)))
|
||||
return true
|
||||
case int64:
|
||||
require.NoError(t, enc.WriteToken(jsontext.Int(val)))
|
||||
return true
|
||||
case uint64:
|
||||
require.NoError(t, enc.WriteToken(jsontext.Uint(val)))
|
||||
return true
|
||||
case float64:
|
||||
require.NoError(t, enc.WriteToken(jsontext.Float(val)))
|
||||
return true
|
||||
case bool:
|
||||
require.NoError(t, enc.WriteToken(jsontext.Bool(val)))
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
type errorWriter struct {
|
||||
N int
|
||||
}
|
||||
|
||||
func (w *errorWriter) Write(p []byte) (int, error) {
|
||||
n := min(len(p), w.N)
|
||||
w.N -= n
|
||||
if w.N <= 0 {
|
||||
return n, assert.AnError
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func TestEncoderComprehensive(t *testing.T) {
|
||||
// encodes an object with all token types and nested structures
|
||||
encode := func(enc *jsontext.Encoder) error {
|
||||
if err := enc.WriteToken(jsontext.BeginObject); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := enc.WriteToken(jsontext.String("simple")); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := enc.WriteToken(jsontext.String("value")); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := enc.WriteToken(jsontext.String("escaped")); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := enc.WriteToken(jsontext.String(`"quoted\"string"`)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := enc.WriteToken(jsontext.String("int")); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := enc.WriteToken(jsontext.Int(-42)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := enc.WriteToken(jsontext.String("uint")); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := enc.WriteToken(jsontext.Uint(100)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := enc.WriteToken(jsontext.String("float")); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := enc.WriteToken(jsontext.Float(3.14)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := enc.WriteToken(jsontext.String("true")); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := enc.WriteToken(jsontext.True); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := enc.WriteToken(jsontext.String("false")); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := enc.WriteToken(jsontext.False); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := enc.WriteToken(jsontext.String("array")); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := enc.WriteToken(jsontext.BeginArray); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := enc.WriteToken(jsontext.String("item1")); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := enc.WriteToken(jsontext.Int(1)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := enc.WriteToken(jsontext.EndArray); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := enc.WriteToken(jsontext.String("nested")); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := enc.WriteToken(jsontext.BeginObject); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := enc.WriteToken(jsontext.EndObject); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := enc.WriteToken(jsontext.EndObject); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
buf := bytes.NewBuffer(nil)
|
||||
enc := jsontext.NewEncoder(buf)
|
||||
require.NoError(t, encode(enc))
|
||||
|
||||
for i := range buf.Len() {
|
||||
enc := jsontext.NewEncoder(&errorWriter{N: i})
|
||||
require.ErrorIs(t, encode(enc), assert.AnError)
|
||||
}
|
||||
}
|
||||
|
||||
func FuzzEncoder(f *testing.F) {
|
||||
examples := []string{
|
||||
`{"hello": "world"}`,
|
||||
`{"foo": 123, "bar": [1, 2, 3]}`,
|
||||
`{"nested": {"a": 1, "b": [true, false, "foobar"]}}`,
|
||||
`[{"x": 1}, {"y": "foo"}]`,
|
||||
`["foo", "bar"]`,
|
||||
`["a", {"b": [1, 2, {"c": "d"}]}, 3]`,
|
||||
`{"emptyObj": {}, "emptyArr": []}`,
|
||||
`{"mixed": [1, "two", {"three": 3}]}`,
|
||||
}
|
||||
for _, tc := range examples {
|
||||
// first test that
|
||||
// 1. it's valid JSON
|
||||
d := json.NewDecoder(bytes.NewReader([]byte(tc)))
|
||||
var expected any
|
||||
require.NoError(f, d.Decode(&expected), "corpus entry `%s` is not valid JSON", tc)
|
||||
// 2. the jsontext encoder can handle
|
||||
enc := jsontext.NewEncoder(&bytes.Buffer{})
|
||||
require.True(f, encodeValue(f, enc, expected), "expected `%s` to be supported", tc)
|
||||
|
||||
f.Add([]byte(tc))
|
||||
}
|
||||
|
||||
var stdlibBuf, ourBuf bytes.Buffer
|
||||
|
||||
f.Fuzz(func(t *testing.T, b []byte) {
|
||||
stdlibBuf.Truncate(0)
|
||||
ourBuf.Truncate(0)
|
||||
stdlibBuf.Grow(len(b))
|
||||
ourBuf.Grow(len(b))
|
||||
|
||||
d := json.NewDecoder(bytes.NewReader(b))
|
||||
var expected any
|
||||
if err := d.Decode(&expected); err != nil {
|
||||
return // invalid JSON
|
||||
}
|
||||
|
||||
// only attempt to handle inputs that the standard library can handle
|
||||
stdlibEnc := json.NewEncoder(&stdlibBuf)
|
||||
require.NoError(t, stdlibEnc.Encode(expected))
|
||||
if !json.Valid(stdlibBuf.Bytes()) {
|
||||
return
|
||||
}
|
||||
|
||||
// then encode using the jsontext encoder
|
||||
enc := jsontext.NewEncoder(&ourBuf)
|
||||
if isSupported := encodeValue(t, enc, expected); !isSupported {
|
||||
return
|
||||
}
|
||||
|
||||
output := ourBuf.Bytes()
|
||||
require.Truef(t, json.Valid(output), "produced invalid JSON: %s", output)
|
||||
|
||||
var got any
|
||||
require.NoError(t, json.Unmarshal(output, &got))
|
||||
require.JSONEq(t, ourBuf.String(), stdlibBuf.String())
|
||||
})
|
||||
}
|
||||
@@ -5,8 +5,7 @@ import (
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
"github.com/quic-go/quic-go/logging"
|
||||
|
||||
"github.com/francoispqt/gojay"
|
||||
"github.com/quic-go/quic-go/qlog/jsontext"
|
||||
)
|
||||
|
||||
func getPacketTypeFromEncryptionLevel(encLevel protocol.EncryptionLevel) logging.PacketType {
|
||||
@@ -28,72 +27,86 @@ type token struct {
|
||||
Raw []byte
|
||||
}
|
||||
|
||||
var _ gojay.MarshalerJSONObject = &token{}
|
||||
|
||||
func (t token) IsNil() bool { return false }
|
||||
func (t token) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
enc.StringKey("data", fmt.Sprintf("%x", t.Raw))
|
||||
func (t token) Encode(enc *jsontext.Encoder) error {
|
||||
h := encoderHelper{enc: enc}
|
||||
h.WriteToken(jsontext.BeginObject)
|
||||
h.WriteToken(jsontext.String("data"))
|
||||
h.WriteToken(jsontext.String(fmt.Sprintf("%x", t.Raw)))
|
||||
h.WriteToken(jsontext.EndObject)
|
||||
return h.err
|
||||
}
|
||||
|
||||
// PacketHeader is a QUIC packet header.
|
||||
// TODO: make this a long header
|
||||
type packetHeader struct {
|
||||
PacketType logging.PacketType
|
||||
|
||||
KeyPhaseBit logging.KeyPhaseBit
|
||||
PacketNumber logging.PacketNumber
|
||||
|
||||
PacketType logging.PacketType
|
||||
KeyPhaseBit logging.KeyPhaseBit
|
||||
PacketNumber logging.PacketNumber
|
||||
Version logging.Version
|
||||
SrcConnectionID logging.ConnectionID
|
||||
DestConnectionID logging.ConnectionID
|
||||
|
||||
Token *token
|
||||
Token *token
|
||||
}
|
||||
|
||||
func transformHeader(hdr *logging.Header) *packetHeader {
|
||||
h := &packetHeader{
|
||||
ph := &packetHeader{
|
||||
PacketType: logging.PacketTypeFromHeader(hdr),
|
||||
SrcConnectionID: hdr.SrcConnectionID,
|
||||
DestConnectionID: hdr.DestConnectionID,
|
||||
Version: hdr.Version,
|
||||
}
|
||||
if len(hdr.Token) > 0 {
|
||||
h.Token = &token{Raw: hdr.Token}
|
||||
ph.Token = &token{Raw: hdr.Token}
|
||||
}
|
||||
return h
|
||||
return ph
|
||||
}
|
||||
|
||||
func transformLongHeader(hdr *logging.ExtendedHeader) *packetHeader {
|
||||
h := transformHeader(&hdr.Header)
|
||||
h.PacketNumber = hdr.PacketNumber
|
||||
h.KeyPhaseBit = hdr.KeyPhase
|
||||
return h
|
||||
ph := transformHeader(&hdr.Header)
|
||||
ph.PacketNumber = hdr.PacketNumber
|
||||
ph.KeyPhaseBit = hdr.KeyPhase
|
||||
return ph
|
||||
}
|
||||
|
||||
func (h packetHeader) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
enc.StringKey("packet_type", packetType(h.PacketType).String())
|
||||
if h.PacketType != logging.PacketTypeRetry {
|
||||
enc.Int64Key("packet_number", int64(h.PacketNumber))
|
||||
func (ph packetHeader) Encode(enc *jsontext.Encoder) error {
|
||||
h := encoderHelper{enc: enc}
|
||||
h.WriteToken(jsontext.BeginObject)
|
||||
h.WriteToken(jsontext.String("packet_type"))
|
||||
h.WriteToken(jsontext.String(packetType(ph.PacketType).String()))
|
||||
if ph.PacketType != logging.PacketTypeRetry {
|
||||
h.WriteToken(jsontext.String("packet_number"))
|
||||
h.WriteToken(jsontext.Int(int64(ph.PacketNumber)))
|
||||
}
|
||||
if h.Version != 0 {
|
||||
enc.StringKey("version", version(h.Version).String())
|
||||
if ph.Version != 0 {
|
||||
h.WriteToken(jsontext.String("version"))
|
||||
h.WriteToken(jsontext.String(version(ph.Version).String()))
|
||||
}
|
||||
if h.PacketType != logging.PacketType1RTT {
|
||||
enc.IntKey("scil", h.SrcConnectionID.Len())
|
||||
if h.SrcConnectionID.Len() > 0 {
|
||||
enc.StringKey("scid", h.SrcConnectionID.String())
|
||||
if ph.PacketType != logging.PacketType1RTT {
|
||||
h.WriteToken(jsontext.String("scil"))
|
||||
h.WriteToken(jsontext.Int(int64(ph.SrcConnectionID.Len())))
|
||||
if ph.SrcConnectionID.Len() > 0 {
|
||||
h.WriteToken(jsontext.String("scid"))
|
||||
h.WriteToken(jsontext.String(ph.SrcConnectionID.String()))
|
||||
}
|
||||
}
|
||||
enc.IntKey("dcil", h.DestConnectionID.Len())
|
||||
if h.DestConnectionID.Len() > 0 {
|
||||
enc.StringKey("dcid", h.DestConnectionID.String())
|
||||
h.WriteToken(jsontext.String("dcil"))
|
||||
h.WriteToken(jsontext.Int(int64(ph.DestConnectionID.Len())))
|
||||
if ph.DestConnectionID.Len() > 0 {
|
||||
h.WriteToken(jsontext.String("dcid"))
|
||||
h.WriteToken(jsontext.String(ph.DestConnectionID.String()))
|
||||
}
|
||||
if h.KeyPhaseBit == logging.KeyPhaseZero || h.KeyPhaseBit == logging.KeyPhaseOne {
|
||||
enc.StringKey("key_phase_bit", h.KeyPhaseBit.String())
|
||||
if ph.KeyPhaseBit == logging.KeyPhaseZero || ph.KeyPhaseBit == logging.KeyPhaseOne {
|
||||
h.WriteToken(jsontext.String("key_phase_bit"))
|
||||
h.WriteToken(jsontext.String(ph.KeyPhaseBit.String()))
|
||||
}
|
||||
if h.Token != nil {
|
||||
enc.ObjectKey("token", h.Token)
|
||||
if ph.Token != nil {
|
||||
h.WriteToken(jsontext.String("token"))
|
||||
if err := ph.Token.Encode(enc); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
h.WriteToken(jsontext.EndObject)
|
||||
return h.err
|
||||
}
|
||||
|
||||
type packetHeaderVersionNegotiation struct {
|
||||
@@ -101,13 +114,21 @@ type packetHeaderVersionNegotiation struct {
|
||||
DestConnectionID logging.ArbitraryLenConnectionID
|
||||
}
|
||||
|
||||
func (h packetHeaderVersionNegotiation) IsNil() bool { return false }
|
||||
func (h packetHeaderVersionNegotiation) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
enc.StringKey("packet_type", "version_negotiation")
|
||||
enc.IntKey("scil", h.SrcConnectionID.Len())
|
||||
enc.StringKey("scid", h.SrcConnectionID.String())
|
||||
enc.IntKey("dcil", h.DestConnectionID.Len())
|
||||
enc.StringKey("dcid", h.DestConnectionID.String())
|
||||
func (phvn packetHeaderVersionNegotiation) Encode(enc *jsontext.Encoder) error {
|
||||
h := encoderHelper{enc: enc}
|
||||
h.WriteToken(jsontext.BeginObject)
|
||||
h.WriteToken(jsontext.String("packet_type"))
|
||||
h.WriteToken(jsontext.String("version_negotiation"))
|
||||
h.WriteToken(jsontext.String("scil"))
|
||||
h.WriteToken(jsontext.Int(int64(phvn.SrcConnectionID.Len())))
|
||||
h.WriteToken(jsontext.String("scid"))
|
||||
h.WriteToken(jsontext.String(phvn.SrcConnectionID.String()))
|
||||
h.WriteToken(jsontext.String("dcil"))
|
||||
h.WriteToken(jsontext.Int(int64(phvn.DestConnectionID.Len())))
|
||||
h.WriteToken(jsontext.String("dcid"))
|
||||
h.WriteToken(jsontext.String(phvn.DestConnectionID.String()))
|
||||
h.WriteToken(jsontext.EndObject)
|
||||
return h.err
|
||||
}
|
||||
|
||||
// a minimal header that only outputs the packet type, and potentially a packet number
|
||||
@@ -116,12 +137,17 @@ type packetHeaderWithType struct {
|
||||
PacketNumber logging.PacketNumber
|
||||
}
|
||||
|
||||
func (h packetHeaderWithType) IsNil() bool { return false }
|
||||
func (h packetHeaderWithType) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
enc.StringKey("packet_type", packetType(h.PacketType).String())
|
||||
if h.PacketNumber != protocol.InvalidPacketNumber {
|
||||
enc.Int64Key("packet_number", int64(h.PacketNumber))
|
||||
func (phwt packetHeaderWithType) Encode(enc *jsontext.Encoder) error {
|
||||
h := encoderHelper{enc: enc}
|
||||
h.WriteToken(jsontext.BeginObject)
|
||||
h.WriteToken(jsontext.String("packet_type"))
|
||||
h.WriteToken(jsontext.String(packetType(phwt.PacketType).String()))
|
||||
if phwt.PacketNumber != protocol.InvalidPacketNumber {
|
||||
h.WriteToken(jsontext.String("packet_number"))
|
||||
h.WriteToken(jsontext.Int(int64(phwt.PacketNumber)))
|
||||
}
|
||||
h.WriteToken(jsontext.EndObject)
|
||||
return h.err
|
||||
}
|
||||
|
||||
// a minimal header that only outputs the packet type
|
||||
@@ -130,10 +156,15 @@ type packetHeaderWithTypeAndPacketNumber struct {
|
||||
PacketNumber logging.PacketNumber
|
||||
}
|
||||
|
||||
func (h packetHeaderWithTypeAndPacketNumber) IsNil() bool { return false }
|
||||
func (h packetHeaderWithTypeAndPacketNumber) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
enc.StringKey("packet_type", packetType(h.PacketType).String())
|
||||
enc.Int64Key("packet_number", int64(h.PacketNumber))
|
||||
func (phwtpn packetHeaderWithTypeAndPacketNumber) Encode(enc *jsontext.Encoder) error {
|
||||
h := encoderHelper{enc: enc}
|
||||
h.WriteToken(jsontext.BeginObject)
|
||||
h.WriteToken(jsontext.String("packet_type"))
|
||||
h.WriteToken(jsontext.String(packetType(phwtpn.PacketType).String()))
|
||||
h.WriteToken(jsontext.String("packet_number"))
|
||||
h.WriteToken(jsontext.Int(int64(phwtpn.PacketNumber)))
|
||||
h.WriteToken(jsontext.EndObject)
|
||||
return h.err
|
||||
}
|
||||
|
||||
type shortHeader struct {
|
||||
@@ -150,12 +181,19 @@ func transformShortHeader(hdr *logging.ShortHeader) *shortHeader {
|
||||
}
|
||||
}
|
||||
|
||||
func (h shortHeader) IsNil() bool { return false }
|
||||
func (h shortHeader) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
enc.StringKey("packet_type", packetType(logging.PacketType1RTT).String())
|
||||
if h.DestConnectionID.Len() > 0 {
|
||||
enc.StringKey("dcid", h.DestConnectionID.String())
|
||||
func (sh shortHeader) Encode(enc *jsontext.Encoder) error {
|
||||
h := encoderHelper{enc: enc}
|
||||
h.WriteToken(jsontext.BeginObject)
|
||||
h.WriteToken(jsontext.String("packet_type"))
|
||||
h.WriteToken(jsontext.String(packetType(logging.PacketType1RTT).String()))
|
||||
if sh.DestConnectionID.Len() > 0 {
|
||||
h.WriteToken(jsontext.String("dcid"))
|
||||
h.WriteToken(jsontext.String(sh.DestConnectionID.String()))
|
||||
}
|
||||
enc.Int64Key("packet_number", int64(h.PacketNumber))
|
||||
enc.StringKey("key_phase_bit", h.KeyPhaseBit.String())
|
||||
h.WriteToken(jsontext.String("packet_number"))
|
||||
h.WriteToken(jsontext.Int(int64(sh.PacketNumber)))
|
||||
h.WriteToken(jsontext.String("key_phase_bit"))
|
||||
h.WriteToken(jsontext.String(sh.KeyPhaseBit.String()))
|
||||
h.WriteToken(jsontext.EndObject)
|
||||
return h.err
|
||||
}
|
||||
|
||||
@@ -5,10 +5,12 @@ import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/francoispqt/gojay"
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
"github.com/quic-go/quic-go/internal/wire"
|
||||
"github.com/quic-go/quic-go/logging"
|
||||
|
||||
"github.com/quic-go/quic-go/qlog/jsontext"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@@ -34,8 +36,8 @@ func TestPacketTypeFromEncryptionLevel(t *testing.T) {
|
||||
|
||||
func checkHeader(t *testing.T, hdr *wire.ExtendedHeader, expected map[string]any) {
|
||||
buf := &bytes.Buffer{}
|
||||
enc := gojay.NewEncoder(buf)
|
||||
require.NoError(t, enc.Encode(transformLongHeader(hdr)))
|
||||
enc := jsontext.NewEncoder(buf)
|
||||
require.NoError(t, transformLongHeader(hdr).Encode(enc))
|
||||
data := buf.Bytes()
|
||||
require.True(t, json.Valid(data))
|
||||
checkEncoding(t, data, expected)
|
||||
|
||||
@@ -5,8 +5,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/quic-go/quic-go/logging"
|
||||
|
||||
"github.com/francoispqt/gojay"
|
||||
"github.com/quic-go/quic-go/qlog/jsontext"
|
||||
)
|
||||
|
||||
// Setting of this only works when quic-go is used as a library.
|
||||
@@ -41,22 +40,38 @@ type topLevel struct {
|
||||
trace trace
|
||||
}
|
||||
|
||||
func (topLevel) IsNil() bool { return false }
|
||||
func (l topLevel) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
enc.StringKey("qlog_format", "JSON-SEQ")
|
||||
enc.StringKey("qlog_version", "0.3")
|
||||
enc.StringKeyOmitEmpty("title", "quic-go qlog")
|
||||
enc.ObjectKey("configuration", configuration{Version: quicGoVersion})
|
||||
enc.ObjectKey("trace", l.trace)
|
||||
func (l topLevel) Encode(enc *jsontext.Encoder) error {
|
||||
h := encoderHelper{enc: enc}
|
||||
h.WriteToken(jsontext.BeginObject)
|
||||
h.WriteToken(jsontext.String("qlog_format"))
|
||||
h.WriteToken(jsontext.String("JSON-SEQ"))
|
||||
h.WriteToken(jsontext.String("qlog_version"))
|
||||
h.WriteToken(jsontext.String("0.3"))
|
||||
h.WriteToken(jsontext.String("title"))
|
||||
h.WriteToken(jsontext.String("quic-go qlog"))
|
||||
h.WriteToken(jsontext.String("configuration"))
|
||||
if err := (configuration{Version: quicGoVersion}).Encode(enc); err != nil {
|
||||
return err
|
||||
}
|
||||
h.WriteToken(jsontext.String("trace"))
|
||||
if err := l.trace.Encode(enc); err != nil {
|
||||
return err
|
||||
}
|
||||
h.WriteToken(jsontext.EndObject)
|
||||
return h.err
|
||||
}
|
||||
|
||||
type configuration struct {
|
||||
Version string
|
||||
}
|
||||
|
||||
func (c configuration) IsNil() bool { return false }
|
||||
func (c configuration) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
enc.StringKey("code_version", c.Version)
|
||||
func (c configuration) Encode(enc *jsontext.Encoder) error {
|
||||
h := encoderHelper{enc: enc}
|
||||
h.WriteToken(jsontext.BeginObject)
|
||||
h.WriteToken(jsontext.String("code_version"))
|
||||
h.WriteToken(jsontext.String(c.Version))
|
||||
h.WriteToken(jsontext.EndObject)
|
||||
return h.err
|
||||
}
|
||||
|
||||
type vantagePoint struct {
|
||||
@@ -64,10 +79,19 @@ type vantagePoint struct {
|
||||
Type string
|
||||
}
|
||||
|
||||
func (p vantagePoint) IsNil() bool { return false }
|
||||
func (p vantagePoint) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
enc.StringKeyOmitEmpty("name", p.Name)
|
||||
enc.StringKeyOmitEmpty("type", p.Type)
|
||||
func (p vantagePoint) Encode(enc *jsontext.Encoder) error {
|
||||
h := encoderHelper{enc: enc}
|
||||
h.WriteToken(jsontext.BeginObject)
|
||||
if p.Name != "" {
|
||||
h.WriteToken(jsontext.String("name"))
|
||||
h.WriteToken(jsontext.String(p.Name))
|
||||
}
|
||||
if p.Type != "" {
|
||||
h.WriteToken(jsontext.String("type"))
|
||||
h.WriteToken(jsontext.String(p.Type))
|
||||
}
|
||||
h.WriteToken(jsontext.EndObject)
|
||||
return h.err
|
||||
}
|
||||
|
||||
type commonFields struct {
|
||||
@@ -77,25 +101,43 @@ type commonFields struct {
|
||||
ReferenceTime time.Time
|
||||
}
|
||||
|
||||
func (f commonFields) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
func (f commonFields) Encode(enc *jsontext.Encoder) error {
|
||||
h := encoderHelper{enc: enc}
|
||||
h.WriteToken(jsontext.BeginObject)
|
||||
if f.ODCID != nil {
|
||||
enc.StringKey("ODCID", f.ODCID.String())
|
||||
enc.StringKey("group_id", f.ODCID.String())
|
||||
h.WriteToken(jsontext.String("ODCID"))
|
||||
h.WriteToken(jsontext.String(f.ODCID.String()))
|
||||
h.WriteToken(jsontext.String("group_id"))
|
||||
h.WriteToken(jsontext.String(f.ODCID.String()))
|
||||
}
|
||||
enc.StringKeyOmitEmpty("protocol_type", f.ProtocolType)
|
||||
enc.Float64Key("reference_time", float64(f.ReferenceTime.UnixNano())/1e6)
|
||||
enc.StringKey("time_format", "relative")
|
||||
if f.ProtocolType != "" {
|
||||
h.WriteToken(jsontext.String("protocol_type"))
|
||||
h.WriteToken(jsontext.String(f.ProtocolType))
|
||||
}
|
||||
h.WriteToken(jsontext.String("reference_time"))
|
||||
h.WriteToken(jsontext.Float(float64(f.ReferenceTime.UnixNano()) / 1e6))
|
||||
h.WriteToken(jsontext.String("time_format"))
|
||||
h.WriteToken(jsontext.String("relative"))
|
||||
h.WriteToken(jsontext.EndObject)
|
||||
return h.err
|
||||
}
|
||||
|
||||
func (f commonFields) IsNil() bool { return false }
|
||||
|
||||
type trace struct {
|
||||
VantagePoint vantagePoint
|
||||
CommonFields commonFields
|
||||
}
|
||||
|
||||
func (trace) IsNil() bool { return false }
|
||||
func (t trace) MarshalJSONObject(enc *gojay.Encoder) {
|
||||
enc.ObjectKey("vantage_point", t.VantagePoint)
|
||||
enc.ObjectKey("common_fields", t.CommonFields)
|
||||
func (t trace) Encode(enc *jsontext.Encoder) error {
|
||||
h := encoderHelper{enc: enc}
|
||||
h.WriteToken(jsontext.BeginObject)
|
||||
h.WriteToken(jsontext.String("vantage_point"))
|
||||
if err := t.VantagePoint.Encode(enc); err != nil {
|
||||
return err
|
||||
}
|
||||
h.WriteToken(jsontext.String("common_fields"))
|
||||
if err := t.CommonFields.Encode(enc); err != nil {
|
||||
return err
|
||||
}
|
||||
h.WriteToken(jsontext.EndObject)
|
||||
return h.err
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/francoispqt/gojay"
|
||||
"github.com/quic-go/quic-go/qlog/jsontext"
|
||||
)
|
||||
|
||||
const eventChanSize = 50
|
||||
@@ -50,20 +50,17 @@ func (w *writer) RecordEvent(eventTime time.Time, details eventDetails) {
|
||||
func (w *writer) Run() {
|
||||
defer close(w.runStopped)
|
||||
buf := &bytes.Buffer{}
|
||||
enc := gojay.NewEncoder(buf)
|
||||
enc := jsontext.NewEncoder(buf)
|
||||
if err := writeRecordSeparator(buf); err != nil {
|
||||
panic(fmt.Sprintf("qlog encoding into a bytes.Buffer failed: %s", err))
|
||||
}
|
||||
if err := enc.Encode(&topLevel{trace: *w.tr}); err != nil {
|
||||
panic(fmt.Sprintf("qlog encoding into a bytes.Buffer failed: %s", err))
|
||||
}
|
||||
if err := buf.WriteByte('\n'); err != nil {
|
||||
if err := (&topLevel{trace: *w.tr}).Encode(enc); err != nil {
|
||||
panic(fmt.Sprintf("qlog encoding into a bytes.Buffer failed: %s", err))
|
||||
}
|
||||
if _, err := w.w.Write(buf.Bytes()); err != nil {
|
||||
w.encodeErr = err
|
||||
}
|
||||
enc = gojay.NewEncoder(w.w)
|
||||
enc = jsontext.NewEncoder(w.w)
|
||||
for ev := range w.events {
|
||||
if w.encodeErr != nil { // if encoding failed, just continue draining the event channel
|
||||
continue
|
||||
@@ -72,13 +69,10 @@ func (w *writer) Run() {
|
||||
w.encodeErr = err
|
||||
continue
|
||||
}
|
||||
if err := enc.Encode(ev); err != nil {
|
||||
if err := ev.Encode(enc); err != nil {
|
||||
w.encodeErr = err
|
||||
continue
|
||||
}
|
||||
if _, err := w.w.Write([]byte{'\n'}); err != nil {
|
||||
w.encodeErr = err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user