Skip to content

Commit 0a91ea1

Browse files
committed
Initial import
0 parents  commit 0a91ea1

File tree

4 files changed

+280
-0
lines changed

4 files changed

+280
-0
lines changed

.github/workflows/main.yml

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
name: ci
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
- master
8+
paths-ignore:
9+
- '**/README.md'
10+
tags:
11+
- '*'
12+
schedule:
13+
- cron: '0 3 * * 1'
14+
workflow_dispatch:
15+
inputs:
16+
push:
17+
description: 'Push image to Docker Hub'
18+
type: boolean
19+
default: false
20+
21+
jobs:
22+
23+
build-and-push:
24+
runs-on: ubuntu-latest
25+
steps:
26+
- name: Checkout
27+
uses: actions/checkout@v3
28+
29+
- name: Inject slug/short variables
30+
uses: rlespinasse/[email protected]
31+
32+
- name: Get curl version
33+
id: curlver
34+
uses: dvershinin/[email protected]
35+
with:
36+
repository: 'https://github.com/curl/curl'
37+
output_format: 'version'
38+
39+
- name: Resolve tags
40+
run: |
41+
set -euo pipefail
42+
CURL_VERSION="${{ steps.curlver.outputs.last_version }}"
43+
CURL_TAG="curl-${CURL_VERSION//./_}"
44+
# determine latest quiche semver tag (v-prefixed or plain), choose highest
45+
QUICHE_VERSION="$(
46+
git ls-remote --tags https://github.com/cloudflare/quiche \
47+
| awk -F'refs/tags/' '/refs\/tags\/v?[0-9]+\.[0-9]+\.[0-9]+(\^\{\})?$/ {gsub(/\^\{\}/,"",$2); gsub(/^v/,"",$2); print $2}' \
48+
| sort -V | tail -n1
49+
)"
50+
if git ls-remote --tags https://github.com/cloudflare/quiche "refs/tags/v${QUICHE_VERSION}" | grep -q "refs/tags/v${QUICHE_VERSION}$"; then
51+
QUICHE_REF="v${QUICHE_VERSION}"
52+
else
53+
QUICHE_REF="${QUICHE_VERSION}"
54+
fi
55+
echo "CURL_VERSION=${CURL_VERSION}" >> $GITHUB_ENV
56+
echo "IMAGE_TAG=${CURL_VERSION}" >> $GITHUB_ENV
57+
echo "CURL_TAG=${CURL_TAG}" >> $GITHUB_ENV
58+
echo "QUICHE_REF=${QUICHE_REF}" >> $GITHUB_ENV
59+
60+
- name: Prepare sources (git shallow clone + tar)
61+
run: |
62+
set -euo pipefail
63+
rm -rf src _dl
64+
mkdir -p src _dl
65+
git clone --depth 1 --branch "${CURL_TAG}" https://github.com/curl/curl src/curl-src
66+
git clone --filter=blob:none --recurse-submodules --shallow-submodules https://github.com/cloudflare/quiche src/quiche-src
67+
git -C src/quiche-src fetch --tags --depth 1 origin "refs/tags/${QUICHE_REF}:refs/tags/${QUICHE_REF}"
68+
git -C src/quiche-src checkout -q "refs/tags/${QUICHE_REF}"
69+
git -C src/quiche-src submodule update --init --recursive --depth 1
70+
tar -czf _dl/curl.tar.gz -C src curl-src
71+
tar -czf _dl/quiche.tar.gz -C src quiche-src
72+
curl -fL "https://raw.githubusercontent.com/b4b4r07/httpstat/master/httpstat.sh" -o _dl/httpstat.sh
73+
74+
- name: Login to Docker Hub
75+
if: inputs.push == true || github.event_name == 'push' || github.event_name == 'schedule'
76+
uses: docker/login-action@v2
77+
with:
78+
username: ${{ secrets.DOCKERHUB_USERNAME }}
79+
password: ${{ secrets.DOCKERHUB_TOKEN }}
80+
81+
- name: Set up QEMU
82+
if: github.event_name == 'schedule'
83+
uses: docker/setup-qemu-action@v3
84+
with:
85+
platforms: linux/arm64
86+
87+
- name: Set up Docker Buildx
88+
if: inputs.push == true || github.event_name == 'push' || github.event_name == 'schedule'
89+
uses: docker/setup-buildx-action@v2
90+
91+
- name: Build (no push) via docker build (act)
92+
if: inputs.push != true && github.event_name != 'push' && env.ACT == 'true'
93+
run: |
94+
DOCKER_BUILDKIT=1 docker build --platform linux/amd64 --load \
95+
-t curl-edge:${IMAGE_TAG} -t curl-edge:latest .
96+
97+
- name: Build (no push)
98+
if: inputs.push != true && github.event_name != 'push' && github.event_name != 'schedule' && env.ACT != 'true'
99+
uses: docker/build-push-action@v4
100+
with:
101+
context: .
102+
push: false
103+
platforms: linux/amd64
104+
load: true
105+
tags: |
106+
curl-edge:${{ env.IMAGE_TAG }}
107+
curl-edge:latest
108+
109+
- name: Test curl -V
110+
if: inputs.push != true && github.event_name != 'push'
111+
run: docker run --rm curl-edge:${IMAGE_TAG} -V
112+
113+
- name: Test HTTP/3 to Cloudflare
114+
if: inputs.push != true && github.event_name != 'push'
115+
run: |
116+
docker run --rm --network host curl-edge:${IMAGE_TAG} \
117+
-I --http3 https://cloudflare-quic.com/ || \
118+
docker run --rm --network host curl-edge:${IMAGE_TAG} \
119+
-I --http3 https://www.cloudflare.com/ --connect-timeout 10 || true
120+
121+
- name: Test httpstat script
122+
if: inputs.push != true && github.event_name != 'push'
123+
run: |
124+
docker run --rm --network host curl-edge:${IMAGE_TAG} \
125+
/opt/httpstat.sh -I --http3 https://cloudflare-quic.com/ || true
126+
127+
- name: Build and push (push/dispatch, amd64 only)
128+
if: inputs.push == true || github.event_name == 'push'
129+
uses: docker/build-push-action@v4
130+
with:
131+
context: .
132+
push: true
133+
platforms: linux/amd64
134+
cache-from: type=gha
135+
cache-to: type=gha,mode=max
136+
tags: |
137+
getpagespeed/curl-edge:amd64-${{ env.IMAGE_TAG }}
138+
getpagespeed/curl-edge:latest-amd64
139+
140+
- name: Build and push (nightly, arm64 only)
141+
if: github.event_name == 'schedule'
142+
uses: docker/build-push-action@v4
143+
with:
144+
context: .
145+
push: true
146+
platforms: linux/arm64
147+
cache-from: type=gha
148+
cache-to: type=gha,mode=max
149+
tags: |
150+
getpagespeed/curl-edge:arm64-${{ env.IMAGE_TAG }}
151+
getpagespeed/curl-edge:latest-arm64
152+
153+
- name: Create multi-arch manifest (nightly)
154+
if: github.event_name == 'schedule'
155+
run: |
156+
docker buildx imagetools create \
157+
-t getpagespeed/curl-edge:${IMAGE_TAG} \
158+
-t getpagespeed/curl-edge:latest \
159+
getpagespeed/curl-edge:amd64-${IMAGE_TAG} \
160+
getpagespeed/curl-edge:arm64-${IMAGE_TAG}

Dockerfile

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
FROM alpine:edge AS builder
2+
3+
LABEL maintainer="Danila Vershinin <[email protected]>"
4+
5+
WORKDIR /opt
6+
7+
RUN apk add --no-cache build-base git autoconf libpsl-dev libtool cmake go curl nghttp2-dev zlib-dev automake rustup clang lld ninja pkgconf python3 linux-headers && rustup-init -y -q
8+
9+
# Prefer clang toolchain for BoringSSL/quiche on all arches (including arm64)
10+
ENV CC=clang
11+
ENV CXX=g++
12+
13+
COPY _dl/quiche.tar.gz /opt/quiche.tar.gz
14+
COPY _dl/curl.tar.gz /opt/curl.tar.gz
15+
16+
RUN mkdir -p /opt/quiche-src && \
17+
tar -xzf /opt/quiche.tar.gz -C /opt/quiche-src --strip-components=1 && \
18+
rm /opt/quiche.tar.gz
19+
RUN cd /opt/quiche-src && \
20+
RUST_BACKTRACE=1 PATH="$HOME/.cargo/bin:$PATH" cargo build -vv --package quiche --release --features ffi,pkg-config-meta,qlog --jobs $(nproc) && \
21+
mkdir -p quiche/deps/boringssl/src/lib && \
22+
ln -vnf $(find target/release -name libcrypto.a -o -name libssl.a) quiche/deps/boringssl/src/lib/
23+
24+
RUN mkdir -p /opt/curl-src && \
25+
tar -xzf /opt/curl.tar.gz -C /opt/curl-src --strip-components=1 && \
26+
rm /opt/curl.tar.gz
27+
RUN cd /opt/curl-src && \
28+
autoreconf -fi && \
29+
./configure LDFLAGS="-Wl,-rpath,/opt/quiche-src/target/release" --with-openssl=/opt/quiche-src/quiche/deps/boringssl/src --with-quiche=/opt/quiche-src/target/release --with-nghttp2 --with-zlib && \
30+
make -j $(nproc) && \
31+
make DESTDIR="/curl/" install
32+
33+
FROM alpine:edge
34+
RUN apk add --no-cache nghttp2 zlib libpsl bash perl ca-certificates
35+
COPY --from=builder /curl/usr/local/ /usr/local/
36+
37+
WORKDIR /opt
38+
# add httpstat script
39+
COPY _dl/httpstat.sh /opt/httpstat.sh
40+
RUN chmod +x /opt/httpstat.sh
41+
42+
ENTRYPOINT ["curl"]

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2023 yurymuski
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# curl-edge
2+
[![](https://img.shields.io/docker/pulls/getpagespeed/curl-edge?style=flat-square)](https://hub.docker.com/r/getpagespeed/curl-edge)
3+
4+
Bleeding‑edge Docker image of `curl` with `BoringSSL` and `quiche` (HTTP/3), plus `httpstat` for visualization.
5+
6+
Link for [curl + http3 manual](https://github.com/curl/curl/blob/master/docs/HTTP3.md#quiche-version)
7+
8+
## Usage
9+
10+
`docker run -it --rm getpagespeed/curl-edge -V`
11+
```
12+
curl 8.1.2-DEV (x86_64-pc-linux-gnu) libcurl/8.1.2-DEV BoringSSL quiche/0.17.2
13+
Release-Date: [unreleased]
14+
Protocols: dict file ftp ftps gopher gophers http https imap imaps mqtt pop3 pop3s rtsp smb smbs smtp smtps telnet tftp
15+
Features: alt-svc AsynchDNS HSTS HTTP3 HTTPS-proxy IPv6 Largefile NTLM NTLM_WB SSL threadsafe UnixSockets
16+
```
17+
18+
19+
`docker run -it --rm getpagespeed/curl-edge -IL https://blog.cloudflare.com --http3`
20+
21+
`docker run -it --rm getpagespeed/curl-edge -IL https://yurets.pro --http3`
22+
23+
```
24+
25+
HTTP/3 200
26+
date: Sun, 28 May 2023 19:03:00 GMT
27+
content-type: text/html
28+
last-modified: Sun, 26 Sep 2021 16:14:14 GMT
29+
strict-transport-security: max-age=15552000; includeSubDomains; preload
30+
cf-cache-status: DYNAMIC
31+
report-to: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=0ahatt6rf%2FLHIouteXEJEQ3KOBYsfdCSbpsCotGOuaWESHJYJBrd4E6yRbUhFiLuQQ%2BsNmRujvr2A48QTpUa5BbI5iHWBNVVOCdpPaDdqqZkEh%2BQxKssoggYjY4Q"}],"group":"cf-nel","max_age":604800}
32+
nel: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
33+
x-content-type-options: nosniff
34+
server: cloudflare
35+
cf-ray: 7ce8c1510e3295a6-TBS
36+
alt-svc: h3=":443"; ma=86400
37+
38+
```
39+
40+
### httpstat support
41+
42+
`docker run -it --rm getpagespeed/curl-edge ./httpstat.sh -ILv https://blog.cloudflare.com --http3`
43+
44+
`docker run -it --rm getpagespeed/curl-edge ./httpstat.sh -ILv https://yurets.pro --http3`
45+
46+
![](httpstat.png?raw=true "HTTPSTAT H3")
47+
48+
49+
## Build
50+
51+
```
52+
docker buildx build --platform linux/amd64 -t getpagespeed/curl-edge:latest -t getpagespeed/curl-edge:8.1.2 . --push
53+
54+
# quiche fails to compile for arm
55+
docker buildx build --platform linux/arm,linux/arm64,linux/amd64 -t getpagespeed/curl-edge:latest -t getpagespeed/curl-edge:8.1.2 . --push
56+
57+
```

0 commit comments

Comments
 (0)