mirror of
https://github.com/refraction-networking/uquic.git
synced 2025-04-03 04:07:35 +03:00
refactor: remove redundancy and clean up
Remove interop which will fail to build and unnecessary for uQUIC. Remove all quic-go CI. Add Go build & test CI.
This commit is contained in:
parent
10eaa8489c
commit
44705664c2
23 changed files with 54 additions and 1242 deletions
|
@ -1,42 +0,0 @@
|
|||
version: 2.1
|
||||
executors:
|
||||
test-go120:
|
||||
docker:
|
||||
- image: "cimg/go:1.20"
|
||||
environment:
|
||||
runrace: true
|
||||
TIMESCALE_FACTOR: 3
|
||||
|
||||
jobs:
|
||||
"test": &test
|
||||
executor: test-go120
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: "Build infos"
|
||||
command: go version
|
||||
- run:
|
||||
name: "Run tools tests"
|
||||
command: go run github.com/onsi/ginkgo/v2/ginkgo -race -r -v -randomize-all -trace integrationtests/tools
|
||||
- run:
|
||||
name: "Run self integration tests"
|
||||
command: go run github.com/onsi/ginkgo/v2/ginkgo -v -randomize-all -trace integrationtests/self
|
||||
- run:
|
||||
name: "Run version negotiation tests"
|
||||
command: go run github.com/onsi/ginkgo/v2/ginkgo -v -randomize-all -trace integrationtests/versionnegotiation
|
||||
- run:
|
||||
name: "Run self integration tests with race detector"
|
||||
command: go run github.com/onsi/ginkgo/v2/ginkgo -race -v -randomize-all -trace integrationtests/self
|
||||
- run:
|
||||
name: "Run self integration tests with qlog"
|
||||
command: go run github.com/onsi/ginkgo/v2/ginkgo -v -randomize-all -trace integrationtests/self -- -qlog
|
||||
- run:
|
||||
name: "Run version negotiation tests with qlog"
|
||||
command: go run github.com/onsi/ginkgo/v2/ginkgo -v -randomize-all -trace integrationtests/versionnegotiation -- -qlog
|
||||
go120:
|
||||
<<: *test
|
||||
|
||||
workflows:
|
||||
workflow:
|
||||
jobs:
|
||||
- go120
|
|
@ -1,8 +0,0 @@
|
|||
# Git Hooks
|
||||
|
||||
This directory contains useful Git hooks for working with quic-go.
|
||||
|
||||
Install them by running
|
||||
```bash
|
||||
git config core.hooksPath .githooks
|
||||
```
|
|
@ -1,34 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Check that test files don't contain focussed test cases.
|
||||
errored=false
|
||||
for f in $(git diff --diff-filter=d --cached --name-only); do
|
||||
if [[ $f != *_test.go ]]; then continue; fi
|
||||
output=$(git show :"$f" | grep -n -e "FIt(" -e "FContext(" -e "FDescribe(")
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "$f contains a focussed test:"
|
||||
echo "$output"
|
||||
echo ""
|
||||
errored=true
|
||||
fi
|
||||
done
|
||||
|
||||
pushd ./integrationtests/gomodvendor > /dev/null
|
||||
go mod tidy
|
||||
if [[ -n $(git diff --diff-filter=d --name-only -- "go.mod" "go.sum") ]]; then
|
||||
echo "go.mod / go.sum in integrationtests/gomodvendor not tidied"
|
||||
errored=true
|
||||
fi
|
||||
popd > /dev/null
|
||||
|
||||
# Check that all Go files are properly gofumpt-ed.
|
||||
output=$(gofumpt -d $(git diff --diff-filter=d --cached --name-only -- '*.go'))
|
||||
if [ -n "$output" ]; then
|
||||
echo "Found files that are not properly gofumpt-ed."
|
||||
echo "$output"
|
||||
errored=true
|
||||
fi
|
||||
|
||||
if [ "$errored" = true ]; then
|
||||
exit 1
|
||||
fi
|
27
.github/workflows/build-interop-docker.yml
vendored
27
.github/workflows/build-interop-docker.yml
vendored
|
@ -1,27 +0,0 @@
|
|||
name: Build interop Docker image
|
||||
on:
|
||||
push:
|
||||
branches: [ interop ]
|
||||
|
||||
jobs:
|
||||
interop:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
with:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
- uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: "{{defaultContext}}:interop"
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: martenseemann/quic-go-interop:latest
|
33
.github/workflows/cross-compile.sh
vendored
33
.github/workflows/cross-compile.sh
vendored
|
@ -1,33 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
dist="$1"
|
||||
goos=$(echo "$dist" | cut -d "/" -f1)
|
||||
goarch=$(echo "$dist" | cut -d "/" -f2)
|
||||
|
||||
# cross-compiling for android is a pain...
|
||||
if [[ "$goos" == "android" ]]; then exit; fi
|
||||
# iOS builds require Cgo, see https://github.com/golang/go/issues/43343
|
||||
# Cgo would then need a C cross compilation setup. Not worth the hassle.
|
||||
if [[ "$goos" == "ios" ]]; then exit; fi
|
||||
|
||||
# Write all log output to a temporary file instead of to stdout.
|
||||
# That allows running this script in parallel, while preserving the correct order of the output.
|
||||
log_file=$(mktemp)
|
||||
|
||||
error_handler() {
|
||||
cat "$log_file" >&2
|
||||
rm "$log_file"
|
||||
exit 1
|
||||
}
|
||||
|
||||
trap 'error_handler' ERR
|
||||
|
||||
echo "$dist" >> "$log_file"
|
||||
out="main-$goos-$goarch"
|
||||
GOOS=$goos GOARCH=$goarch go build -o $out example/main.go >> "$log_file" 2>&1
|
||||
rm $out
|
||||
|
||||
cat "$log_file"
|
||||
rm "$log_file"
|
23
.github/workflows/cross-compile.yml
vendored
23
.github/workflows/cross-compile.yml
vendored
|
@ -1,23 +0,0 @@
|
|||
on: [push, pull_request]
|
||||
jobs:
|
||||
crosscompile:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
go: [ "1.20.x", "1.21.0-rc.3" ]
|
||||
runs-on: ${{ fromJSON(vars['CROSS_COMPILE_RUNNER_UBUNTU'] || '"ubuntu-latest"') }}
|
||||
name: "Cross Compilation (Go ${{matrix.go}})"
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ matrix.go }}
|
||||
- name: Install build utils
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y gcc-multilib
|
||||
- name: Install dependencies
|
||||
run: go build example/main.go
|
||||
- name: Run cross compilation
|
||||
# run in parallel on as many cores as are available on the machine
|
||||
run: go tool dist list | xargs -I % -P "$(nproc)" .github/workflows/cross-compile.sh %
|
23
.github/workflows/go-generate.sh
vendored
23
.github/workflows/go-generate.sh
vendored
|
@ -1,23 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
DIR=$(pwd)
|
||||
TMP=$(mktemp -d)
|
||||
cd "$TMP"
|
||||
cp -r "$DIR" orig
|
||||
cp -r "$DIR" generated
|
||||
|
||||
cd generated
|
||||
# delete all go-generated files generated (that adhere to the comment convention)
|
||||
grep --include \*.go -lrIZ "^// Code generated .* DO NOT EDIT\.$" . | xargs --null rm
|
||||
|
||||
# First regenerate sys_conn_buffers_write.go.
|
||||
# If it doesn't exist, the following mockgen calls will fail.
|
||||
go generate -run "sys_conn_buffers_write.go"
|
||||
# now generate everything
|
||||
go generate ./...
|
||||
cd ..
|
||||
|
||||
# don't compare fuzzing corpora
|
||||
diff --exclude=corpus --exclude=.git -ruN orig generated
|
13
.github/workflows/go-generate.yml
vendored
13
.github/workflows/go-generate.yml
vendored
|
@ -1,13 +0,0 @@
|
|||
on: [push, pull_request]
|
||||
jobs:
|
||||
gogenerate:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: "1.20.x"
|
||||
- name: Install dependencies
|
||||
run: go build
|
||||
- name: Run code generators
|
||||
run: .github/workflows/go-generate.sh
|
27
.github/workflows/go1.20.yml
vendored
Normal file
27
.github/workflows/go1.20.yml
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
# This workflow will build a golang project
|
||||
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go
|
||||
|
||||
name: "Go 1.20"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
pull_request:
|
||||
branches: [ "master" ]
|
||||
|
||||
jobs:
|
||||
build_and_test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '1.20'
|
||||
|
||||
- name: Build
|
||||
run: go build -v ./...
|
||||
|
||||
- name: Test
|
||||
run: go test -v ./...
|
27
.github/workflows/go1.21.yml
vendored
Normal file
27
.github/workflows/go1.21.yml
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
# This workflow will build a golang project
|
||||
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go
|
||||
|
||||
name: "Go 1.21rc4"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
pull_request:
|
||||
branches: [ "master" ]
|
||||
|
||||
jobs:
|
||||
build_and_test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '1.21.0-rc.4'
|
||||
|
||||
- name: Build
|
||||
run: go build -v ./...
|
||||
|
||||
- name: Test
|
||||
run: go test -v ./...
|
52
.github/workflows/integration.yml
vendored
52
.github/workflows/integration.yml
vendored
|
@ -1,52 +0,0 @@
|
|||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
integration:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
go: [ "1.20.x", "1.21.0-rc.3" ]
|
||||
runs-on: ${{ fromJSON(vars['INTEGRATION_RUNNER_UBUNTU'] || '"ubuntu-latest"') }}
|
||||
env:
|
||||
DEBUG: false # set this to true to export qlogs and save them as artifacts
|
||||
TIMESCALE_FACTOR: 3
|
||||
name: Integration Tests (Go ${{ matrix.go }})
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
stable: '!contains(${{ matrix.go }}, "beta") && !contains(${{ matrix.go }}, "rc")'
|
||||
go-version: ${{ matrix.go }}
|
||||
- run: go version
|
||||
- name: set qlogger
|
||||
if: env.DEBUG == 'true'
|
||||
run: echo "QLOGFLAG= -qlog" >> $GITHUB_ENV
|
||||
- name: Run other tests
|
||||
run: |
|
||||
go run github.com/onsi/ginkgo/v2/ginkgo -r -v -randomize-all -randomize-suites -trace -skip-package self,versionnegotiation integrationtests
|
||||
go run github.com/onsi/ginkgo/v2/ginkgo -r -v -randomize-all -randomize-suites -trace integrationtests/versionnegotiation -- ${{ env.QLOGFLAG }}
|
||||
- name: Run self tests, using QUIC v1
|
||||
if: success() || failure() # run this step even if the previous one failed
|
||||
run: go run github.com/onsi/ginkgo/v2/ginkgo -r -v -randomize-all -randomize-suites -trace integrationtests/self -- -version=1 ${{ env.QLOGFLAG }}
|
||||
- name: Run self tests, using QUIC v2
|
||||
if: success() || failure() # run this step even if the previous one failed
|
||||
run: go run github.com/onsi/ginkgo/v2/ginkgo -r -v -randomize-all -randomize-suites -trace integrationtests/self -- -version=2 ${{ env.QLOGFLAG }}
|
||||
- name: Run set tests, with GSO enabled
|
||||
if: success() || failure() # run this step even if the previous one failed
|
||||
env:
|
||||
QUIC_GO_ENABLE_GSO: true
|
||||
run: go run github.com/onsi/ginkgo/v2/ginkgo -r -v -randomize-all -randomize-suites -trace integrationtests/self -- -version=1 ${{ env.QLOGFLAG }}
|
||||
- name: Run tests (32 bit)
|
||||
if: success() || failure() # run this step even if the previous one failed
|
||||
env:
|
||||
GOARCH: 386
|
||||
run: |
|
||||
go run github.com/onsi/ginkgo/v2/ginkgo -r -v -randomize-all -randomize-suites -trace -skip-package self,versionnegotiation integrationtests
|
||||
go run github.com/onsi/ginkgo/v2/ginkgo -r -v -randomize-all -randomize-suites -trace integrationtests/versionnegotiation -- ${{ env.QLOGFLAG }}
|
||||
go run github.com/onsi/ginkgo/v2/ginkgo -r -v -randomize-all -randomize-suites -trace integrationtests/self -- ${{ env.QLOGFLAG }}
|
||||
- name: save qlogs
|
||||
if: ${{ always() && env.DEBUG == 'true' }}
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: qlogs
|
||||
path: integrationtests/self/*.qlog
|
73
.github/workflows/lint.yml
vendored
73
.github/workflows/lint.yml
vendored
|
@ -1,73 +0,0 @@
|
|||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
skip-pkg-cache: true
|
||||
go-version: "1.20.x"
|
||||
- name: Check that no non-test files import Ginkgo or Gomega
|
||||
run: .github/workflows/no_ginkgo.sh
|
||||
- name: Check that go.mod is tidied
|
||||
run: |
|
||||
cp go.mod go.mod.orig
|
||||
cp go.sum go.sum.orig
|
||||
go mod tidy
|
||||
diff go.mod go.mod.orig
|
||||
diff go.sum go.sum.orig
|
||||
- name: Check that go mod vendor works
|
||||
run: |
|
||||
cd integrationtests/gomodvendor
|
||||
go mod vendor
|
||||
golangci-lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: "1.20.x"
|
||||
- name: golangci-lint (Linux)
|
||||
uses: golangci/golangci-lint-action@v3
|
||||
with:
|
||||
skip-pkg-cache: true
|
||||
args: --timeout=3m
|
||||
version: v1.52.2
|
||||
- name: golangci-lint (Windows)
|
||||
if: success() || failure() # run this step even if the previous one failed
|
||||
uses: golangci/golangci-lint-action@v3
|
||||
env:
|
||||
GOOS: "windows"
|
||||
with:
|
||||
skip-pkg-cache: true
|
||||
args: --timeout=3m
|
||||
version: v1.52.2
|
||||
- name: golangci-lint (OSX)
|
||||
if: success() || failure() # run this step even if the previous one failed
|
||||
uses: golangci/golangci-lint-action@v3
|
||||
env:
|
||||
GOOS: "darwin"
|
||||
with:
|
||||
skip-pkg-cache: true
|
||||
args: --timeout=3m
|
||||
version: v1.52.2
|
||||
- name: golangci-lint (FreeBSD)
|
||||
if: success() || failure() # run this step even if the previous one failed
|
||||
uses: golangci/golangci-lint-action@v3
|
||||
env:
|
||||
GOOS: "freebsd"
|
||||
with:
|
||||
skip-pkg-cache: true
|
||||
args: --timeout=3m
|
||||
version: v1.52.2
|
||||
- name: golangci-lint (others)
|
||||
if: success() || failure() # run this step even if the previous one failed
|
||||
uses: golangci/golangci-lint-action@v3
|
||||
env:
|
||||
GOOS: "solaris" # some OS that we don't have any build tags for
|
||||
with:
|
||||
skip-pkg-cache: true
|
||||
args: --timeout=3m
|
||||
version: v1.52.2
|
24
.github/workflows/no_ginkgo.sh
vendored
24
.github/workflows/no_ginkgo.sh
vendored
|
@ -1,24 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Verify that no non-test files import Ginkgo or Gomega.
|
||||
|
||||
set -e
|
||||
|
||||
HAS_TESTING=false
|
||||
|
||||
cd ..
|
||||
for f in $(find . -name "*.go" ! -name "*_test.go" ! -name "tools.go"); do
|
||||
if grep -q "github.com/onsi/ginkgo" $f; then
|
||||
echo "$f imports github.com/onsi/ginkgo/v2"
|
||||
HAS_TESTING=true
|
||||
fi
|
||||
if grep -q "github.com/onsi/gomega" $f; then
|
||||
echo "$f imports github.com/onsi/gomega"
|
||||
HAS_TESTING=true
|
||||
fi
|
||||
done
|
||||
|
||||
if "$HAS_TESTING"; then
|
||||
exit 1
|
||||
fi
|
||||
exit 0
|
48
.github/workflows/unit.yml
vendored
48
.github/workflows/unit.yml
vendored
|
@ -1,48 +0,0 @@
|
|||
on: [push, pull_request]
|
||||
|
||||
|
||||
jobs:
|
||||
unit:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ "ubuntu", "windows", "macos" ]
|
||||
go: [ "1.20.x", "1.21.0-rc.3" ]
|
||||
runs-on: ${{ fromJSON(vars[format('UNIT_RUNNER_{0}', matrix.os)] || format('"{0}-latest"', matrix.os)) }}
|
||||
name: Unit tests (${{ matrix.os}}, Go ${{ matrix.go }})
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ matrix.go }}
|
||||
- run: go version
|
||||
- name: Run tests
|
||||
env:
|
||||
TIMESCALE_FACTOR: 10
|
||||
run: go run github.com/onsi/ginkgo/v2/ginkgo -r -v -cover -randomize-all -randomize-suites -trace -skip-package integrationtests
|
||||
- name: Run tests as root
|
||||
if: ${{ matrix.os == 'ubuntu' }}
|
||||
env:
|
||||
TIMESCALE_FACTOR: 10
|
||||
FILE: sys_conn_helper_linux_test.go
|
||||
run: |
|
||||
test -f $FILE # make sure the file actually exists
|
||||
go run github.com/onsi/ginkgo/v2/ginkgo build -cover -tags root .
|
||||
sudo ./quic-go.test -ginkgo.v -ginkgo.trace -ginkgo.randomize-all -ginkgo.focus-file=$FILE -test.coverprofile coverage-root.txt
|
||||
rm quic-go.test
|
||||
- name: Run tests (32 bit)
|
||||
if: ${{ matrix.os != 'macos' }} # can't run 32 bit tests on OSX.
|
||||
env:
|
||||
TIMESCALE_FACTOR: 10
|
||||
GOARCH: 386
|
||||
run: go run github.com/onsi/ginkgo/v2/ginkgo -r -v -cover -coverprofile coverage.txt -output-dir . -randomize-all -randomize-suites -trace -skip-package integrationtests
|
||||
- name: Run tests with race detector
|
||||
if: ${{ matrix.os == 'ubuntu' }} # speed things up. Windows and OSX VMs are slow
|
||||
env:
|
||||
TIMESCALE_FACTOR: 20
|
||||
run: go run github.com/onsi/ginkgo/v2/ginkgo -r -v -race -randomize-all -randomize-suites -trace -skip-package integrationtests
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
files: coverage.txt,coverage-root.txt
|
||||
env_vars: OS=${{ matrix.os }}, GO=${{ matrix.go }}
|
|
@ -1,42 +0,0 @@
|
|||
FROM martenseemann/quic-network-simulator-endpoint:latest AS builder
|
||||
|
||||
ARG TARGETPLATFORM
|
||||
RUN echo "TARGETPLATFORM: ${TARGETPLATFORM}"
|
||||
|
||||
RUN apt-get update && apt-get install -y wget tar git
|
||||
|
||||
ENV GOVERSION=1.20.2
|
||||
|
||||
RUN platform=$(echo ${TARGETPLATFORM} | tr '/' '-') && \
|
||||
filename="go${GOVERSION}.${platform}.tar.gz" && \
|
||||
wget https://dl.google.com/go/${filename} && \
|
||||
tar xfz ${filename} && \
|
||||
rm ${filename}
|
||||
|
||||
ENV PATH="/go/bin:${PATH}"
|
||||
|
||||
# build with --build-arg CACHEBUST=$(date +%s)
|
||||
ARG CACHEBUST=1
|
||||
|
||||
RUN git clone https://github.com/quic-go/quic-go && \
|
||||
cd quic-go && \
|
||||
git fetch origin interop && git checkout -t origin/interop && \
|
||||
go get ./...
|
||||
|
||||
WORKDIR /quic-go
|
||||
|
||||
RUN git rev-parse HEAD > commit.txt
|
||||
RUN go build -o server -ldflags="-X github.com/quic-go/quic-go/qlog.quicGoVersion=$(git describe --always --long --dirty)" interop/server/main.go
|
||||
RUN go build -o client -ldflags="-X github.com/quic-go/quic-go/qlog.quicGoVersion=$(git describe --always --long --dirty)" interop/client/main.go
|
||||
|
||||
|
||||
FROM martenseemann/quic-network-simulator-endpoint:latest
|
||||
|
||||
WORKDIR /quic-go
|
||||
|
||||
COPY --from=builder /quic-go/commit.txt /quic-go/server /quic-go/client ./
|
||||
|
||||
COPY run_endpoint.sh .
|
||||
RUN chmod +x run_endpoint.sh
|
||||
|
||||
ENTRYPOINT [ "./run_endpoint.sh" ]
|
|
@ -1,211 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
tls "github.com/refraction-networking/utls"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
"github.com/quic-go/quic-go"
|
||||
"github.com/quic-go/quic-go/http3"
|
||||
"github.com/quic-go/quic-go/internal/handshake"
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
"github.com/quic-go/quic-go/internal/qtls"
|
||||
"github.com/quic-go/quic-go/interop/http09"
|
||||
"github.com/quic-go/quic-go/interop/utils"
|
||||
)
|
||||
|
||||
var errUnsupported = errors.New("unsupported test case")
|
||||
|
||||
var tlsConf *tls.Config
|
||||
|
||||
func main() {
|
||||
logFile, err := os.Create("/logs/log.txt")
|
||||
if err != nil {
|
||||
fmt.Printf("Could not create log file: %s\n", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
defer logFile.Close()
|
||||
log.SetOutput(logFile)
|
||||
|
||||
keyLog, err := utils.GetSSLKeyLog()
|
||||
if err != nil {
|
||||
fmt.Printf("Could not create key log: %s\n", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
if keyLog != nil {
|
||||
defer keyLog.Close()
|
||||
}
|
||||
|
||||
tlsConf = &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
KeyLogWriter: keyLog,
|
||||
}
|
||||
testcase := os.Getenv("TESTCASE")
|
||||
if err := runTestcase(testcase); err != nil {
|
||||
if err == errUnsupported {
|
||||
fmt.Printf("unsupported test case: %s\n", testcase)
|
||||
os.Exit(127)
|
||||
}
|
||||
fmt.Printf("Downloading files failed: %s\n", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func runTestcase(testcase string) error {
|
||||
flag.Parse()
|
||||
urls := flag.Args()
|
||||
|
||||
quicConf := &quic.Config{Tracer: utils.NewQLOGConnectionTracer}
|
||||
|
||||
if testcase == "http3" {
|
||||
r := &http3.RoundTripper{
|
||||
TLSClientConfig: tlsConf,
|
||||
QuicConfig: quicConf,
|
||||
}
|
||||
defer r.Close()
|
||||
return downloadFiles(r, urls, false)
|
||||
}
|
||||
|
||||
r := &http09.RoundTripper{
|
||||
TLSClientConfig: tlsConf,
|
||||
QuicConfig: quicConf,
|
||||
}
|
||||
defer r.Close()
|
||||
|
||||
switch testcase {
|
||||
case "handshake", "transfer", "retry":
|
||||
case "keyupdate":
|
||||
handshake.FirstKeyUpdateInterval = 100
|
||||
case "chacha20":
|
||||
reset := qtls.SetCipherSuite(tls.TLS_CHACHA20_POLY1305_SHA256)
|
||||
defer reset()
|
||||
case "multiconnect":
|
||||
return runMultiConnectTest(r, urls)
|
||||
case "versionnegotiation":
|
||||
return runVersionNegotiationTest(r, urls)
|
||||
case "resumption":
|
||||
return runResumptionTest(r, urls, false)
|
||||
case "zerortt":
|
||||
return runResumptionTest(r, urls, true)
|
||||
default:
|
||||
return errUnsupported
|
||||
}
|
||||
|
||||
return downloadFiles(r, urls, false)
|
||||
}
|
||||
|
||||
func runVersionNegotiationTest(r *http09.RoundTripper, urls []string) error {
|
||||
if len(urls) != 1 {
|
||||
return errors.New("expected at least 2 URLs")
|
||||
}
|
||||
protocol.SupportedVersions = []protocol.VersionNumber{0x1a2a3a4a}
|
||||
err := downloadFile(r, urls[0], false)
|
||||
if err == nil {
|
||||
return errors.New("expected version negotiation to fail")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "No compatible QUIC version found") {
|
||||
return fmt.Errorf("expect version negotiation error, got: %s", err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func runMultiConnectTest(r *http09.RoundTripper, urls []string) error {
|
||||
for _, url := range urls {
|
||||
if err := downloadFile(r, url, false); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type sessionCache struct {
|
||||
tls.ClientSessionCache
|
||||
put chan<- struct{}
|
||||
}
|
||||
|
||||
func newSessionCache(c tls.ClientSessionCache) (tls.ClientSessionCache, <-chan struct{}) {
|
||||
put := make(chan struct{}, 100)
|
||||
return &sessionCache{ClientSessionCache: c, put: put}, put
|
||||
}
|
||||
|
||||
func (c *sessionCache) Put(key string, cs *tls.ClientSessionState) {
|
||||
c.ClientSessionCache.Put(key, cs)
|
||||
c.put <- struct{}{}
|
||||
}
|
||||
|
||||
func runResumptionTest(r *http09.RoundTripper, urls []string, use0RTT bool) error {
|
||||
if len(urls) < 2 {
|
||||
return errors.New("expected at least 2 URLs")
|
||||
}
|
||||
|
||||
var put <-chan struct{}
|
||||
tlsConf.ClientSessionCache, put = newSessionCache(tls.NewLRUClientSessionCache(1))
|
||||
|
||||
// do the first transfer
|
||||
if err := downloadFiles(r, urls[:1], false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// wait for the session ticket to arrive
|
||||
select {
|
||||
case <-time.NewTimer(10 * time.Second).C:
|
||||
return errors.New("expected to receive a session ticket within 10 seconds")
|
||||
case <-put:
|
||||
}
|
||||
|
||||
if err := r.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// reestablish the connection, using the session ticket that the server (hopefully provided)
|
||||
defer r.Close()
|
||||
return downloadFiles(r, urls[1:], use0RTT)
|
||||
}
|
||||
|
||||
func downloadFiles(cl http.RoundTripper, urls []string, use0RTT bool) error {
|
||||
var g errgroup.Group
|
||||
for _, u := range urls {
|
||||
url := u
|
||||
g.Go(func() error {
|
||||
return downloadFile(cl, url, use0RTT)
|
||||
})
|
||||
}
|
||||
return g.Wait()
|
||||
}
|
||||
|
||||
func downloadFile(cl http.RoundTripper, url string, use0RTT bool) error {
|
||||
method := http.MethodGet
|
||||
if use0RTT {
|
||||
method = http09.MethodGet0RTT
|
||||
}
|
||||
req, err := http.NewRequest(method, url, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rsp, err := cl.RoundTrip(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer rsp.Body.Close()
|
||||
|
||||
file, err := os.Create("/downloads" + req.URL.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
_, err = io.Copy(file, rsp.Body)
|
||||
return err
|
||||
}
|
|
@ -1,160 +0,0 @@
|
|||
package http09
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
tls "github.com/refraction-networking/utls"
|
||||
|
||||
"golang.org/x/net/idna"
|
||||
|
||||
"github.com/quic-go/quic-go"
|
||||
)
|
||||
|
||||
// MethodGet0RTT allows a GET request to be sent using 0-RTT.
|
||||
// Note that 0-RTT data doesn't provide replay protection.
|
||||
const MethodGet0RTT = "GET_0RTT"
|
||||
|
||||
// RoundTripper performs HTTP/0.9 roundtrips over QUIC.
|
||||
type RoundTripper struct {
|
||||
mutex sync.Mutex
|
||||
|
||||
TLSClientConfig *tls.Config
|
||||
QuicConfig *quic.Config
|
||||
|
||||
clients map[string]*client
|
||||
}
|
||||
|
||||
var _ http.RoundTripper = &RoundTripper{}
|
||||
|
||||
// RoundTrip performs a HTTP/0.9 request.
|
||||
// It only supports GET requests.
|
||||
func (r *RoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
if req.Method != http.MethodGet && req.Method != MethodGet0RTT {
|
||||
return nil, errors.New("only GET requests supported")
|
||||
}
|
||||
|
||||
log.Printf("Requesting %s.\n", req.URL)
|
||||
|
||||
r.mutex.Lock()
|
||||
hostname := authorityAddr("https", hostnameFromRequest(req))
|
||||
if r.clients == nil {
|
||||
r.clients = make(map[string]*client)
|
||||
}
|
||||
c, ok := r.clients[hostname]
|
||||
if !ok {
|
||||
tlsConf := &tls.Config{}
|
||||
if r.TLSClientConfig != nil {
|
||||
tlsConf = r.TLSClientConfig.Clone()
|
||||
}
|
||||
tlsConf.NextProtos = []string{h09alpn}
|
||||
c = &client{
|
||||
hostname: hostname,
|
||||
tlsConf: tlsConf,
|
||||
quicConf: r.QuicConfig,
|
||||
}
|
||||
r.clients[hostname] = c
|
||||
}
|
||||
r.mutex.Unlock()
|
||||
return c.RoundTrip(req)
|
||||
}
|
||||
|
||||
// Close closes the roundtripper.
|
||||
func (r *RoundTripper) Close() error {
|
||||
r.mutex.Lock()
|
||||
defer r.mutex.Unlock()
|
||||
|
||||
for id, c := range r.clients {
|
||||
if err := c.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
delete(r.clients, id)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type client struct {
|
||||
hostname string
|
||||
tlsConf *tls.Config
|
||||
quicConf *quic.Config
|
||||
|
||||
once sync.Once
|
||||
conn quic.EarlyConnection
|
||||
dialErr error
|
||||
}
|
||||
|
||||
func (c *client) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
c.once.Do(func() {
|
||||
c.conn, c.dialErr = quic.DialAddrEarly(context.Background(), c.hostname, c.tlsConf, c.quicConf)
|
||||
})
|
||||
if c.dialErr != nil {
|
||||
return nil, c.dialErr
|
||||
}
|
||||
if req.Method != MethodGet0RTT {
|
||||
<-c.conn.HandshakeComplete()
|
||||
}
|
||||
return c.doRequest(req)
|
||||
}
|
||||
|
||||
func (c *client) doRequest(req *http.Request) (*http.Response, error) {
|
||||
str, err := c.conn.OpenStreamSync(context.Background())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cmd := "GET " + req.URL.Path + "\r\n"
|
||||
if _, err := str.Write([]byte(cmd)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := str.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rsp := &http.Response{
|
||||
Proto: "HTTP/0.9",
|
||||
ProtoMajor: 0,
|
||||
ProtoMinor: 9,
|
||||
Request: req,
|
||||
Body: io.NopCloser(str),
|
||||
}
|
||||
return rsp, nil
|
||||
}
|
||||
|
||||
func (c *client) Close() error {
|
||||
if c.conn == nil {
|
||||
return nil
|
||||
}
|
||||
return c.conn.CloseWithError(0, "")
|
||||
}
|
||||
|
||||
func hostnameFromRequest(req *http.Request) string {
|
||||
if req.URL != nil {
|
||||
return req.URL.Host
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// authorityAddr returns a given authority (a host/IP, or host:port / ip:port)
|
||||
// and returns a host:port. The port 443 is added if needed.
|
||||
func authorityAddr(scheme string, authority string) (addr string) {
|
||||
host, port, err := net.SplitHostPort(authority)
|
||||
if err != nil { // authority didn't have a port
|
||||
port = "443"
|
||||
if scheme == "http" {
|
||||
port = "80"
|
||||
}
|
||||
host = authority
|
||||
}
|
||||
if a, err := idna.ToASCII(host); err == nil {
|
||||
host = a
|
||||
}
|
||||
// IPv6 address literal, without a port:
|
||||
if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") {
|
||||
return host + ":" + port
|
||||
}
|
||||
return net.JoinHostPort(host, port)
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
package http09
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
func TestHttp09(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "HTTP/0.9 Suite")
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
package http09
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
|
||||
tls "github.com/refraction-networking/utls"
|
||||
|
||||
"github.com/quic-go/quic-go"
|
||||
"github.com/quic-go/quic-go/internal/testdata"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("HTTP 0.9 integration tests", func() {
|
||||
var (
|
||||
server *Server
|
||||
saddr net.Addr
|
||||
done chan struct{}
|
||||
)
|
||||
|
||||
http.HandleFunc("/helloworld", func(w http.ResponseWriter, r *http.Request) {
|
||||
_, _ = w.Write([]byte("Hello World!"))
|
||||
})
|
||||
|
||||
BeforeEach(func() {
|
||||
server = &Server{
|
||||
Server: &http.Server{TLSConfig: testdata.GetTLSConfig()},
|
||||
}
|
||||
done = make(chan struct{})
|
||||
go func() {
|
||||
defer GinkgoRecover()
|
||||
defer close(done)
|
||||
_ = server.ListenAndServe()
|
||||
}()
|
||||
var ln *quic.EarlyListener
|
||||
Eventually(func() *quic.EarlyListener {
|
||||
server.mutex.Lock()
|
||||
defer server.mutex.Unlock()
|
||||
ln = server.listener
|
||||
return server.listener
|
||||
}).ShouldNot(BeNil())
|
||||
saddr = ln.Addr()
|
||||
saddr.(*net.UDPAddr).IP = net.IP{127, 0, 0, 1}
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
Expect(server.Close()).To(Succeed())
|
||||
Eventually(done).Should(BeClosed())
|
||||
})
|
||||
|
||||
It("performs request", func() {
|
||||
rt := &RoundTripper{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}
|
||||
defer rt.Close()
|
||||
req := httptest.NewRequest(
|
||||
http.MethodGet,
|
||||
fmt.Sprintf("https://%s/helloworld", saddr),
|
||||
nil,
|
||||
)
|
||||
rsp, err := rt.RoundTrip(req)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
data, err := io.ReadAll(rsp.Body)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(data).To(Equal([]byte("Hello World!")))
|
||||
})
|
||||
|
||||
It("allows setting of headers", func() {
|
||||
http.HandleFunc("/headers", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Add("foo", "bar")
|
||||
w.WriteHeader(1337)
|
||||
_, _ = w.Write([]byte("done"))
|
||||
})
|
||||
|
||||
rt := &RoundTripper{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}
|
||||
defer rt.Close()
|
||||
req := httptest.NewRequest(
|
||||
http.MethodGet,
|
||||
fmt.Sprintf("https://%s/headers", saddr),
|
||||
nil,
|
||||
)
|
||||
rsp, err := rt.RoundTrip(req)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
data, err := io.ReadAll(rsp.Body)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(data).To(Equal([]byte("done")))
|
||||
})
|
||||
})
|
|
@ -1,160 +0,0 @@
|
|||
package http09
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/quic-go/quic-go"
|
||||
)
|
||||
|
||||
const h09alpn = "hq-interop"
|
||||
|
||||
type responseWriter struct {
|
||||
io.Writer
|
||||
headers http.Header
|
||||
}
|
||||
|
||||
var _ http.ResponseWriter = &responseWriter{}
|
||||
|
||||
func (w *responseWriter) Header() http.Header {
|
||||
if w.headers == nil {
|
||||
w.headers = make(http.Header)
|
||||
}
|
||||
return w.headers
|
||||
}
|
||||
|
||||
func (w *responseWriter) WriteHeader(int) {}
|
||||
|
||||
// Server is a HTTP/0.9 server listening for QUIC connections.
|
||||
type Server struct {
|
||||
*http.Server
|
||||
|
||||
QuicConfig *quic.Config
|
||||
|
||||
mutex sync.Mutex
|
||||
listener *quic.EarlyListener
|
||||
}
|
||||
|
||||
// Close closes the server.
|
||||
func (s *Server) Close() error {
|
||||
s.mutex.Lock()
|
||||
defer s.mutex.Unlock()
|
||||
|
||||
return s.listener.Close()
|
||||
}
|
||||
|
||||
// ListenAndServe listens and serves HTTP/0.9 over QUIC.
|
||||
func (s *Server) ListenAndServe() error {
|
||||
if s.Server == nil {
|
||||
return errors.New("use of http3.Server without http.Server")
|
||||
}
|
||||
|
||||
udpAddr, err := net.ResolveUDPAddr("udp", s.Addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
conn, err := net.ListenUDP("udp", udpAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tlsConf := s.TLSConfig.Clone()
|
||||
tlsConf.NextProtos = []string{h09alpn}
|
||||
ln, err := quic.ListenEarly(conn, tlsConf, s.QuicConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.mutex.Lock()
|
||||
s.listener = ln
|
||||
s.mutex.Unlock()
|
||||
|
||||
for {
|
||||
conn, err := ln.Accept(context.Background())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
go s.handleConn(conn)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) handleConn(conn quic.Connection) {
|
||||
for {
|
||||
str, err := conn.AcceptStream(context.Background())
|
||||
if err != nil {
|
||||
log.Printf("Error accepting stream: %s\n", err.Error())
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
if err := s.handleStream(str); err != nil {
|
||||
log.Printf("Handling stream failed: %s\n", err.Error())
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) handleStream(str quic.Stream) error {
|
||||
reqBytes, err := io.ReadAll(str)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
request := string(reqBytes)
|
||||
request = strings.TrimRight(request, "\r\n")
|
||||
request = strings.TrimRight(request, " ")
|
||||
|
||||
log.Printf("Received request: %s\n", request)
|
||||
|
||||
if request[:5] != "GET /" {
|
||||
str.CancelWrite(42)
|
||||
return nil
|
||||
}
|
||||
|
||||
u, err := url.Parse(request[4:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
u.Scheme = "https"
|
||||
|
||||
req := &http.Request{
|
||||
Method: http.MethodGet,
|
||||
Proto: "HTTP/0.9",
|
||||
ProtoMajor: 0,
|
||||
ProtoMinor: 9,
|
||||
Body: str,
|
||||
URL: u,
|
||||
}
|
||||
|
||||
handler := s.Handler
|
||||
if handler == nil {
|
||||
handler = http.DefaultServeMux
|
||||
}
|
||||
|
||||
var panicked bool
|
||||
func() {
|
||||
defer func() {
|
||||
if p := recover(); p != nil {
|
||||
// Copied from net/http/server.go
|
||||
const size = 64 << 10
|
||||
buf := make([]byte, size)
|
||||
buf = buf[:runtime.Stack(buf, false)]
|
||||
log.Printf("http: panic serving: %v\n%s", p, buf)
|
||||
panicked = true
|
||||
}
|
||||
}()
|
||||
handler.ServeHTTP(&responseWriter{Writer: str}, req)
|
||||
}()
|
||||
|
||||
if panicked {
|
||||
if _, err := str.Write([]byte("500")); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return str.Close()
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Set up the routing needed for the simulation.
|
||||
/setup.sh
|
||||
|
||||
echo "Using commit:" `cat commit.txt`
|
||||
|
||||
if [ "$ROLE" == "client" ]; then
|
||||
# Wait for the simulator to start up.
|
||||
/wait-for-it.sh sim:57832 -s -t 10
|
||||
echo "Starting QUIC client..."
|
||||
echo "Client params: $CLIENT_PARAMS"
|
||||
echo "Test case: $TESTCASE"
|
||||
QUIC_GO_LOG_LEVEL=debug ./client $CLIENT_PARAMS $REQUESTS
|
||||
else
|
||||
echo "Running QUIC server."
|
||||
QUIC_GO_LOG_LEVEL=debug ./server "$@"
|
||||
fi
|
|
@ -1,96 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
tls "github.com/refraction-networking/utls"
|
||||
|
||||
"github.com/quic-go/quic-go"
|
||||
"github.com/quic-go/quic-go/http3"
|
||||
"github.com/quic-go/quic-go/internal/qtls"
|
||||
"github.com/quic-go/quic-go/interop/http09"
|
||||
"github.com/quic-go/quic-go/interop/utils"
|
||||
)
|
||||
|
||||
var tlsConf *tls.Config
|
||||
|
||||
func main() {
|
||||
logFile, err := os.Create("/logs/log.txt")
|
||||
if err != nil {
|
||||
fmt.Printf("Could not create log file: %s\n", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
defer logFile.Close()
|
||||
log.SetOutput(logFile)
|
||||
|
||||
keyLog, err := utils.GetSSLKeyLog()
|
||||
if err != nil {
|
||||
fmt.Printf("Could not create key log: %s\n", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
if keyLog != nil {
|
||||
defer keyLog.Close()
|
||||
}
|
||||
|
||||
testcase := os.Getenv("TESTCASE")
|
||||
|
||||
quicConf := &quic.Config{
|
||||
RequireAddressValidation: func(net.Addr) bool { return testcase == "retry" },
|
||||
Allow0RTT: testcase == "zerortt",
|
||||
Tracer: utils.NewQLOGConnectionTracer,
|
||||
}
|
||||
cert, err := tls.LoadX509KeyPair("/certs/cert.pem", "/certs/priv.key")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
tlsConf = &tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
KeyLogWriter: keyLog,
|
||||
}
|
||||
|
||||
switch testcase {
|
||||
case "versionnegotiation", "handshake", "retry", "transfer", "resumption", "multiconnect", "zerortt":
|
||||
err = runHTTP09Server(quicConf)
|
||||
case "chacha20":
|
||||
reset := qtls.SetCipherSuite(tls.TLS_CHACHA20_POLY1305_SHA256)
|
||||
defer reset()
|
||||
err = runHTTP09Server(quicConf)
|
||||
case "http3":
|
||||
err = runHTTP3Server(quicConf)
|
||||
default:
|
||||
fmt.Printf("unsupported test case: %s\n", testcase)
|
||||
os.Exit(127)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
fmt.Printf("Error running server: %s\n", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func runHTTP09Server(quicConf *quic.Config) error {
|
||||
server := http09.Server{
|
||||
Server: &http.Server{
|
||||
Addr: ":443",
|
||||
TLSConfig: tlsConf,
|
||||
},
|
||||
QuicConfig: quicConf,
|
||||
}
|
||||
http.DefaultServeMux.Handle("/", http.FileServer(http.Dir("/www")))
|
||||
return server.ListenAndServe()
|
||||
}
|
||||
|
||||
func runHTTP3Server(quicConf *quic.Config) error {
|
||||
server := http3.Server{
|
||||
Addr: ":443",
|
||||
TLSConfig: tlsConf,
|
||||
QuicConfig: quicConf,
|
||||
}
|
||||
http.DefaultServeMux.Handle("/", http.FileServer(http.Dir("/www")))
|
||||
return server.ListenAndServe()
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/quic-go/quic-go"
|
||||
"github.com/quic-go/quic-go/internal/utils"
|
||||
"github.com/quic-go/quic-go/logging"
|
||||
"github.com/quic-go/quic-go/qlog"
|
||||
)
|
||||
|
||||
// GetSSLKeyLog creates a file for the TLS key log
|
||||
func GetSSLKeyLog() (io.WriteCloser, error) {
|
||||
filename := os.Getenv("SSLKEYLOGFILE")
|
||||
if len(filename) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
f, err := os.Create(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// NewQLOGConnectionTracer create a qlog file in QLOGDIR
|
||||
func NewQLOGConnectionTracer(_ context.Context, p logging.Perspective, connID quic.ConnectionID) logging.ConnectionTracer {
|
||||
qlogDir := os.Getenv("QLOGDIR")
|
||||
if len(qlogDir) == 0 {
|
||||
return nil
|
||||
}
|
||||
if _, err := os.Stat(qlogDir); os.IsNotExist(err) {
|
||||
if err := os.MkdirAll(qlogDir, 0o666); err != nil {
|
||||
log.Fatalf("failed to create qlog dir %s: %v", qlogDir, err)
|
||||
}
|
||||
}
|
||||
path := fmt.Sprintf("%s/%x.qlog", strings.TrimRight(qlogDir, "/"), connID)
|
||||
f, err := os.Create(path)
|
||||
if err != nil {
|
||||
log.Printf("Failed to create qlog file %s: %s", path, err.Error())
|
||||
return nil
|
||||
}
|
||||
log.Printf("Created qlog file: %s\n", path)
|
||||
return qlog.NewConnectionTracer(utils.NewBufferedWriteCloser(bufio.NewWriter(f), f), p, connID)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue