Showing preview only (2,120K chars total). Download the full file or copy to clipboard to get everything.
Repository: fastly/Viceroy
Branch: main
Commit: 8d7969ff77ba
Files: 304
Total size: 2.0 MB
Directory structure:
gitextract_63zfz6_u/
├── .github/
│ └── workflows/
│ ├── changelog.yml
│ ├── release.yml
│ ├── rust.yml
│ └── test.yml
├── .gitignore
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Cargo.toml
├── Dockerfile
├── LICENSE
├── Makefile
├── README.md
├── SECURITY.md
├── cli/
│ ├── Cargo.toml
│ ├── src/
│ │ ├── execute_ctx.rs
│ │ ├── main.rs
│ │ ├── opts.rs
│ │ ├── subcommands/
│ │ │ ├── adapt.rs
│ │ │ ├── run.rs
│ │ │ └── serve.rs
│ │ └── subcommands.rs
│ └── tests/
│ ├── integration/
│ │ ├── acl.rs
│ │ ├── args.rs
│ │ ├── async_io.rs
│ │ ├── body.rs
│ │ ├── cache.rs
│ │ ├── client_certs.rs
│ │ ├── common/
│ │ │ └── backends.rs
│ │ ├── common.rs
│ │ ├── config_store_lookup.rs
│ │ ├── device_detection_lookup.rs
│ │ ├── dictionary_lookup.rs
│ │ ├── downstream_req.rs
│ │ ├── early_hints.rs
│ │ ├── edge_rate_limiting.rs
│ │ ├── env_vars.rs
│ │ ├── fastly_key_is_valid.rs
│ │ ├── geolocation_lookup.rs
│ │ ├── grpc.rs
│ │ ├── hello_world.gzip
│ │ ├── http_semantics.rs
│ │ ├── inspect.rs
│ │ ├── invalid_status_code.rs
│ │ ├── kv_store.rs
│ │ ├── logging.rs
│ │ ├── main.rs
│ │ ├── memory.rs
│ │ ├── profiling.rs
│ │ ├── request.rs
│ │ ├── response.rs
│ │ ├── reusable_sandboxes.rs
│ │ ├── secret_store.rs
│ │ ├── sending_response.rs
│ │ ├── shielding.rs
│ │ ├── sleep.rs
│ │ ├── unknown_import_behavior.rs
│ │ ├── upstream.rs
│ │ ├── upstream_async.rs
│ │ ├── upstream_dynamic.rs
│ │ ├── upstream_streaming.rs
│ │ └── vcpu_time.rs
│ ├── trap-test/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ └── main.rs
│ └── wasm/
│ ├── exit_code_4.wat
│ ├── invalid.wat
│ ├── minimal.wasm
│ ├── minimal.wat
│ └── trapping.wat
├── doc/
│ └── RELEASING.md
├── proptest-regressions/
│ ├── body.txt
│ ├── cache.txt
│ └── collecting_body.txt
├── rust-toolchain.toml
├── rustfmt.toml
├── src/
│ ├── acl.rs
│ ├── adapt.rs
│ ├── async_io.rs
│ ├── body.rs
│ ├── body_tee.rs
│ ├── cache/
│ │ ├── store.rs
│ │ └── variance.rs
│ ├── cache.rs
│ ├── collecting_body.rs
│ ├── component/
│ │ ├── adapter/
│ │ │ └── http_req.rs
│ │ ├── adapter.rs
│ │ ├── backend.rs
│ │ ├── compute/
│ │ │ ├── acl.rs
│ │ │ ├── async_io.rs
│ │ │ ├── backend.rs
│ │ │ ├── cache.rs
│ │ │ ├── compute_runtime.rs
│ │ │ ├── config_store.rs
│ │ │ ├── device_detection.rs
│ │ │ ├── dictionary.rs
│ │ │ ├── erl.rs
│ │ │ ├── error.rs
│ │ │ ├── geo.rs
│ │ │ ├── headers.rs
│ │ │ ├── http_body.rs
│ │ │ ├── http_cache.rs
│ │ │ ├── http_downstream.rs
│ │ │ ├── http_req.rs
│ │ │ ├── http_resp.rs
│ │ │ ├── http_types.rs
│ │ │ ├── image_optimizer.rs
│ │ │ ├── kv_store.rs
│ │ │ ├── log.rs
│ │ │ ├── purge.rs
│ │ │ ├── secret_store.rs
│ │ │ ├── security.rs
│ │ │ ├── shielding.rs
│ │ │ └── types.rs
│ │ ├── compute.rs
│ │ ├── erl.rs
│ │ ├── handles.rs
│ │ ├── http_req.rs
│ │ ├── image_optimizer.rs
│ │ ├── shielding.rs
│ │ └── wasi.rs
│ ├── component.rs
│ ├── config/
│ │ ├── acl.rs
│ │ ├── backends/
│ │ │ └── client_cert_info.rs
│ │ ├── backends.rs
│ │ ├── device_detection.rs
│ │ ├── dictionaries.rs
│ │ ├── geolocation.rs
│ │ ├── limits.rs
│ │ ├── object_store.rs
│ │ ├── secret_store.rs
│ │ └── unit_tests.rs
│ ├── config.rs
│ ├── downstream.rs
│ ├── error.rs
│ ├── execute.rs
│ ├── framing.rs
│ ├── handoff.rs
│ ├── headers.rs
│ ├── lib.rs
│ ├── linking.rs
│ ├── logging.rs
│ ├── object_store.rs
│ ├── sandbox/
│ │ ├── async_item.rs
│ │ └── downstream.rs
│ ├── sandbox.rs
│ ├── secret_store.rs
│ ├── service.rs
│ ├── shielding_site.rs
│ ├── shift_mem.rs
│ ├── streaming_body.rs
│ ├── upstream.rs
│ ├── wiggle_abi/
│ │ ├── acl.rs
│ │ ├── backend_impl.rs
│ │ ├── body_impl.rs
│ │ ├── cache.rs
│ │ ├── compute_runtime.rs
│ │ ├── config_store.rs
│ │ ├── device_detection_impl.rs
│ │ ├── dictionary_impl.rs
│ │ ├── entity.rs
│ │ ├── erl_impl.rs
│ │ ├── fastly_purge_impl.rs
│ │ ├── geo_impl.rs
│ │ ├── headers.rs
│ │ ├── http_cache.rs
│ │ ├── http_downstream.rs
│ │ ├── image_optimizer.rs
│ │ ├── kv_store_impl.rs
│ │ ├── log_impl.rs
│ │ ├── obj_store_impl.rs
│ │ ├── req_impl.rs
│ │ ├── resp_impl.rs
│ │ ├── secret_store_impl.rs
│ │ ├── shielding.rs
│ │ └── uap_impl.rs
│ └── wiggle_abi.rs
├── test-fixtures/
│ ├── Cargo.toml
│ ├── combined_heap_limits.wat
│ ├── data/
│ │ ├── ca.key
│ │ ├── ca.pem
│ │ ├── ca.srl
│ │ ├── client.crt
│ │ ├── client.csr
│ │ ├── client.key
│ │ ├── device-detection-mapping.json
│ │ ├── geolocation-mapping.json
│ │ ├── json-config_store.json
│ │ ├── json-dictionary.json
│ │ ├── json-kv_store-invalid_1.json
│ │ ├── json-kv_store-invalid_2.json
│ │ ├── json-kv_store.json
│ │ ├── json-secret_store.json
│ │ ├── kv-store.txt
│ │ ├── my-acl-1.json
│ │ ├── my-acl-2.json
│ │ ├── server.crt
│ │ ├── server.csr
│ │ ├── server.ext
│ │ └── server.key
│ ├── return_ok.wat
│ └── src/
│ ├── bin/
│ │ ├── acl.rs
│ │ ├── args.rs
│ │ ├── async_io.rs
│ │ ├── bad-framing-headers.rs
│ │ ├── cache.rs
│ │ ├── config-store-lookup.rs
│ │ ├── content-length.rs
│ │ ├── device-detection-lookup.rs
│ │ ├── dictionary-lookup.rs
│ │ ├── downstream-req.rs
│ │ ├── early-hints.rs
│ │ ├── edge-rate-limiting.rs
│ │ ├── env-vars.rs
│ │ ├── expects-hello.rs
│ │ ├── fastly-key-is-valid.rs
│ │ ├── geolocation-lookup-default.rs
│ │ ├── geolocation-lookup.rs
│ │ ├── grpc.rs
│ │ ├── gzipped-response.rs
│ │ ├── inspect.rs
│ │ ├── invalid-status-code.rs
│ │ ├── kv_store.rs
│ │ ├── logging.rs
│ │ ├── manual-framing-headers.rs
│ │ ├── mutual-tls.rs
│ │ ├── noop.rs
│ │ ├── panic.rs
│ │ ├── request.rs
│ │ ├── response.rs
│ │ ├── reusable-sandboxes.rs
│ │ ├── secret-store.rs
│ │ ├── shielding.rs
│ │ ├── sleep.rs
│ │ ├── streaming-response.rs
│ │ ├── teapot-status.rs
│ │ ├── unknown-import.rs
│ │ ├── upstream-async.rs
│ │ ├── upstream-dynamic.rs
│ │ ├── upstream-streaming.rs
│ │ ├── upstream.rs
│ │ ├── vcpu_time_test.rs
│ │ ├── write-and-read-body.rs
│ │ └── write-body.rs
│ └── limits.rs
└── wasm_abi/
├── adapter/
│ ├── Cargo.toml
│ ├── README.md
│ ├── build.rs
│ ├── byte-array-literals/
│ │ ├── Cargo.toml
│ │ ├── README.md
│ │ └── src/
│ │ └── lib.rs
│ └── src/
│ ├── descriptors.rs
│ ├── fastly/
│ │ ├── cache.rs
│ │ ├── config_store.rs
│ │ ├── core.rs
│ │ ├── error.rs
│ │ ├── http_cache.rs
│ │ ├── macros.rs
│ │ └── mod.rs
│ ├── lib.rs
│ └── macros.rs
├── compute-at-edge-abi/
│ ├── README.md
│ ├── cache.witx
│ ├── compute-at-edge.witx
│ ├── config-store.witx
│ ├── http-cache.witx
│ ├── shielding.witx
│ └── typenames.witx
├── data/
│ ├── viceroy-component-adapter.library.noshift.wasm
│ ├── viceroy-component-adapter.library.wasm
│ ├── viceroy-component-adapter.noshift.wasm
│ └── viceroy-component-adapter.wasm
└── wit/
├── deps/
│ ├── cli/
│ │ ├── command.wit
│ │ ├── environment.wit
│ │ ├── exit.wit
│ │ ├── imports.wit
│ │ ├── run.wit
│ │ ├── stdio.wit
│ │ └── terminal.wit
│ ├── clocks/
│ │ ├── monotonic-clock.wit
│ │ ├── timezone.wit
│ │ ├── wall-clock.wit
│ │ └── world.wit
│ ├── fastly/
│ │ └── compute.wit
│ ├── fastly-adapter/
│ │ └── adapter.wit
│ ├── filesystem/
│ │ ├── preopens.wit
│ │ ├── types.wit
│ │ └── world.wit
│ ├── io/
│ │ ├── error.wit
│ │ ├── poll.wit
│ │ ├── streams.wit
│ │ └── world.wit
│ ├── random/
│ │ ├── insecure-seed.wit
│ │ ├── insecure.wit
│ │ ├── random.wit
│ │ └── world.wit
│ └── sockets/
│ ├── instance-network.wit
│ ├── ip-name-lookup.wit
│ ├── network.wit
│ ├── tcp-create-socket.wit
│ ├── tcp.wit
│ ├── udp-create-socket.wit
│ ├── udp.wit
│ └── world.wit
└── viceroy.wit
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/workflows/changelog.yml
================================================
name: Changelog
on:
pull_request:
types: [opened, synchronize, reopened, labeled, unlabeled]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
with:
# We want to check modified files from base_ref (merge target) to the current commit,
# so we need the full history of the current branch.
fetch-depth: 0
- name: Check for skip label
id: check-skip
run: |
if [[ "${{ contains(github.event.pull_request.labels.*.name, 'skip-changelog') }}" == "true" ]]; then
echo "skip=true" >> $GITHUB_OUTPUT
echo "Skipping changelog validation due to skip-changelog label"
else
echo "skip=false" >> $GITHUB_OUTPUT
fi
- name: Validate changelog entry
if: steps.check-skip.outputs.skip == 'false'
run: |
# --quiet implies --exit-code (but doesn't produce output).
# --exit-code exits 1 if there are differences, or 0 if there are no differences.
# So: this command exits 1 if CHANGELOG.md was changed between the base and HEAD,
# or 0 if there are no diffs.
if git diff --quiet origin/"${{ github.base_ref }}"...HEAD -- CHANGELOG.md; then
echo "::error::No changelog entry found. Please add an entry to CHANGELOG.md or add the 'skip-changelog' label if this change does not require a changelog entry."
exit 1
else
echo "Changelog has been updated"
fi
================================================
FILE: .github/workflows/release.yml
================================================
name: Main
on:
push:
tags:
- "v*.*.*"
jobs:
build:
strategy:
matrix:
os: [ubuntu-24.04, macos-14, windows-2022]
arch: [amd64, arm64]
exclude:
- os: windows-2022
arch: arm64
include:
- os: ubuntu-24.04
name: linux
rust_abi: unknown-linux-gnu
- os: macos-14
name: darwin
rust_abi: apple-darwin
- os: windows-2022
name: windows
rust_abi: pc-windows-msvc
extension: .exe
- arch: arm64
rust_arch: aarch64
- arch: amd64
rust_arch: x86_64
runs-on: ${{ matrix.os }}
outputs:
draft_release_id: ${{ steps.release.outputs.id }}
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: Install Rust
run: rustup target add ${{ matrix.rust_arch }}-${{ matrix.rust_abi }}
shell: bash
- name: Install C cross-compilation toolchain
if: ${{ matrix.name == 'linux' && matrix.arch != 'amd64' }}
run: |
sudo apt-get update
sudo apt install -f -y gcc-${{ matrix.rust_arch }}-linux-gnu
echo CC=${{ matrix.rust_arch }}-linux-gnu-gcc >> $GITHUB_ENV
echo RUSTFLAGS='-C linker=${{ matrix.rust_arch }}-linux-gnu-gcc' >> $GITHUB_ENV
- name: Extract tag name
uses: olegtarasov/get-tag@v2.1.2
id: tagName
- name: Build
run: |
cargo build --release --workspace --locked --target=${{ matrix.rust_arch }}-${{ matrix.rust_abi }}
- name: Strip symbols (linux)
if: ${{ matrix.name == 'linux' }}
run: |
${{ matrix.rust_arch }}-linux-gnu-strip target/${{ matrix.rust_arch }}-${{ matrix.rust_abi }}/release/viceroy${{ matrix.extension }}
- name: Strip symbols (non-linux)
if: ${{ matrix.name != 'linux' }}
run: |
strip target/${{ matrix.rust_arch }}-${{ matrix.rust_abi }}/release/viceroy${{ matrix.extension }}
- name: Package
run: |
cd target/${{ matrix.rust_arch }}-${{ matrix.rust_abi }}/release
tar czf viceroy_${{ steps.tagName.outputs.tag }}_${{ matrix.name }}-${{ matrix.arch }}.tar.gz viceroy${{ matrix.extension }}
- name: Release
id: release
uses: softprops/action-gh-release@v1
with:
draft: true
files: |
target/${{ matrix.rust_arch }}-${{ matrix.rust_abi }}/release/viceroy_${{ steps.tagName.outputs.tag }}_${{ matrix.name }}-${{ matrix.arch }}.tar.gz
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
publish:
needs: build
runs-on: ubuntu-24.04
steps:
- name: publish
uses: actions/github-script@v6
with:
script: |
github.rest.repos.updateRelease({
release_id: ${{ needs.build.outputs.draft_release_id }},
owner: context.repo.owner,
repo: context.repo.repo,
draft: false
})
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
publish-crates:
needs: build
runs-on: ubuntu-24.04
permissions:
id-token: write
contents: read
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: Install Rust
run: rustup show
- name: Authenticate with crates.io
uses: rust-lang/crates-io-auth-action@v1
id: auth
- name: Publish viceroy-lib
run: cargo publish -p viceroy-lib --locked
env:
CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}
- name: Publish viceroy
run: cargo publish -p viceroy --locked
env:
CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}
================================================
FILE: .github/workflows/rust.yml
================================================
name: Test Rust versions
on:
schedule:
- cron: "2 13 * * 1"
workflow_dispatch:
jobs:
test:
strategy:
matrix:
rust: [stable, beta, nightly]
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v5
with:
submodules: true
- name: Install Rust
run: rustup default ${{ matrix.rust }}
- run: make ci
================================================
FILE: .github/workflows/test.yml
================================================
name: Test
on: [pull_request]
env:
CACHE_GENERATION: 0
jobs:
test:
strategy:
matrix:
platform: [ubuntu-22.04, ubuntu-24.04, windows-2022, macos-14, macos-15]
runs-on: ${{ matrix.platform }}
env:
SCCACHE_GHA_ENABLED: "true"
RUSTC_WRAPPER: "sccache"
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
submodules: true
- name: Cache cargo
uses: actions/cache@v3
with:
path: |
~/.cargo/registry
key: ${{ matrix.platform }}-cargo-v${{ env.CACHE_GENERATION }}-${{ hashFiles('**/Cargo.lock') }}
- name: Run sccache-cache
uses: mozilla-actions/sccache-action@v0.0.9
- name: Check formatting
run: cargo fmt --all -- --check
shell: bash
- name: test
run: make ci
shell: bash
- name: adapter
run: cd wasm_abi/adapter && cargo build --release -p viceroy-component-adapter --target wasm32-unknown-unknown
# Run the trap test in an isolated job. It needs different cargo features than the usual build, so
# it entails rebuilding the whole workspace if we combine them in a single job. This way, we
# achieve some parallelism via Actions jobs.
trap-test:
strategy:
matrix:
platform: [ubuntu-22.04, ubuntu-24.04, windows-2022, macos-14, macos-15]
runs-on: ${{ matrix.platform }}
env:
SCCACHE_GHA_ENABLED: "true"
RUSTC_WRAPPER: "sccache"
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
submodules: true
- name: Cache cargo
uses: actions/cache@v3
with:
path: |
~/.cargo/registry
key: ${{ matrix.platform }}-cargo-trap-v${{ env.CACHE_GENERATION }}-${{ hashFiles('**/Cargo.lock') }}
- name: Run sccache-cache
uses: mozilla-actions/sccache-action@v0.0.9
- name: trap-test
run: make trap-test-ci
shell: bash
package-check:
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: Check crates can be published
run: cargo publish --dry-run --package=viceroy-lib
shell: bash
================================================
FILE: .gitignore
================================================
**/target/
publish
vendor/
verify-publishable/
.vscode
================================================
FILE: CHANGELOG.md
================================================
## Unreleased
- Rename 'session' to 'sandbox' since that is the preferred term in public documentation. ([#617](https://github.com/fastly/Viceroy/pull/617))
- Add support for "WebSockets passthrough" ([#621](https://github.com/fastly/Viceroy/pull/621))
- Provide extra context in error messages for backend connection failures ([#613](https://github.com/fastly/Viceroy/pull/613))
## 0.17.0 (2026-04-27)
- Add stub implementations for resvpnproxy hostcalls. ([#596](https://github.com/fastly/Viceroy/pull/596))
- Add `fake_valid_fastly_keys` config parameter to allow testing `fastly_key_is_valid` hostcall with fake valid keys. ([#599](https://github.com/fastly/Viceroy/pull/599))
- Add `health` config parameter for backends to mock backend health status in testing. ([#605](https://github.com/fastly/Viceroy/pulls/606))
- Use `cargo clippy` to lint code in CI. ([#603](https://github.com/fastly/Viceroy/pull/603))
- Rename `Error::InvalidAlpnRepsonse` to correct a typo ([#612](https://github.com/fastly/Viceroy/pull/612))
- Upgrade to Rust 1.95 ([#604](https://github.com/fastly/Viceroy/pull/604))
- Add options for experimenting with wasm gc and exceptions. ([#601](https://github.com/fastly/Viceroy/pull/601))
- Improve TLS certificate loading, handling and validation ([#478](https://github.com/fastly/Viceroy/pull/478))
## 0.16.5 (2026-03-23)
- Remove most adapter-only interfaces from the Viceroy component adapter. ([#583](https://github.com/fastly/Viceroy/pull/583))
- Add support for "library" components which don't export `http_incoming`. ([#529](https://github.com/fastly/Viceroy/pull/529))
- Add non-shift adapter when user module is using wit-bindgen. ([#582](https://github.com/fastly/Viceroy/pull/582))
- Update to Wasmtime 39 ([#584](https://github.com/fastly/Viceroy/pull/584))
- Remove unused WIT files from the source tree. ([#580](https://github.com/fastly/Viceroy/pull/580))
- Refactor the CLI, with each subcommand in its own file. ([#581](https://github.com/fastly/Viceroy/pull/581))
- Make "viceroy adapt" add "produced-by" metadata to its output. ([#586](https://github.com/fastly/Viceroy/pull/586))
- Update to Rust 2024 Edition. ([#588](https://github.com/fastly/Viceroy/pull/588))
- Add stub implementations for bot detection hostcalls. ([#592](https://github.com/fastly/Viceroy/pull/592))
- Add no-op implementations for stale-if-error hostcalls ([#591](https://github.com/fastly/Viceroy/pull/591))
- Guest profiling support added for components. ([#593](https://github.com/fastly/Viceroy/pull/593))
- Add `manifest_version` validation to fastly.toml parsing. ([#590](https://github.com/fastly/Viceroy/pull/590))
## 0.16.4 (2026-01-26)
- Update to the latest WITs (0.1.0—no more "prerelease") and adapter. ([#574](https://github.com/fastly/Viceroy/pull/574))
## 0.16.3 (2026-01-20)
- Implement `fastly_compute_runtime::get_heap_mib` hostcall ([#572](https://github.com/fastly/Viceroy/pull/572))
- Update to latest `moka` release to fix use-after-free bug ([#569](https://github.com/fastly/Viceroy/pull/569))
- Fix manual framing headers logic to avoid falling back to automatic framing headers ([#571](https://github.com/fastly/Viceroy/pull/571))
## 0.16.2 (2025-12-10)
- Update to the latest WITs and adapter. ([#564](https://github.com/fastly/Viceroy/pull/564))
This applies version "0.0.0-prerelease.0" to wasm_abi/wit/deps/fastly/compute.wit.
As a prerelease, this version is not guaranteed to be supported long-term, however
from this point forward, changes will be described by version number bumps.
- fix: use original static backend host ([#549](https://github.com/fastly/Viceroy/pull/549))
- Return InvalidArgument for bad arguments to register_dynamic_backend ([#563](https://github.com/fastly/Viceroy/pull/563))
## 0.16.1 (2025-11-25)
- Fix off-by-one error in reusable sandboxes limit ([#561](https://github.com/fastly/Viceroy/pull/561))
- Add stubs for new dynamic backend config options ([#560](https://github.com/fastly/Viceroy/pull/560))
- Fix yaml syntax in rust.yml ([#559](https://github.com/fastly/Viceroy/pull/559))
- Add a CI script to test different Rust versions ([#556](https://github.com/fastly/Viceroy/pull/556))
- Return `InvalidArgument` for non-103 1xx status codes ([#557](https://github.com/fastly/Viceroy/pull/557))
- Fix test for 103 Early Hints ([#558](https://github.com/fastly/Viceroy/pull/558))
## 0.16.0 (2025-11-10)
- Add rudimentary support for 103 responses ([#550](https://github.com/fastly/Viceroy/pull/550))
- Add support for manual HTTP framing headers ([#551](https://github.com/fastly/Viceroy/pull/551))
- Core cache: Only return `FOUND` if the object is not expired ([#552](https://github.com/fastly/Viceroy/pull/552))
## 0.15.0 (2025-10-27)
- fix: don't throw error when exit code is 0 ([#537](https://github.com/fastly/Viceroy/pull/537))
- Update adapter with the memory shift fix ([#538](https://github.com/fastly/Viceroy/pull/538))
- Enable relaxed-simd-deterministic for Viceroy. ([#539](https://github.com/fastly/Viceroy/pull/539))
- Return 5XX for requests that land in a reused session that crashes ([#540](https://github.com/fastly/Viceroy/pull/540))
- Update to the latest WITs and adapter. ([#543](https://github.com/fastly/Viceroy/pull/543))
- Allow components to have multiple memories. ([#545](https://github.com/fastly/Viceroy/pull/545))
## 0.14.4 (2025-10-01)
- Enable loading Secret Store configuration through environment variables ([#527](https://github.com/fastly/Viceroy/pull/527))
- Remove deprecated `macos-13` runners from CI matrix ([#528](https://github.com/fastly/Viceroy/pull/528))
- Remove now-unneeded adapter profiles from the top-level Cargo.toml. ([#530](https://github.com/fastly/Viceroy/pull/530))
- Fix double borrows in `get_with_by_ref()` calls ([#532](https://github.com/fastly/Viceroy/pull/532))
- Fix warnings due to SDK deprecations ([#532](https://github.com/fastly/Viceroy/pull/532))
- Update references of `wasm32-wasi` to `wasm32-wasip1` in README ([#533](https://github.com/fastly/Viceroy/pull/533))
## 0.14.3 (2025-09-17)
- Upgrade to wasmtime v35 ([#513](https://github.com/fastly/Viceroy/pull/513))
- Fix implementation of `downstream_compliance_region` hostcall ([#519](https://github.com/fastly/Viceroy/pull/519))
- Fix warnings due to `mismatched_lifetime_syntaxes` lint in Rust 1.89 ([#522](https://github.com/fastly/Viceroy/pull/522))
- Enable tracing in WIT bindings ([#521](https://github.com/fastly/Viceroy/pull/521))
- Support overriding client IP with `inspect` hostcall ([#523](https://github.com/fastly/Viceroy/pull/523))
- Add stub for `downstream_client_tls_servername` hostcall ([#524](https://github.com/fastly/Viceroy/pull/524))
## 0.14.2 (2025-08-12)
- Upgrade to wasmtime v28
## 0.14.1 (2025-08-08)
- Fix Cargo.lock file to allow publication on crates.io
## 0.14.0 (2025-08-08)
- Fix for shielding support ([#503](https://github.com/fastly/Viceroy/pull/503))
Shielding support in 0.13.0 was, alas, slightly broken: the `toml` settings were
not passed through to the main library.
- Add support for integrating with a local Pushpin instance ([#497](https://github.com/fastly/Viceroy/pull/497))
Viceroy can be invoked with `--local-pushpin-proxy-port=<port>` to cause
requests that invoke the `fastly_http_req.redirect_to_grip_proxy` and `_v2`
hostcalls to be proxied through a local Pushpin instance running on the
specified port. This enables developers to locally test Fanout (real-time
messaging) features like HTTP streaming or WebSockets-over-HTTP.
Requests forwarded this way will be replayed:
- Method, headers, path, and query of the forwarded request will be based on
the request whose handle is passed to `redirect_to_grip_proxy_v2` (or from
the downstream request if `redirect_to_grip_proxy` was called).
- The request header `pushpin-route` will be added, its value set to the backend name.
- Request body of the forwarded request will contain the full body of the
downstream request.
This mechanism expects Pushpin to be configured with `accept_pushpin_route`
to be set to `true` and for its routes to be set up properly. This is
configured automatically if Viceroy is called through the Fastly CLI's
`fastly compute serve` command.
- Support the simple cache API ([#487](https://github.com/fastly/Viceroy/issues/487)) and core cache API
The [simple cache API](https://docs.rs/fastly/latest/fastly/cache/simple/index.html) is fully supported in Viceroy.
The [core cache API](https://docs.rs/fastly/latest/fastly/cache/core/index.html) is also supported, with the exception of the "replace" family of calls ([#495](https://github.com/fastly/Viceroy/issues/495)).
Both of these use an in-memory store for cached data; restarting Viceroy flushes the cache.
The HTTP cache layer (readthrough cache) is not supported at this time ([#496](https://github.com/fastly/Viceroy/issues/496)).
- Experimental support for reusable sessions
The default behavior for Viceroy (and Fastly Compute) is to launch a new WASM instance
for each inbound HTTP request.
This default behavior remains unchanged. However, this release adds experimental
hostcalls that allow a WASM instance to receive and respond to additional HTTP requests
after the first.
This is an experimental feature (not yet available through any SDK),
and requires an opt-in (using the new hostcalls).
Fastly may modify or remove this feature in the future- don't rely on it (yet)!
- Make `SecretStore` public ([#486](https://github.com/fastly/Viceroy/pull/486))
Make the `SecretStore` type public, so it can be configured in integration tests that use `viceroy-lib`.
## 0.13.0 (2025-04-25)
- Add support for shielding primitives in Viceroy ([#455](https://github.com/fastly/Viceroy/pull/455))
Shielding definitions can be creating inside `fastly.toml` using the
`local-server.shielding_sites` key. These definitions are just a normal TOML
dictionary mapping shield sites (e.g., "pdx-or-us", "bfi-wa-us", etc.) to
either the string "Local" (meaning that Viceroy should pretend to be operating
in that POP), or a dictionary mapping "unencrypted" and "encrypted" to target
URLs (to mimic operating off the shield POP). For example:
```
[local_server.shielding_sites]
"pdx-or-us" = "Local"
"bfi-wa-us".unencrypted = "http://localhost"
"bfi-wa-us".encrypted = "https://localhost"
```
This snippet defines two shield POPs: "pdx-or-us", which Viceroy should
pretend to be running on, and "bfi-wa-us", which is remote. If the guest
program asks for a backend to "bfi-wa-us", Viceroy will use `localhost`
as the target server, using HTTPS for encrypted traffic and HTTP for
unencrypted traffic.
## 0.12.4 (2025-04-07)
- Add support for `file` entries in KV Stores defined using "file"/"format" ([#463](https://github.com/fastly/Viceroy/pull/463))
## 0.12.3 (2025-03-28)
- Add `downstream_client_ddos_detected` hostcall stub ([#460](https://github.com/fastly/Viceroy/pull/460))
- Add support for metadata in local_server.kv_stores ([#459](https://github.com/fastly/Viceroy/pull/459))
- Add support for the Image Optimizer hostcalls ([#458](https://github.com/fastly/Viceroy/pull/458))
- Guest Profile sample period configuration support ([#456](https://github.com/fastly/Viceroy/pull/456))
- Fix cache key type in component interface ([#453](https://github.com/fastly/Viceroy/pull/453))
- Remove ubuntu-20.04 from CI ([#451](https://github.com/fastly/Viceroy/pull/451))
- Allow environment variable tests to pass based on validity, rather than their value ([#450](https://github.com/fastly/Viceroy/pull/450))
- Add `FASTLY_IS_STAGING` environment variable ([#449](https://github.com/fastly/Viceroy/pull/449))
- Update KV Store key naming restrictions ([#447](https://github.com/fastly/Viceroy/pull/447))
- Fixes to CI ([#448](https://github.com/fastly/Viceroy/pull/448))
- Update to 0.11.1 of the Fastly Rust SDK ([#445](https://github.com/fastly/Viceroy/pull/445))
- Update CI to remove tests for macOS 12 and add tests for macOS 15 ([#436](https://github.com/fastly/Viceroy/pull/436))
## 0.12.2 (2024-12-02)
- Add support for the `on_behalf_of` hostcalls ([#440](https://github.com/fastly/Viceroy/pull/440))
- Add new `lookup_wait_v2` to fix generation parsing bug ([#439](https://github.com/fastly/Viceroy/pull/439))
- Add `fastly_acl` hostcalls ([#438](https://github.com/fastly/Viceroy/pull/438))
## 0.12.1 (2024-10-04)
- Stub new HTTP cache hostcalls ([#433](https://github.com/fastly/Viceroy/pull/433))
- Add support for reading secrets from a JSON file ([#428](https://github.com/fastly/Viceroy/pull/428))
- Added hostcalls for the new builder api hostcalls ([#427](https://github.com/fastly/Viceroy/pull/427))
## 0.12.0 (2024-09-03)
- Add ReplaceHandle hostcall stubs for upcoming SDK release ([#424](https://github.com/fastly/Viceroy/pull/424))
- Add keepalive options for dynamic backends ([#423](https://github.com/fastly/Viceroy/pull/423))
- Fix bug in `inspect` implementation and add a test ([#422](https://github.com/fastly/Viceroy/pull/422))
- Add the missing adapter calls for new cache operations ([#419](https://github.com/fastly/Viceroy/pull/419))
- Implement component traits on ComponentCtx ([#421](https://github.com/fastly/Viceroy/pull/421))
- Split info spans when logging request IDs ([#420](https://github.com/fastly/Viceroy/pull/420))
- Rename the kv-store interface to object-store in compute.wit ([#415](https://github.com/fastly/Viceroy/pull/415))
## 0.11.0 (2024-08-20)
- Add support for JSON files in `local_server.kv_stores` ([#365](https://github.com/fastly/Viceroy/pull/365))
- Add `get_vcpu_ms` hostcall ([#412](https://github.com/fastly/Viceroy/pull/412))
- Add `inspect` hostcall ([#417](https://github.com/fastly/Viceroy/pull/417))
- Add `downstream_compliance_region` hostcall ([#403](https://github.com/fastly/Viceroy/pull/403))
- Emit the status code for responses, in addition to other stats ([#416](https://github.com/fastly/Viceroy/pull/416))
- Update `compute.wit` and the adapter for some api fixes ([#414](https://github.com/fastly/Viceroy/pull/414))
- Use `mozilla-actions/sccache-action` for caching builds ([#411](https://github.com/fastly/Viceroy/pull/411))
## 0.10.2 (2024-07-22)
- Add support for supplying client certificates in fastly.toml, through the use of the
`client_cert_info` table, which must have one of a "certificate" or "certificate_file"
key, as well as one of a "key" and "key_file" key. The "_file" variants can be used to
point to certificate/key files on disk, whereas the non-"_file" variants should be
multi-line string constants in the toml. In all cases, they should be in PEM format.
- Restore compatibility with older glibc versions in release artifacts
## 0.10.1 (2024-07-11)
- Revert a CI configuration change that inadvertently prevented builds being created for amd64 macOS endpoints ([#405](https://github.com/fastly/Viceroy/pull/405))
## 0.10.0 (2024-07-09)
- Add `get_addr_dest_{ip,port}` hostcalls ([#402](https://github.com/fastly/Viceroy/pull/402))
- Add `downstream_server_ip_addr` hostcall ([#401](https://github.com/fastly/Viceroy/pull/401))
- Support `wat` files when adapting core wasm ([#399](https://github.com/fastly/Viceroy/pull/399))
- Add support for environment variables in the adapter ([#400](https://github.com/fastly/Viceroy/pull/400))
- Run tests as components ([#396](https://github.com/fastly/Viceroy/pull/396))
- Remove some unused memory management code in the adapter ([#398](https://github.com/fastly/Viceroy/pull/398))
- Allow capturing logging endpoint messages ([#397](https://github.com/fastly/Viceroy/pull/397))
- Support cli args in the adapter ([#394](https://github.com/fastly/Viceroy/pull/394))
- Rework component testing support to make test updates easier ([#395](https://github.com/fastly/Viceroy/pull/395))
- Populate the guest cli args ([#393](https://github.com/fastly/Viceroy/pull/393))
- Update to wasmtime 22.0.0 ([#392](https://github.com/fastly/Viceroy/pull/392))
- Populate `nwritten_out` when errors occur in config-store::get or dictionary::get ([#389](https://github.com/fastly/Viceroy/pull/389))
- Switch to using the on-demand allocator, instead of the pooling allocator ([#391](https://github.com/fastly/Viceroy/pull/391))
- Explicitly test the dictionary host calls in the dictionary fixture ([#390](https://github.com/fastly/Viceroy/pull/390))
- Enable the config-store-lookup tests ([#387](https://github.com/fastly/Viceroy/pull/387))
- Run the `request` tests as a component ([#386](https://github.com/fastly/Viceroy/pull/386))
- Update Ubuntu and macOS runners to latest (and non-EOL) versions ([#388](https://github.com/fastly/Viceroy/pull/388))
- Fix trap handling when running components ([#382](https://github.com/fastly/Viceroy/pull/382))
- fix(wiggle_abi): write the result's length, not the guest buffer's ([#385](https://github.com/fastly/Viceroy/pull/385))
- Add adaptive buffer support for geo + device detection lookups ([#383](https://github.com/fastly/Viceroy/pull/383))
- Fix buffer-len handling in the component adapter ([#381](https://github.com/fastly/Viceroy/pull/381))
- Switch to reading dictionaries during the `fastly_dictionary_open` call ([#379](https://github.com/fastly/Viceroy/pull/379))
- Support adapting core wasm to components ([#374](https://github.com/fastly/Viceroy/pull/374))
## 0.9.7 (2024-05-24)
- Update to wasmtime-21.0.0 ([#369](https://github.com/fastly/Viceroy/pull/369))
- Initial WebAssembly component support ([#367](https://github.com/fastly/Viceroy/pull/367))
- Add stubs for new busy-handle hostcalls ([#373](https://github.com/fastly/Viceroy/pull/373))
## 0.9.6 (2024-04-08)
- Return a ValueAbsent for all the downstream-tls related functions instead of a NotAvailable ([#315](https://github.com/fastly/Viceroy/pull/315))
## 0.9.5 (2024-03-15)
- Bug fix: Honor CA certificates when they are supplied, either as part of a dynamic backend
definition or as part of a backend defined in fastly.toml. (In the latter case, CA certificates
can be added using the "ca_certificate" key.) ([#305](https://github.com/fastly/Viceroy/pull/305))
- Consistently use Error::NotAvailable instead of Unsupported ([#349](https://github.com/fastly/Viceroy/pull/349))
## 0.9.4 (2024-02-22)
- Added `delete_async` hostcall for KV stores ([#332](https://github.com/fastly/Viceroy/pull/332))
- Added `known_length` hostcall for body handles ([#344](https://github.com/fastly/Viceroy/pull/344))
- Added stubs for new functionality available in production Compute ([#333](https://github.com/fastly/Viceroy/pull/333), [#337](https://github.com/fastly/Viceroy/pull/337), [#344](https://github.com/fastly/Viceroy/pull/344))
- Fixed inconsistent behavior for not-found geolocation lookups compared to production Compute ([#341](https://github.com/fastly/Viceroy/pull/341))
## 0.9.3 (2023-11-09)
- Renamed Compute@Edge to Compute. ([#328](https://github.com/fastly/Viceroy/pull/328))
- Added asynchronous versions of the KV store `lookup` and `insert` operations. ([#329](https://github.com/fastly/Viceroy/pull/329))
- Added support for device detection. ([#330](https://github.com/fastly/Viceroy/pull/330))
## 0.9.2 (2023-10-23)
- Warn instead of fail when certificates can't be loaded ([#325](https://github.com/fastly/Viceroy/pull/325))
- Add support for trailers. Trailer modification calls should be considered experimental,
as we finalize interfaces ([#327](https://github.com/fastly/Viceroy/pull/327))
## 0.9.1 (2023-10-09)
- Match the number of memories to the number of core instances ([#322](https://github.com/fastly/Viceroy/pull/322))
## 0.9.0 (2023-10-09)
- Add options to customize behavior of unknown Wasm imports ([#313](https://github.com/fastly/Viceroy/pull/313))
- Lower Hostcall error log level to DEBUG ([#314](https://github.com/fastly/Viceroy/pull/314))
- Add perfmap profiling strategy ([#316](https://github.com/fastly/Viceroy/pull/316))
- Update to wasmtime-13.0.0 ([#317](https://github.com/fastly/Viceroy/pull/317))
- Revamp profile handling CLI flags ([#318](https://github.com/fastly/Viceroy/pull/318))
## 0.8.1 (2023-09-18)
- Fix a bug in which static backends were marked as GRPC by default ([#311](https://github.com/fastly/Viceroy/pull/311))
## 0.8.0 (2023-09-15)
- Make `viceroy_lib::Error` non-exhaustive
- Support the gRPC flag for dynamic backends ([#308](https://github.com/fastly/Viceroy/pull/308))
- Update ABI definitions and stub out some hostcalls ([#307](https://github.com/fastly/Viceroy/pull/307))
## 0.7.0 (2023-08-14)
- Add --profile-guest support to serve mode. ([#301](https://github.com/fastly/Viceroy/pull/301))
- Use a ResourceLimiter for tracking allocations. ([#300](https://github.com/fastly/Viceroy/pull/300))
- Support the new mTLS features for dynamic backends, allowing two-way authentication for backend connections. ([#297](https://github.com/fastly/Viceroy/pull/297))
## 0.6.1 (2023-08-03)
- Support the new config store hostcalls. ([#296](https://github.com/fastly/Viceroy/pull/296))
- Bump to wasmtime-11.0.1 ([#295](https://github.com/fastly/Viceroy/pull/295))
- Unblock Secret::from_bytes test by upgrading the fastly crate dependency. ([#294](https://github.com/fastly/Viceroy/pull/294))
- Map Error::UnknownBackend to FastlyStatus::Inval ([#293](https://github.com/fastly/Viceroy/pull/293))
- When an upstream body is unexpectedly closed, return Httpincomplete ([#290](https://github.com/fastly/Viceroy/pull/290))
- Error::ValueAbsent should map to FastlyStatus::None, not Inval ([#291](https://github.com/fastly/Viceroy/pull/280))
- Switch default log level to "error", add -v to run ([#288](https://github.com/fastly/Viceroy/pull/288))
- Update rustls and various dependencies ([#278](https://github.com/fastly/Viceroy/pull/278))
- Change default port from 7878 to 7676, which is what the Fastly CLI defaults to ([#287](https://github.com/fastly/Viceroy/pull/287))
## 0.6.0 (2023-07-12)
- ⏱️ Add cross-platform ability to profile guest code in run mode ([#280](https://github.com/fastly/Viceroy/pull/280))
- pin to hyper 0.14.26 for the time being ([#285](https://github.com/fastly/Viceroy/pull/285))
- 😯 Add support for the new secret from_bytes extension. ([#283](https://github.com/fastly/Viceroy/pull/283))
- feat: Add a stub for downstream_client_h2_fingerprint ([#277](https://github.com/fastly/Viceroy/pull/277))
- Fill downstream_client_request_id in ([#282](https://github.com/fastly/Viceroy/pull/282))
- Bump to wasmtime-10.0.0 ([#279](https://github.com/fastly/Viceroy/pull/279))
- Add a stub for downstream_client_request_id ([#276](https://github.com/fastly/Viceroy/pull/276))
- Fix various warnings ([#271](https://github.com/fastly/Viceroy/pull/271))
- ⛽ -> ⏲️ Switch from fuel to epoch interruptions. ([#273](https://github.com/fastly/Viceroy/pull/273))
- Bump wasmtime dependencies to 9.0.1 ([#272](https://github.com/fastly/Viceroy/pull/272))
- ⏩ none should not be defined in cache_override_tag witx ([#269](https://github.com/fastly/Viceroy/pull/269))
- in single run mode, keep the response receiver alive during execution ([#270](https://github.com/fastly/Viceroy/pull/270))
- Return appropriate exit code in run-mode, rather than just 0 or 1 ([#224](https://github.com/fastly/Viceroy/pull/224))
## 0.5.1 (2023-05-17)
- Update crates and add http_keepalive_mode_set ([#266](https://github.com/fastly/Viceroy/pull/266))
## 0.5.0 (2023-05-11)
- 🚧 Add stubs for Cache API primitives ([#260](https://github.com/fastly/Viceroy/pull/260))
- Make is_healthy always return Unknown instead of an unsupporte…
- 🕷️ Rework integration tests to allow parallel test execution ([#257](https://github.com/fastly/Viceroy/pull/257))
- Add KVStore async lookup ([#253](https://github.com/fastly/Viceroy/pull/253))
- Update to Wasmtime 8 ([#251](https://github.com/fastly/Viceroy/pull/251))
- Add documentation explaining how to run rust unit tests w/ viceroy ([#242](https://github.com/fastly/Viceroy/pull/242))
## 0.4.5 (2023-04-13)
- Remove validation on config store and dictionary names ([#248](https://github.com/fastly/Viceroy/pull/248))
## 0.4.4 (2023-04-11)
- feat: Allow local KV Stores to be defined using `[local_server.kv_stores]` ([#245](https://github.com/fastly/Viceroy/pull/245))
## 0.4.3 (2023-04-04)
- Add the `fastly_backend` module to the wiggle abi ([#243](https://github.com/fastly/Viceroy/pull/243))
## 0.4.2 (2023-03-30)
- Allow config-stores to be defined using `[local_server.config_stores]` ([#240](https://github.com/fastly/Viceroy/pull/240))
## 0.4.1 (2023-03-23)
- Add `fastly_backend` interfaces for backend introspection ([#236](https://github.com/fastly/Viceroy/pull/236))
## 0.4.0 (2023-03-17)
- Add a run-mode that executes the input program once and then exits ([#211](https://github.com/fastly/Viceroy/pull/211))
- Update to Wasmtime 6.0.0 ([#226](https://github.com/fastly/Viceroy/pull/226))
- Make object and secret store config names consistent ([#206](https://github.com/fastly/Viceroy/pull/206))
- Remove dictionary count limit ([#227](https://github.com/fastly/Viceroy/pull/227))
- Split out run-mode and serve mode into subcommands ([#229](https://github.com/fastly/Viceroy/pull/229))
## 0.3.5 (2023-01-20)
- Add support for Secret Store ([#210](https://github.com/fastly/Viceroy/pull/210))
## 0.3.4 (2023-01-19)
- Update to Wasmtime 4.0.0
([#217](https://github.com/fastly/Viceroy/pull/217))
- Set fixed release build images to improve compatibility of precompiled release artifacts
([#216](https://github.com/fastly/Viceroy/pull/216))
## 0.3.3 (2023-01-18)
- Support the streaming body `finish()` method introduced in version 0.9.0 of the Rust SDK
([#203](https://github.com/fastly/Viceroy/pull/203))
- Update to wasmtime 3.0.0 and enable experimental wasi-nn interface
([#209](https://github.com/fastly/Viceroy/pull/209))
## 0.3.2 (2022-11-17)
- Add geolocation implementation to Viceroy
([#165](https://github.com/fastly/Viceroy/pull/165))
- Implement async select hostcalls for Viceroy
([#188](https://github.com/fastly/Viceroy/pull/188))
- Update wasmtime dependency to 2.0
([#194](https://github.com/fastly/Viceroy/pull/194))
- Return a FastlyStatus::Inval when opening a non-existant object-store
([#196](https://github.com/fastly/Viceroy/pull/196))
- Add limit exceeded variant to fastly_status witx definition
([#199](https://github.com/fastly/Viceroy/pull/199))
## 0.3.1 (2022-10-11)
- Add stubs for fastly purge
([#184](https://github.com/fastly/Viceroy/pull/184))
- Add stubs for mTLS information
([#186](https://github.com/fastly/Viceroy/pull/186))
- Allow to enable wasmtime's profiling support
([#181](https://github.com/fastly/Viceroy/pull/181))
- Add stubs for `redirect_to_`
([#187](https://github.com/fastly/Viceroy/pull/187))
## 0.3.0 (2022-10-11)
- Tagged but not released due to invalid metadata added in
[#173](https://github.com/fastly/Viceroy/pull/189). See
[#189](https://github.com/fastly/Viceroy/pull/189) for more details
## 0.2.15 (2022-08-19)
- Add support for `ObjectStore`
([#167](https://github.com/fastly/Viceroy/pull/167))
- Add support for dynamic backends
([#163](https://github.com/fastly/Viceroy/pull/163))
- Extend backend TLS configuration with cert host and SNI
([#168](https://github.com/fastly/Viceroy/pull/168))
## 0.2.14 (2022-05-23)
- Add support for inline TOML dictionaries ([#150](https://github.com/fastly/Viceroy/pull/150))
## 0.2.13 (2022-05-03)
- Add stubs for JA3 hashes and WebSocket upgrades ([#153](https://github.com/fastly/Viceroy/pull/153))
## 0.2.12 (2022-03-08)
- Add stubs for framing header controls, now available on Compute ([#139](https://github.com/fastly/Viceroy/pull/139))
## 0.2.11 (2022-02-15)
- Implement automatic decompression of gzip backend responses ([#125](https://github.com/fastly/Viceroy/pull/125))
- Remove excess logging for programs that exit with a zero exit code ([#128](https://github.com/fastly/Viceroy/pull/128))
## 0.2.10 (2022-02-08)
- Add telemetry for wall-clock duration ([#121](https://github.com/fastly/Viceroy/pull/121))
- Bump various runtime limits ([#123](https://github.com/fastly/Viceroy/pull/123))
## 0.2.9 (2022-01-11)
- Do not panic when `auto_decompress_response_set` is called ([#116](https://github.com/fastly/Viceroy/pull/116))
## 0.2.8 (2022-01-07)
- Allow partial CA store to be loaded ([#104](https://github.com/fastly/Viceroy/pull/104))
- Update ABI and stub out new function ([#113](https://github.com/fastly/Viceroy/pull/104))
## 0.2.7 (2021-12-01)
- Disable ALPN by using rustls more directly ([#100](https://github.com/fastly/Viceroy/pull/100))
## 0.2.6 (2021-11-15)
- Catch interrupt signals ([#85](https://github.com/fastly/Viceroy/pull/85))
- Include aarch64 tarballs for Linux and macOS ([#88](https://github.com/fastly/Viceroy/pull/88))
- Align URI and Host header semantics with production Compute ([#90](https://github.com/fastly/Viceroy/pull/90))
## 0.2.5 (2021-10-21)
- Replaced `hyper-tls` with `hyper-rustls`. ([#75](https://github.com/fastly/Viceroy/pull/75))
- Unknown dictionary items are now logged at debug level. ([#80](https://github.com/fastly/Viceroy/pull/80))
- Windows releases are now built in CI. ([#82](https://github.com/fastly/Viceroy/pull/82))
## 0.2.4 (2021-09-08)
- Improved error messages when a file could not be read. ([#70](https://github.com/fastly/Viceroy/pull/70))
- Fixed a bug for dictionary lookups that returned and error rather than `None`. ([#69](https://github.com/fastly/Viceroy/pull/69))
## 0.2.3 (2021-08-23)
### Additions
- Added the close functionality for `RequestHandle`, `ResponseHandle`,
`BodyHandle`, and `StreamingBodyHandle` in the upcoming Rust Compute `0.8.0` SDK
release ([#65](https://github.com/fastly/Viceroy/pull/65))
- Added local dictionary support so that Compute programs that need dictionaries can work in Viceroy ([#61](https://github.com/fastly/Viceroy/pull/61))
- Added the ability to do host overrides from the TOML configuration ([#48](https://github.com/fastly/Viceroy/pull/48))
### Changes
- Viceroy now tracks the latest stable Rust which as of this release is 1.54.0
## 0.2.2 (2021-07-15)
### Enhancements
- Renamed `viceroy-cli` package to `viceroy`, in preparation for `cargo install viceroy` ([#41](https://github.com/fastly/Viceroy/pull/41)).
- Improved UI for traces and errors ([#37](https://github.com/fastly/Viceroy/pull/37)).
- Increase limit on functions per wasm module ([#33](https://github.com/fastly/Viceroy/pull/33)).
- Be more flexible with wasm module input, allowing for WAT input as well ([#32](https://github.com/fastly/Viceroy/pull/32)).
### Fixes
- Correctly pull in wasi tokio bindings ([#44](https://github.com/fastly/Viceroy/pull/44)).
- Correct `--help` output for `--addr` ([#34](https://github.com/fastly/Viceroy/pull/34)).
## 0.2.1 (2021-07-12)
### Fixes
- Changed release artifacts naming format.
## 0.2.0 (2021-07-09)
- Initial release.
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, caste, color, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
[oss@fastly.com](mailto:oss@fastly.com).
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
[https://www.contributor-covenant.org/version/2/0/code_of_conduct.html][v2.0].
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available
at [https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.0]: https://www.contributor-covenant.org/version/2/0/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to Viceroy
First off thank you for wanting to contribute to making Viceroy better! We
appreciate you taking time to improve the Compute experience for developers
everywhere. There are many ways you can contribute that include but aren't
limited to documentation, opening issues, issue triage, and code contributions.
We'll cover some of the ways you can contribute below, but if you don't see
instructions for what you want to do, open up an issue and ask us!
## Table of Contents
1. Documentation
1. Feature Requests
1. Bugs
1. Issue Triage
1. Code Contributions
## Documentation
Was something in our documentation unclear? Does something have no documentation,
but should? This is a perfect way to make an easy contribution to Viceroy. If
you're not sure what the documentation should contain, please open up an issue!
We're happy to guide you with the correct information needed or if you already
know what needs to be done, open up a PR and we'll review it for you before
merging your changes.
## Feature Requests
Do you think there's something Viceroy should have that would make the
experience better? Feature requests are a great way to let us know. Before
opening up a feature request on the issue tracker first make sure that there is
no currently open issue asking for the same thing. If there's not, open up an
issue asking for what you want and the motivation behind the change.
## Bugs
Sometimes you run into issues and the code is not working properly. If you do
run into a bug and you can't figure it out or if you do figure out the bug, open
up an issue on the issue tracker. Just make sure it's not already an issue that
has been filed yet. If you do open up an issue let us know what you expected to
happen, what actually happened, what your operating system is, as well as a case
we can use to reproduce the issue if you have one!
## Issue Triage
Sometimes issues get stale and are no longer an issue, need to be updated, or
have been fixed by a PR and were never closed. While we try to stay on top of
issues and keep the backlog groomed, we are only human and can miss out on
things. If you find that an issue can be closed,
## Code Contributions
If you want to contribute code to Viceroy thank you! A few things before you do
get started adding a change and open up a PR
1. Make sure there's a tracking issue for your code change. We don't want you to
do a lot of work only for us to reject the PR because it's a feature change
we won't accept for instance.
1. Before opening your PR make sure you have tests and things working locally.
You can run `make ci` in order to run the tests we run on CI which includes
the test suite, `clippy`, and a `cargo fmt` check
It also helps to understand how we structure Viceroy. Under `cli` is the code
related to setting up and running the Viceroy CLI tool. This includes things
like argument parsing, setting up logging, and reading in options. It's fairly
small on purpose as most of the actual logic that runs Viceroy is found under
`lib`. This contains all the logic for how Viceroy works. You'll most likely
make changes here to fix an issue or add functionality!
Thanks again for contributing to Viceroy. We really do appreciate you wanting to
help out and make it better!
================================================
FILE: Cargo.toml
================================================
[package]
name = "viceroy-lib"
version = "0.17.1"
description = "Viceroy implementation details."
authors = ["Fastly"]
edition = "2024"
license = "Apache-2.0 WITH LLVM-exception"
documentation = "https://docs.rs/viceroy-lib"
homepage = "https://github.com/fastly/Viceroy"
repository = "https://github.com/fastly/Viceroy"
keywords = ["wasm", "fastly"]
categories = [
"development-tools",
"network-programming",
"simulation",
"wasm"
]
include = [
"CHANGELOG.md",
"SECURITY.md",
"src/**/*",
"wasm_abi/wit/**/*",
"wasm_abi/compute-at-edge-abi/**/*.witx",
"wasm_abi/data/*.wasm",
]
rust-version = "1.95"
[dependencies]
anyhow = { workspace = true }
async-trait = "0.1.59"
bytes = "^1.2.1"
bytesize = "^1.1.0"
cfg-if = "^1.0"
clap = { workspace = true }
cranelift-entity = "^0.123.0"
fastly-shared = "^0.11.5"
flate2 = "^1.0.24"
futures = { workspace = true }
http = "^0.2.8"
http-body = "^0.4.5"
hyper = { workspace = true }
itertools = { workspace = true }
lazy_static = "^1.4.0"
pin-project = { workspace = true }
regex = "^1.3.9"
rustls = "^0.21.1"
rustls-native-certs = "^0.6.3"
rustls-pemfile = "^1.0.3"
serde = "^1.0.145"
serde_derive = "^1.0.114"
serde_json = { workspace = true }
thiserror = "^1.0.37"
tokio = { workspace = true }
tokio-rustls = "^0.24.1"
toml = "^0.5.9"
tracing = { workspace = true }
tracing-futures = { workspace = true }
url = { workspace = true }
wasmparser = { workspace = true }
wasm-encoder = { workspace = true }
# Disable the "serde" feature which we don't need.
wasm-metadata = { version = "0.244.0", default-features = false }
wit-component = { workspace = true }
wasmtime = { workspace = true }
wasmtime-wasi = { workspace = true }
wasmtime-wasi-io = { workspace = true }
wasmtime-wasi-nn = { workspace = true }
wat = { workspace = true }
wiggle = { workspace = true }
base64 = { workspace = true }
moka = { version = "0.12.12", features = ["future"] }
walrus = "0.23.3"
[dev-dependencies]
proptest = "1.6.0"
proptest-derive = "0.5.1"
tempfile = "3.6.0"
[features]
default = []
test-fatalerror-config = []
[workspace]
members = [
"cli",
]
resolver = "3"
# Exclude our integration test fixtures, which need to be compiled to wasm
# (managed by the Makefile)
exclude = [
"test-fixtures",
]
# Specify `cli` as the default workspace member to operate on. This means that
# commands like `cargo run` will run the CLI binary by default.
# See: https://doc.rust-lang.org/cargo/reference/workspaces.html#package-selection
default-members = [ "cli" ]
[profile.dev]
# Since some of the integration tests involve compiling Wasm, a little optimization goes a long way
# toward making the test suite not take forever
opt-level = 1
[workspace.dependencies]
anyhow = "1.0.31"
base64 = "0.21.2"
clap = { version = "^4.0.18", features = ["derive"] }
hyper = { version = "=0.14.26", features = ["full"] }
itertools = "0.10.5"
pin-project = "1.0.8"
rustls = { version = "0.21.5", features = ["dangerous_configuration"] }
rustls-pemfile = "1.0.3"
serde_json = "1.0.59"
tokio = { version = "1.49.0", features = ["full"] }
tokio-rustls = "0.24.1"
tracing = "0.1.37"
tracing-futures = "0.2.5"
futures = "0.3.24"
url = "2.3.1"
# Wasmtime dependencies
wasmtime = { version = "39.0.2", features = ["call-hook"] }
wasmtime-wasi = "39.0.2"
wasmtime-wasi-io = "39.0.2"
wasmtime-wasi-nn = "39.0.2"
wiggle = "39.0.2"
wat = "1.240.0"
wasmparser = "0.240.0"
wasm-encoder = { version = "0.240.0", features = ["wasmparser"] }
wit-component = "0.240.0"
================================================
FILE: Dockerfile
================================================
FROM ubuntu:bionic
ARG VICEROY_SRC=/Viceroy
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
build-essential \
curl \
git \
ca-certificates \
pkg-config \
libssl-dev
# Setting a consistent LD_LIBRARY_PATH across the entire environment prevents
# unnecessary Cargo rebuilds.
ENV LD_LIBRARY_PATH=/usr/local/lib
# Install Rust, rustfmt, and the wasm32-wasi cross-compilation target
RUN curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain stable -y
ENV PATH=/root/.cargo/bin:$PATH
WORKDIR $VICEROY_SRC
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
--- LLVM Exceptions to the Apache 2.0 License ----
As an exception, if, as a result of your compiling your source code, portions
of this Software are embedded into an Object form of such source code, you
may redistribute such embedded portions in such Object form without complying
with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
In addition, if you combine or link compiled forms of this Software with
software that is licensed under the GPLv2 ("Combined Software") and if a
court of competent jurisdiction determines that the patent provision (Section
3), the indemnity provision (Section 9) or other Section of the License
conflicts with the conditions of the GPLv2, you may retroactively and
prospectively choose to deem waived or otherwise exclude such Section(s) of
the License, but only in their entirety and only with respect to the Combined
Software.
================================================
FILE: Makefile
================================================
# Default to using regular `cargo`. CI targets may override this.
VICEROY_CARGO=cargo
.PHONY: format
format: ## Apply standard formatting with `cargo fmt`.
$(VICEROY_CARGO) fmt
cd wasm_abi/adapter && $(VICEROY_CARGO) fmt
.PHONY: format-check
format-check: ## Check formatting, without updating.
$(VICEROY_CARGO) fmt -- --check
.PHONY: clippy
clippy: ## Ask for Clippy lints.
$(VICEROY_CARGO) clippy --all-targets --all-features -- -D warnings
.PHONY: test
test: test-crates trap-test ## Run all tests.
.PHONY: test-crates
test-crates: fix-build
RUST_BACKTRACE=1 $(VICEROY_CARGO) test --all
.PHONY: fix-build
fix-build:
cd test-fixtures && $(VICEROY_CARGO) build --target=wasm32-wasip1
.PHONY: trap-test
trap-test: fix-build
cd cli/tests/trap-test && RUST_BACKTRACE=1 $(VICEROY_CARGO) test fatal_error_traps -- --nocapture
# The `trap-test` is its own top-level target for CI in order to achieve better build parallelism.
.PHONY: trap-test-ci
trap-test-ci: VICEROY_CARGO=cargo --locked
trap-test-ci: trap-test
.PHONY: ci
ci: VICEROY_CARGO=cargo --locked
ci: format-check test-crates ## The main CI target; runs all tests except `trap-test`.
.PHONY: clean
clean: ## Clean up Cargo outputs and cache.
$(VICEROY_CARGO) clean
cd cli/tests/trap-test/ && $(VICEROY_CARGO) clean
.PHONY: doc
doc: ## Open the documentation for the workspace in a browser.
$(VICEROY_CARGO) doc --workspace --open
.PHONY: doc-dev
doc-dev: ## Open the documentation for the workspace in a browser, including private items. Useful for development.
$(VICEROY_CARGO) doc --no-deps --document-private-items --workspace --open
.PHONY: generate-lockfile
generate-lockfile: ## Run `cargo generate-lockfile` for all of the crates in the project, updating dependencies.
$(VICEROY_CARGO) generate-lockfile
$(VICEROY_CARGO) generate-lockfile --manifest-path=test-fixtures/Cargo.toml
$(VICEROY_CARGO) generate-lockfile --manifest-path=cli/tests/trap-test/Cargo.toml
# Regenerate the adapter, and move it into `wasm_abi/data`
.PHONY: build-adapter
build-adapter:
# Build the component adapter for adapting the host-call abi to the
# component model. This version uses `--no-default-features` to disable
# the default "exports" feature, to build the imports-only "library"
# version of the adapter.
( \
cd wasm_abi/adapter && \
cargo build \
--package viceroy-component-adapter \
--target wasm32-unknown-unknown \
--no-default-features \
--profile release-library \
)
# Build the non-shift "library" version of the adapter.
( \
cd wasm_abi/adapter && \
cargo build \
--package viceroy-component-adapter \
--target wasm32-unknown-unknown \
--no-default-features \
--profile release-library-noshift \
--features noshift \
)
# Build the component adapter for adapting the host-call abi to the
# component model. This is the normal version that includes the exports.
( \
cd wasm_abi/adapter && \
cargo build \
--package viceroy-component-adapter \
--target wasm32-unknown-unknown \
--release \
)
# Build the non-shift normal version of the adapter.
( \
cd wasm_abi/adapter && \
cargo build \
--package viceroy-component-adapter \
--target wasm32-unknown-unknown \
--profile release-noshift \
--features noshift \
)
cp wasm_abi/adapter/target/wasm32-unknown-unknown/release/viceroy_component_adapter.wasm \
wasm_abi/data/viceroy-component-adapter.wasm
cp wasm_abi/adapter/target/wasm32-unknown-unknown/release-noshift/viceroy_component_adapter.wasm \
wasm_abi/data/viceroy-component-adapter.noshift.wasm
cp wasm_abi/adapter/target/wasm32-unknown-unknown/release-library/viceroy_component_adapter.wasm \
wasm_abi/data/viceroy-component-adapter.library.wasm
cp wasm_abi/adapter/target/wasm32-unknown-unknown/release-library-noshift/viceroy_component_adapter.wasm \
wasm_abi/data/viceroy-component-adapter.library.noshift.wasm
.PHONY: help
help: ## Print help text for all documented commands. (Document with a ## comment.)
@grep -E '^[a-zA-Z_-]+:[^#]*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":[^#]*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
# Note that we don't sort; targets appear in the order they are in the file.
# So, put more important targets first (or is it last?)
================================================
FILE: README.md
================================================
# Viceroy
Viceroy provides local testing for developers working with Fastly Compute. It
allows you to run services written against the Compute APIs on your local
development machine, and allows you to configure testing backends for your
service to communicate with.
Viceroy is normally used through the [Fastly CLI's `fastly compute serve`
command][cli], where it is fully integrated into Compute workflows.
However, it is also a standalone open source tool with its own CLI and a
Rust library that can be embedded into your own testing infrastructure.
[cli]: https://developer.fastly.com/learning/compute/testing/#running-a-local-testing-server
## Installation
### Via the Fastly CLI
As mentioned above, most users of Compute should do local testing via the
Fastly CLI, rather than working with Viceroy directly. Any [CLI release] of
version 0.34 or above supports local testing, and the workflow is documented
[here][cli].
[CLI release]: https://github.com/fastly/cli/releases
### As a standalone tool from crates.io
To install Viceroy as a standalone tool, you'll need to first
[install Rust](https://www.rust-lang.org/tools/install) if you haven't already.
Then run `cargo install --locked viceroy`, which will download and build the latest
Viceroy release.
## Usage as a library
Viceroy can be used as a [Rust library](https://docs.rs/viceroy-lib/). This is useful if you want to run integration tests in the same codebase. We provide a helper method [`handle_request`](https://docs.rs/viceroy-lib/0.2.6/viceroy_lib/struct.ExecuteCtx.html#method.handle_request). Before you build or test your code, we recommend to set the release flag e.g. `cargo test --release` otherwise, the execution will be very slow. This has to do with the Cranelift compiler, which is extremely slow when compiled in debug mode. Besides that, if you use GitHub Actions don't forget to set up a build [cache](https://github.com/actions/cache/blob/main/examples.md#rust---cargo) for Rust. This will speed up your build times a lot.
## Usage as a standalone tool
**NOTE**: the Viceroy standalone CLI has a somewhat different interface from that
of [the Fastly CLI][cli]. Command-line options below describe the standalone
Viceroy interface.
After installation, the `viceroy` command should be available on your path. The
only required argument is the path to a compiled `.wasm` blob, which can be
built by `fastly compute build`. The Fastly CLI should put the blob at
`bin/main.wasm`. To test the service, you can run:
```
viceroy bin/main.wasm
```
This will start a local server (by default at: `http://127.0.0.1:7676`), which can
be used to make requests to your Compute service locally. You can make requests
by using [curl](https://curl.se/), or you can send a simple GET request by visiting
the URL in your web browser.
## Usage as a test runner
Viceroy can also be used as a test runner for running Rust unit tests for Compute applications in the following way:
1. Ensure the `viceroy` command is available in your path
2. Add the following to your project's `.cargo/config.toml`:
```
[build]
target = "wasm32-wasip1"
[target.wasm32-wasip1]
runner = "viceroy run -C fastly.toml -- "
```
3. Install [cargo-nextest](https://nexte.st/book/installation.html)
4. Write your tests that use the fastly crate. For example:
```Rust
#[test]
fn test_using_client_request() {
let client_req = fastly::Request::from_client();
assert_eq!(client_req.get_method(), Method::GET);
assert_eq!(client_req.get_path(), "/");
}
#[test]
fn test_using_bodies() {
let mut body1 = fastly::Body::new();
body1.write_str("hello, ");
let mut body2 = fastly::Body::new();
body2.write_str("Viceroy!");
body1.append(body2);
let appended_str = body1.into_string();
assert_eq!(appended_str, "hello, Viceroy!");
}
#[test]
fn test_a_handler_with_fastly_types() {
let req = fastly::Request::get("http://example.com/Viceroy");
let resp = some_handler(req).expect("request succeeds");
assert_eq!(resp.get_content_type(), Some(TEXT_PLAIN_UTF_8));
assert_eq!(resp.into_body_str(), "hello, /Viceroy!");
}
```
5. Run your tests with `cargo nextest run`:
```
% cargo nextest run
Compiling unit-tests-test v0.1.0
Finished test [unoptimized + debuginfo] target(s) in 1.16s
Starting 3 tests across 1 binaries
PASS [ 2.106s] unit-tests-test::bin/unit-tests-test tests::test_a_handler_with_fastly_types
PASS [ 2.225s] unit-tests-test::bin/unit-tests-test tests::test_using_bodies
PASS [ 2.223s] unit-tests-test::bin/unit-tests-test tests::test_using_client_request
------------
Summary [ 2.230s] 3 tests run: 3 passed, 0 skipped
```
The reason that `cargo-nextest` is needed rather than just `cargo test` is to allow tests to keep executing if any other test fails. There is no way to recover from a panic in wasm, so test execution would halt as soon as the first test failure occurs. Because of this, we need each test to be executed in its own wasm instance and have the results aggregated to report overall success/failure. cargo-nextest [handles that orchestration for us](https://nexte.st/book/how-it-works.html#the-nextest-model).
## Documentation
Since the Fastly CLI uses Viceroy under the hood, the two share documentation for
everything other than CLI differences. You can find general documentation for
local testing [here][cli], and documentation about configuring local testing
[here][toml-docs]. Documentation for Viceroy's CLI can be found via `--help`.
[toml-docs]: https://developer.fastly.com/reference/fastly-toml/#local-server
## Colophon

The viceroy is a butterfly whose color and pattern mimics that of the monarch
butterfly but is smaller in size.
================================================
FILE: SECURITY.md
================================================
## Report a security issue
The fastly/Viceroy project team welcomes security reports and is committed to providing prompt attention to security issues. Security issues should be reported privately via [Fastly’s security issue reporting process](https://www.fastly.com/security/report-security-issue).
## Security advisories
Remediation of security vulnerabilities is prioritized by the project team. The project team endeavors to coordinate remediation with third-party stakeholders, and is committed to transparency in the disclosure process. The fastly/Viceroy team announces security issues in release notes as well as GitHub Security Advisories on a best-effort basis.
Note that communications related to security issues in Fastly-maintained OSS as described here are distinct from [Fastly Security Advisories](https://www.fastly.com/security-advisories).
================================================
FILE: cli/Cargo.toml
================================================
[package]
name = "viceroy"
description = "Viceroy is a local testing daemon for Fastly Compute."
version = "0.17.1"
authors = ["Fastly"]
readme = "../README.md"
edition = "2024"
license = "Apache-2.0 WITH LLVM-exception"
documentation = "https://developer.fastly.com/learning/compute/testing/#running-a-local-testing-server"
homepage = "https://developer.fastly.com/learning/compute/"
repository = "https://github.com/fastly/Viceroy"
keywords = ["wasm", "fastly"]
categories = [
"command-line-utilities",
"development-tools",
"network-programming",
"simulation",
"wasm"
]
include = [
"../README.md",
"../CHANGELOG.md",
"../SECURITY.md",
"../doc/logo.png",
"src/**/*"
]
[[bin]]
name = "viceroy"
path = "src/main.rs"
[dependencies]
anyhow = { workspace = true }
base64 = { workspace = true }
hyper = { workspace = true }
itertools = { workspace = true }
serde_json = { workspace = true }
clap = { workspace = true }
rustls = { workspace = true }
rustls-pemfile = { workspace = true }
tokio = { workspace = true }
tokio-rustls = { workspace = true }
tracing = { workspace = true }
tracing-subscriber = { version = "^0.3.16", features = ["env-filter", "fmt"] }
viceroy-lib = { path = "..", version = "=0.17.1" }
wat = "^1.0.38"
wasmtime = { workspace = true }
wasmtime-wasi = { workspace = true }
libc = "^0.2.139"
[dev-dependencies]
anyhow = { workspace = true }
futures = { workspace = true }
url = { workspace = true }
tls-listener = { version = "^0.7.0", features = ["rustls", "hyper-h1", "tokio-net", "rt"] }
tempfile = "3"
serde_json = { workspace = true }
================================================
FILE: cli/src/execute_ctx.rs
================================================
use crate::opts::SharedArgs;
use hyper::{Body, Request, client::Client};
use std::io::{self, Stderr, Stdout};
use std::sync::Arc;
use std::time::Duration;
use tokio::time::timeout;
use tracing::{Level, Metadata, event};
use tracing_subscriber::fmt::writer::MakeWriter;
use viceroy_lib::{BackendConnector, ExecuteCtx, GuestProfileConfig, config::FastlyConfig};
pub(crate) enum Stdio {
Stdout(Stdout),
Stderr(Stderr),
}
impl io::Write for Stdio {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
match self {
Self::Stdout(out) => out.write(buf),
Self::Stderr(err) => err.write(buf),
}
}
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
match self {
Self::Stdout(out) => out.write_all(buf),
Self::Stderr(err) => err.write_all(buf),
}
}
fn flush(&mut self) -> io::Result<()> {
match self {
Self::Stdout(out) => out.flush(),
Self::Stderr(err) => err.flush(),
}
}
}
pub(crate) struct StdWriter;
impl StdWriter {
pub(crate) fn new() -> Self {
Self {}
}
}
impl<'a> MakeWriter<'a> for StdWriter {
type Writer = Stdio;
// We need to implement a default behavior so we'll use stdout
fn make_writer(&self) -> Self::Writer {
Stdio::Stdout(io::stdout())
}
// This is where we can set where we want to send data actually based off
// the log level. In this case we want errors to go to stderr as if we used
// eprintln and to stdout for everything else.
fn make_writer_for(&self, meta: &Metadata<'_>) -> Self::Writer {
if meta.level() == &Level::ERROR {
Stdio::Stderr(io::stderr())
} else {
Stdio::Stdout(io::stdout())
}
}
}
pub(crate) async fn create_execution_context(
args: &SharedArgs,
check_backends: bool,
guest_profile_config: Option<GuestProfileConfig>,
) -> Result<Arc<ExecuteCtx>, anyhow::Error> {
let input = args.input();
let ctx = ExecuteCtx::build(
input,
args.profiling_strategy(),
args.wasi_modules(),
guest_profile_config,
args.unknown_import_behavior(),
args.adapt(),
args.wasm_features(),
)?
.with_log_stderr(args.log_stderr())
.with_log_stdout(args.log_stdout())
.with_local_pushpin_proxy_port(args.local_pushpin_proxy_port());
let Some(config_path) = args.config_path() else {
event!(
Level::WARN,
"no configuration provided, invoke with `-C <TOML_FILE>` to provide a configuration"
);
return Ok(ctx.finish()?);
};
let config = FastlyConfig::from_file(config_path)?;
let acls = config.acls();
let backends = config.backends();
let device_detection = config.device_detection();
let geolocation = config.geolocation();
let dictionaries = config.dictionaries();
let object_stores = config.object_stores();
let secret_stores = config.secret_stores();
let shielding_sites = config.shielding_sites();
let fake_valid_fastly_keys = config.fake_valid_fastly_keys();
let backend_names = itertools::join(backends.keys(), ", ");
let ctx = ctx
.with_acls(acls.clone())
.with_backends(backends.clone())
.with_device_detection(device_detection.clone())
.with_geolocation(geolocation.clone())
.with_dictionaries(dictionaries.clone())
.with_object_stores(object_stores.clone())
.with_secret_stores(secret_stores.clone())
.with_shielding_sites(shielding_sites.clone())
.with_fake_valid_fastly_keys(fake_valid_fastly_keys.clone())
.with_config_path(config_path.into())
.finish()?;
if backend_names.is_empty() {
event!(
Level::WARN,
"no backend definitions found in {}",
config_path.display()
);
}
if check_backends {
for (name, backend) in backends.iter() {
let client = Client::builder().build(BackendConnector::new(
backend.clone(),
ctx.tls_config().clone(),
));
let req = Request::get(&backend.uri).body(Body::empty()).unwrap();
event!(Level::INFO, "checking if backend '{}' is up", name);
match timeout(Duration::from_secs(5), client.request(req)).await {
// In the case that we don't time out but we have an error, we
// check that it's specifically a connection error as this is
// the only one that happens if the server is not up.
//
// We can't combine this with the case above due to needing the
// inner error to check if it's a connection error. The type
// checker complains about it.
Ok(Err(ref e)) if e.is_connect() => event!(
Level::WARN,
"backend '{}' on '{}' is not up right now",
name,
backend.uri
),
// In the case we timeout we assume the backend is not up as 5
// seconds to do a simple get should be enough for a healthy
// service
Err(_) => event!(
Level::WARN,
"backend '{}' on '{}' is not up right now",
name,
backend.uri
),
Ok(_) => event!(Level::INFO, "backend '{}' is up", name),
}
}
}
Ok(ctx)
}
================================================
FILE: cli/src/main.rs
================================================
//! Fastly's local testing daemon for Compute.
// When building the project in release mode:
// (1): Promote warnings into errors.
// (2): Deny broken documentation links.
// (3): Deny invalid codeblock attributes in documentation.
// (4): Promote warnings in examples into errors, except for unused variables.
#![cfg_attr(not(debug_assertions), deny(warnings))]
#![cfg_attr(not(debug_assertions), deny(clippy::all))]
#![cfg_attr(not(debug_assertions), deny(broken_intra_doc_links))]
#![cfg_attr(not(debug_assertions), deny(invalid_codeblock_attributes))]
#![cfg_attr(not(debug_assertions), doc(test(attr(deny(warnings)))))]
#![cfg_attr(not(debug_assertions), doc(test(attr(allow(dead_code)))))]
#![cfg_attr(not(debug_assertions), doc(test(attr(allow(unused_variables)))))]
mod execute_ctx;
mod opts;
mod subcommands;
use {
crate::execute_ctx::*,
crate::opts::*,
clap::Parser,
std::env,
std::process::ExitCode,
tracing::{Level, event},
tracing_subscriber::{FmtSubscriber, filter::EnvFilter},
};
#[tokio::main]
async fn main() -> ExitCode {
// Parse the command-line options, exiting if there are any errors
let opts = Opts::parse();
let cmd = opts.command.unwrap_or(Commands::Serve(opts.serve));
match cmd {
Commands::Run(run_args) => subcommands::run::exec(run_args).await,
Commands::Serve(serve_args) => subcommands::serve::exec(serve_args).await,
Commands::Adapt(adapt_args) => subcommands::adapt::exec(adapt_args),
}
}
fn install_tracing_subscriber(verbosity: u8) {
// Default to whatever a user provides, but if not set logging to work for
// viceroy and viceroy-lib so that they can have output in the terminal
if env::var("RUST_LOG").ok().is_none() {
// SAFETY: We are called early in `main` when there are no other
// threads created yet.
unsafe {
match verbosity {
0 => env::set_var("RUST_LOG", "viceroy=error,viceroy-lib=error"),
1 => env::set_var("RUST_LOG", "viceroy=info,viceroy-lib=info"),
2 => env::set_var("RUST_LOG", "viceroy=debug,viceroy-lib=debug"),
_ => env::set_var("RUST_LOG", "viceroy=trace,viceroy-lib=trace"),
}
}
}
// Build a subscriber, using the default `RUST_LOG` environment variable for our filter.
let builder = FmtSubscriber::builder()
.with_writer(StdWriter::new())
.with_env_filter(EnvFilter::from_default_env())
.with_target(false);
match env::var("RUST_LOG_PRETTY") {
// If the `RUST_LOG_PRETTY` environment variable is set to "true", we should emit logs in a
// pretty, human-readable output format.
Ok(s) if s == "true" => builder
.pretty()
// Show levels, because ANSI escape sequences are normally used to indicate this.
.with_level(true)
.init(),
// Otherwise, we should install the subscriber without any further additions.
_ => builder.with_ansi(false).init(),
}
event!(
Level::DEBUG,
"RUST_LOG set to '{}'",
env::var("RUST_LOG").unwrap_or_else(|_| String::from("<Could not get env>"))
);
}
================================================
FILE: cli/src/opts.rs
================================================
//! Command line arguments.
use std::time::Duration;
use viceroy_lib::{GuestProfileConfig, config::UnknownImportBehavior};
use {
clap::{Args, Parser, Subcommand, ValueEnum},
std::net::{IpAddr, Ipv4Addr},
std::{
collections::HashSet,
net::SocketAddr,
path::{Path, PathBuf},
},
viceroy_lib::{Error, ProfilingStrategy, config::ExperimentalModule},
wasmtime::WasmFeatures,
};
// Command-line arguments for the Viceroy CLI.
//
// This struct is used to derive a command-line argument parser. See the
// [clap](https://docs.rs/clap/latest/clap/) documentation for more information.
//
// Note that the doc comment below is used as descriptive text in the `--help` output.
/// Viceroy is a local testing daemon for Compute.
#[derive(Parser, Debug)]
#[command(name = "viceroy", author, version, about)]
#[command(propagate_version = true)]
#[command(args_conflicts_with_subcommands = true)]
pub struct Opts {
#[command(subcommand)]
pub command: Option<Commands>,
#[command(flatten)]
pub serve: ServeArgs,
}
#[derive(Subcommand, Debug, Clone)]
pub enum Commands {
/// Run the wasm in a Viceroy server. This is the default if no subcommand
/// is given.
Serve(ServeArgs),
/// Run the input wasm once and then exit.
Run(RunArgs),
/// Adapt core wasm to a component.
Adapt(AdaptArgs),
}
#[derive(Debug, Args, Clone)]
pub struct ServeArgs {
/// The IP address that the service should be bound to.
#[arg(long = "addr")]
socket_addr: Option<SocketAddr>,
#[command(flatten)]
shared: SharedArgs,
}
#[derive(Args, Debug, Clone)]
pub struct RunArgs {
#[command(flatten)]
shared: SharedArgs,
/// Args to pass along to the binary being executed.
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
wasm_args: Vec<String>,
}
#[derive(Args, Debug, Clone)]
pub struct SharedArgs {
/// The path to the service's Wasm module.
#[arg(value_parser = check_module, required=true)]
input: Option<PathBuf>,
/// The path to a TOML file containing `local_server` configuration.
#[arg(short = 'C', long = "config")]
config_path: Option<PathBuf>,
/// Whether to treat stdout as a logging endpoint
#[arg(long = "log-stdout", default_value = "false")]
log_stdout: bool,
/// Whether to treat stderr as a logging endpoint
#[arg(long = "log-stderr", default_value = "false")]
log_stderr: bool,
/// Profiling strategy (valid options are: perfmap, jitdump, vtune, guest)
///
/// The perfmap, jitdump, and vtune profiling strategies integrate Viceroy
/// with external profilers such as `perf`.
///
/// The guest profiling strategy enables in-process sampling. By default,
/// when Viceroy is running as a server it will write the captured
/// per-request profiles to the `guest-profiles` directory, and as a test
/// runner it will write the captured profile to the `guest-profile.json`
/// file. These profiles can be viewed at https://profiler.firefox.com/.
///
/// The `guest` option can be additionally configured as:
///
/// --profile=guest[,path[,sample]]
///
/// where `path` is the directory or filename to write the profile(s) to and
/// `sample` is the duration between profiler samples (default 50μs). Time
/// units supported are "s" (seconds), "ms" (milliseconds"), "us"/"μs"
/// (microseconds), and "ns" (nanoseconds).
#[arg(long = "profile", value_name = "STRATEGY", value_parser = check_wasmtime_profiler_mode)]
profile: Option<Profile>,
/// Port running local Pushpin proxy. If not provided, Pushpin functionality
/// is disabled.
#[arg(long = "local-pushpin-proxy-port")]
local_pushpin_proxy_port: Option<u16>,
/// Set of experimental WASI modules to link against.
#[arg(value_enum, long = "experimental_modules", required = false)]
experimental_modules: Vec<ExperimentalModuleArg>,
/// Set the behavior for unknown imports.
///
/// Note that if a program only works with a non-default setting for this flag, it is unlikely
/// to be publishable to Fastly.
#[arg(long = "unknown-import-behavior", value_enum, default_value_t = UnknownImportBehavior::LinkError)]
unknown_import_behavior: UnknownImportBehavior,
/// Verbosity of logs for Viceroy. `-v` sets the log level to INFO,
/// `-vv` to DEBUG, and `-vvv` to TRACE. This option will not take
/// effect if you set RUST_LOG to a value before starting Viceroy
#[arg(short = 'v', action = clap::ArgAction::Count)]
verbosity: u8,
/// Whether or not to automatically adapt core-wasm modules to
/// components before running them.
#[arg(long = "adapt")]
adapt: bool,
/// Enable the Wasm Exception Handling feature.
#[arg(long)]
wasm_exceptions: bool,
/// Enable the Wasm GC feature.
#[arg(long)]
wasm_gc: bool,
/// Enable component-model GC integration.
#[arg(long)]
wasm_cm_gc: bool,
}
#[derive(Debug, Clone)]
enum Profile {
Native(ProfilingStrategy),
Guest {
path: Option<String>,
sample_period: Option<Duration>,
},
}
impl ServeArgs {
/// The address that the service should be bound to.
pub fn addr(&self) -> SocketAddr {
self.socket_addr
.unwrap_or_else(|| SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 7676))
}
pub fn shared(&self) -> &SharedArgs {
&self.shared
}
}
impl RunArgs {
/// The arguments to pass to the underlying binary when run_mode=true
pub fn wasm_args(&self) -> &Vec<String> {
&self.wasm_args
}
pub fn shared(&self) -> &SharedArgs {
&self.shared
}
}
impl SharedArgs {
/// The path to the service's Wasm binary.
pub fn input(&self) -> PathBuf {
self.input.as_ref().unwrap().clone()
}
/// The path to a `local_server` configuration file.
pub fn config_path(&self) -> Option<&Path> {
self.config_path.as_deref()
}
/// Whether to treat stdout as a logging endpoint
pub fn log_stdout(&self) -> bool {
self.log_stdout
}
/// Whether to treat stderr as a logging endpoint
pub fn log_stderr(&self) -> bool {
self.log_stderr
}
/// Whether to enable wasmtime's builtin profiler.
pub fn profiling_strategy(&self) -> ProfilingStrategy {
match self.profile {
Some(Profile::Native(s)) => s,
_ => ProfilingStrategy::None,
}
}
/// Port running local Pushpin proxy.
pub fn local_pushpin_proxy_port(&self) -> Option<u16> {
self.local_pushpin_proxy_port
}
/// Configuration for guest profiling if enabled
pub fn guest_profile_config(&self) -> Option<GuestProfileConfig> {
if let Some(Profile::Guest {
path,
sample_period,
}) = &self.profile
{
Some(GuestProfileConfig {
path: PathBuf::from(
path.as_ref()
.map(|p| p.as_str())
.unwrap_or("guest-profiles"),
),
sample_period: sample_period.unwrap_or_else(|| Duration::from_micros(50)),
})
} else {
None
}
}
/// Set of experimental wasi modules to link against.
pub fn wasi_modules(&self) -> HashSet<ExperimentalModule> {
self.experimental_modules.iter().map(|x| x.into()).collect()
}
/// Unknown import behavior
pub fn unknown_import_behavior(&self) -> UnknownImportBehavior {
self.unknown_import_behavior
}
/// Verbosity of logs for Viceroy. `-v` sets the log level to DEBUG and
/// `-vv` to TRACE. This option will not take effect if you set RUST_LOG
/// to a value before starting Viceroy
pub fn verbosity(&self) -> u8 {
self.verbosity
}
pub fn adapt(&self) -> bool {
self.adapt
}
pub fn wasm_features(&self) -> WasmFeatures {
let mut wasm_features = WasmFeatures::default();
if self.wasm_exceptions {
wasm_features.insert(WasmFeatures::EXCEPTIONS);
}
if self.wasm_gc {
wasm_features.insert(WasmFeatures::GC);
}
if self.wasm_cm_gc {
wasm_features.insert(WasmFeatures::CM_GC);
}
wasm_features
}
}
#[derive(Args, Debug, Clone)]
pub struct AdaptArgs {
/// The path to the Wasm module to adapt.
#[arg(value_parser = check_module, required=true)]
input: PathBuf,
/// The output name
#[arg(short = 'o', long = "output")]
output: Option<PathBuf>,
/// Verbosity of logs for Viceroy. `-v` sets the log level to INFO,
/// `-vv` to DEBUG, and `-vvv` to TRACE. This option will not take
/// effect if you set RUST_LOG to a value before starting Viceroy
#[arg(short = 'v', action = clap::ArgAction::Count)]
verbosity: u8,
}
impl AdaptArgs {
pub(crate) fn input(&self) -> PathBuf {
self.input.clone()
}
pub(crate) fn output(&self) -> PathBuf {
if let Some(output) = self.output.as_ref() {
return output.clone();
}
let mut output = PathBuf::from(self.input.file_name().expect("input filename"));
output.set_extension("component.wasm");
output
}
/// Verbosity of logs for Viceroy. `-v` sets the log level to DEBUG and
/// `-vv` to TRACE. This option will not take effect if you set RUST_LOG
/// to a value before starting Viceroy
pub fn verbosity(&self) -> u8 {
self.verbosity
}
}
/// Enum of available (experimental) wasi modules
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Hash)]
pub enum ExperimentalModuleArg {
WasiNn,
}
impl From<ExperimentalModuleArg> for ExperimentalModule {
fn from(arg: ExperimentalModuleArg) -> ExperimentalModule {
match arg {
ExperimentalModuleArg::WasiNn => ExperimentalModule::WasiNn,
}
}
}
impl From<&ExperimentalModuleArg> for ExperimentalModule {
fn from(arg: &ExperimentalModuleArg) -> ExperimentalModule {
match arg {
ExperimentalModuleArg::WasiNn => ExperimentalModule::WasiNn,
}
}
}
impl From<ExperimentalModule> for ExperimentalModuleArg {
fn from(module: ExperimentalModule) -> ExperimentalModuleArg {
match module {
ExperimentalModule::WasiNn => ExperimentalModuleArg::WasiNn,
}
}
}
impl From<&ExperimentalModule> for ExperimentalModuleArg {
fn from(module: &ExperimentalModule) -> ExperimentalModuleArg {
match module {
ExperimentalModule::WasiNn => ExperimentalModuleArg::WasiNn,
}
}
}
/// A parsing function used by [`Opts`][opts] to check that the input is a valid Wasm module in
/// binary or text format.
///
/// [opts]: struct.Opts.html
fn check_module(s: &str) -> Result<PathBuf, Error> {
let path = PathBuf::from(s);
let contents = std::fs::read(&path)?;
match wat::parse_bytes(&contents) {
Ok(_) => Ok(path),
_ => Err(Error::FileFormat),
}
}
/// Parse a string as a duration
///
/// This implementation is mostly borrowed from the wasmtime cli
fn parse_profile_sample_duration(s: &str) -> Result<Duration, Error> {
// assume an integer without a unit specified is a number of seconds ...
if let Ok(val) = s.parse() {
return Ok(Duration::from_secs(val));
}
if let Some(num) = s.strip_suffix("s")
&& let Ok(val) = num.parse()
{
return Ok(Duration::from_secs(val));
}
if let Some(num) = s.strip_suffix("ms")
&& let Ok(val) = num.parse()
{
return Ok(Duration::from_millis(val));
}
if let Some(num) = s.strip_suffix("us").or(s.strip_suffix("μs"))
&& let Ok(val) = num.parse()
{
return Ok(Duration::from_micros(val));
}
if let Some(num) = s.strip_suffix("ns")
&& let Ok(val) = num.parse()
{
return Ok(Duration::from_nanos(val));
}
Err(Error::ProfilingStrategy)
}
/// A parsing function used by [`Opts`][opts] to check that the input is valid wasmtime's profiling strategy.
///
/// [opts]: struct.Opts.html
fn check_wasmtime_profiler_mode(s: &str) -> Result<Profile, Error> {
let parts = s.split(',').collect::<Vec<_>>();
match &parts[..] {
["jitdump"] => Ok(Profile::Native(ProfilingStrategy::JitDump)),
["perfmap"] => Ok(Profile::Native(ProfilingStrategy::PerfMap)),
["vtune"] => Ok(Profile::Native(ProfilingStrategy::VTune)),
["guest"] => Ok(Profile::Guest {
path: None,
sample_period: None,
}),
["guest", path] => Ok(Profile::Guest {
path: Some(path.to_string()),
sample_period: None,
}),
["guest", path, sample_period] => Ok(Profile::Guest {
path: path.to_string().into(),
sample_period: Some(parse_profile_sample_duration(sample_period)?),
}),
_ => Err(Error::ProfilingStrategy),
}
}
/// A collection of unit tests for our CLI argument parsing.
///
/// Note: When using [`Clap::try_parse_from`][from] to test how command line arguments are
/// parsed, note that the first argument will be parsed as the binary name. `dummy-program-name` is
/// used to highlight that this argument is ignored.
///
/// [from]: https://docs.rs/clap/latest/clap/trait.Parser.html#method.try_parse_from
#[cfg(test)]
mod opts_tests {
use {
super::{Commands, Opts},
clap::{Parser, error::ErrorKind},
std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
std::path::PathBuf,
};
fn test_file(name: &str) -> String {
let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("tests")
.join("wasm");
path.push(name);
assert!(path.exists(), "test file does not exist");
path.into_os_string().into_string().unwrap()
}
/// A small type alias for test results, with a boxed error type.
type TestResult = Result<(), anyhow::Error>;
/// Test that the default address works as expected.
#[test]
fn default_addr_works() -> TestResult {
let empty_args = &["dummy-program-name", &test_file("minimal.wat")];
let opts = Opts::try_parse_from(empty_args)?;
let cmd = opts.command.unwrap_or(Commands::Serve(opts.serve));
let expected = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 7676);
if let Commands::Serve(serve_args) = cmd {
assert_eq!(serve_args.addr(), expected);
}
Ok(())
}
/// Test that an `--addr` value with an invalid IPv4 address is rejected.
#[test]
fn invalid_addrs_are_rejected() -> TestResult {
let args_with_bad_addr = &[
"dummy-program-name",
"--addr",
"999.0.0.1:7676",
&test_file("minimal.wat"),
];
match Opts::try_parse_from(args_with_bad_addr) {
Err(err)
if err.kind() == ErrorKind::ValueValidation
&& (err.to_string().contains("invalid socket address syntax")
|| err.to_string().contains("invalid IP address syntax")) =>
{
Ok(())
}
res => panic!("unexpected result: {:?}", res),
}
}
/// IPv6 addresses are supported. Test that they are accepted.
#[test]
fn ipv6_addrs_are_accepted() -> TestResult {
let args_with_ipv6_addr = &[
"dummy-program-name",
"--addr",
"[::1]:7676",
&test_file("minimal.wat"),
];
let opts = Opts::try_parse_from(args_with_ipv6_addr)?;
let cmd = opts.command.unwrap_or(Commands::Serve(opts.serve));
let addr_v6 = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
let expected = SocketAddr::new(addr_v6, 7676);
if let Commands::Serve(serve_args) = cmd {
assert_eq!(serve_args.addr(), expected);
}
Ok(())
}
/// Test that a nonexistent file is rejected properly.
#[test]
fn nonexistent_file_is_rejected() -> TestResult {
let args_with_nonexistent_file = &["dummy-program-name", "path/to/a/nonexistent/file"];
match Opts::try_parse_from(args_with_nonexistent_file) {
Err(err)
if err.kind() == ErrorKind::ValueValidation
&& (err.to_string().contains("No such file or directory")
|| err.to_string().contains("cannot find the path specified")) =>
{
Ok(())
}
res => panic!("unexpected result: {:?}", res),
}
}
/// Test that an invalid file is rejected.
#[test]
fn invalid_file_is_rejected() -> TestResult {
let args_with_invalid_file = &["dummy-program-name", &test_file("invalid.wat")];
let expected_msg = format!("{}", viceroy_lib::Error::FileFormat);
match Opts::try_parse_from(args_with_invalid_file) {
Err(err)
if err.kind() == ErrorKind::ValueValidation
&& err.to_string().contains(&expected_msg) =>
{
Ok(())
}
res => panic!("unexpected result: {:?}", res),
}
}
/// Test that a Wasm module in text format is accepted.
#[test]
fn text_format_is_accepted() -> TestResult {
let args = &["dummy-program-name", &test_file("minimal.wat")];
match Opts::try_parse_from(args) {
Ok(_) => Ok(()),
res => panic!("unexpected result: {:?}", res),
}
}
/// Test that a Wasm module in binary format is accepted.
#[test]
fn binary_format_is_accepted() -> TestResult {
let args = &["dummy-program-name", &test_file("minimal.wasm")];
match Opts::try_parse_from(args) {
Ok(_) => Ok(()),
res => panic!("unexpected result: {:?}", res),
}
}
/// Test that wasmtime's jitdump profiling strategy is accepted.
#[test]
fn wasmtime_profiling_strategy_jitdump_is_accepted() -> TestResult {
let args = &[
"dummy-program-name",
"--profile",
"jitdump",
&test_file("minimal.wat"),
];
match Opts::try_parse_from(args) {
Ok(_) => Ok(()),
res => panic!("unexpected result: {:?}", res),
}
}
/// Test that wasmtime's VTune profiling strategy is accepted.
#[test]
fn wasmtime_profiling_strategy_vtune_is_accepted() -> TestResult {
let args = &[
"dummy-program-name",
"--profile",
"vtune",
&test_file("minimal.wat"),
];
match Opts::try_parse_from(args) {
Ok(_) => Ok(()),
res => panic!("unexpected result: {:?}", res),
}
}
/// Test that wasmtime's PerfMap profiling strategy is accepted.
#[test]
fn wasmtime_profiling_strategy_perfmap_is_accepted() -> TestResult {
let args = &[
"dummy-program-name",
"--profile",
"perfmap",
&test_file("minimal.wat"),
];
match Opts::try_parse_from(args) {
Ok(_) => Ok(()),
res => panic!("unexpected result: {:?}", res),
}
}
/// Test that wasmtime's guest profiling strategy without path is accepted.
#[test]
fn wasmtime_profiling_strategy_guest_without_path_is_accepted() -> TestResult {
let args = &[
"dummy-program-name",
"--profile",
"guest",
&test_file("minimal.wat"),
];
match Opts::try_parse_from(args) {
Ok(_) => Ok(()),
res => panic!("unexpected result: {:?}", res),
}
}
/// Test that wasmtime's guest profiling strategy with path is accepted.
#[test]
fn wasmtime_profiling_strategy_guest_with_path_is_accepted() -> TestResult {
let args = &[
"dummy-program-name",
"--profile",
"guest,/some/path",
&test_file("minimal.wat"),
];
match Opts::try_parse_from(args) {
Ok(_) => Ok(()),
res => panic!("unexpected result: {:?}", res),
}
}
#[test]
fn wasmtime_profiling_strategy_guest_with_path_and_period_is_accepted() -> TestResult {
let args = &[
"dummy-program-name",
"--profile",
"guest,/some/path,250ns",
&test_file("minimal.wat"),
];
match Opts::try_parse_from(args) {
Ok(_) => Ok(()),
res => panic!("unexpected result: {:?}", res),
}
}
/// Test that an invalid wasmtime's profiling strategy rejected.
#[test]
fn invalid_wasmtime_profiling_strategy_is_rejected() -> TestResult {
let args = &[
"dummy-program-name",
"--profile",
"invalid_profiling_strategy",
&test_file("minimal.wat"),
];
match Opts::try_parse_from(args) {
Ok(_) => panic!("unexpected result"),
Err(_) => Ok(()),
}
}
/// Test that trailing arguments are collected successfully
#[test]
fn trailing_args_are_collected_in_run_mode() -> TestResult {
let args = &[
"dummy-program-name",
"run",
&test_file("minimal.wat"),
"--",
"--trailing-arg",
"--trailing-arg-2",
];
let opts = Opts::try_parse_from(args)?;
let cmd = opts.command.unwrap_or(Commands::Serve(opts.serve));
if let Commands::Run(run_args) = cmd {
assert_eq!(
run_args.wasm_args(),
&["--trailing-arg", "--trailing-arg-2"]
);
}
Ok(())
}
/// Input is still accepted after double-dash. This is how the input will be
/// passed by cargo nextest if using Viceroy in run-mode to run tests
#[test]
fn input_accepted_after_double_dash() -> TestResult {
let args = &[
"dummy-program-name",
"run",
"--",
&test_file("minimal.wat"),
"--trailing-arg",
"--trailing-arg-2",
];
let opts = match Opts::try_parse_from(args) {
Ok(opts) => opts,
res => panic!("unexpected result: {:?}", res),
};
let cmd = opts.command.unwrap_or(Commands::Serve(opts.serve));
if let Commands::Run(run_args) = cmd {
assert_eq!(
run_args.shared.input().to_str().unwrap(),
&test_file("minimal.wat")
);
assert_eq!(
run_args.wasm_args(),
&["--trailing-arg", "--trailing-arg-2"]
);
}
Ok(())
}
}
================================================
FILE: cli/src/subcommands/adapt.rs
================================================
use crate::install_tracing_subscriber;
use crate::opts::AdaptArgs;
use std::process::ExitCode;
use tracing::{Level, event};
pub(crate) fn exec(adapt_args: AdaptArgs) -> ExitCode {
install_tracing_subscriber(adapt_args.verbosity());
let input = adapt_args.input();
let output = adapt_args.output();
let bytes = match std::fs::read(&input) {
Ok(bytes) => bytes,
Err(_) => {
event!(
Level::ERROR,
"Failed to read module from: {}",
input.display()
);
return ExitCode::FAILURE;
}
};
if viceroy_lib::adapt::is_component(&bytes) {
event!(
Level::ERROR,
"File is already a component: {}",
input.display()
);
return ExitCode::FAILURE;
}
let is_wat = input.extension().map(|str| str == "wat").unwrap_or(false);
let module = if is_wat {
let text = match String::from_utf8(bytes) {
Ok(module) => module,
Err(e) => {
event!(Level::ERROR, "Failed to parse wat: {e:?}");
return ExitCode::FAILURE;
}
};
match viceroy_lib::adapt::adapt_wat(&text) {
Ok(module) => module,
Err(e) => {
event!(Level::ERROR, "Failed to adapt wat: {e:?}");
return ExitCode::FAILURE;
}
}
} else {
match viceroy_lib::adapt::adapt_bytes(&bytes) {
Ok(module) => module,
Err(e) => {
event!(Level::ERROR, "Failed to adapt module: {e:?}");
return ExitCode::FAILURE;
}
}
};
event!(Level::INFO, "Writing component to: {}", output.display());
match std::fs::write(output, module) {
Ok(_) => ExitCode::SUCCESS,
Err(e) => {
event!(Level::ERROR, "Failed to write component: {e:?}");
ExitCode::FAILURE
}
}
}
================================================
FILE: cli/src/subcommands/run.rs
================================================
use crate::execute_ctx::create_execution_context;
use crate::install_tracing_subscriber;
use crate::opts::RunArgs;
use std::process::ExitCode;
use tracing::{Level, event};
use wasmtime_wasi::I32Exit;
pub(crate) async fn exec(run_args: RunArgs) -> ExitCode {
install_tracing_subscriber(run_args.shared().verbosity());
match run_wasm_main(run_args).await {
Ok(_) => ExitCode::SUCCESS,
Err(e) => {
// Suppress stack trace if the error is due to a
// normal call to proc_exit, leading to a process
// exit.
if !e.is::<I32Exit>() {
event!(Level::ERROR, "{}", e);
}
get_exit_code(e)
}
}
}
/// Execute a Wasm program in the Viceroy environment.
async fn run_wasm_main(run_args: RunArgs) -> Result<(), anyhow::Error> {
// Load the wasm module into an execution context
let ctx = create_execution_context(
run_args.shared(),
false,
run_args.shared().guest_profile_config(),
)
.await?;
let input = run_args.shared().input();
let program_name = match input.file_stem() {
Some(stem) => stem.to_string_lossy(),
None => panic!("program cannot be a directory"),
};
ctx.run_main(&program_name, run_args.wasm_args()).await
}
// This function is based on similar exit code logic in the wasmtime cli:
// https://github.com/bytecodealliance/wasmtime/blob/cc768f/src/commands/run.rs#L214-L246
fn get_exit_code(e: anyhow::Error) -> ExitCode {
// If we exited with a specific WASI exit code, forward that to
// the process
if let Some(exit) = e.downcast_ref::<I32Exit>() {
// On Windows, exit status 3 indicates an abort (see below),
// so return 1 indicating a non-zero status to avoid ambiguity.
if cfg!(windows) && exit.0 >= 3 {
return ExitCode::FAILURE;
}
return ExitCode::from(exit.0 as u8);
}
// If the program exited because of a trap, return an error code
// to the outside environment indicating a more severe problem
// than a simple failure.
if e.is::<wasmtime::Trap>() {
if cfg!(unix) {
// On Unix, return the error code of an abort.
return ExitCode::from(128u8 + libc::SIGABRT as u8);
} else if cfg!(windows) {
// On Windows, return 3.
// https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/abort?view=vs-2019
return ExitCode::from(3u8);
}
}
// Otherwise just return 1
ExitCode::FAILURE
}
================================================
FILE: cli/src/subcommands/serve.rs
================================================
use crate::opts::ServeArgs;
use crate::{create_execution_context, install_tracing_subscriber};
use std::process::ExitCode;
use tracing::{Level, event};
use viceroy_lib::{Error, ViceroyService};
pub(crate) async fn exec(serve_args: ServeArgs) -> ExitCode {
install_tracing_subscriber(serve_args.shared().verbosity());
match {
tokio::select! {
_ = tokio::signal::ctrl_c() => {
Ok(())
}
res = serve(serve_args) => {
if let Err(ref e) = res {
event!(Level::ERROR, "{}", e);
}
res
}
}
} {
Ok(_) => ExitCode::SUCCESS,
Err(_) => ExitCode::FAILURE,
}
}
/// Starts up a Viceroy server.
///
/// Create a new server, bind it to an address, and serve responses until an error occurs.
async fn serve(serve_args: ServeArgs) -> Result<(), Error> {
// Load the wasm module into an execution context
let ctx = create_execution_context(
serve_args.shared(),
true,
serve_args.shared().guest_profile_config(),
)
.await?;
if let Some(guest_profile_config) = serve_args.shared().guest_profile_config() {
std::fs::create_dir_all(guest_profile_config.path)?;
}
let addr = serve_args.addr();
ViceroyService::new(ctx).serve(addr).await?;
unreachable!()
}
================================================
FILE: cli/src/subcommands.rs
================================================
//! Module for `viceroy` CLI commands.
pub mod adapt;
pub mod run;
pub mod serve;
================================================
FILE: cli/tests/integration/acl.rs
================================================
use crate::{common::Test, common::TestResult, viceroy_test};
use hyper::{StatusCode, body::to_bytes};
use viceroy_lib::config::FastlyConfig;
use viceroy_lib::error::{AclConfigError, FastlyConfigError};
viceroy_test!(acl_works, |is_component| {
const FASTLY_TOML: &str = r#"
name = "acl"
description = "acl test"
authors = ["Test User <test_user@fastly.com>"]
language = "rust"
[local_server]
acls.my-acl-1 = "../test-fixtures/data/my-acl-1.json"
acls.my-acl-2 = {file = "../test-fixtures/data/my-acl-2.json"}
"#;
let resp = Test::using_fixture("acl.wasm")
.adapt_component(is_component)
.using_fastly_toml(FASTLY_TOML)?
.log_stderr()
.log_stdout()
.against_empty()
.await?;
assert_eq!(resp.status(), StatusCode::OK);
assert!(
to_bytes(resp.into_body())
.await
.expect("can read body")
.to_vec()
.is_empty()
);
Ok(())
});
fn bad_config_test(local_server_fragment: &str) -> Result<FastlyConfig, FastlyConfigError> {
let toml = format!(
r#"
name = "acl"
description = "acl test"
authors = ["Test User <test_user@fastly.com>"]
language = "rust"
[local_server]
{}
"#,
local_server_fragment
);
toml.parse::<FastlyConfig>()
}
#[tokio::test(flavor = "multi_thread")]
async fn bad_config_invalid_path() -> TestResult {
const TOML_FRAGMENT: &str = "acls.bad = 1";
match bad_config_test(TOML_FRAGMENT) {
Err(FastlyConfigError::InvalidAclDefinition {
err: AclConfigError::InvalidType,
..
}) => (),
Err(_) => panic!(
"expected a FastlyConfigError::InvalidAclDefinition with AclConfigError::InvalidType"
),
_ => panic!("Expected an error"),
}
Ok(())
}
#[tokio::test(flavor = "multi_thread")]
async fn bad_config_missing_key() -> TestResult {
const TOML_FRAGMENT: &str = "acls.bad = { \"other\" = true }";
match bad_config_test(TOML_FRAGMENT) {
Err(FastlyConfigError::InvalidAclDefinition {
err: AclConfigError::MissingFile,
..
}) => (),
Err(_) => panic!(
"expected a FastlyConfigError::InvalidAclDefinition with AclConfigError::MissingFile"
),
_ => panic!("Expected an error"),
}
Ok(())
}
#[tokio::test(flavor = "multi_thread")]
async fn bad_config_missing_file() -> TestResult {
const TOML_FRAGMENT: &str = "acls.bad = \"/does/not/exist\"";
match bad_config_test(TOML_FRAGMENT) {
Err(FastlyConfigError::InvalidAclDefinition {
err: AclConfigError::IoError(_),
..
}) => (),
Err(_) => panic!(
"expected a FastlyConfigError::InvalidAclDefinition with AclConfigError::IoError"
),
_ => panic!("Expected an error"),
}
Ok(())
}
#[tokio::test(flavor = "multi_thread")]
async fn bad_config_invalid_json() -> TestResult {
const TOML_FRAGMENT: &str = "acls.bad = \"../Cargo.toml\"";
match bad_config_test(TOML_FRAGMENT) {
Err(FastlyConfigError::InvalidAclDefinition {
err: AclConfigError::JsonError(_),
..
}) => (),
Err(_) => panic!(
"expected a FastlyConfigError::InvalidAclDefinition with AclConfigError::JsonError"
),
_ => panic!("Expected an error"),
}
Ok(())
}
================================================
FILE: cli/tests/integration/args.rs
================================================
use crate::common::{Test, TestResult};
use hyper::{StatusCode, body::to_bytes};
/// Run a program that tests its args. This checks that we're populating the argument list with the
/// singleton "compute-app" value.
/// Check that an empty response is sent downstream by default.
///
/// `args.wasm` is a guest program checks its cli args.
#[tokio::test(flavor = "multi_thread")]
async fn empty_ok_response_by_default_after_args() -> TestResult {
let resp = Test::using_fixture("args.wasm").against_empty().await?;
assert_eq!(resp.status(), StatusCode::OK);
assert!(
to_bytes(resp.into_body())
.await
.expect("can read body")
.to_vec()
.is_empty()
);
Ok(())
}
/// Run a program that tests its args. This checks that we're populating the argument list with the
/// singleton "compute-app" value.
/// Check that an empty response is sent downstream by default.
///
/// `args.wasm` is a guest program checks its cli args.
#[tokio::test(flavor = "multi_thread")]
async fn empty_ok_response_by_default_after_args_component() {
let resp = Test::using_fixture("args.wasm")
.adapt_component(true)
.against_empty()
.await
.unwrap();
assert_eq!(resp.status(), StatusCode::OK);
assert!(
to_bytes(resp.into_body())
.await
.expect("can read body")
.to_vec()
.is_empty()
);
}
================================================
FILE: cli/tests/integration/async_io.rs
================================================
// On Windows, streaming body backpressure doesn't seem to work as expected, either
// due to the Hyper client or server too eagerly clearing the chunk buffer. This issue does
// not appear related to async I/O hostcalls; the behavior is seen within the streaming body
// implementation in general. For the time being, this test is unix-only.
//
// https://github.com/fastly/Viceroy/issues/207 tracks the broader issue.
#![cfg(target_family = "unix")]
use crate::{
common::{Test, TestResult},
viceroy_test,
};
use hyper::{Body, Request, Response, StatusCode, body::HttpBody};
use std::sync::{
Arc,
atomic::{AtomicUsize, Ordering},
};
use tokio::sync::Barrier;
viceroy_test!(async_io_methods, |is_component| {
let request_count = Arc::new(AtomicUsize::new(0));
let req_count_1 = request_count.clone();
let req_count_2 = request_count.clone();
let req_count_3 = request_count.clone();
let req_count_4 = request_count.clone();
let barrier = Arc::new(Barrier::new(3));
let barrier_1 = barrier.clone();
let barrier_2 = barrier.clone();
let sync_barrier = Arc::new(Barrier::new(2));
let sync_barrier_1 = sync_barrier.clone();
// We set up 4 async backends below, configured to test different
// combinations of async behavior from the guest. The first three backends
// are things we are actually testing, and the fourth ("Semaphore") is just
// used as a synchronization mechanism. Each backend will receive 4 requests
// total and will behave differently depending on which request # it is
// processing.
let test = Test::using_fixture("async_io.wasm")
.adapt_component(is_component)
.async_backend("Simple", "/", None, move |req: Request<Body>| {
assert_eq!(req.headers()["Host"], "simple.org");
let req_count_1 = req_count_1.clone();
let barrier_1 = barrier_1.clone();
Box::new(async move {
match req_count_1.load(Ordering::Relaxed) {
1 => Response::builder()
.status(StatusCode::OK)
.body(Body::empty())
.unwrap(),
0 | 2 | 3 => {
barrier_1.wait().await;
Response::builder()
.status(StatusCode::OK)
.body(Body::empty())
.unwrap()
}
_ => unreachable!(),
}
})
})
.await
.async_backend("ReadBody", "/", None, move |req: Request<Body>| {
assert_eq!(req.headers()["Host"], "readbody.org");
let req_count_2 = req_count_2.clone();
Box::new(async move {
match req_count_2.load(Ordering::Relaxed) {
2 => Response::builder()
.status(StatusCode::OK)
.body(Body::empty())
.unwrap(),
0 | 1 | 3 => Response::builder()
.header("Transfer-Encoding", "chunked")
.status(StatusCode::OK)
.body(Body::empty())
.unwrap(),
_ => unreachable!(),
}
})
})
.await
.async_backend("WriteBody", "/", None, move |req: Request<Body>| {
assert_eq!(req.headers()["Host"], "writebody.org");
let req_count_3 = req_count_3.clone();
let barrier_2 = barrier_2.clone();
let sync_barrier = sync_barrier.clone();
Box::new(async move {
match req_count_3.load(Ordering::Relaxed) {
3 => {
// Read at least 4MB and one 8K chunk from the request
// to relieve back-pressure for the guest. These numbers
// come from the amount of data that the guest writes to
// the request body in test-fixtures/src/bin/async_io.rs
let mut bod = req.into_body();
let mut bytes_read = 0;
while bytes_read < (4 * 1024 * 1024) + (8 * 1024) {
if let Some(Ok(bytes)) = bod.data().await {
bytes_read += bytes.len();
}
}
// The guest will have another outstanding request to
// the Semaphore backend below. Awaiting on the barrier
// here will cause that request to return indicating to
// the guest that we have read from the request body
// and the write handle should be ready again.
sync_barrier.wait().await;
let _body = hyper::body::to_bytes(bod);
Response::builder()
.status(StatusCode::OK)
.body(Body::empty())
.unwrap()
}
0..=2 => {
barrier_2.wait().await;
Response::builder()
.status(StatusCode::OK)
.body(Body::empty())
.unwrap()
}
_ => unreachable!(),
}
})
})
.await
.async_backend("Semaphore", "/", None, move |req: Request<Body>| {
assert_eq!(req.headers()["Host"], "writebody.org");
let req_count_4 = req_count_4.clone();
let sync_barrier_1 = sync_barrier_1.clone();
Box::new(async move {
match req_count_4.load(Ordering::Relaxed) {
3 => {
sync_barrier_1.wait().await;
Response::builder()
.status(StatusCode::OK)
.body(Body::empty())
.unwrap()
}
0..=2 => Response::builder()
.status(StatusCode::OK)
.body(Body::empty())
.unwrap(),
_ => unreachable!(),
}
})
})
.await;
// request_count is 0 here
let resp = test.against_empty().await?;
assert_eq!(resp.status(), StatusCode::OK);
assert_eq!(resp.headers()["Simple-Ready"], "false");
assert_eq!(resp.headers()["Read-Ready"], "false");
assert_eq!(resp.headers()["Write-Ready"], "false");
assert_eq!(resp.headers()["Ready-Index"], "timeout");
barrier.wait().await;
request_count.store(1, Ordering::Relaxed);
let resp = test.against_empty().await?;
assert_eq!(resp.status(), StatusCode::OK);
assert_eq!(resp.headers()["Simple-Ready"], "true");
assert_eq!(resp.headers()["Read-Ready"], "false");
assert_eq!(resp.headers()["Write-Ready"], "false");
assert_eq!(resp.headers()["Ready-Index"], "0");
let temp_barrier = barrier.clone();
let _task = tokio::task::spawn(async move { temp_barrier.wait().await });
barrier.wait().await;
request_count.store(2, Ordering::Relaxed);
let resp = test.against_empty().await?;
assert_eq!(resp.status(), StatusCode::OK);
assert_eq!(resp.headers()["Simple-Ready"], "false");
assert_eq!(resp.headers()["Read-Ready"], "true");
assert_eq!(resp.headers()["Write-Ready"], "false");
assert_eq!(resp.headers()["Ready-Index"], "1");
barrier.wait().await;
request_count.store(3, Ordering::Relaxed);
let resp = test.against_empty().await?;
assert_eq!(resp.status(), StatusCode::OK);
assert_eq!(resp.headers()["Simple-Ready"], "false");
assert_eq!(resp.headers()["Read-Ready"], "false");
assert_eq!(resp.headers()["Write-Ready"], "true");
assert_eq!(resp.headers()["Ready-Index"], "2");
let temp_barrier = barrier.clone();
let _task = tokio::task::spawn(async move { temp_barrier.wait().await });
barrier.wait().await;
let resp = test
.against(
Request::get("/")
.header("Empty-Select-Timeout", "0")
.body(Body::empty())
.unwrap(),
)
.await?;
assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
let resp = test
.against(
Request::get("/")
.header("Empty-Select-Timeout", "1")
.body(Body::empty())
.unwrap(),
)
.await?;
assert_eq!(resp.status(), StatusCode::OK);
assert_eq!(resp.headers()["Ready-Index"], "timeout");
Ok(())
});
================================================
FILE: cli/tests/integration/body.rs
================================================
//! Tests related to HTTP request and response bodies.
use {
crate::{
common::{Test, TestResult},
viceroy_test,
},
hyper::{HeaderMap, Response, StatusCode, body},
};
viceroy_test!(bodies_can_be_written_and_appended, |is_component| {
let resp = Test::using_fixture("write-body.wasm")
.adapt_component(is_component)
.against_empty()
.await?;
let body = body::to_bytes(resp.into_body())
.await
.expect("can read body")
.to_vec();
let body = String::from_utf8(body)?;
assert_eq!(&body, "Hello, Viceroy!");
Ok(())
});
viceroy_test!(bodies_can_be_written_and_read, |is_component| {
let resp = Test::using_fixture("write-and-read-body.wasm")
.adapt_component(is_component)
.against_empty()
.await?;
assert_eq!(resp.status(), StatusCode::OK);
Ok(())
});
viceroy_test!(zero_length_raw_chunks_are_transparent, |is_component| {
let resp = Test::using_fixture("expects-hello.wasm")
.adapt_component(is_component)
.async_backend(
"ReturnsHello",
"/",
None,
move |_req: hyper::Request<hyper::Body>| {
Box::new(async move {
// We'll "trickle back" our response.
let (mut write, read) = hyper::Body::channel();
// Assume a Tokio runtime for writing the response...
tokio::spawn(async move {
for chunk in ["", "hello", "", " ", "", "world", ""] {
let Ok(_) = write.send_data(chunk.into()).await else {
return;
};
tokio::task::yield_now().await;
}
let _ = write.send_trailers(HeaderMap::default()).await;
});
Response::builder()
.status(StatusCode::OK)
.body(read)
.unwrap()
})
},
)
.await
.against_empty()
.await?;
assert_eq!(resp.status(), StatusCode::OK);
Ok(())
});
viceroy_test!(gzip_breaks_are_ok, |is_component| {
let resp = Test::using_fixture("expects-hello.wasm")
.adapt_component(is_component)
.async_backend(
"ReturnsHello",
"/",
None,
move |req: hyper::Request<hyper::Body>| {
Box::new(async move {
let Some(encoding) = req.headers().get("accept-encoding") else {
return Response::builder()
.status(StatusCode::BAD_REQUEST)
.body(hyper::Body::empty())
.unwrap();
};
if !encoding.to_str().unwrap().to_lowercase().contains("gzip") {
return Response::builder()
.status(StatusCode::BAD_REQUEST)
.body(hyper::Body::empty())
.unwrap();
}
// Produced by: echo -n "hello world" | gzip >hello_world.gzip
const GZ_BODY: &[u8] = include_bytes!("hello_world.gzip");
// We'll "trickle back" our response.
let (mut write, read) = hyper::Body::channel();
// Assume a Tokio runtime for writing the response...
tokio::spawn(async move {
for &byte in GZ_BODY.iter() {
let Ok(_) =
write.send_data(body::Bytes::copy_from_slice(&[byte])).await
else {
return;
};
tokio::task::yield_now().await;
}
let _ = write.send_trailers(HeaderMap::default()).await;
});
Response::builder()
.status(StatusCode::OK)
.header("content-encoding", "gzip")
.body(read)
.unwrap()
})
},
)
.await
.against_empty()
.await?;
assert_eq!(resp.status(), StatusCode::OK);
Ok(())
});
================================================
FILE: cli/tests/integration/cache.rs
================================================
use {
crate::{
common::{Test, TestResult},
viceroy_test,
},
hyper::StatusCode,
};
viceroy_test!(cache, |is_component| {
let resp = Test::using_fixture("cache.wasm")
.adapt_component(is_component)
.against_empty()
.await?;
assert_eq!(resp.status(), StatusCode::OK);
Ok(())
});
================================================
FILE: cli/tests/integration/client_certs.rs
================================================
use crate::{
common::{Test, TestResult},
viceroy_test,
};
use base64::engine::{Engine, general_purpose};
use hyper::http::response;
use hyper::server::conn::AddrIncoming;
use hyper::service::{make_service_fn, service_fn};
use hyper::{Request, Server, StatusCode};
use rustls::server::{AllowAnyAuthenticatedClient, ServerConfig};
use rustls::{Certificate, PrivateKey, RootCertStore};
use std::io::Cursor;
use std::net::SocketAddr;
use std::sync::Arc;
use tls_listener::TlsListener;
use tokio_rustls::TlsAcceptor;
use tokio_rustls::server::TlsStream;
// So, let's say you want to regenerate some of the keys used in these tests,
// because they've expired or you want to try different algorithms. To do so,
// you need to:
//
// Create a key for the certificate authority:
// > openssl genrsa -des3 -out ca.key 2048
// You must set a passphrase for this key. In this case, I chose "Viceroy"
//
// Now we create a root certificate, or a CA certificate that we can use as
// our "known good" authority. This one will last for 10 years. You'll get
// asked a bunch of questions that don't actually matter:
// > openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 -out ca.pem
//
// Now we create a server certificate key:
// > openssl genrsa -out server.key 2048
// Then create a certificate signing request (CSR), which is an annoying middle
// step:
// > openssl req -new -key server.key -out server.csr
// Which will also ask you a bunch of questions that don't much matter. At this
// point, it's important to know what you're going to use it for. In this case,
// we want a server to run on localhost. Must TLS/HTTPS things get very picky
// about what certificates they'll accept for a server, so we need to mark the
// certificate appropriately; in this case, as being associated with localhost.
// So we'll create an extension file called 'server.ext' that contains:
//
// authorityKeyIdentifier=keyid,issuer
// basicConstraints=CA:FALSE
// keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
// subjectAltName = @alt_names
// [alt_names]
// DNS.1 = localhost
// IP.1 = 127.0.0.1
//
// Now we can create a signed certificate to go with our server key, by running:
// > openssl x509 -req -in server.csr -CA ca.pem -CAkey ca.key -CAcreateserial \
// -out server.crt -days 3650 -sha256 -extfile server.ext
//
// Repeat this for as many keys as you need. In the case of these tests, we need
// another one for the client.
// NOTE(ACW): This test setup is much more complicated than it feels like it should
// be, but this is the only consistent way I can build a server that requires and
// passes back TLS client certificates.
struct Watcher {
inner: AllowAnyAuthenticatedClient,
}
impl rustls::server::ClientCertVerifier for Watcher {
fn client_auth_root_subjects(&self) -> &[rustls::DistinguishedName] {
tracing::warn!("client_auth_root_subjects");
self.inner.client_auth_root_subjects()
}
fn verify_client_cert(
&self,
end_entity: &Certificate,
intermediates: &[Certificate],
now: std::time::SystemTime,
) -> Result<rustls::server::ClientCertVerified, rustls::Error> {
tracing::warn!("varify_client_cert");
self.inner
.verify_client_cert(end_entity, intermediates, now)
}
}
fn build_server_tls_config() -> ServerConfig {
let mut roots = RootCertStore::empty();
let ca_cert_bytes = include_bytes!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/../test-fixtures/data/ca.pem"
));
let mut ca_cursor = Cursor::new(ca_cert_bytes);
let mut root_certs = rustls_pemfile::certs(&mut ca_cursor).expect("pem ca certs");
for cert in root_certs.drain(..) {
roots.add(&Certificate(cert)).expect("can add root certs");
}
let server_cert_bytes: &[u8] = include_bytes!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/../test-fixtures/data/server.crt"
));
let mut server_cursor = Cursor::new(server_cert_bytes);
let server_cert_list: Vec<Certificate> = rustls_pemfile::certs(&mut server_cursor)
.expect("can read server cert")
.into_iter()
.map(Certificate)
.collect();
let server_key_bytes: &[u8] = include_bytes!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/../test-fixtures/data/server.key"
));
let mut key_cursor = Cursor::new(server_key_bytes);
let server_key = rustls_pemfile::rsa_private_keys(&mut key_cursor)
.expect("have a key")
.into_iter()
.map(PrivateKey)
.next()
.expect("have one key");
ServerConfig::builder()
.with_safe_default_cipher_suites()
.with_safe_default_kx_groups()
.with_safe_default_protocol_versions()
.expect("basic tls server config")
.with_client_cert_verifier(Arc::new(Watcher {
inner: AllowAnyAuthenticatedClient::new(roots),
}))
.with_single_cert(server_cert_list, server_key)
.expect("valid server cert")
}
viceroy_test!(custom_ca_works, |is_component| {
let test = Test::using_fixture("mutual-tls.wasm").adapt_component(is_component);
let server_addr: SocketAddr = "127.0.0.1:0".parse().expect("localhost parses");
let incoming = AddrIncoming::bind(&server_addr).expect("bind");
let bound_port = incoming.local_addr().port();
let acceptor = TlsAcceptor::from(Arc::new(build_server_tls_config()));
let listener = TlsListener::new_hyper(acceptor, incoming);
let service = make_service_fn(|stream: &TlsStream<_>| {
let (_, server_connection) = stream.get_ref();
let peer_certs = server_connection.peer_certificates().map(|x| x.to_vec());
async move {
Ok::<_, std::io::Error>(service_fn(move |_req| {
let peer_certs = peer_certs.clone();
async {
match peer_certs {
None => response::Builder::new()
.status(401)
.body("could not identify client certificate".to_string()),
Some(vec) if vec.len() != 1 => response::Builder::new()
.status(406)
.body(format!("can only handle 1 cert, got {}", vec.len())),
Some(mut cert_vec) => {
let Certificate(cert) = cert_vec.remove(0);
let base64_cert = general_purpose::STANDARD.encode(cert);
response::Builder::new().status(200).body(base64_cert)
}
}
}
}))
}
});
let server = Server::builder(listener).serve(service);
tokio::spawn(server);
// positive test: setting the CA should allow this
let resp = test
.against(
Request::post("/")
.header("port", bound_port)
.header("set-ca", "please")
.body("Hello, Viceroy!")
.unwrap(),
)
.await;
let resp = resp.expect("got response");
assert_eq!(resp.status(), StatusCode::OK);
assert_eq!(
resp.into_body().read_into_string().await?,
"Hello, Viceroy!"
);
// negative test: if we don't set the CA, we should get a failure
let resp = test
.against(
Request::post("/")
.header("port", bound_port)
.body("Hello, Viceroy!")
.unwrap(),
)
.await;
assert_eq!(
resp.expect("got response").status(),
StatusCode::SERVICE_UNAVAILABLE
);
Ok(())
});
viceroy_test!(client_certs_work, |is_component| {
// Set up the test harness
// SAFETY: This isn't actually safe, but this is just a test and we haven't
// seen problems so far.
unsafe {
std::env::set_var(
"SSL_CERT_FILE",
concat!(env!("CARGO_MANIFEST_DIR"), "/../test-fixtures/data/ca.pem"),
)
};
let test = Test::using_fixture("mutual-tls.wasm").adapt_component(is_component);
let server_addr: SocketAddr = "127.0.0.1:0".parse().expect("localhost parses");
let incoming = AddrIncoming::bind(&server_addr).expect("bind");
let bound_port = incoming.local_addr().port();
let acceptor = TlsAcceptor::from(Arc::new(build_server_tls_config()));
let listener = TlsListener::new_hyper(acceptor, incoming);
let service = make_service_fn(|stream: &TlsStream<_>| {
let (_, server_connection) = stream.get_ref();
let peer_certs = server_connection.peer_certificates().map(|x| x.to_vec());
async move {
Ok::<_, std::io::Error>(service_fn(move |_req| {
let peer_certs = peer_certs.clone();
async {
match peer_certs {
None => response::Builder::new()
.status(401)
.body("could not identify client certificate".to_string()),
Some(vec) if vec.len() != 1 => response::Builder::new()
.status(406)
.body(format!("can only handle 1 cert, got {}", vec.len())),
Some(mut cert_vec) => {
let Certificate(cert) = cert_vec.remove(0);
let base64_cert = general_purpose::STANDARD.encode(cert);
response::Builder::new().status(200).body(base64_cert)
}
}
}
}))
}
});
let server = Server::builder(listener).serve(service);
tokio::spawn(server);
let resp = test
.against(
Request::post("/")
.header("port", bound_port)
.header("set-ca", "please")
.body("Hello, Viceroy!")
.unwrap(),
)
.await?;
assert_eq!(resp.status(), StatusCode::OK);
assert_eq!(
resp.into_body().read_into_string().await?,
"Hello, Viceroy!"
);
// SAFETY: See the comment above about `set_var`.
unsafe { std::env::remove_var("SSL_CERT_FILE") };
Ok(())
});
================================================
FILE: cli/tests/integration/common/backends.rs
================================================
use std::collections::HashMap;
use std::sync::{Arc, Weak};
use hyper::http::HeaderValue;
use hyper::http::uri::PathAndQuery;
use hyper::{Body as HyperBody, Request, Response, Uri};
use tokio::sync::Mutex;
use super::{AsyncResp, TestServer, TestService};
pub type BackendName = String;
/// A set of test backend definitions and possibly-running test servers for those backends.
#[derive(Clone, Debug)]
pub struct TestBackends {
inner: Arc<Mutex<Inner>>,
}
impl TestBackends {
/// Create a new, empty set of test backends.
pub fn new() -> Self {
Self {
inner: Arc::new(Mutex::new(Inner::new())),
}
}
/// Initialize a set of test backends from [`viceroy_lib::config::Backends`] that probably came
/// from a `fastly.toml` file.
///
/// Note that this constructor adds backend definitions without an associated test service. A
/// test service must be set for each backend with [`TestBackends::set_test_service()`] or
/// [`TestBackends::set_async_test_service()`] before starting the test servers.
pub fn from_backend_configs(backend_configs: &viceroy_lib::config::Backends) -> Self {
let mut inner = Inner::new();
for (name, backend_config) in backend_configs {
let test_backend = TestBackend {
path: backend_config
.uri
.path_and_query()
.cloned()
.unwrap_or_else(|| PathAndQuery::from_static("/")),
override_host: backend_config.override_host.clone(),
cert_host: backend_config.cert_host.clone(),
use_sni: backend_config.use_sni,
test_service: None,
test_server: None,
};
inner.map.insert(name.clone(), test_backend);
}
Self {
inner: Arc::new(Mutex::new(inner)),
}
}
/// Get [`viceroy_lib::config::Backends`] for the defined test backends and their test servers.
///
/// Panics if the test servers have not been started, as the ephemeral ports bound during test
/// server startup are required in order to provide complete backend configurations.
pub async fn backend_configs(&self) -> viceroy_lib::config::Backends {
let inner = self.inner.lock().await;
let mut backends = viceroy_lib::config::Backends::new();
for (name, backend) in inner.map.iter() {
let addr = backend
.test_server
.as_ref()
.expect("TestBackend servers must be running to get backend configurations")
.bound_addr;
let uri = format!("http://{addr}{}", backend.path)
.parse()
.expect("backend uri must be valid");
let backend_config = viceroy_lib::config::Backend {
uri,
override_host: backend.override_host.clone(),
cert_host: backend.cert_host.clone(),
use_sni: backend.use_sni,
grpc: false,
client_cert: None,
ca_certs: vec![],
health: viceroy_lib::config::BackendHealth::Unknown,
};
backends.insert(name.to_string(), Arc::new(backend_config));
}
backends
}
/// Get a [`TestBackendBuilder`] that will add a backend of the given name when built.
pub fn test_backend(&self, name: &str) -> TestBackendBuilder {
TestBackendBuilder {
inner: Arc::downgrade(&self.inner),
name: name.to_string(),
path: "/".to_string(),
override_host: None,
use_sni: true,
test_service: None,
}
}
/// Set the test service for the backend of the given name.
///
/// Panics if the test servers have already been started.
#[allow(unused)] // It's not used for now, but could be useful for advanced backend chicanery.
pub async fn set_test_service<TestServiceFn>(&self, name: &str, test_service: TestServiceFn)
where
TestServiceFn: Fn(Request<Vec<u8>>) -> Response<Vec<u8>>,
TestServiceFn: Send + Sync + 'static,
{
let mut inner = self.inner.lock().await;
assert!(
!inner.servers_are_running,
"cannot set a test service once servers are running"
);
inner
.map
.get_mut(name)
.unwrap_or_else(|| panic!("backend {name:?} not found"))
.test_service = Some(TestService::Sync(Arc::new(test_service)));
}
/// Set the asynchronous test service for the backend of the given name.
///
/// Panics if the test servers have already been started.
#[allow(unused)] // It's not used for now, but could be useful for advanced backend chicanery.
pub async fn set_async_test_service<TestServiceFn>(
&self,
name: &str,
test_service: TestServiceFn,
) where
TestServiceFn: Fn(Request<HyperBody>) -> AsyncResp,
TestServiceFn: Send + Sync + 'static,
{
let mut inner = self.inner.lock().await;
assert!(
!inner.servers_are_running,
"cannot set a test service once servers are running"
);
inner
.map
.get_mut(name)
.unwrap_or_else(|| panic!("backend {name:?} not found"))
.test_service = Some(TestService::Async(Arc::new(test_service)));
}
/// Are the backend test servers running?
pub async fn servers_are_running(&self) -> bool {
self.inner.lock().await.servers_are_running
}
/// Start the backend test servers.
///
/// Panics if the servers are already running, or if any backend is missing a test service.
pub async fn start_servers(&self) {
let mut inner = self.inner.lock().await;
assert!(
!inner.servers_are_running,
"cannot start TestBackend servers more than once"
);
for (name, backend) in inner.map.iter_mut() {
let Some(service) = backend.test_service.as_ref() else {
panic!("no service defined for backend {name}");
};
backend.test_server = Some(Arc::new(service.spawn()));
}
inner.servers_are_running = true;
}
/// Get the [`Uri`] suitable for sending a request to a running backend test server.
///
/// Specifically, this `Uri` will include the ephemeral port assigned when the test server was
/// started, which must be known in advance to properly test fixtures using dynamic backends.
///
/// Panics if no backend by this name is defined, or if the backend test servers have not yet been
/// started.
pub async fn uri_for_backend_server(&self, name: &str) -> Uri {
let inner = self.inner.lock().await;
let backend = inner.map.get(name).expect("backend not found");
let addr = backend
.test_server
.as_ref()
.expect("TestBackend servers must be running to get backend configurations")
.bound_addr;
format!("http://{addr}{}", backend.path)
.parse()
.expect("backend uri must be valid")
}
}
#[derive(Debug)]
struct Inner {
map: HashMap<BackendName, TestBackend>,
servers_are_running: bool,
}
impl Inner {
pub fn new() -> Self {
Self {
map: HashMap::new(),
servers_are_running: false,
}
}
}
#[derive(Clone, Debug)]
pub struct TestBackend {
path: PathAndQuery,
override_host: Option<HeaderValue>,
cert_host: Option<String>,
use_sni: bool,
test_service: Option<TestService>,
test_server: Option<Arc<TestServer>>,
}
#[derive(Debug)]
pub struct TestBackendBuilder {
inner: Weak<Mutex<Inner>>,
name: String,
path: String,
override_host: Option<String>,
use_sni: bool,
test_service: Option<TestService>,
}
impl TestBackendBuilder {
/// Set the path to be prepended to requests sent to this backend (`/` by default).
pub fn path(mut self, path: &str) -> Self {
self.path = path.to_owned();
self
}
/// Set the `override_host` parameter on this backend (not set by default).
pub fn override_host(mut self, override_host: &str) -> Self {
self.override_host = Some(override_host.to_string());
self
}
/// Set the `use_sni` parameter on this backend (`true` by default).
pub fn use_sni(mut self, use_sni: bool) -> Self {
self.use_sni = use_sni;
self
}
/// Set the synchronous service function to use for this backend.
///
/// The service function takes a request argument with a byte vector body, and returns a
/// response with a byte vector body. It will be called for each request sent to this backend's
/// test server.
///
/// A test service (sync or async) must be set before starting the test servers.
pub fn test_service<TestServiceFn>(mut self, test_service: TestServiceFn) -> Self
where
TestServiceFn: Fn(Request<Vec<u8>>) -> Response<Vec<u8>>,
TestServiceFn: Send + Sync + 'static,
{
self.test_service = Some(TestService::Sync(Arc::new(test_service)));
self
}
/// Set the asynchronous service function to use for this backend.
///
/// The service function takes a request argument with a `hyper::Body`, and returns a response
/// with a `hyper::Body`. It will be called for each request sent to this backend's test server.
///
/// A test service (sync or async) must be set before starting the test servers.
pub fn async_test_service<TestServiceFn>(mut self, test_service: TestServiceFn) -> Self
where
TestServiceFn: Fn(Request<HyperBody>) -> AsyncResp,
TestServiceFn: Send + Sync + 'static,
{
self.test_service = Some(TestService::Async(Arc::new(test_service)));
self
}
/// Finish building this backend and add it to the [`TestBackends`] that created this builder.
///
/// Panics if:
///
/// * The `TestBackends` that created this builder no longer exists, or its test servers have
/// already been started
/// * The `path` does not parse as a valid `PathAndQuery`
/// * The `override_host` does not parse as a valid `HeaderValue`
pub async fn build(self) {
let inner_arc = self.inner.upgrade().expect("TestBackends dropped");
let path = self.path.parse().expect("invalid backend path");
let override_host = self
.override_host
.map(|s| s.parse().expect("can parse override_host"));
let mut inner = inner_arc.lock().await;
if inner.servers_are_running {
panic!("cannot add test backends after starting servers");
}
inner.map.insert(
self.name,
TestBackend {
path,
override_host,
cert_host: None,
use_sni: self.use_sni,
test_service: self.test_service,
test_server: None,
},
);
}
}
================================================
FILE: cli/tests/integration/common.rs
================================================
//! Common values and types used by test fixtures
use futures::stream::StreamExt;
use hyper::{Body as HyperBody, Request, Response, Server, Uri, service};
use std::{
collections::HashSet,
convert::Infallible,
future::Future,
io::Write,
net::{Ipv4Addr, SocketAddr},
path::PathBuf,
sync::{Arc, Mutex},
};
use tracing_subscriber::filter::EnvFilter;
use viceroy_lib::config::UnknownImportBehavior;
use viceroy_lib::{
ExecuteCtx, ProfilingStrategy, ViceroyService,
body::Body,
config::{
Acls, DeviceDetection, Dictionaries, FakeValidFastlyKeys, FastlyConfig, Geolocation,
ObjectStores, SecretStores, ShieldingSites,
},
};
use wasmtime::WasmFeatures;
pub use self::backends::TestBackends;
mod backends;
#[macro_export]
macro_rules! viceroy_test {
($name:ident, |$is_component:ident| $body:block) => {
mod $name {
use super::*;
async fn test_impl($is_component: bool) -> TestResult {
$body
}
#[tokio::test(flavor = "multi_thread")]
async fn core_wasm() -> TestResult {
test_impl(false).await
}
#[tokio::test(flavor = "multi_thread")]
async fn component() -> TestResult {
test_impl(true).await
}
}
};
}
/// A shorthand for the path to our test fixtures' build artifacts for Rust tests.
///
/// This value can be appended with the name of a fixture's `.wasm` in a test program, using the
/// [`format!`][fmt] macro. For example:
///
/// ```
/// let module_path = format!("{}/guest.wasm", RUST_FIXTURE_PATH);
/// ```
pub static RUST_FIXTURE_PATH: &str = "../test-fixtures/target/wasm32-wasip1/debug/";
/// A shorthand for the path to our test fixtures' build artifacts for WAT tests.
///
/// This value can be appended with the name of a fixture's `.wat` in a test program, using the
/// [`format!`][fmt] macro. For example:
///
/// ```
/// let module_path = format!("{}/guest.wat", WAT_FIXTURE_PATH);
/// ```
pub static WAT_FIXTURE_PATH: &str = "../test-fixtures/";
/// A catch-all error, so we can easily use `?` in test cases.
pub type Error = Box<dyn std::error::Error + Send + Sync>;
/// Handy alias for the return type of async Tokio tests
pub type TestResult = Result<(), Error>;
/// A builder for running individual requests through a wasm fixture.
pub struct Test {
module_path: PathBuf,
acls: Acls,
backends: TestBackends,
device_detection: DeviceDetection,
dictionaries: Dictionaries,
geolocation: Geolocation,
object_stores: ObjectStores,
secret_stores: SecretStores,
shielding_sites: ShieldingSites,
fake_valid_fastly_keys: FakeValidFastlyKeys,
capture_logs: Arc<Mutex<dyn Write + Send>>,
log_stdout: bool,
log_stderr: bool,
via_hyper: bool,
unknown_import_behavior: UnknownImportBehavior,
adapt_component: bool,
profiling_strategy: ProfilingStrategy,
guest_profile_config: Option<viceroy_lib::GuestProfileConfig>,
}
impl Test {
/// Create a new test given the file name for its wasm fixture.
pub fn using_fixture(fixture: &str) -> Self {
let mut module_path = PathBuf::from(RUST_FIXTURE_PATH);
module_path.push(fixture);
Self {
module_path,
acls: Acls::new(),
backends: TestBackends::new(),
device_detection: DeviceDetection::new(),
dictionaries: Dictionaries::new(),
geolocation: Geolocation::new(),
object_stores: ObjectStores::new(),
secret_stores: SecretStores::new(),
shielding_sites: ShieldingSites::new(),
fake_valid_fastly_keys: FakeValidFastlyKeys::new(),
capture_logs: Arc::new(Mutex::new(std::io::stdout())),
log_stdout: false,
log_stderr: false,
via_hyper: false,
unknown_import_behavior: Default::default(),
adapt_component: false,
profiling_strategy: ProfilingStrategy::None,
guest_profile_config: None,
}
}
/// Create a new test given the file name for its wasm fixture.
pub fn using_wat_fixture(fixture: &str) -> Self {
let mut module_path = PathBuf::from(WAT_FIXTURE_PATH);
module_path.push(fixture);
Self {
module_path,
acls: Acls::new(),
backends: TestBackends::new(),
device_detection: DeviceDetection::new(),
dictionaries: Dictionaries::new(),
geolocation: Geolocation::new(),
object_stores: ObjectStores::new(),
secret_stores: SecretStores::new(),
shielding_sites: ShieldingSites::new(),
fake_valid_fastly_keys: FakeValidFastlyKeys::new(),
capture_logs: Arc::new(Mutex::new(std::io::stdout())),
log_stdout: false,
log_stderr: false,
via_hyper: false,
unknown_import_behavior: Default::default(),
adapt_component: false,
profiling_strategy: ProfilingStrategy::None,
guest_profile_config: None,
}
}
/// Use backend and dictionary settings provided in a `fastly.toml` file.
pub fn using_fastly_toml(self, fastly_toml: &str) -> Result<Self, Error> {
let config = fastly_toml.parse::<FastlyConfig>()?;
Ok(Self {
acls: config.acls().to_owned(),
backends: TestBackends::from_backend_configs(config.backends()),
device_detection: config.device_detection().to_owned(),
dictionaries: config.dictionaries().to_owned(),
geolocation: config.geolocation().to_owned(),
object_stores: config.object_stores().to_owned(),
secret_stores: config.secret_stores().to_owned(),
shielding_sites: config.shielding_sites().to_owned(),
fake_valid_fastly_keys: config.fake_valid_fastly_keys().to_owned(),
..self
})
}
/// Use existing [`TestBackends`] for this test, replacing any previously existing backends.
#[allow(unused)] // It's not used for now, but could be useful for advanced backend chicanery.
pub fn using_test_backends(mut self, test_backends: &TestBackends) -> Self {
self.backends = test_backends.clone();
self
}
/// Use the specified [`UnknownImportBehavior`] for this test.
pub fn using_unknown_import_behavior(
mut self,
unknown_import_behavior: UnknownImportBehavior,
) -> Self {
self.unknown_import_behavior = unknown_import_behavior;
self
}
/// Add a backend definition to this test.
///
/// The `name` is the static backend name that can be passed as, for example, the argument to
/// `Request::send()`.
///
/// The `path` is the path that will be prepended to the URLs of requests sent to this
/// backend. Note that the host and port used to send requests to this backend will be
/// automatically determined when the test servers are started.
///
/// `override_host` optionally sets the corresponding parameter in the backend definition.
///
/// `service` is the synchronous function that the test server will run on each request this
/// backend receives in order to determine what response to send.
pub async fn backend<ServiceFn>(
self,
name: &str,
path: &str,
override_host: Option<&str>,
service: ServiceFn,
) -> Self
where
ServiceFn: Fn(Request<Vec<u8>>) -> Response<Vec<u8>>,
ServiceFn: Send + Sync + 'static,
{
let uri: Uri = path.parse().expect("invalid backend URL");
let mut builder = self
.backends
.test_backend(name)
.path(uri.path())
.use_sni(true)
.test_service(service);
if let Some(override_host) = override_host {
builder = builder.override_host(override_host);
}
builder.build().await;
self
}
/// Add a backend definition to this test with an asynchronous test server function.
///
/// The `name` is the static backend name that can be passed as, for example, the argument to
/// `Request::send()`.
///
/// The `path` is the path that will be prepended to the URLs of requests sent to this
/// backend. Note that the host and port used to send requests to this backend will be
/// automatically determined when the test servers are started.
///
/// `override_host` optionally sets the corresponding parameter in the backend definition.
///
/// `service` is the asynchronous function that the test server will run on each request this
/// backend receives in order to determine what response to send.
pub async fn async_backend<ServiceFn>(
self,
name: &str,
url: &str,
override_host: Option<&str>,
service: ServiceFn,
) -> Self
where
ServiceFn: Fn(Request<HyperBody>) -> AsyncResp,
ServiceFn: Send + Sync + 'static,
{
let uri: Uri = url.parse().expect("invalid backend URL");
let mut builder = self
.backends
.test_backend(name)
.path(uri.path())
.use_sni(true)
.async_test_service(service);
if let Some(override_host) = override_host {
builder = builder.override_host(override_host);
}
builder.build().await;
self
}
pub fn capture_logs(mut self, capture_logs: Arc<Mutex<dyn Write + Send>>) -> Self {
self.capture_logs = capture_logs;
self
}
/// Treat stderr as a logging endpoint for this test.
pub fn log_stderr(self) -> Self {
Self {
log_stderr: true,
..self
}
}
/// Treat stdout as a logging endpoint for this test.
pub fn log_stdout(self) -> Self {
Self {
log_stdout: true,
..self
}
}
/// Actually spin up a hyper server and client for this test, rather than just
/// passing the request through the guest code.
pub fn via_hyper(self) -> Self {
Self {
via_hyper: true,
..self
}
}
/// Automatically adapt the wasm to a component before running.
pub fn adapt_component(mut self, adapt: bool) -> Self {
self.adapt_component = adapt;
self
}
/// Enable guest profiling with the specified configuration.
pub fn with_guest_profiling(mut self, config: viceroy_lib::GuestProfileConfig) -> Self {
self.guest_profile_config = Some(config);
self
}
/// Pass the given requests through this test, returning the associated responses.
///
/// A `Test` can be used repeatedly against different requests, either individually (as with
/// `against()`) or in batches (as with `against_many()`).
///
/// The difference between calling this function with many requests, rather than calling
/// `against()` multiple times, is that the requests shared in an `against_many()` call will
/// share the same Wasm execution context. This can be useful when validating interactions
/// across shared state in the context. Subsequent calls to `against_many()` (or `against()`)
/// will use a fresh context.
///
/// When this function is called, the test servers for its defined backends will be started, if
/// they have not been already. Those test servers will remain running for the lifetime of this
/// [`Test`] object, and are therefore potentially reused for multiple `against*()` invocations.
pub async fn against_many(
&self,
mut reqs: Vec<Request<impl Into<HyperBody>>>,
) -> Result<Vec<Response<Body>>, Error> {
let mut responses = Vec::with_capacity(reqs.len());
// Install a tracing subscriber. We use a human-readable event formatter in tests, using a
// writer that supports input capturing for `cargo test`. This subscribes to all events in
// the `viceroy-lib` library.
tracing_subscriber::fmt()
.with_env_filter(
EnvFilter::from_default_env().add_directive("viceroy_lib=trace".parse().unwrap()),
)
.pretty()
.with_test_writer()
// `try_init` returns an `Err` if the initialization was unsuccessful, likely because a
// global subscriber was already installed. we will ignore this error if it happens.
.try_init()
.ok();
// Start the backend test servers so that we can ask `TestBackends` for the final backend
// configurations, including the ephemeral ports we'll need for requests to actually land on
// the right servers. The test servers will remain running until after this [`Test`] is
// dropped.
if !self.backends.servers_are_running().await {
self.backends.start_servers().await;
}
let ctx = ExecuteCtx::build(
&self.module_path,
self.profiling_strategy,
HashSet::new(),
self.guest_profile_config.clone(),
self.unknown_import_behavior,
self.adapt_component,
WasmFeatures::default(),
)?
.with_acls(self.acls.clone())
.with_backends(self.backends.backend_configs().await)
.with_dictionaries(self.dictionaries.clone())
.with_device_detection(self.device_detection.clone())
.with_geolocation(self.geolocation.clone())
.with_object_stores(self.object_stores.clone())
.with_secret_stores(self.secret_stores.clone())
.with_shielding_sites(self.shielding_sites.clone())
.with_fake_valid_fastly_keys(self.fake_valid_fastly_keys.clone())
.with_capture_logs(self.capture_logs.clone())
.with_log_stderr(self.log_stderr)
.with_log_stdout(self.log_stdout)
.finish()?;
if self.via_hyper {
let svc = ViceroyService::new(ctx);
// We use the "graceful shutdown" capability of Hyper, with a oneshot channel signaling
// completion:
let (tx, rx) = tokio::sync::oneshot::channel();
// NB the server is spawned onto a dedicated async task; we are going to use the
// _current_ task to act as the client.
let (server_handle, server_addr) = {
// Bind the server to an ephemeral port to allow for parallel test execution.
let server = hyper::Server::bind(&([127, 0, 0, 1], 0).into()).serve(svc);
let server_addr = server.local_addr();
let server_handle = tokio::spawn(server.with_graceful_shutdown(async {
rx.await
.expect("receiver error while shutting down hyper server")
}));
(server_handle, server_addr)
};
for mut req in reqs.drain(..) {
// Fix up the request URI to include the ephemeral port assignment. The `http::Uri`
// interface makes this unfortunately verbose.
let new_uri = Uri::builder()
.scheme("http")
.authority(server_addr.to_string())
.path_and_query(
req.uri()
.path_and_query()
.map(|p_and_q| p_and_q.as_str())
.unwrap_or(""),
)
.build()
.unwrap();
*req.uri_mut() = new_uri;
// Pass the request to the server via a Hyper client on the _current_ task:
let resp = hyper::Client::new().request(req.map(Into::into)).await?;
responses.push(resp.map(Into::into));
}
// We're done with these test requests, so shut down the server.
tx.send(())
.expect("sender error while shutting down hyper server");
// Reap the task handle to ensure that the server did indeed shut down.
let _ = server_handle.await?;
} else {
for mut req in reqs.drain(..) {
// We do not have to worry about an ephemeral port in the non-hyper scenario, but we
// still normalize the request URI for consistency.
let new_uri = Uri::builder()
.scheme("http")
.authority("localhost")
.path_and_query(
req.uri()
.path_and_query()
.map(|p_and_q| p_and_q.as_str())
.unwrap_or(""),
)
.build()
.unwrap();
*req.uri_mut() = new_uri;
let local = (Ipv4Addr::LOCALHOST, 80).into();
let remote = (Ipv4Addr::LOCALHOST, 0).into();
let resp = ctx
.clone()
.handle_request(req.map(Into::into), local, remote)
.await
.map(|result| {
match result {
(resp, None) => resp,
(_, Some(err)) => {
// Splat the string representation of the runtime error into a synthetic
// 500. This is a bit of a hack, but good enough to check for expected error
// strings.
let body = err.to_string();
Response::builder()
.status(hyper::StatusCode::INTERNAL_SERVER_ERROR)
.body(Body::from(body.as_bytes()))
.unwrap()
}
}
})?;
responses.push(resp);
}
}
Ok(responses)
}
/// Pass the given request to a Viceroy execution context defined by this test.
///
/// Only the path, query, and fragment of the request URI will be used; the host and port will
/// be rewritten as appropriate to connect to the Viceroy context.
///
/// A `Test` can be used repeatedly against different requests. Note, however, that
/// a fresh execution context is set up each time.
pub async fn against(
&self,
req: Request<impl Into<HyperBody>>,
) -> Result<Response<Body>, Error> {
Ok(self
.against_many(vec![req])
.await?
.pop()
.expect("singleton back from against_many"))
}
/// Pass an empty `GET /` request through this test.
pub async fn against_empty(&self) -> Result<Response<Body>, Error> {
self.against(Request::get("/").body("").unwrap()).await
}
/// Start the test servers for this test's [`TestBackends`].
///
/// Panics if a test service has not been set for all configured backends. This is unlikely to
/// occur unless using [`Test::using_fastly_toml()] or [`Test::using_backends()`], as the
/// convenience methods for defining backends require a test service.
pub async fn start_backend_servers(&self) {
self.backends.start_servers().await;
}
/// Get the [`Uri`] suitable for sending a request to a running backend test server.
///
/// Specifically, this `Uri` will include the ephemeral port assigned when the test server was
/// started, which must be known in advance to properly test fixtures using dynamic backends.
///
/// Panics if no backend by this name is defined, or if the backend test servers have not yet
/// been started.
pub async fn uri_for_backend_server(&self, name: &str) -> Uri {
self.backends.uri_for_backend_server(name).await
}
}
/// A handle to a running test server, used to keep track of its assigned ephemeral port and to
/// gracefully shut down the server when it's no longer needed.
#[derive(Debug)]
struct TestServer {
bound_addr: SocketAddr,
terminate_signal: Option<tokio::sync::oneshot::Sender<()>>,
task_handle: tokio::task::JoinHandle<()>,
}
impl Drop for TestServer {
fn drop(&mut self) {
self.terminate_signal
.take()
.unwrap()
.send(())
.expect("could not send terminate signal to test server");
if !self.task_handle.is_finished() {
self.task_handle.abort();
}
}
}
type SyncService = dyn Fn(Request<Vec<u8>>) -> Response<Vec<u8>> + Send + Sync;
type AsyncResp = Box<dyn Future<Output = Response<HyperBody>> + Send + Sync>;
type AsyncService = dyn Fn(Request<HyperBody>) -> AsyncResp + Send + Sync;
#[derive(Clone)]
enum TestService {
Sync(Arc<SyncService>),
Async(Arc<AsyncService>),
}
impl std::fmt::Debug for TestService {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Sync(_) => f.debug_tuple("Sync").finish(),
Self::Async(_) => f.debug_tuple("Async").finish(),
}
}
}
impl TestService {
/// Spawn a test server onto a dedicated Tokio task, returning a handle to allow for graceful
/// termination of the server when it is no longer needed.
fn spawn(&self) -> TestServer {
let service = self.clone();
// we transform `service` into an async function that consumes Hyper bodies. that requires a bit
// of `Arc` and `move` operations because each invocation needs to produce a distinct `Future`
let async_service = Arc::new(move |req: Request<HyperBody>| {
let service = service.clone();
async move {
let resp = match service {
TestService::Sync(s) => {
let (parts, body) = req.into_parts();
let mut body = Box::new(body); // for pinning
// read out all of the bytes from the body into a vector, then re-assemble the request
let mut body_bytes = Vec::new();
while let Some(chunk) = body.next().await {
body_bytes.extend_from_slice(&chunk.unwrap());
}
let req = Request::from_parts(parts, body_bytes);
// pass the request through the service function, then convert its body into
// the form that Hyper wants
s(req).map(HyperBody::from)
}
TestService::Async(s) => Box::into_pin(s(req)).await.map(HyperBody::from),
};
let res: Result<_, hyper::Error> = Ok(resp);
res
}
});
// now we go through Tower's service layers, wrapping `async_host`
let make_service = service::make_service_fn(move |_conn| {
let async_host = async_service.clone();
async move { Ok::<_, Infallible>(service::service_fn(move |req| async_host(req))) }
});
// we set up a "graceful shutdown" for the server, with a oneshot channel signaling completion.
let (terminate_signal, rx) = tokio::sync::oneshot::channel();
// Bind the test server to an ephemeral port to avoid conflicts between
// concurrently-executing tests.
let server = Server::bind(&([127, 0, 0, 1], 0).into()).serve(make_service);
let bound_addr = server.local_addr();
let graceful_server = server.with_graceful_shutdown(async {
rx.await
.expect("receiver error while shutting down mock host")
});
let task_handle = tokio::spawn(async {
graceful_server
.await
.expect("mock host shut down with hyper error")
});
TestServer {
bound_addr,
terminate_signal: Some(terminate_signal),
task_handle,
}
}
}
================================================
FILE: cli/tests/integration/config_store_lookup.rs
================================================
use crate::{
common::{Test, TestResult},
viceroy_test,
};
use hyper::{StatusCode, body::to_bytes};
viceroy_test!(json_config_store_lookup_works, |is_component| {
const FASTLY_TOML: &str = r#"
name = "json-config_store-lookup"
description = "json config_store lookup test"
authors = ["Jill Bryson <jbryson@fastly.com>", "Rose McDowall <rmcdowall@fastly.com>"]
language = "rust"
[local_server.config_stores.animals]
file = "../test-fixtures/data/json-config_store.json"
format = "json"
"#;
let resp = Test::using_fixture("config-store-lookup.wasm")
.adapt_component(is_component)
.using_fastly_toml(FASTLY_TOML)?
.against_empty()
.await?;
assert_eq!(resp.status(), StatusCode::OK);
assert!(
to_bytes(resp.into_body())
.await
.expect("can read body")
.to_vec()
.is_empty()
);
Ok(())
});
viceroy_test!(inline_toml_config_store_lookup_works, |is_component| {
const FASTLY_TOML: &str = r#"
name = "inline-toml-config_store-lookup"
description = "inline toml config_store lookup test"
authors = ["Jill Bryson <jbryson@fastly.com>", "Rose McDowall <rmcdowall@fastly.com>"]
language = "rust"
[local_server.config_stores.animals]
format = "inline-toml"
[local_server.config_stores.animals.contents]
dog = "woof"
cat = "meow"
"#;
let resp = Test::using_fixture("config-store-lookup.wasm")
.adapt_component(is_component)
.using_fastly_toml(FASTLY_TOML)?
.against_empty()
.await?;
assert_eq!(resp.status(), StatusCode::OK);
assert!(
to_bytes(resp.into_body())
.await
.expect("can read body")
.to_vec()
.is_empty()
);
Ok(())
});
viceroy_test!(missing_config_store_works, |is_component| {
const FASTLY_TOML: &str = r#"
name = "missing-config_store-config"
description = "missing config_store test"
language = "rust"
"#;
let resp = Test::using_fixture("config-store-lookup.wasm")
.adapt_component(is_component)
.using_fastly_toml(FASTLY_TOML)?
.against_empty()
.await?;
assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
Ok(())
});
================================================
FILE: cli/tests/integration/device_detection_lookup.rs
================================================
use crate::{
common::{Test, TestResult},
viceroy_test,
};
use hyper::{StatusCode, body::to_bytes};
viceroy_test!(json_device_detection_lookup_works, |is_component| {
const FASTLY_TOML: &str = r#"
name = "json-device-detection-lookup"
description = "json device detection lookup test"
authors = ["Test User <test_user@fastly.com>"]
language = "rust"
[local_server]
[local_server.device_detection]
file = "../test-fixtures/data/device-detection-mapping.json"
format = "json"
"#;
let resp = Test::using_fixture("device-detection-lookup.wasm")
.adapt_component(is_component)
.using_fastly_toml(FASTLY_TOML)?
.against_empty()
.await?;
assert_eq!(resp.status(), StatusCode::OK);
assert!(
to_bytes(resp.into_body())
.await
.expect("can read body")
.to_vec()
.is_empty()
);
Ok(())
});
viceroy_test!(inline_toml_device_detection_lookup_works, |is_component| {
const FASTLY_TOML: &str = r#"
name = "inline-toml-device-detection-lookup"
description = "inline toml device detection lookup test"
authors = ["Test User <test_user@fastly.com>"]
language = "rust"
[local_server]
[local_server.device_detection]
format = "inline-toml"
[local_server.device_detection.user_agents]
[local_server.device_detection.user_agents."Mozilla/5.0 (X11; Linux x86_64; rv:10.0) Gecko/20100101 Firefox/10.0 [FBAN/FBIOS;FBAV/8.0.0.28.18;FBBV/1665515;FBDV/iPhone4,1;FBMD/iPhone;FBSN/iPhone OS;FBSV/7.0.4;FBSS/2; FBCR/Telekom.de;FBID/phone;FBLC/de_DE;FBOP/5]"]
user_agent = {}
os = {}
device = {name = "iPhone", brand = "Apple", model = "iPhone4,1", hwtype = "Mobile Phone", is_ereader = false, is_gameconsole = false, is_mediaplayer = false, is_mobile = true, is_smarttv = false, is_tablet = false, is_tvplayer = false, is_desktop = false, is_touchscreen = true }
[local_server.device_detection.user_agents."ghosts-app/1.0.2.1 (ASUSTeK COMPUTER INC.; X550CC; Windows 8 (X86); en)"]
user_agent = {}
os = {}
device = {name = "Asus TeK", brand = "Asus", model = "TeK", is_desktop = false }
"#;
let resp = Test::using_fixture("device-detection-lookup.wasm")
.adapt_component(is_component)
.using_fastly_toml(FASTLY_TOML)?
.against_empty()
.await?;
assert_eq!(resp.status(), StatusCode::OK);
assert!(
to_bytes(resp.into_body())
.await
.expect("can read body")
.to_vec()
.is_empty()
);
Ok(())
});
================================================
FILE: cli/tests/integration/dictionary_lookup.rs
================================================
use crate::{
common::{Test, TestResult},
viceroy_test,
};
use hyper::{StatusCode, body::to_bytes};
viceroy_test!(json_dictionary_lookup_works, |is_component| {
const FASTLY_TOML: &str = r#"
name = "json-dictionary-lookup"
description = "json dictionary lookup test"
authors = ["Jill Bryson <jbryson@fastly.com>", "Rose McDowall <rmcdowall@fastly.com>"]
language = "rust"
[local_server]
[local_server.dictionaries]
[local_server.dictionaries.animals]
file = "../test-fixtures/data/json-dictionary.json"
format = "json"
"#;
let resp = Test::using_fixture("dictionary-lookup.wasm")
.adapt_component(is_component)
.using_fastly_toml(FASTLY_TOML)?
.against_empty()
.await?;
assert_eq!(resp.status(), StatusCode::OK);
assert!(
to_bytes(resp.into_body())
.await
.expect("can read body")
.to_vec()
.is_empty()
);
Ok(())
});
viceroy_test!(inline_toml_dictionary_lookup_works, |is_component| {
const FASTLY_TOML: &str = r#"
name = "inline-toml-dictionary-lookup"
description = "inline toml dictionary lookup test"
authors = ["Jill Bryson <jbryson@fastly.com>", "Rose McDowall <rmcdowall@fastly.com>"]
language = "rust"
[local_server]
[local_server.dictionaries]
[local_server.dictionaries.animals]
format = "inline-toml"
[local_server.dictionaries.animals.contents]
dog = "woof"
cat = "meow"
"#;
let resp = Test::using_fixture("dictionary-lookup.wasm")
.adapt_component(is_component)
.using_fastly_toml(FASTLY_TOML)?
.against_empty()
.await?;
assert_eq!(resp.status(), StatusCode::OK);
assert!(
to_bytes(resp.into_body())
.await
.expect("can read body")
.to_vec()
.is_empty()
);
Ok(())
});
viceroy_test!(missing_dictionary_works, |is_component| {
const FASTLY_TOML: &str = r#"
name = "missing-dictionary-config"
description = "missing dictionary test"
language = "rust"
"#;
let resp = Test::using_fixture("dictionary-lookup.wasm")
.adapt_component(is_component)
.using_fastly_toml(FASTLY_TOML)?
.against_empty()
.await?;
assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
Ok(())
});
================================================
FILE: cli/tests/integration/downstream_req.rs
================================================
use {
crate::{
common::{Test, TestResult},
viceroy_test,
},
hyper::{Request, StatusCode},
};
viceroy_test!(downstream_request_works, |is_component| {
let req = Request::get("/")
.header("Accept", "text/html")
.header("X-Custom-Test", "abcdef")
.body("Hello, world!")?;
let resp = Test::using_fixture("downstream-req.wasm")
.adapt_component(is_component)
.against(req)
.await?;
assert_eq!(resp.status(), StatusCode::OK);
Ok(())
});
================================================
FILE: cli/tests/integration/early_hints.rs
================================================
// A test to ensure that early hints (103 responses) don't cause errors in Viceroy.
use crate::{
common::{Test, TestResult},
viceroy_test,
};
viceroy_test!(early_hints, |is_component| {
let resp = Test::using_fixture("early-hints.wasm")
.adapt_component(is_component)
.against_empty()
.await?;
assert!(resp.status().is_success());
Ok(())
});
================================================
FILE: cli/tests/integration/edge_rate_limiting.rs
================================================
//! Tests related to HTTP request and response bodies.
use {
crate::{
common::{Test, TestResult},
viceroy_test,
},
hyper::StatusCode,
};
viceroy_test!(check_hostcalls_implemented, |is_component| {
let resp = Test::using_fixture("edge-rate-limiting.wasm")
.adapt_component(is_component)
.against_empty()
.await?;
assert_eq!(resp.status(), StatusCode::OK);
Ok(())
});
================================================
FILE: cli/tests/integration/env_vars.rs
================================================
use crate::{
common::{Test, TestResult},
viceroy_test,
};
viceroy_test!(env_vars_are_set, |is_component| {
let resp = Test::using_fixture("env-vars.wasm")
.adapt_component(is_component)
.against_empty()
.await?;
assert!(resp.status().is_success());
Ok(())
});
================================================
FILE: cli/tests/integration/fastly_key_is_valid.rs
================================================
use {
crate::{
common::{Test, TestResult},
viceroy_test,
},
hyper::{Request, StatusCode},
};
viceroy_test!(fastly_key_is_valid_with_valid_key, |is_component| {
let resp = Test::using_fixture("fastly-key-is-valid.wasm")
.adapt_component(is_component)
.using_fastly_toml(
r#"
manifest_version = 3
name = "fastly-key-is-valid-test"
language = "rust"
[local_server]
fake_valid_fastly_keys = ["test-key-123", "another-key"]
"#,
)?
.against(
Request::get("/")
.header("fastly-key", "test-key-123")
.body("")?,
)
.await?;
assert_eq!(resp.status(), StatusCode::OK);
let body = resp.into_body().read_into_string().await?;
assert!(
body.contains("is_valid=true"),
"expected valid key, got: {body}"
);
Ok(())
});
viceroy_test!(fastly_key_is_valid_with_invalid_key, |is_component| {
let resp = Test::using_fixture("fastly-key-is-valid.wasm")
.adapt_component(is_component)
.using_fastly_toml(
r#"
manifest_version = 3
name = "fastly-key-is-valid-test"
language = "rust"
[local_server]
fake_valid_fastly_keys = ["test-key-123", "another-key"]
"#,
)?
.against(
Request::get("/")
.header("fastly-key", "wrong-key")
.body("")?,
)
.await?;
assert_eq!(resp.status(), StatusCode::OK);
let body = resp.into_body().read_into_string().await?;
assert!(
body.contains("is_valid=false"),
"expected invalid key, got: {body}"
);
Ok(())
});
viceroy_test!(fastly_key_is_valid_with_no_header, |is_component| {
let resp = Test::using_fixture("fastly-key-is-valid.wasm")
.adapt_component(is_component)
.using_fastly_toml(
r#"
manifest_version = 3
name = "fastly-key-is-valid-test"
language = "rust"
[local_server]
fake_valid_fastly_keys = ["test-key-123"]
"#,
)?
.against(Request::get("/").body("")?)
.await?;
assert_eq!(resp.status(), StatusCode::OK);
let body = resp.into_body().read_into_string().await?;
assert!(
body.contains("is_valid=false"),
"expected invalid without header, got: {body}"
);
Ok(())
});
viceroy_test!(
fastly_key_is_valid_with_no_keys_configured,
|is_component| {
let resp = Test::using_fixture("fastly-key-is-valid.wasm")
.adapt_component(is_component)
.against(Request::get("/").header("fastly-key", "any-key").body("")?)
.await?;
assert_eq!(resp.status(), StatusCode::OK);
let body = resp.into_body().read_into_string().await?;
assert!(
body.contains("is_valid=false"),
"expected invalid when no keys configured, got: {body}"
);
Ok(())
}
);
================================================
FILE: cli/tests/integration/geolocation_lookup.rs
================================================
use crate::{
common::{Test, TestResult},
viceroy_test,
};
use hyper::{StatusCode, body::to_bytes};
viceroy_test!(json_geolocation_lookup_works, |is_component| {
const FASTLY_TOML: &str = r#"
name = "json-geolocation-lookup"
description = "json geolocation lookup test"
authors = ["Test User <test_user@fastly.com>"]
language = "rust"
[local_server]
[local_server.geolocation]
use_default_loopback = false
file = "../test-fixtures/data/geolocation-mapping.json"
format = "json"
"#;
let resp = Test::using_fixture("geolocation-lookup.wasm")
.adapt_component(is_component)
.using_fastly_toml(FASTLY_TOML)?
.against_empty()
.await?;
assert_eq!(resp.status(), StatusCode::OK);
assert!(
to_bytes(resp.into_body())
.await
.expect("can read body")
.to_vec()
.is_empty()
);
Ok(())
});
viceroy_test!(inline_toml_geolocation_lookup_works, |is_component| {
const FASTLY_TOML: &str = r#"
name = "inline-toml-geolocation-lookup"
description = "inline toml geolocation lookup test"
authors = ["Test User <test_user@fastly.com>"]
language = "rust"
[local_server]
[local_server.geolocation]
use_default_loopback = false
format = "inline-toml"
[local_server.geolocation.addresses]
[local_server.geolocation.addresses."127.0.0.1"]
as_name = "Fastly Test"
as_number = 12345
area_code = 123
city = "Test City"
conn_speed = "broadband"
conn_type = "wired"
continent = "NA"
country_code = "CA"
country_code3 = "CAN"
country_name = "Canada"
latitude = 12.345
longitude = 54.321
metro_code = 0
postal_code = "12345"
proxy_description = "?"
proxy_type = "?"
region = "BC"
utc_offset = -700
[local_server.geolocation.addresses."0000:0000:0000:0000:0000:0000:0000:0001"]
as_name = "Fastly Test IPv6"
as_number = 12345
area_code = 123
city = "Test City IPv6"
conn_speed = "broadband"
conn_type = "wired"
continent = "NA"
country_code = "CA"
country_code3 = "CAN"
country_name = "Canada"
latitude = 12.345
longitude = 54.321
metro_code = 0
postal_code = "12345"
proxy_description = "?"
proxy_type = "?"
region = "BC"
utc_offset = -700
"#;
let resp = Test::using_fixture("geolocation-lookup.wasm")
.adapt_component(is_component)
.using_fastly_toml(FASTLY_TOML)?
.against_empty()
.await?;
assert_eq!(resp.status(), StatusCode::OK);
assert!(
to_bytes(resp.into_body())
.await
.expect("can read body")
.to_vec()
.is_empty()
);
Ok(())
});
viceroy_test!(
default_configuration_geolocation_lookup_works,
|is_component| {
const FASTLY_TOML: &str = r#"
name = "default-config-geolocation-lookup"
description = "default config geolocation lookup test"
authors = ["Test User <test_user@fastly.com>"]
language = "rust"
"#;
let resp = Test::using_fixture("geolocation-lookup-default.wasm")
.adapt_component(is_component)
.using_fastly_toml(FASTLY_TOML)?
.against_empty()
.await?;
assert_eq!(resp.status(), StatusCode::OK);
assert!(
to_bytes(resp.into_body())
.await
.expect("can read body")
.to_vec()
gitextract_63zfz6_u/
├── .github/
│ └── workflows/
│ ├── changelog.yml
│ ├── release.yml
│ ├── rust.yml
│ └── test.yml
├── .gitignore
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Cargo.toml
├── Dockerfile
├── LICENSE
├── Makefile
├── README.md
├── SECURITY.md
├── cli/
│ ├── Cargo.toml
│ ├── src/
│ │ ├── execute_ctx.rs
│ │ ├── main.rs
│ │ ├── opts.rs
│ │ ├── subcommands/
│ │ │ ├── adapt.rs
│ │ │ ├── run.rs
│ │ │ └── serve.rs
│ │ └── subcommands.rs
│ └── tests/
│ ├── integration/
│ │ ├── acl.rs
│ │ ├── args.rs
│ │ ├── async_io.rs
│ │ ├── body.rs
│ │ ├── cache.rs
│ │ ├── client_certs.rs
│ │ ├── common/
│ │ │ └── backends.rs
│ │ ├── common.rs
│ │ ├── config_store_lookup.rs
│ │ ├── device_detection_lookup.rs
│ │ ├── dictionary_lookup.rs
│ │ ├── downstream_req.rs
│ │ ├── early_hints.rs
│ │ ├── edge_rate_limiting.rs
│ │ ├── env_vars.rs
│ │ ├── fastly_key_is_valid.rs
│ │ ├── geolocation_lookup.rs
│ │ ├── grpc.rs
│ │ ├── hello_world.gzip
│ │ ├── http_semantics.rs
│ │ ├── inspect.rs
│ │ ├── invalid_status_code.rs
│ │ ├── kv_store.rs
│ │ ├── logging.rs
│ │ ├── main.rs
│ │ ├── memory.rs
│ │ ├── profiling.rs
│ │ ├── request.rs
│ │ ├── response.rs
│ │ ├── reusable_sandboxes.rs
│ │ ├── secret_store.rs
│ │ ├── sending_response.rs
│ │ ├── shielding.rs
│ │ ├── sleep.rs
│ │ ├── unknown_import_behavior.rs
│ │ ├── upstream.rs
│ │ ├── upstream_async.rs
│ │ ├── upstream_dynamic.rs
│ │ ├── upstream_streaming.rs
│ │ └── vcpu_time.rs
│ ├── trap-test/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ └── main.rs
│ └── wasm/
│ ├── exit_code_4.wat
│ ├── invalid.wat
│ ├── minimal.wasm
│ ├── minimal.wat
│ └── trapping.wat
├── doc/
│ └── RELEASING.md
├── proptest-regressions/
│ ├── body.txt
│ ├── cache.txt
│ └── collecting_body.txt
├── rust-toolchain.toml
├── rustfmt.toml
├── src/
│ ├── acl.rs
│ ├── adapt.rs
│ ├── async_io.rs
│ ├── body.rs
│ ├── body_tee.rs
│ ├── cache/
│ │ ├── store.rs
│ │ └── variance.rs
│ ├── cache.rs
│ ├── collecting_body.rs
│ ├── component/
│ │ ├── adapter/
│ │ │ └── http_req.rs
│ │ ├── adapter.rs
│ │ ├── backend.rs
│ │ ├── compute/
│ │ │ ├── acl.rs
│ │ │ ├── async_io.rs
│ │ │ ├── backend.rs
│ │ │ ├── cache.rs
│ │ │ ├── compute_runtime.rs
│ │ │ ├── config_store.rs
│ │ │ ├── device_detection.rs
│ │ │ ├── dictionary.rs
│ │ │ ├── erl.rs
│ │ │ ├── error.rs
│ │ │ ├── geo.rs
│ │ │ ├── headers.rs
│ │ │ ├── http_body.rs
│ │ │ ├── http_cache.rs
│ │ │ ├── http_downstream.rs
│ │ │ ├── http_req.rs
│ │ │ ├── http_resp.rs
│ │ │ ├── http_types.rs
│ │ │ ├── image_optimizer.rs
│ │ │ ├── kv_store.rs
│ │ │ ├── log.rs
│ │ │ ├── purge.rs
│ │ │ ├── secret_store.rs
│ │ │ ├── security.rs
│ │ │ ├── shielding.rs
│ │ │ └── types.rs
│ │ ├── compute.rs
│ │ ├── erl.rs
│ │ ├── handles.rs
│ │ ├── http_req.rs
│ │ ├── image_optimizer.rs
│ │ ├── shielding.rs
│ │ └── wasi.rs
│ ├── component.rs
│ ├── config/
│ │ ├── acl.rs
│ │ ├── backends/
│ │ │ └── client_cert_info.rs
│ │ ├── backends.rs
│ │ ├── device_detection.rs
│ │ ├── dictionaries.rs
│ │ ├── geolocation.rs
│ │ ├── limits.rs
│ │ ├── object_store.rs
│ │ ├── secret_store.rs
│ │ └── unit_tests.rs
│ ├── config.rs
│ ├── downstream.rs
│ ├── error.rs
│ ├── execute.rs
│ ├── framing.rs
│ ├── handoff.rs
│ ├── headers.rs
│ ├── lib.rs
│ ├── linking.rs
│ ├── logging.rs
│ ├── object_store.rs
│ ├── sandbox/
│ │ ├── async_item.rs
│ │ └── downstream.rs
│ ├── sandbox.rs
│ ├── secret_store.rs
│ ├── service.rs
│ ├── shielding_site.rs
│ ├── shift_mem.rs
│ ├── streaming_body.rs
│ ├── upstream.rs
│ ├── wiggle_abi/
│ │ ├── acl.rs
│ │ ├── backend_impl.rs
│ │ ├── body_impl.rs
│ │ ├── cache.rs
│ │ ├── compute_runtime.rs
│ │ ├── config_store.rs
│ │ ├── device_detection_impl.rs
│ │ ├── dictionary_impl.rs
│ │ ├── entity.rs
│ │ ├── erl_impl.rs
│ │ ├── fastly_purge_impl.rs
│ │ ├── geo_impl.rs
│ │ ├── headers.rs
│ │ ├── http_cache.rs
│ │ ├── http_downstream.rs
│ │ ├── image_optimizer.rs
│ │ ├── kv_store_impl.rs
│ │ ├── log_impl.rs
│ │ ├── obj_store_impl.rs
│ │ ├── req_impl.rs
│ │ ├── resp_impl.rs
│ │ ├── secret_store_impl.rs
│ │ ├── shielding.rs
│ │ └── uap_impl.rs
│ └── wiggle_abi.rs
├── test-fixtures/
│ ├── Cargo.toml
│ ├── combined_heap_limits.wat
│ ├── data/
│ │ ├── ca.key
│ │ ├── ca.pem
│ │ ├── ca.srl
│ │ ├── client.crt
│ │ ├── client.csr
│ │ ├── client.key
│ │ ├── device-detection-mapping.json
│ │ ├── geolocation-mapping.json
│ │ ├── json-config_store.json
│ │ ├── json-dictionary.json
│ │ ├── json-kv_store-invalid_1.json
│ │ ├── json-kv_store-invalid_2.json
│ │ ├── json-kv_store.json
│ │ ├── json-secret_store.json
│ │ ├── kv-store.txt
│ │ ├── my-acl-1.json
│ │ ├── my-acl-2.json
│ │ ├── server.crt
│ │ ├── server.csr
│ │ ├── server.ext
│ │ └── server.key
│ ├── return_ok.wat
│ └── src/
│ ├── bin/
│ │ ├── acl.rs
│ │ ├── args.rs
│ │ ├── async_io.rs
│ │ ├── bad-framing-headers.rs
│ │ ├── cache.rs
│ │ ├── config-store-lookup.rs
│ │ ├── content-length.rs
│ │ ├── device-detection-lookup.rs
│ │ ├── dictionary-lookup.rs
│ │ ├── downstream-req.rs
│ │ ├── early-hints.rs
│ │ ├── edge-rate-limiting.rs
│ │ ├── env-vars.rs
│ │ ├── expects-hello.rs
│ │ ├── fastly-key-is-valid.rs
│ │ ├── geolocation-lookup-default.rs
│ │ ├── geolocation-lookup.rs
│ │ ├── grpc.rs
│ │ ├── gzipped-response.rs
│ │ ├── inspect.rs
│ │ ├── invalid-status-code.rs
│ │ ├── kv_store.rs
│ │ ├── logging.rs
│ │ ├── manual-framing-headers.rs
│ │ ├── mutual-tls.rs
│ │ ├── noop.rs
│ │ ├── panic.rs
│ │ ├── request.rs
│ │ ├── response.rs
│ │ ├── reusable-sandboxes.rs
│ │ ├── secret-store.rs
│ │ ├── shielding.rs
│ │ ├── sleep.rs
│ │ ├── streaming-response.rs
│ │ ├── teapot-status.rs
│ │ ├── unknown-import.rs
│ │ ├── upstream-async.rs
│ │ ├── upstream-dynamic.rs
│ │ ├── upstream-streaming.rs
│ │ ├── upstream.rs
│ │ ├── vcpu_time_test.rs
│ │ ├── write-and-read-body.rs
│ │ └── write-body.rs
│ └── limits.rs
└── wasm_abi/
├── adapter/
│ ├── Cargo.toml
│ ├── README.md
│ ├── build.rs
│ ├── byte-array-literals/
│ │ ├── Cargo.toml
│ │ ├── README.md
│ │ └── src/
│ │ └── lib.rs
│ └── src/
│ ├── descriptors.rs
│ ├── fastly/
│ │ ├── cache.rs
│ │ ├── config_store.rs
│ │ ├── core.rs
│ │ ├── error.rs
│ │ ├── http_cache.rs
│ │ ├── macros.rs
│ │ └── mod.rs
│ ├── lib.rs
│ └── macros.rs
├── compute-at-edge-abi/
│ ├── README.md
│ ├── cache.witx
│ ├── compute-at-edge.witx
│ ├── config-store.witx
│ ├── http-cache.witx
│ ├── shielding.witx
│ └── typenames.witx
├── data/
│ ├── viceroy-component-adapter.library.noshift.wasm
│ ├── viceroy-component-adapter.library.wasm
│ ├── viceroy-component-adapter.noshift.wasm
│ └── viceroy-component-adapter.wasm
└── wit/
├── deps/
│ ├── cli/
│ │ ├── command.wit
│ │ ├── environment.wit
│ │ ├── exit.wit
│ │ ├── imports.wit
│ │ ├── run.wit
│ │ ├── stdio.wit
│ │ └── terminal.wit
│ ├── clocks/
│ │ ├── monotonic-clock.wit
│ │ ├── timezone.wit
│ │ ├── wall-clock.wit
│ │ └── world.wit
│ ├── fastly/
│ │ └── compute.wit
│ ├── fastly-adapter/
│ │ └── adapter.wit
│ ├── filesystem/
│ │ ├── preopens.wit
│ │ ├── types.wit
│ │ └── world.wit
│ ├── io/
│ │ ├── error.wit
│ │ ├── poll.wit
│ │ ├── streams.wit
│ │ └── world.wit
│ ├── random/
│ │ ├── insecure-seed.wit
│ │ ├── insecure.wit
│ │ ├── random.wit
│ │ └── world.wit
│ └── sockets/
│ ├── instance-network.wit
│ ├── ip-name-lookup.wit
│ ├── network.wit
│ ├── tcp-create-socket.wit
│ ├── tcp.wit
│ ├── udp-create-socket.wit
│ ├── udp.wit
│ └── world.wit
└── viceroy.wit
SYMBOL INDEX (2373 symbols across 166 files)
FILE: cli/src/execute_ctx.rs
type Stdio (line 11) | pub(crate) enum Stdio {
method write (line 17) | fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
method write_all (line 24) | fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
method flush (line 31) | fn flush(&mut self) -> io::Result<()> {
type StdWriter (line 39) | pub(crate) struct StdWriter;
method new (line 42) | pub(crate) fn new() -> Self {
type Writer (line 48) | type Writer = Stdio;
method make_writer (line 51) | fn make_writer(&self) -> Self::Writer {
method make_writer_for (line 58) | fn make_writer_for(&self, meta: &Metadata<'_>) -> Self::Writer {
function create_execution_context (line 67) | pub(crate) async fn create_execution_context(
FILE: cli/src/main.rs
function main (line 31) | async fn main() -> ExitCode {
function install_tracing_subscriber (line 42) | fn install_tracing_subscriber(verbosity: u8) {
FILE: cli/src/opts.rs
type Opts (line 30) | pub struct Opts {
type Commands (line 39) | pub enum Commands {
type ServeArgs (line 52) | pub struct ServeArgs {
method addr (line 150) | pub fn addr(&self) -> SocketAddr {
method shared (line 155) | pub fn shared(&self) -> &SharedArgs {
type RunArgs (line 62) | pub struct RunArgs {
method wasm_args (line 162) | pub fn wasm_args(&self) -> &Vec<String> {
method shared (line 166) | pub fn shared(&self) -> &SharedArgs {
type SharedArgs (line 72) | pub struct SharedArgs {
method input (line 173) | pub fn input(&self) -> PathBuf {
method config_path (line 178) | pub fn config_path(&self) -> Option<&Path> {
method log_stdout (line 183) | pub fn log_stdout(&self) -> bool {
method log_stderr (line 188) | pub fn log_stderr(&self) -> bool {
method profiling_strategy (line 193) | pub fn profiling_strategy(&self) -> ProfilingStrategy {
method local_pushpin_proxy_port (line 201) | pub fn local_pushpin_proxy_port(&self) -> Option<u16> {
method guest_profile_config (line 206) | pub fn guest_profile_config(&self) -> Option<GuestProfileConfig> {
method wasi_modules (line 226) | pub fn wasi_modules(&self) -> HashSet<ExperimentalModule> {
method unknown_import_behavior (line 231) | pub fn unknown_import_behavior(&self) -> UnknownImportBehavior {
method verbosity (line 238) | pub fn verbosity(&self) -> u8 {
method adapt (line 242) | pub fn adapt(&self) -> bool {
method wasm_features (line 246) | pub fn wasm_features(&self) -> WasmFeatures {
type Profile (line 140) | enum Profile {
type AdaptArgs (line 262) | pub struct AdaptArgs {
method input (line 279) | pub(crate) fn input(&self) -> PathBuf {
method output (line 283) | pub(crate) fn output(&self) -> PathBuf {
method verbosity (line 296) | pub fn verbosity(&self) -> u8 {
type ExperimentalModuleArg (line 303) | pub enum ExperimentalModuleArg {
method from (line 324) | fn from(module: ExperimentalModule) -> ExperimentalModuleArg {
method from (line 332) | fn from(module: &ExperimentalModule) -> ExperimentalModuleArg {
method from (line 308) | fn from(arg: ExperimentalModuleArg) -> ExperimentalModule {
method from (line 316) | fn from(arg: &ExperimentalModuleArg) -> ExperimentalModule {
function check_module (line 343) | fn check_module(s: &str) -> Result<PathBuf, Error> {
function parse_profile_sample_duration (line 355) | fn parse_profile_sample_duration(s: &str) -> Result<Duration, Error> {
function check_wasmtime_profiler_mode (line 388) | fn check_wasmtime_profiler_mode(s: &str) -> Result<Profile, Error> {
function test_file (line 426) | fn test_file(name: &str) -> String {
type TestResult (line 436) | type TestResult = Result<(), anyhow::Error>;
function default_addr_works (line 440) | fn default_addr_works() -> TestResult {
function invalid_addrs_are_rejected (line 453) | fn invalid_addrs_are_rejected() -> TestResult {
function ipv6_addrs_are_accepted (line 474) | fn ipv6_addrs_are_accepted() -> TestResult {
function nonexistent_file_is_rejected (line 493) | fn nonexistent_file_is_rejected() -> TestResult {
function invalid_file_is_rejected (line 509) | fn invalid_file_is_rejected() -> TestResult {
function text_format_is_accepted (line 525) | fn text_format_is_accepted() -> TestResult {
function binary_format_is_accepted (line 535) | fn binary_format_is_accepted() -> TestResult {
function wasmtime_profiling_strategy_jitdump_is_accepted (line 545) | fn wasmtime_profiling_strategy_jitdump_is_accepted() -> TestResult {
function wasmtime_profiling_strategy_vtune_is_accepted (line 560) | fn wasmtime_profiling_strategy_vtune_is_accepted() -> TestResult {
function wasmtime_profiling_strategy_perfmap_is_accepted (line 575) | fn wasmtime_profiling_strategy_perfmap_is_accepted() -> TestResult {
function wasmtime_profiling_strategy_guest_without_path_is_accepted (line 590) | fn wasmtime_profiling_strategy_guest_without_path_is_accepted() -> TestR...
function wasmtime_profiling_strategy_guest_with_path_is_accepted (line 605) | fn wasmtime_profiling_strategy_guest_with_path_is_accepted() -> TestResu...
function wasmtime_profiling_strategy_guest_with_path_and_period_is_accepted (line 619) | fn wasmtime_profiling_strategy_guest_with_path_and_period_is_accepted() ...
function invalid_wasmtime_profiling_strategy_is_rejected (line 634) | fn invalid_wasmtime_profiling_strategy_is_rejected() -> TestResult {
function trailing_args_are_collected_in_run_mode (line 649) | fn trailing_args_are_collected_in_run_mode() -> TestResult {
function input_accepted_after_double_dash (line 672) | fn input_accepted_after_double_dash() -> TestResult {
FILE: cli/src/subcommands/adapt.rs
function exec (line 6) | pub(crate) fn exec(adapt_args: AdaptArgs) -> ExitCode {
FILE: cli/src/subcommands/run.rs
function exec (line 8) | pub(crate) async fn exec(run_args: RunArgs) -> ExitCode {
function run_wasm_main (line 25) | async fn run_wasm_main(run_args: RunArgs) -> Result<(), anyhow::Error> {
function get_exit_code (line 43) | fn get_exit_code(e: anyhow::Error) -> ExitCode {
FILE: cli/src/subcommands/serve.rs
function exec (line 7) | pub(crate) async fn exec(serve_args: ServeArgs) -> ExitCode {
function serve (line 30) | async fn serve(serve_args: ServeArgs) -> Result<(), Error> {
FILE: cli/tests/integration/acl.rs
function bad_config_test (line 37) | fn bad_config_test(local_server_fragment: &str) -> Result<FastlyConfig, ...
function bad_config_invalid_path (line 54) | async fn bad_config_invalid_path() -> TestResult {
function bad_config_missing_key (line 70) | async fn bad_config_missing_key() -> TestResult {
function bad_config_missing_file (line 86) | async fn bad_config_missing_file() -> TestResult {
function bad_config_invalid_json (line 102) | async fn bad_config_invalid_json() -> TestResult {
FILE: cli/tests/integration/args.rs
function empty_ok_response_by_default_after_args (line 10) | async fn empty_ok_response_by_default_after_args() -> TestResult {
function empty_ok_response_by_default_after_args_component (line 31) | async fn empty_ok_response_by_default_after_args_component() {
FILE: cli/tests/integration/client_certs.rs
type Watcher (line 63) | struct Watcher {
method client_auth_root_subjects (line 68) | fn client_auth_root_subjects(&self) -> &[rustls::DistinguishedName] {
method verify_client_cert (line 73) | fn verify_client_cert(
function build_server_tls_config (line 85) | fn build_server_tls_config() -> ServerConfig {
FILE: cli/tests/integration/common.rs
type Error (line 74) | pub type Error = Box<dyn std::error::Error + Send + Sync>;
type TestResult (line 77) | pub type TestResult = Result<(), Error>;
type Test (line 80) | pub struct Test {
method using_fixture (line 103) | pub fn using_fixture(fixture: &str) -> Self {
method using_wat_fixture (line 130) | pub fn using_wat_fixture(fixture: &str) -> Self {
method using_fastly_toml (line 157) | pub fn using_fastly_toml(self, fastly_toml: &str) -> Result<Self, Erro...
method using_test_backends (line 175) | pub fn using_test_backends(mut self, test_backends: &TestBackends) -> ...
method using_unknown_import_behavior (line 181) | pub fn using_unknown_import_behavior(
method backend (line 202) | pub async fn backend<ServiceFn>(
method async_backend (line 240) | pub async fn async_backend<ServiceFn>(
method capture_logs (line 265) | pub fn capture_logs(mut self, capture_logs: Arc<Mutex<dyn Write + Send...
method log_stderr (line 271) | pub fn log_stderr(self) -> Self {
method log_stdout (line 279) | pub fn log_stdout(self) -> Self {
method via_hyper (line 288) | pub fn via_hyper(self) -> Self {
method adapt_component (line 296) | pub fn adapt_component(mut self, adapt: bool) -> Self {
method with_guest_profiling (line 302) | pub fn with_guest_profiling(mut self, config: viceroy_lib::GuestProfil...
method against_many (line 321) | pub async fn against_many(
method against (line 467) | pub async fn against(
method against_empty (line 479) | pub async fn against_empty(&self) -> Result<Response<Body>, Error> {
method start_backend_servers (line 488) | pub async fn start_backend_servers(&self) {
method uri_for_backend_server (line 499) | pub async fn uri_for_backend_server(&self, name: &str) -> Uri {
type TestServer (line 507) | struct TestServer {
method drop (line 514) | fn drop(&mut self) {
type SyncService (line 525) | type SyncService = dyn Fn(Request<Vec<u8>>) -> Response<Vec<u8>> + Send ...
type AsyncResp (line 527) | type AsyncResp = Box<dyn Future<Output = Response<HyperBody>> + Send + S...
type AsyncService (line 528) | type AsyncService = dyn Fn(Request<HyperBody>) -> AsyncResp + Send + Sync;
type TestService (line 531) | enum TestService {
method fmt (line 537) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method spawn (line 548) | fn spawn(&self) -> TestServer {
FILE: cli/tests/integration/common/backends.rs
type BackendName (line 11) | pub type BackendName = String;
type TestBackends (line 15) | pub struct TestBackends {
method new (line 21) | pub fn new() -> Self {
method from_backend_configs (line 33) | pub fn from_backend_configs(backend_configs: &viceroy_lib::config::Bac...
method backend_configs (line 59) | pub async fn backend_configs(&self) -> viceroy_lib::config::Backends {
method test_backend (line 87) | pub fn test_backend(&self, name: &str) -> TestBackendBuilder {
method set_test_service (line 102) | pub async fn set_test_service<TestServiceFn>(&self, name: &str, test_s...
method set_async_test_service (line 123) | pub async fn set_async_test_service<TestServiceFn>(
method servers_are_running (line 144) | pub async fn servers_are_running(&self) -> bool {
method start_servers (line 151) | pub async fn start_servers(&self) {
method uri_for_backend_server (line 173) | pub async fn uri_for_backend_server(&self, name: &str) -> Uri {
type Inner (line 188) | struct Inner {
method new (line 194) | pub fn new() -> Self {
type TestBackend (line 203) | pub struct TestBackend {
type TestBackendBuilder (line 213) | pub struct TestBackendBuilder {
method path (line 224) | pub fn path(mut self, path: &str) -> Self {
method override_host (line 230) | pub fn override_host(mut self, override_host: &str) -> Self {
method use_sni (line 236) | pub fn use_sni(mut self, use_sni: bool) -> Self {
method test_service (line 248) | pub fn test_service<TestServiceFn>(mut self, test_service: TestService...
method async_test_service (line 263) | pub fn async_test_service<TestServiceFn>(mut self, test_service: TestS...
method build (line 280) | pub async fn build(self) {
FILE: cli/tests/integration/logging.rs
type LogWriter (line 13) | struct LogWriter(Vec<Vec<u8>>);
method write (line 16) | fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
method flush (line 21) | fn flush(&mut self) -> io::Result<()> {
FILE: cli/tests/integration/secret_store.rs
function bad_config_test (line 45) | fn bad_config_test(toml_fragment: &str) -> Result<FastlyConfig, FastlyCo...
function bad_config_store_not_array (line 63) | async fn bad_config_store_not_array() -> TestResult {
function bad_config_store_not_table (line 79) | async fn bad_config_store_not_table() -> TestResult {
function bad_config_no_key (line 95) | async fn bad_config_no_key() -> TestResult {
function bad_config_key_not_string (line 111) | async fn bad_config_key_not_string() -> TestResult {
function bad_config_no_store_field (line 128) | async fn bad_config_no_store_field() -> TestResult {
function bad_config_store_fields_not_exclusive (line 144) | async fn bad_config_store_fields_not_exclusive() -> TestResult {
function bad_config_data_not_string (line 189) | async fn bad_config_data_not_string() -> TestResult {
function bad_config_file_not_string (line 205) | async fn bad_config_file_not_string() -> TestResult {
function bad_config_env_not_string (line 221) | async fn bad_config_env_not_string() -> TestResult {
function bad_config_file_nonexistent (line 237) | async fn bad_config_file_nonexistent() -> TestResult {
function bad_config_invalid_store_name (line 254) | async fn bad_config_invalid_store_name() -> TestResult {
function bad_config_invalid_secret_name (line 266) | async fn bad_config_invalid_secret_name() -> TestResult {
function bad_config_secret_name_too_long (line 283) | async fn bad_config_secret_name_too_long() -> TestResult {
FILE: cli/tests/integration/unknown_import_behavior.rs
function default_behavior_link_failure (line 8) | async fn default_behavior_link_failure() -> TestResult {
function trap_behavior_function_called (line 24) | async fn trap_behavior_function_called() -> TestResult {
function trap_behavior_function_not_called (line 51) | async fn trap_behavior_function_not_called() -> TestResult {
FILE: cli/tests/trap-test/src/main.rs
constant RUST_FIXTURE_PATH (line 8) | const RUST_FIXTURE_PATH: &str = "../../../test-fixtures/target/wasm32-wa...
type Error (line 11) | pub type Error = Box<dyn std::error::Error + Send + Sync>;
type TestResult (line 14) | pub type TestResult = Result<(), Error>;
function fatal_error_traps_impl (line 16) | async fn fatal_error_traps_impl(adapt_core_wasm: bool) -> TestResult {
function fatal_error_traps (line 48) | async fn fatal_error_traps() -> TestResult {
function fatal_error_traps_component (line 53) | async fn fatal_error_traps_component() -> TestResult {
FILE: src/acl.rs
type Acls (line 9) | pub struct Acls {
method new (line 14) | pub fn new() -> Self {
method get_acl (line 20) | pub fn get_acl(&self, name: &str) -> Option<&Arc<Acl>> {
method insert (line 24) | pub fn insert(&mut self, name: String, acl: Acl) {
type Acl (line 47) | pub struct Acl {
method lookup (line 58) | pub fn lookup(&self, ip: IpAddr) -> Option<&Entry> {
type Entry (line 72) | pub struct Entry {
type Prefix (line 79) | pub struct Prefix {
method new (line 85) | pub(crate) fn new(ip: IpAddr, mask: u8) -> Self {
method is_match (line 111) | pub(crate) fn is_match(&self, ip: IpAddr) -> Option<u8> {
method deserialize (line 128) | fn deserialize<D>(de: D) -> Result<Self, D::Error>
method fmt (line 122) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method serialize (line 170) | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
constant ACTION_ALLOW (line 178) | const ACTION_ALLOW: &str = "ALLOW";
constant ACTION_BLOCK (line 179) | const ACTION_BLOCK: &str = "BLOCK";
type Action (line 183) | pub enum Action {
method deserialize (line 190) | fn deserialize<D>(de: D) -> Result<Self, D::Error>
method serialize (line 204) | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
function prefix_is_match (line 217) | fn prefix_is_match() {
function acl_lookup (line 246) | fn acl_lookup() {
function acl_json_parse (line 291) | fn acl_json_parse() {
function prefix_json_roundtrip (line 348) | fn prefix_json_roundtrip() {
function action_json_roundtrip (line 384) | fn action_json_roundtrip() {
FILE: src/adapt.rs
constant ADAPTER_BYTES (line 4) | const ADAPTER_BYTES: &[u8] = include_bytes!("../wasm_abi/data/viceroy-co...
constant ADAPTER_NOSHIFT_BYTES (line 5) | const ADAPTER_NOSHIFT_BYTES: &[u8] =
constant LIBRARY_ADAPTER_BYTES (line 12) | const LIBRARY_ADAPTER_BYTES: &[u8] =
constant LIBRARY_ADAPTER_NOSHIFT_BYTES (line 14) | const LIBRARY_ADAPTER_NOSHIFT_BYTES: &[u8] =
function is_component (line 18) | pub fn is_component(bytes: &[u8]) -> bool {
function adapt_wat (line 24) | pub fn adapt_wat(wat: &str) -> anyhow::Result<Vec<u8>> {
function adapt_bytes (line 31) | pub fn adapt_bytes(bytes: &[u8]) -> anyhow::Result<Vec<u8>> {
function mangle_imports (line 87) | fn mangle_imports(bytes: &[u8]) -> anyhow::Result<wasm_encoder::Module> {
function has_export (line 150) | fn has_export(bytes: &[u8], wanted: &str) -> bool {
function is_fastly_module (line 169) | fn is_fastly_module(module: &str) -> bool {
function has_wit_bindgen_imports (line 172) | fn has_wit_bindgen_imports(bytes: &[u8]) -> bool {
FILE: src/async_io.rs
method select (line 14) | async fn select(
method is_ready (line 47) | fn is_ready(
FILE: src/body.rs
type DecoderState (line 21) | type DecoderState = Box<GzDecoder<bytes::buf::Writer<BytesMut>>>;
type Chunk (line 29) | pub enum Chunk {
method compressed_body (line 47) | pub fn compressed_body(body: hyper::Body) -> Chunk {
method from (line 54) | fn from(bytes: &[u8]) -> Self {
method from (line 60) | fn from(vec: Vec<u8>) -> Self {
method from (line 66) | fn from(bytes: bytes::Bytes) -> Self {
method from (line 72) | fn from(body: hyper::Body) -> Self {
method from (line 78) | fn from(chan: mpsc::Receiver<StreamingBodyItem>) -> Self {
type Body (line 92) | pub struct Body {
method empty (line 100) | pub fn empty() -> Self {
method push_back (line 105) | pub fn push_back(&mut self, chunk: impl Into<Chunk>) {
method push_front (line 110) | pub fn push_front(&mut self, chunk: impl Into<Chunk>) {
method append (line 115) | pub fn append(&mut self, body: Self) {
method read (line 124) | pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, error::E...
method read_into_vec (line 149) | pub async fn read_into_vec(self) -> Result<Vec<u8>, error::Error> {
method read_into_string (line 164) | pub async fn read_into_string(self) -> Result<String, error::Error> {
method await_ready (line 169) | pub async fn await_ready(&mut self) {
method len (line 178) | pub fn len(&self) -> Option<u64> {
method is_empty (line 192) | pub fn is_empty(&self) -> Option<bool> {
method from (line 198) | fn from(chunk: T) -> Self {
method extend (line 206) | fn extend<I: IntoIterator<Item = Chunk>>(&mut self, iter: I) {
type Item (line 212) | type Item = Chunk;
type IntoIter (line 213) | type IntoIter = <VecDeque<Chunk> as IntoIterator>::IntoIter;
method into_iter (line 214) | fn into_iter(self) -> Self::IntoIter {
type Data (line 220) | type Data = bytes::Bytes;
type Error (line 221) | type Error = error::Error;
method poll_data (line 223) | fn poll_data(
method poll_trailers (line 347) | fn poll_trailers(
method size_hint (line 363) | fn size_hint(&self) -> SizeHint {
function some_bytes (line 397) | fn some_bytes() -> impl Strategy<Value = Bytes> {
function compress_body (line 402) | fn compress_body(body: &[u8]) -> Bytes {
function trickle_body (line 413) | async fn trickle_body(mut sender: hyper::body::Sender, body: Bytes, chun...
function check_body_read (line 433) | async fn check_body_read(
function test_chunked_body (line 454) | async fn test_chunked_body(
function test_gzip_body (line 477) | async fn test_gzip_body(
FILE: src/body_tee.rs
type StringError (line 11) | pub struct StringError(String);
method fmt (line 14) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
type ConsumerState (line 22) | struct ConsumerState {
type SharedState (line 30) | struct SharedState {
method default (line 42) | fn default() -> Self {
type BodyTeeStream (line 63) | pub struct BodyTeeStream {
function tee (line 69) | pub async fn tee(mut hyper_body: Body) -> (Body, Body) {
type Data (line 129) | type Data = Bytes;
type Error (line 132) | type Error = Box<dyn std::error::Error + Send + Sync>;
method poll_data (line 134) | fn poll_data(
method poll_trailers (line 169) | fn poll_trailers(
method is_end_stream (line 176) | fn is_end_stream(&self) -> bool {
type Item (line 189) | type Item = Result<Bytes, Box<dyn std::error::Error + Send + Sync>>;
method poll_next (line 191) | fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<...
method drop (line 197) | fn drop(&mut self) {
function drain_buffer (line 213) | fn drain_buffer(state: &mut SharedState) {
function test_simple_duplication (line 237) | async fn test_simple_duplication() {
function test_error_propagation (line 267) | async fn test_error_propagation() {
function test_error_with_one_consumer_dropped (line 304) | async fn test_error_with_one_consumer_dropped() {
function test_size_hint_preservation (line 323) | async fn test_size_hint_preservation() {
FILE: src/cache.rs
type Error (line 24) | pub enum Error {
function from (line 45) | fn from(value: Error) -> Self {
method from (line 51) | fn from(value: &Error) -> Self {
method from (line 66) | fn from(value: Error) -> Self {
type CacheKey (line 83) | pub struct CacheKey(
constant MAX_LENGTH (line 89) | pub const MAX_LENGTH: usize = 4096;
type Error (line 93) | type Error = Error;
method try_from (line 95) | fn try_from(value: &Vec<u8>) -> Result<Self, Self::Error> {
type Error (line 101) | type Error = Error;
method try_from (line 103) | fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
type Error (line 113) | type Error = Error;
method try_from (line 115) | fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
type Error (line 125) | type Error = Error;
method try_from (line 127) | fn try_from(value: &str) -> Result<Self, Self::Error> {
type CacheEntry (line 134) | pub struct CacheEntry {
method with_always_use_requested_range (line 154) | pub fn with_always_use_requested_range(self, always_use_requested_rang...
method stub (line 162) | pub fn stub(&self) -> CacheEntry {
method key (line 172) | pub fn key(&self) -> &CacheKey {
method found (line 176) | pub fn found(&self) -> Option<&Found> {
method found_mut (line 181) | pub fn found_mut(&mut self) -> Option<&mut Found> {
method go_get (line 186) | pub fn go_get(&self) -> Option<&Obligation> {
method cancel (line 192) | pub fn cancel(&mut self) -> bool {
method body (line 197) | pub async fn body(&self, from: Option<u64>, to: Option<u64>) -> Result...
method insert (line 213) | pub fn insert(
method update (line 230) | pub async fn update(&mut self, options: WriteOptions) -> Result<(), cr...
type Found (line 245) | pub struct Found {
method from (line 258) | fn from(data: Arc<CacheData>) -> Self {
method get_body (line 267) | fn get_body(&self) -> GetBodyBuilder<'_> {
method meta (line 272) | pub fn meta(&self) -> &ObjectMeta {
method length (line 277) | pub fn length(&self) -> Option<u64> {
type Cache (line 288) | pub struct Cache {
method lookup (line 307) | pub async fn lookup(&self, key: &CacheKey, headers: &HeaderMap) -> Cac...
method transaction_lookup (line 326) | pub async fn transaction_lookup(
method insert (line 349) | pub async fn insert(
method purge (line 367) | pub fn purge(&self, key: SurrogateKey, soft_purge: bool) -> usize {
method default (line 293) | fn default() -> Self {
type WriteOptions (line 377) | pub struct WriteOptions {
method new (line 390) | pub fn new(max_age: Duration) -> Self {
type CacheOverride (line 407) | pub enum CacheOverride {
method is_pass (line 425) | pub fn is_pass(&self) -> bool {
method from_abi (line 433) | pub fn from_abi(
constant MAX_SURROGATE_KEYS_LENGTH (line 468) | const MAX_SURROGATE_KEYS_LENGTH: usize = 16 * 1024;
constant MAX_SURROGATE_KEY_LENGTH (line 470) | const MAX_SURROGATE_KEY_LENGTH: usize = 1024;
type SurrogateKeySet (line 473) | pub struct SurrogateKeySet(HashSet<SurrogateKey>);
method fmt (line 476) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
type Error (line 490) | type Error = crate::Error;
method try_from (line 492) | fn try_from(s: &[u8]) -> Result<Self, Self::Error> {
type Err (line 508) | type Err = crate::Error;
method from_str (line 510) | fn from_str(s: &str) -> Result<Self, Self::Err> {
type SurrogateKey (line 517) | pub struct SurrogateKey(String);
method fmt (line 520) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
type Error (line 526) | type Error = Error;
method try_from (line 528) | fn try_from(b: &[u8]) -> Result<Self, Self::Error> {
type Err (line 549) | type Err = Error;
method from_str (line 551) | fn from_str(s: &str) -> Result<Self, Self::Err> {
function parse_surrogate_keys (line 618) | fn parse_surrogate_keys() {
function insert_immediately_stale (line 628) | async fn insert_immediately_stale() {
function test_vary (line 652) | async fn test_vary() {
function insert_stale_while_revalidate (line 685) | async fn insert_stale_while_revalidate() {
function insert_and_revalidate (line 710) | async fn insert_and_revalidate() {
function cannot_revalidate_first_insert (line 767) | async fn cannot_revalidate_first_insert() {
function purge_by_surrogate_key (line 787) | async fn purge_by_surrogate_key() {
function purge_variant_by_surrogate_key (line 810) | async fn purge_variant_by_surrogate_key() {
function soft_purge (line 853) | async fn soft_purge() {
FILE: src/cache/store.rs
type ObjectMeta (line 20) | pub struct ObjectMeta {
method age (line 52) | pub fn age(&self) -> Duration {
method max_age (line 58) | pub fn max_age(&self) -> Duration {
method is_fresh (line 63) | pub fn is_fresh(&self) -> bool {
method is_usable (line 68) | pub fn is_usable(&self) -> bool {
method request_headers (line 73) | pub fn request_headers(&self) -> &HeaderMap {
method vary_rule (line 78) | pub fn vary_rule(&self) -> &VaryRule {
method variant (line 83) | pub fn variant(&self) -> Variant {
method user_metadata (line 87) | pub fn user_metadata(&self) -> Bytes {
method new (line 93) | fn new(value: WriteOptions, request_headers: HeaderMap) -> Self {
type CacheKeyObjects (line 127) | pub struct CacheKeyObjects(watch::Sender<CacheKeyObjectsInner>);
method get (line 131) | pub fn get(&self, request_headers: &HeaderMap) -> Option<Arc<CacheData...
method transaction_get (line 155) | pub async fn transaction_get(
method insert (line 338) | pub fn insert(
method purge (line 391) | pub fn purge(&self, key: &super::SurrogateKey, soft_purge: bool) -> us...
type CacheKeyObjectsInner (line 452) | struct CacheKeyObjectsInner {
type CacheValue (line 472) | struct CacheValue {
type Obligation (line 482) | pub struct Obligation {
method insert (line 494) | pub fn insert(mut self, options: WriteOptions, body: Body) -> Found {
method update (line 507) | pub(super) async fn update(
method drop (line 531) | fn drop(&mut self) {
type CacheData (line 554) | pub(crate) struct CacheData {
method body (line 656) | pub(crate) fn body(&self) -> GetBodyBuilder<'_> {
method get_meta (line 666) | pub(crate) fn get_meta(&self) -> &ObjectMeta {
method length (line 671) | pub fn length(&self) -> Option<u64> {
type GetBodyBuilder (line 560) | pub struct GetBodyBuilder<'a> {
function with_range (line 573) | pub fn with_range(self, from: Option<u64>, to: Option<u64>) -> Self {
function with_always_use_requested_range (line 577) | pub fn with_always_use_requested_range(self, always_use_requested_range:...
function build (line 589) | pub async fn build(self) -> Result<Body, crate::Error> {
function single_obligation (line 691) | async fn single_obligation() {
function obligation_when_stale (line 721) | async fn obligation_when_stale() {
function obligation_by_vary_key (line 737) | async fn obligation_by_vary_key() {
function modified_vary (line 825) | async fn modified_vary() {
function drop_obligation (line 861) | async fn drop_obligation() {
function immediate_with_no_results (line 878) | async fn immediate_with_no_results() {
function returns_written_object (line 901) | async fn returns_written_object() {
FILE: src/cache/variance.rs
type VaryRule (line 27) | pub struct VaryRule {
method new (line 42) | pub fn new<'a>(headers: impl IntoIterator<Item = &'a HeaderName>) -> V...
method variant (line 52) | pub fn variant(&self, headers: &HeaderMap) -> Variant {
type Err (line 32) | type Err = Error;
method from_str (line 34) | fn from_str(s: &str) -> Result<Self, Self::Err> {
type Variant (line 80) | pub struct Variant {
function vary_rule_unique_sorted (line 92) | fn vary_rule_unique_sorted() {
FILE: src/collecting_body.rs
type CollectingBody (line 30) | pub struct CollectingBody {
method length (line 42) | pub fn length(&self) -> Option<u64> {
method known_length (line 54) | pub async fn known_length(&self) -> Result<u64, error::Error> {
method wait_length (line 77) | pub async fn wait_length(&self, want: u64) -> Result<(), error::Error> {
method new (line 108) | pub fn new(from: Body, length: Option<u64>) -> CollectingBody {
method tee (line 121) | async fn tee(
method read (line 192) | pub fn read(&self) -> Result<Body, error::Error> {
method read_range (line 198) | pub fn read_range(&self, start: u64, end: Option<u64>) -> Result<Body,...
method default (line 35) | fn default() -> Self {
type CollectingBodyInner (line 310) | enum CollectingBodyInner {
method chunks (line 321) | fn chunks(&self) -> &[Bytes] {
method trailers (line 334) | fn trailers(&self) -> Option<&HeaderMap> {
function stream_and_collect (line 359) | async fn stream_and_collect() {
function stream_and_receive (line 378) | async fn stream_and_receive() {
function partial_read_partial_stream (line 421) | async fn partial_read_partial_stream() {
function unfinished_stream (line 459) | async fn unfinished_stream() {
function reads_trailers (line 495) | async fn reads_trailers() {
function completed_stream (line 527) | async fn completed_stream() {
function precise_length (line 541) | async fn precise_length() {
function error_on_expected_length_underfill (line 556) | async fn error_on_expected_length_underfill() {
function error_on_range_underfill (line 569) | async fn error_on_range_underfill() {
function error_on_overfill (line 584) | async fn error_on_overfill() {
function some_bytes (line 597) | fn some_bytes() -> impl Strategy<Value = Bytes> {
function some_chunks (line 602) | fn some_chunks() -> impl Strategy<Value = Vec<Bytes>> {
function fail_test_case (line 607) | fn fail_test_case<E: std::fmt::Display>(
function test_start_range (line 613) | async fn test_start_range(body_chunks: Vec<Bytes>, start: u64) -> Result...
function test_start_end_range (line 659) | async fn test_start_end_range(
FILE: src/component.rs
function link_host_functions (line 126) | pub fn link_host_functions(linker: &mut component::Linker<ComponentCtx>)...
FILE: src/component/adapter/http_req.rs
type DsView (line 13) | trait DsView {
method ds_req_handle (line 14) | fn ds_req_handle(&self) -> Resource<http_req::Request>;
method ds_req_handle (line 17) | fn ds_req_handle(&self) -> Resource<http_req::Request> {
method get_original_header_names (line 23) | fn get_original_header_names(
method original_header_count (line 36) | fn original_header_count(&mut self) -> Result<u32, types::Error> {
method downstream_tls_cipher_openssl_name (line 41) | fn downstream_tls_cipher_openssl_name(
method downstream_tls_protocol (line 49) | fn downstream_tls_protocol(&mut self, max_len: u64) -> Result<Option<Vec...
method downstream_tls_raw_client_certificate_deprecated (line 54) | fn downstream_tls_raw_client_certificate_deprecated(
FILE: src/component/backend.rs
function register_dynamic_backend (line 14) | pub(crate) async fn register_dynamic_backend(
function exists (line 159) | pub(crate) fn exists(sandbox: &mut Sandbox, backend: &str) -> bool {
function is_healthy (line 163) | pub(crate) fn is_healthy(
function is_dynamic (line 175) | pub(crate) fn is_dynamic(sandbox: &mut Sandbox, backend: &str) -> Result...
function get_host (line 185) | pub(crate) fn get_host(
function get_override_host (line 198) | pub(crate) fn get_override_host(
function get_port (line 221) | pub(crate) fn get_port(sandbox: &mut Sandbox, backend: &str) -> Result<u...
function get_connect_timeout_ms (line 235) | pub(crate) fn get_connect_timeout_ms(
function get_first_byte_timeout_ms (line 247) | pub(crate) fn get_first_byte_timeout_ms(
function get_between_bytes_timeout_ms (line 259) | pub(crate) fn get_between_bytes_timeout_ms(
function is_tls (line 271) | pub(crate) fn is_tls(sandbox: &mut Sandbox, backend: &str) -> Result<boo...
function get_tls_min_version (line 276) | pub(crate) fn get_tls_min_version(
function get_tls_max_version (line 289) | pub(crate) fn get_tls_max_version(
function get_http_keepalive_time (line 302) | pub(crate) fn get_http_keepalive_time(
function get_tcp_keepalive_enable (line 312) | pub(crate) fn get_tcp_keepalive_enable(
function get_tcp_keepalive_interval (line 322) | pub(crate) fn get_tcp_keepalive_interval(
function get_tcp_keepalive_probes (line 332) | pub(crate) fn get_tcp_keepalive_probes(
function get_tcp_keepalive_time (line 342) | pub(crate) fn get_tcp_keepalive_time(
FILE: src/component/compute/acl.rs
method open (line 9) | fn open(&mut self, acl_name: String) -> Result<Resource<acl::Acl>, types...
method lookup (line 17) | fn lookup(
method drop (line 37) | fn drop(&mut self, _acl_handle: Resource<acl::Acl>) -> wasmtime::Result<...
FILE: src/component/compute/async_io.rs
method select (line 14) | async fn select(&mut self, hs: Vec<Resource<async_io::Pollable>>) -> was...
method select_with_timeout (line 28) | async fn select_with_timeout(
method new_ready (line 45) | fn new_ready(&mut self) -> Resource<async_io::Pollable> {
method is_ready (line 49) | fn is_ready(&mut self, handle: Resource<async_io::Pollable>) -> bool {
method drop (line 59) | fn drop(&mut self, handle: Resource<async_io::Pollable>) -> wasmtime::Re...
FILE: src/component/compute/backend.rs
method register_dynamic_backend (line 13) | async fn register_dynamic_backend(
method open (line 31) | fn open(&mut self, name: String) -> Result<Resource<String>, backend::Op...
method get_name (line 41) | fn get_name(&mut self, name: Resource<String>) -> String {
method is_healthy (line 45) | fn is_healthy(
method is_dynamic (line 53) | fn is_dynamic(&mut self, name: Resource<String>) -> Result<bool, types::...
method get_host (line 58) | fn get_host(&mut self, name: Resource<String>, max_len: u64) -> Result<S...
method get_override_host (line 63) | fn get_override_host(
method get_port (line 72) | fn get_port(&mut self, backend: Resource<String>) -> Result<u16, types::...
method get_connect_timeout_ms (line 77) | fn get_connect_timeout_ms(&mut self, backend: Resource<String>) -> Resul...
method get_first_byte_timeout_ms (line 82) | fn get_first_byte_timeout_ms(
method get_between_bytes_timeout_ms (line 90) | fn get_between_bytes_timeout_ms(
method get_http_keepalive_time (line 98) | fn get_http_keepalive_time(
method get_tcp_keepalive_enable (line 106) | fn get_tcp_keepalive_enable(
method get_tcp_keepalive_interval (line 114) | fn get_tcp_keepalive_interval(
method get_tcp_keepalive_probes (line 122) | fn get_tcp_keepalive_probes(
method get_tcp_keepalive_time (line 130) | fn get_tcp_keepalive_time(
method is_tls (line 138) | fn is_tls(&mut self, backend: Resource<String>) -> Result<bool, types::E...
method get_tls_min_version (line 143) | fn get_tls_min_version(
method get_tls_max_version (line 151) | fn get_tls_max_version(
method drop (line 159) | fn drop(&mut self, backend: Resource<String>) -> wasmtime::Result<()> {
type BackendBuilder (line 167) | pub struct BackendBuilder {
method default (line 195) | fn default() -> Self {
method new (line 226) | fn new(&mut self) -> wasmtime::Result<Resource<backend::DynamicBackendOp...
method override_host (line 232) | fn override_host(&mut self, config: Resource<backend::DynamicBackendOpti...
method connect_timeout (line 236) | fn connect_timeout(&mut self, config: Resource<backend::DynamicBackendOp...
method first_byte_timeout (line 240) | fn first_byte_timeout(&mut self, config: Resource<backend::DynamicBacken...
method between_bytes_timeout (line 244) | fn between_bytes_timeout(
method use_tls (line 252) | fn use_tls(&mut self, config: Resource<backend::DynamicBackendOptions>, ...
method tls_min_version (line 256) | fn tls_min_version(
method tls_max_version (line 264) | fn tls_max_version(
method cert_hostname (line 272) | fn cert_hostname(&mut self, config: Resource<backend::DynamicBackendOpti...
method ca_certificate (line 276) | fn ca_certificate(&mut self, config: Resource<backend::DynamicBackendOpt...
method tls_ciphers (line 280) | fn tls_ciphers(&mut self, config: Resource<backend::DynamicBackendOption...
method sni_hostname (line 284) | fn sni_hostname(&mut self, config: Resource<backend::DynamicBackendOptio...
method client_cert (line 288) | fn client_cert(
method http_keepalive_time_ms (line 298) | fn http_keepalive_time_ms(
method tcp_keepalive_enable (line 308) | fn tcp_keepalive_enable(
method tcp_keepalive_interval_secs (line 318) | fn tcp_keepalive_interval_secs(
method tcp_keepalive_probes (line 328) | fn tcp_keepalive_probes(
method tcp_keepalive_time_secs (line 338) | fn tcp_keepalive_time_secs(
method max_connections (line 348) | fn max_connections(&mut self, config: Resource<backend::DynamicBackendOp...
method max_use (line 352) | fn max_use(&mut self, config: Resource<backend::DynamicBackendOptions>, ...
method max_lifetime_ms (line 356) | fn max_lifetime_ms(&mut self, config: Resource<backend::DynamicBackendOp...
method grpc (line 360) | fn grpc(&mut self, config: Resource<backend::DynamicBackendOptions>, val...
method pooling (line 364) | fn pooling(&mut self, config: Resource<backend::DynamicBackendOptions>, ...
method prefer_ipv6 (line 368) | fn prefer_ipv6(&mut self, config: Resource<backend::DynamicBackendOption...
method drop (line 372) | fn drop(&mut self, options: Resource<backend::DynamicBackendOptions>) ->...
FILE: src/component/compute/cache.rs
function get_key (line 18) | fn get_key(key: Vec<u8>) -> Result<CacheKey, types::Error> {
function load_write_options (line 23) | fn load_write_options(options: &api::WriteOptions) -> Result<WriteOption...
type LookupOptions (line 93) | struct LookupOptions {
function load_lookup_options (line 98) | fn load_lookup_options(
method insert (line 119) | async fn insert(
method replace_insert (line 143) | async fn replace_insert(
method await_entry (line 154) | async fn await_entry(
method close_pending_entry (line 171) | fn close_pending_entry(
method close_entry (line 181) | async fn close_entry(&mut self, handle: Resource<api::Entry>) -> Result<...
method close_replace_entry (line 191) | async fn close_replace_entry(
method replace (line 203) | async fn replace(
method get_age_ns (line 215) | async fn get_age_ns(
method get_body (line 225) | async fn get_body(
method get_hits (line 236) | async fn get_hits(
method get_length (line 246) | async fn get_length(
method get_max_age_ns (line 256) | async fn get_max_age_ns(
method get_stale_while_revalidate_ns (line 266) | async fn get_stale_while_revalidate_ns(
method get_state (line 276) | async fn get_state(
method get_user_metadata (line 286) | async fn get_user_metadata(
method drop (line 297) | fn drop(&mut self, _entry: Resource<api::ReplaceEntry>) -> wasmtime::Res...
method lookup (line 303) | async fn lookup(
method get_body (line 328) | async fn get_body(
method transaction_lookup (line 378) | async fn transaction_lookup(
method transaction_lookup_async (line 387) | async fn transaction_lookup_async(
method transaction_insert (line 425) | async fn transaction_insert(
method transaction_insert_and_stream_back (line 438) | async fn transaction_insert_and_stream_back(
method transaction_update (line 467) | async fn transaction_update(
method transaction_cancel (line 486) | async fn transaction_cancel(
method get_state (line 498) | async fn get_state(
method get_user_metadata (line 525) | async fn get_user_metadata(
method get_length (line 543) | async fn get_length(
method get_max_age_ns (line 553) | async fn get_max_age_ns(
method get_stale_while_revalidate_ns (line 565) | async fn get_stale_while_revalidate_ns(
method get_age_ns (line 575) | async fn get_age_ns(
method get_hits (line 587) | async fn get_hits(
method drop (line 597) | fn drop(&mut self, _entry: Resource<api::Entry>) -> wasmtime::Result<()> {
method new (line 603) | fn new(&mut self) -> wasmtime::Result<Resource<api::ExtraReplaceOptions>> {
method drop (line 607) | fn drop(&mut self, _options: Resource<api::ExtraReplaceOptions>) -> wasm...
method drop (line 613) | fn drop(&mut self, _options: Resource<api::ExtraGetBodyOptions>) -> wasm...
method new (line 619) | fn new(&mut self) -> wasmtime::Result<Resource<api::ExtraWriteOptions>> {
method drop (line 623) | fn drop(&mut self, _options: Resource<api::ExtraWriteOptions>) -> wasmti...
method new (line 629) | fn new(&mut self) -> wasmtime::Result<Resource<api::ExtraLookupOptions>> {
method drop (line 633) | fn drop(&mut self, _options: Resource<api::ExtraLookupOptions>) -> wasmt...
FILE: src/component/compute/compute_runtime.rs
method get_vcpu_ms (line 6) | fn get_vcpu_ms(&mut self) -> u64 {
method get_heap_mib (line 10) | fn get_heap_mib(&mut self) -> compute_runtime::MemoryMib {
method get_sandbox_id (line 14) | fn get_sandbox_id(&mut self) -> String {
method get_hostname (line 18) | fn get_hostname(&mut self) -> String {
method get_pop (line 22) | fn get_pop(&mut self) -> String {
method get_region (line 26) | fn get_region(&mut self) -> String {
method get_cache_generation (line 30) | fn get_cache_generation(&mut self) -> u64 {
method get_customer_id (line 34) | fn get_customer_id(&mut self) -> String {
method get_is_staging (line 38) | fn get_is_staging(&mut self) -> bool {
method get_service_id (line 42) | fn get_service_id(&mut self) -> String {
method get_service_version (line 46) | fn get_service_version(&mut self) -> u64 {
method get_namespace_id (line 50) | fn get_namespace_id(&mut self) -> String {
FILE: src/component/compute/config_store.rs
method open (line 9) | fn open(&mut self, name: String) -> Result<Resource<config_store::Store>...
method get (line 15) | fn get(
method drop (line 37) | fn drop(&mut self, _store: Resource<config_store::Store>) -> wasmtime::R...
FILE: src/component/compute/device_detection.rs
method lookup (line 7) | fn lookup(&mut self, user_agent: String, max_len: u64) -> Result<Option<...
FILE: src/component/compute/dictionary.rs
method open (line 8) | fn open(&mut self, name: String) -> Result<Resource<dictionary::Dictiona...
method lookup (line 13) | fn lookup(
method drop (line 34) | fn drop(&mut self, _dictionary: Resource<dictionary::Dictionary>) -> was...
FILE: src/component/compute/erl.rs
method open (line 11) | fn open(&mut self, name: String) -> Result<Resource<String>, erl::OpenEr...
method get_name (line 17) | fn get_name(&mut self, rc: Resource<String>) -> String {
method check_rate (line 21) | fn check_rate(
method increment (line 45) | fn increment(
method lookup_rate (line 55) | fn lookup_rate(
method lookup_count (line 65) | fn lookup_count(
method drop (line 75) | fn drop(&mut self, ratecounter: Resource<String>) -> wasmtime::Result<()> {
method open (line 82) | fn open(&mut self, name: String) -> Result<Resource<String>, erl::OpenEr...
method get_name (line 88) | fn get_name(&mut self, pb: Resource<String>) -> String {
method add (line 92) | fn add(&mut self, pb: Resource<String>, entry: String, ttl: u32) -> Resu...
method has (line 97) | fn has(&mut self, pb: Resource<String>, entry: String) -> Result<bool, t...
method drop (line 102) | fn drop(&mut self, penaltybox: Resource<String>) -> wasmtime::Result<()> {
FILE: src/component/compute/error.rs
function with_empty_detail (line 19) | pub fn with_empty_detail(self) -> http_req::ErrorWithDetail {
function from (line 28) | fn from(_: std::convert::Infallible) -> Self {
function from (line 34) | fn from(_: HandleError) -> Self {
function from (line 40) | fn from(_: ClientCertError) -> Self {
function from (line 46) | fn from(_: InvalidStatusCode) -> Self {
function from (line 52) | fn from(_: InvalidHeaderName) -> Self {
function from (line 58) | fn from(_: InvalidHeaderValue) -> Self {
function from (line 64) | fn from(_: std::str::Utf8Error) -> Self {
function from (line 70) | fn from(_: std::io::Error) -> Self {
function from (line 76) | fn from(_: ToStrError) -> Self {
function from (line 82) | fn from(_: InvalidMethod) -> Self {
function from (line 88) | fn from(_: InvalidUri) -> Self {
function from (line 94) | fn from(_: std::string::FromUtf8Error) -> Self {
function from (line 100) | fn from(err: wiggle::GuestError) -> Self {
function from (line 123) | fn from(err: ObjectStoreError) -> Self {
function from (line 134) | fn from(err: KvStoreError) -> Self {
function from (line 148) | fn from(err: ResourceTableError) -> Self {
method from (line 154) | fn from(err: KvStoreError) -> Self {
function from (line 168) | fn from(_: KeyValidationError) -> Self {
function from (line 174) | fn from(err: SecretStoreError) -> Self {
function from (line 188) | fn from(err: DictionaryError) -> Self {
function from (line 200) | fn from(err: error::Error) -> Self {
function from (line 276) | fn from(err: error::Error) -> Self {
method from (line 295) | fn from(err: error::Error) -> Self {
FILE: src/component/compute/geo.rs
method lookup (line 8) | fn lookup(&mut self, addr: types::IpAddress, max_len: u64) -> Result<Str...
FILE: src/component/compute/headers.rs
type MultiValueCursor (line 6) | type MultiValueCursor = u32;
constant MAX_HEADER_NAME_LEN (line 9) | const MAX_HEADER_NAME_LEN: usize = 1 << (16 - 1);
function write_values (line 17) | fn write_values<I, T>(
function write_names (line 60) | fn write_names<I, T>(
function get_names (line 108) | pub fn get_names<Keys, T>(
function get_values (line 121) | pub fn get_values(
FILE: src/component/compute/http_body.rs
constant MAX_HEADER_NAME_LEN (line 17) | pub const MAX_HEADER_NAME_LEN: usize = (1 << 16) - 1;
method new (line 20) | fn new(&mut self) -> Result<Resource<http_body::Body>, types::Error> {
method write (line 24) | async fn write(
method write_front (line 49) | async fn write_front(
method append (line 73) | async fn append(
method read (line 95) | async fn read(
method close (line 111) | fn close(&mut self, h: Resource<http_body::Body>) -> Result<(), types::E...
method get_known_length (line 123) | fn get_known_length(&mut self, h: Resource<http_body::Body>) -> Option<u...
method append_trailer (line 132) | fn append_trailer(
method get_trailer_names (line 159) | fn get_trailer_names(
method get_trailer_value (line 183) | fn get_trailer_value(
method get_trailer_values (line 226) | fn get_trailer_values(
function from (line 253) | fn from(err: T) -> Self {
FILE: src/component/compute/http_cache.rs
method is_request_cacheable (line 8) | fn is_request_cacheable(
method get_suggested_cache_key (line 18) | fn get_suggested_cache_key(
method close_entry (line 29) | fn close_entry(&mut self, _handle: Resource<http_cache::Entry>) -> Resul...
method get_max_age_ns (line 38) | fn get_max_age_ns(
method get_vary_rule (line 45) | fn get_vary_rule(
method get_initial_age_ns (line 56) | fn get_initial_age_ns(
method get_stale_while_revalidate_ns (line 63) | fn get_stale_while_revalidate_ns(
method get_stale_if_error_ns (line 70) | fn get_stale_if_error_ns(
method get_surrogate_keys (line 77) | fn get_surrogate_keys(
method get_length (line 88) | fn get_length(
method get_sensitive_data (line 95) | fn get_sensitive_data(&mut self, _rep: Resource<http_cache::SuggestedWri...
method drop (line 99) | fn drop(&mut self, _rep: Resource<http_cache::SuggestedWriteOptions>) ->...
method drop (line 105) | fn drop(&mut self, _h: Resource<http_cache::ExtraWriteOptions>) -> wasmt...
method drop (line 111) | fn drop(&mut self, _h: Resource<http_cache::ExtraLookupOptions>) -> wasm...
method transaction_lookup (line 117) | fn transaction_lookup(
method transaction_insert (line 128) | fn transaction_insert(
method transaction_insert_and_stream_back (line 140) | fn transaction_insert_and_stream_back(
method transaction_update (line 152) | fn transaction_update(
method transaction_update_and_return_fresh (line 164) | fn transaction_update_and_return_fresh(
method transaction_record_not_cacheable (line 176) | fn transaction_record_not_cacheable(
method get_suggested_backend_request (line 187) | fn get_suggested_backend_request(
method get_suggested_write_options (line 197) | fn get_suggested_write_options(
method prepare_response_for_storage (line 208) | fn prepare_response_for_storage(
method get_found_response (line 219) | fn get_found_response(
method get_state (line 231) | fn get_state(
method get_length (line 241) | fn get_length(
method get_max_age_ns (line 251) | fn get_max_age_ns(
method get_stale_while_revalidate_ns (line 261) | fn get_stale_while_revalidate_ns(
method get_stale_if_error_ns (line 271) | fn get_stale_if_error_ns(
method get_age_ns (line 281) | fn get_age_ns(
method get_hits (line 291) | fn get_hits(
method get_sensitive_data (line 301) | fn get_sensitive_data(
method get_surrogate_keys (line 311) | fn get_surrogate_keys(
method get_vary_rule (line 322) | fn get_vary_rule(
method transaction_abandon (line 333) | fn transaction_abandon(
method transaction_choose_stale (line 343) | fn transaction_choose_stale(
method drop (line 353) | fn drop(&mut self, _handle: Resource<http_cache::Entry>) -> wasmtime::Re...
FILE: src/component/compute/http_downstream.rs
method next_request (line 13) | async fn next_request(
method await_request (line 28) | async fn await_request(
method downstream_client_ip_addr (line 41) | fn downstream_client_ip_addr(
method downstream_server_ip_addr (line 51) | fn downstream_server_ip_addr(
method downstream_client_ddos_detected (line 61) | fn downstream_client_ddos_detected(
method downstream_tls_cipher_openssl_name (line 68) | fn downstream_tls_cipher_openssl_name(
method downstream_tls_protocol (line 76) | fn downstream_tls_protocol(
method downstream_tls_client_servername (line 84) | fn downstream_tls_client_servername(
method downstream_tls_client_hello (line 92) | fn downstream_tls_client_hello(
method downstream_tls_raw_client_certificate (line 100) | fn downstream_tls_raw_client_certificate(
method downstream_tls_client_cert_verify_result (line 108) | fn downstream_tls_client_cert_verify_result(
method downstream_tls_ja3_md5 (line 115) | fn downstream_tls_ja3_md5(
method downstream_client_h2_fingerprint (line 122) | fn downstream_client_h2_fingerprint(
method downstream_client_request_id (line 133) | fn downstream_client_request_id(
method downstream_client_oh_fingerprint (line 153) | fn downstream_client_oh_fingerprint(
method downstream_tls_ja4 (line 164) | fn downstream_tls_ja4(
method downstream_compliance_region (line 172) | fn downstream_compliance_region(
method downstream_original_header_names (line 187) | fn downstream_original_header_names(
method downstream_original_header_count (line 202) | fn downstream_original_header_count(
method fastly_key_is_valid (line 215) | fn fastly_key_is_valid(
method downstream_bot_analyzed (line 224) | fn downstream_bot_analyzed(
method downstream_bot_detected (line 231) | fn downstream_bot_detected(
method downstream_bot_name (line 238) | fn downstream_bot_name(
method downstream_bot_category (line 246) | fn downstream_bot_category(
method downstream_bot_category_kind (line 254) | fn downstream_bot_category_kind(
method downstream_bot_verified (line 261) | fn downstream_bot_verified(
method downstream_resvpnproxy_is_anonymous (line 268) | fn downstream_resvpnproxy_is_anonymous(
method downstream_resvpnproxy_is_anonymous_vpn (line 275) | fn downstream_resvpnproxy_is_anonymous_vpn(
method downstream_resvpnproxy_is_hosting_provider (line 282) | fn downstream_resvpnproxy_is_hosting_provider(
method downstream_resvpnproxy_is_proxy_over_vpn (line 289) | fn downstream_resvpnproxy_is_proxy_over_vpn(
method downstream_resvpnproxy_is_public_proxy (line 296) | fn downstream_resvpnproxy_is_public_proxy(
method downstream_resvpnproxy_is_relay_proxy (line 303) | fn downstream_resvpnproxy_is_relay_proxy(
method downstream_resvpnproxy_is_residential_proxy (line 310) | fn downstream_resvpnproxy_is_residential_proxy(
method downstream_resvpnproxy_is_smart_dns_proxy (line 317) | fn downstream_resvpnproxy_is_smart_dns_proxy(
method downstream_resvpnproxy_is_tor_exit_node (line 324) | fn downstream_resvpnproxy_is_tor_exit_node(
method downstream_resvpnproxy_is_vpn_datacenter (line 331) | fn downstream_resvpnproxy_is_vpn_datacenter(
method downstream_resvpnproxy_vpn_service_name (line 338) | fn downstream_resvpnproxy_vpn_service_name(
method drop (line 348) | fn drop(
type ExtraBotCategory (line 356) | pub struct ExtraBotCategory {
method as_raw (line 361) | fn as_raw(&mut self, h: wasmtime::component::Resource<ExtraBotCategory>)...
method drop (line 365) | fn drop(&mut self, h: wasmtime::component::Resource<ExtraBotCategory>) -...
type MetadataView (line 371) | pub(in super::super) trait MetadataView {
method absent_metadata_value (line 375) | fn absent_metadata_value<T>(
method absent_metadata_value (line 381) | fn absent_metadata_value<T>(
FILE: src/component/compute/http_req.rs
constant MAX_HEADER_NAME_LEN (line 44) | const MAX_HEADER_NAME_LEN: usize = (1 << 16) - 1;
method send (line 47) | async fn send(
method send_uncached (line 58) | async fn send_uncached(
method send_async (line 69) | async fn send_async(
method send_async_uncached (line 80) | async fn send_async_uncached(
method send_async_uncached_streaming (line 91) | async fn send_async_uncached_streaming(
method send_async_streaming (line 108) | async fn send_async_streaming(
method await_response (line 120) | async fn await_response(
method close (line 136) | fn close(&mut self, h: Resource<http_req::Request>) -> Result<(), types:...
method upgrade_websocket (line 143) | fn upgrade_websocket(&mut self, backend: Resource<String>) -> Result<(),...
method get_method (line 150) | fn get_method(
method get_uri (line 167) | fn get_uri(
method set_cache_override (line 183) | fn set_cache_override(
method new (line 192) | fn new(&mut self) -> Result<Resource<http_req::Request>, types::Error> {
method get_header_names (line 197) | fn get_header_names(
method get_header_value (line 210) | fn get_header_value(
method get_header_values (line 234) | fn get_header_values(
method set_header_values (line 248) | fn set_header_values(
method insert_header (line 282) | fn insert_header(
method append_header (line 300) | fn append_header(
method remove_header (line 318) | fn remove_header(
method set_method (line 334) | fn set_method(
method set_uri (line 344) | fn set_uri(&mut self, h: Resource<http_req::Request>, uri: String) -> Re...
method get_version (line 350) | fn get_version(
method set_version (line 359) | fn set_version(
method set_auto_decompress_response (line 369) | fn set_auto_decompress_response(
method redirect_to_websocket_proxy (line 397) | fn redirect_to_websocket_proxy(
method set_framing_headers_mode (line 406) | fn set_framing_headers_mode(
method redirect_to_grip_proxy (line 437) | fn redirect_to_grip_proxy(
method drop (line 446) | fn drop(&mut self, _request: Resource<http_req::Request>) -> wasmtime::R...
method drop (line 452) | fn drop(
method drop (line 461) | fn drop(&mut self, _details: Resource<http_req::ExtraSendErrorDetail>) -...
FILE: src/component/compute/http_resp.rs
constant MAX_HEADER_NAME_LEN (line 23) | const MAX_HEADER_NAME_LEN: usize = (1 << 16) - 1;
method send_downstream (line 26) | fn send_downstream(
method send_downstream_streaming (line 42) | fn send_downstream_streaming(
method close (line 58) | fn close(&mut self, h: Resource<http_resp::Response>) -> Result<(), type...
method new (line 67) | fn new(&mut self) -> Result<Resource<http_resp::Response>, types::Error> {
method get_status (line 72) | fn get_status(
method set_status (line 80) | fn set_status(
method append_header (line 91) | fn append_header(
method get_header_names (line 108) | fn get_header_names(
method get_header_value (line 121) | fn get_header_value(
method get_header_values (line 148) | fn get_header_values(
method set_header_values (line 182) | fn set_header_values(
method insert_header (line 216) | fn insert_header(
method remove_header (line 234) | fn remove_header(
method get_version (line 250) | fn get_version(
method set_version (line 259) | fn set_version(
method set_framing_headers_mode (line 269) | fn set_framing_headers_mode(
method set_http_keepalive_mode (line 304) | fn set_http_keepalive_mode(
method get_remote_ip_addr (line 317) | fn get_remote_ip_addr(
method get_remote_port (line 327) | fn get_remote_port(&mut self, resp_handle: Resource<http_resp::Response>...
method drop (line 334) | fn drop(&mut self, _response: Resource<http_resp::Response>) -> wasmtime...
FILE: src/component/compute/http_types.rs
type Error (line 11) | type Error = types::Error;
function try_from (line 12) | fn try_from(v: http::version::Version) -> Result<Self, Self::Error> {
function from (line 25) | fn from(v: http_types::HttpVersion) -> http::version::Version {
FILE: src/component/compute/image_optimizer.rs
method transform_image_optimizer_request (line 8) | fn transform_image_optimizer_request(
method drop (line 28) | fn drop(
FILE: src/component/compute/kv_store.rs
type Entry (line 24) | pub struct Entry {
method take_body (line 31) | fn take_body(
method metadata (line 38) | fn metadata(
method generation (line 55) | fn generation(&mut self, rep: wasmtime::component::Resource<kv_store::En...
method drop (line 59) | fn drop(
method await_lookup (line 69) | async fn await_lookup(
method await_insert (line 104) | async fn await_insert(
method await_delete (line 123) | async fn await_delete(
method await_list (line 142) | async fn await_list(
method open (line 163) | fn open(&mut self, name: String) -> Result<Resource<kv_store::Store>, ty...
method lookup (line 177) | async fn lookup(
method lookup_async (line 188) | async fn lookup_async(
method insert (line 203) | async fn insert(
method insert_async (line 216) | async fn insert_async(
method delete (line 260) | async fn delete(
method delete_async (line 271) | async fn delete_async(
method list (line 286) | async fn list(
method list_async (line 297) | async fn list_async(
method drop (line 316) | fn drop(&mut self, _store: Resource<kv_store::Store>) -> wasmtime::Resul...
method drop (line 322) | fn drop(&mut self, _options: Resource<kv_store::ExtraInsertOptions>) -> ...
method drop (line 328) | fn drop(&mut self, _options: Resource<kv_store::ExtraListOptions>) -> wa...
method drop (line 334) | fn drop(&mut self, _options: Resource<kv_store::ExtraKvError>) -> wasmti...
FILE: src/component/compute/log.rs
function is_reserved_endpoint (line 8) | fn is_reserved_endpoint(name: &[u8]) -> bool {
method open (line 23) | fn open(&mut self, name: String) -> Result<Resource<log::Endpoint>, type...
method write (line 33) | fn write(&mut self, h: Resource<log::Endpoint>, msg: Vec<u8>) {
method drop (line 44) | fn drop(&mut self, _endpoint: Resource<log::Endpoint>) -> wasmtime::Resu...
FILE: src/component/compute/purge.rs
method purge_surrogate_key (line 9) | fn purge_surrogate_key(
method purge_surrogate_key_verbose (line 21) | fn purge_surrogate_key_verbose(
method drop (line 35) | fn drop(&mut self, _options: Resource<purge::ExtraPurgeOptions>) -> wasm...
FILE: src/component/compute/secret_store.rs
method open (line 15) | fn open(&mut self, name: String) -> Result<Resource<secret_store::Store>...
method get (line 23) | fn get(
method drop (line 39) | fn drop(&mut self, _store: Resource<secret_store::Store>) -> wasmtime::R...
method plaintext (line 45) | fn plaintext(
method from_bytes (line 89) | fn from_bytes(
method drop (line 96) | fn drop(&mut self, _secret: Resource<secret_store::Secret>) -> wasmtime:...
FILE: src/component/compute/security.rs
method inspect (line 8) | fn inspect(
method drop (line 42) | fn drop(&mut self, _options: Resource<security::ExtraInspectOptions>) ->...
FILE: src/component/compute/shielding.rs
method shield_info (line 7) | fn shield_info(&mut self, name: String, max_len: u64) -> Result<String, ...
method backend_for_shield (line 47) | fn backend_for_shield(
method set_first_byte_timeout (line 69) | fn set_first_byte_timeout(
method set_cache_key (line 76) | fn set_cache_key(
method new (line 83) | fn new(&mut self) -> Result<Resource<shielding::ShieldBackendOptions>, a...
method drop (line 90) | fn drop(
FILE: src/component/compute/types.rs
function from (line 6) | fn from(addr: std::net::IpAddr) -> Self {
function from (line 15) | fn from(addr: types::IpAddress) -> Self {
FILE: src/component/erl.rs
function check_rate (line 4) | pub(crate) fn check_rate(
function ratecounter_increment (line 17) | pub(crate) fn ratecounter_increment(
function ratecounter_lookup_rate (line 26) | pub(crate) fn ratecounter_lookup_rate(
function ratecounter_lookup_count (line 35) | pub(crate) fn ratecounter_lookup_count(
function penaltybox_add (line 44) | pub(crate) fn penaltybox_add(
function penaltybox_has (line 53) | pub(crate) fn penaltybox_has(
FILE: src/component/http_req.rs
function redirect_to_websocket_proxy (line 9) | pub(crate) fn redirect_to_websocket_proxy(
function redirect_to_grip_proxy (line 33) | pub(crate) fn redirect_to_grip_proxy(
function upgrade_websocket (line 57) | pub(crate) fn upgrade_websocket(
function send (line 64) | pub(crate) async fn send(
function send_uncached (line 91) | pub(crate) async fn send_uncached(
function send_async (line 101) | pub(crate) async fn send_async(
function send_async_uncached (line 129) | pub(crate) async fn send_async_uncached(
function send_async_uncached_streaming (line 138) | pub(crate) async fn send_async_uncached_streaming(
function send_async_streaming (line 147) | pub(crate) async fn send_async_streaming(
FILE: src/component/image_optimizer.rs
function transform_image_optimizer_request (line 7) | pub(crate) fn transform_image_optimizer_request(
FILE: src/component/shielding.rs
function backend_for_shield (line 9) | pub(crate) fn backend_for_shield(
FILE: src/component/wasi.rs
method now (line 14) | fn now(&mut self) -> wasi::clocks::wall_clock::Datetime {
method resolution (line 24) | fn resolution(&mut self) -> wasi::clocks::wall_clock::Datetime {
method now (line 37) | fn now(&mut self) -> wasi::clocks::monotonic_clock::Instant {
method resolution (line 42) | fn resolution(&mut self) -> wasi::clocks::monotonic_clock::Duration {
method subscribe_instant (line 49) | fn subscribe_instant(
method subscribe_duration (line 60) | fn subscribe_duration(
method poll (line 73) | async fn poll(&mut self, pollables: Vec<Resource<wasi::io::poll::Pollabl...
method ready (line 81) | fn ready(&mut self, pollable: Resource<wasi::io::poll::Pollable>) -> bool {
method block (line 88) | async fn block(&mut self, pollable: Resource<wasi::io::poll::Pollable>) {
method drop (line 93) | fn drop(&mut self, pollable: Resource<wasi::io::poll::Pollable>) -> wasm...
method to_debug_string (line 101) | fn to_debug_string(&mut self, self_: Resource<wasi::io::error::Error>) -...
method drop (line 109) | fn drop(&mut self, rep: Resource<wasi::io::error::Error>) -> wasmtime::R...
method convert_stream_error (line 115) | fn convert_stream_error(
method write (line 130) | fn write(
method blocking_write_and_flush (line 142) | async fn blocking_write_and_flush(
method flush (line 155) | fn flush(
method blocking_flush (line 165) | async fn blocking_flush(
method check_write (line 176) | fn check_write(
method subscribe (line 186) | fn subscribe(
method write_zeroes (line 197) | fn write_zeroes(
method blocking_write_zeroes_and_flush (line 209) | async fn blocking_write_zeroes_and_flush(
method splice (line 222) | fn splice(
method blocking_splice (line 236) | async fn blocking_splice(
method drop (line 251) | fn drop(&mut self, rep: Resource<wasi::io::streams::OutputStream>) -> wa...
method read (line 260) | fn read(
method blocking_read (line 272) | async fn blocking_read(
method skip (line 285) | fn skip(
method blocking_skip (line 297) | async fn blocking_skip(
method subscribe (line 310) | fn subscribe(
method drop (line 321) | fn drop(&mut self, rep: Resource<wasi::io::streams::InputStream>) -> was...
method get_random_bytes (line 330) | fn get_random_bytes(&mut self, len: u64) -> Vec<u8> {
method get_random_u64 (line 338) | fn get_random_u64(&mut self) -> u64 {
method get_insecure_random_bytes (line 345) | fn get_insecure_random_bytes(&mut self, len: u64) -> Vec<u8> {
method get_insecure_random_u64 (line 353) | fn get_insecure_random_u64(&mut self) -> u64 {
method insecure_seed (line 362) | fn insecure_seed(&mut self) -> (u64, u64) {
method get_environment (line 371) | fn get_environment(&mut self) -> Vec<(String, String)> {
method get_arguments (line 376) | fn get_arguments(&mut self) -> Vec<String> {
method initial_cwd (line 380) | fn initial_cwd(&mut self) -> Option<String> {
method get_stdin (line 386) | fn get_stdin(&mut self) -> Resource<wasi::cli::stdin::InputStream> {
method get_stdout (line 392) | fn get_stdout(&mut self) -> Resource<wasi::cli::stdout::OutputStream> {
method get_stderr (line 398) | fn get_stderr(&mut self) -> Resource<wasi::cli::stderr::OutputStream> {
method exit (line 404) | fn exit(&mut self, status: Result<(), ()>) -> wasmtime::Result<()> {
method exit_with_code (line 408) | fn exit_with_code(&mut self, status_code: u8) -> wasmtime::Result<()> {
FILE: src/config.rs
type Dictionaries (line 33) | pub type Dictionaries = HashMap<String, Dictionary>;
type Backends (line 44) | pub type Backends = HashMap<String, Arc<Backend>>;
type FakeValidFastlyKeys (line 71) | pub type FakeValidFastlyKeys = HashSet<String>;
type FastlyConfig (line 77) | pub struct FastlyConfig {
method name (line 87) | pub fn name(&self) -> &str {
method description (line 92) | pub fn description(&self) -> &str {
method authors (line 97) | pub fn authors(&self) -> &[String] {
method language (line 102) | pub fn language(&self) -> &str {
method acls (line 107) | pub fn acls(&self) -> &Acls {
method backends (line 112) | pub fn backends(&self) -> &Backends {
method device_detection (line 117) | pub fn device_detection(&self) -> &DeviceDetection {
method geolocation (line 122) | pub fn geolocation(&self) -> &Geolocation {
method dictionaries (line 127) | pub fn dictionaries(&self) -> &Dictionaries {
method object_stores (line 132) | pub fn object_stores(&self) -> &ObjectStores {
method secret_stores (line 137) | pub fn secret_stores(&self) -> &SecretStores {
method shielding_sites (line 141) | pub fn shielding_sites(&self) -> &ShieldingSites {
method fake_valid_fastly_keys (line 146) | pub fn fake_valid_fastly_keys(&self) -> &FakeValidFastlyKeys {
method from_file (line 151) | pub fn from_file(path: impl AsRef<Path>) -> Result<Self, FastlyConfigE...
method from_str (line 161) | fn from_str(toml: impl AsRef<str>) -> Result<Self, FastlyConfigError> {
type Err (line 169) | type Err = FastlyConfigError;
method from_str (line 170) | fn from_str(s: &str) -> Result<Self, Self::Err> {
type TomlFastlyConfig (line 183) | struct TomlFastlyConfig {
type Error (line 201) | type Error = FastlyConfigError;
method try_into (line 202) | fn try_into(self) -> Result<FastlyConfig, Self::Error> {
constant MAX_MANIFEST_VERSION (line 198) | const MAX_MANIFEST_VERSION: u32 = 3;
type LocalServerConfig (line 241) | pub struct LocalServerConfig {
type ExperimentalModule (line 255) | pub enum ExperimentalModule {
type RawLocalServerConfig (line 264) | struct RawLocalServerConfig {
type Error (line 279) | type Error = FastlyConfigError;
method try_into (line 280) | fn try_into(self) -> Result<LocalServerConfig, Self::Error> {
type UnknownImportBehavior (line 353) | pub enum UnknownImportBehavior {
FILE: src/config/acl.rs
type AclConfig (line 4) | pub struct AclConfig(pub(crate) acl::Acls);
type Error (line 17) | type Error = FastlyConfigError;
method try_from (line 18) | fn try_from(toml: Table) -> Result<Self, Self::Error> {
FILE: src/config/backends.rs
type BackendHealth (line 12) | pub enum BackendHealth {
type Backend (line 24) | pub struct Backend {
type Error (line 102) | type Error = BackendConfigError;
method try_from (line 103) | fn try_from(mut toml: Table) -> Result<Self, Self::Error> {
type BackendsConfig (line 37) | pub struct BackendsConfig(pub HashMap<String, Arc<Backend>>);
type Error (line 79) | type Error = FastlyConfigError;
method try_from (line 80) | fn try_from(toml: Table) -> Result<Self, Self::Error> {
function into_table (line 58) | fn into_table(value: Value) -> Result<Table, BackendConfigError> {
function check_for_unrecognized_keys (line 68) | fn check_for_unrecognized_keys(table: &Table) -> Result<(), BackendConfi...
function parse_ca_cert_section (line 199) | fn parse_ca_cert_section(
FILE: src/config/backends/client_cert_info.rs
type ClientCertInfo (line 6) | pub struct ClientCertInfo {
method fmt (line 12) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
method new (line 36) | pub fn new(certificate_bytes: &[u8], certificate_key: &[u8]) -> Result...
method certs (line 79) | pub fn certs(&self) -> Vec<Certificate> {
method key (line 83) | pub fn key(&self) -> PrivateKey {
type Error (line 140) | type Error = ClientCertError;
method try_from (line 142) | fn try_from(value: toml::Value) -> Result<Self, Self::Error> {
type ClientCertError (line 18) | pub enum ClientCertError {
function inline_reader_for_field (line 88) | fn inline_reader_for_field<'a>(
function file_reader_for_field (line 102) | fn file_reader_for_field(
function read_certificates (line 119) | fn read_certificates<R: std::io::BufRead>(
function read_key (line 127) | fn read_key<R: std::io::BufRead>(reader: &mut R) -> Result<PrivateKey, C...
function client_certs_parse (line 176) | fn client_certs_parse() {
FILE: src/config/device_detection.rs
type DeviceDetection (line 8) | pub struct DeviceDetection {
method new (line 30) | pub fn new() -> Self {
method lookup (line 34) | pub fn lookup(&self, user_agent: &str) -> Option<DeviceDetectionData> {
type Error (line 52) | type Error = FastlyConfigError;
method try_from (line 54) | fn try_from(toml: Table) -> Result<Self, Self::Error> {
type DeviceDetectionMapping (line 13) | pub enum DeviceDetectionMapping {
method get (line 163) | pub fn get(&self, user_agent: &str) -> Option<DeviceDetectionData> {
method read_json_contents (line 180) | pub fn read_json_contents(
type DeviceDetectionData (line 25) | pub struct DeviceDetectionData {
method from (line 221) | fn from(value: HashMap<&str, SerdeValue>) -> Self {
method from (line 233) | fn from(data: &Map<String, SerdeValue>) -> Self {
method new (line 241) | pub fn new() -> Self {
method insert (line 245) | pub fn insert(&mut self, field: String, value: SerdeValue) {
method fmt (line 251) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
function process_inline_toml_dictionary (line 87) | fn process_inline_toml_dictionary(
function process_json_entries (line 139) | fn process_json_entries(
method default (line 215) | fn default() -> Self {
FILE: src/config/dictionaries.rs
type Dictionary (line 15) | pub enum Dictionary {
method is_json (line 26) | pub fn is_json(&self) -> bool {
method file_path (line 31) | pub fn file_path(&self) -> Option<&Path> {
method read_json_contents (line 39) | fn read_json_contents(file: &Path) -> Result<HashMap<String, String>, ...
method load (line 72) | pub fn load(&self) -> Result<LoadedDictionary, DictionaryConfigError> {
type LoadedDictionary (line 86) | pub struct LoadedDictionary {
type DictionariesConfig (line 92) | pub struct DictionariesConfig(pub HashMap<String, Dictionary>);
type Error (line 125) | type Error = FastlyConfigError;
method try_from (line 126) | fn try_from(toml: Table) -> Result<Self, Self::Error> {
function check_for_unrecognized_keys (line 114) | fn check_for_unrecognized_keys(table: &Table) -> Result<(), DictionaryCo...
function process_inline_toml_dictionary (line 171) | fn process_inline_toml_dictionary(
function process_json_dictionary (line 201) | fn process_json_dictionary(toml: &mut Table) -> Result<Dictionary, Dicti...
function validate_dictionary_contents (line 222) | pub(super) fn validate_dictionary_contents(
FILE: src/config/geolocation.rs
type Geolocation (line 11) | pub struct Geolocation {
method new (line 43) | pub fn new() -> Self {
method lookup (line 47) | pub fn lookup(&self, addr: &IpAddr) -> Option<GeolocationData> {
type Error (line 72) | type Error = FastlyConfigError;
method try_from (line 74) | fn try_from(toml: Table) -> Result<Self, Self::Error> {
type GeolocationMapping (line 17) | pub enum GeolocationMapping {
method get (line 186) | pub fn get(&self, address: &IpAddr) -> Option<GeolocationData> {
method read_json_contents (line 203) | pub fn read_json_contents(
type GeolocationData (line 29) | pub struct GeolocationData {
method from (line 271) | fn from(value: HashMap<&str, SerdeValue>) -> Self {
method from (line 283) | fn from(data: &Map<String, SerdeValue>) -> Self {
method new (line 291) | pub fn new() -> Self {
method insert (line 295) | pub fn insert(&mut self, field: String, value: SerdeValue) {
method fmt (line 301) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
method default (line 34) | fn default() -> Self {
function parse_ip_address (line 112) | pub fn parse_ip_address(address: &str) -> Result<IpAddr, GeolocationConf...
function process_inline_toml_dictionary (line 117) | fn process_inline_toml_dictionary(
function process_json_entries (line 162) | fn process_json_entries(
method default (line 238) | fn default() -> Self {
FILE: src/config/limits.rs
constant DICTIONARY_ITEM_KEY_MAX_LEN (line 2) | pub const DICTIONARY_ITEM_KEY_MAX_LEN: usize = 256;
constant DICTIONARY_ITEM_VALUE_MAX_LEN (line 3) | pub const DICTIONARY_ITEM_VALUE_MAX_LEN: usize = 8000;
FILE: src/config/object_store.rs
type ObjectStoreEntry (line 15) | struct ObjectStoreEntry {
type ObjectStoreConfig (line 22) | pub struct ObjectStoreConfig(pub(crate) ObjectStores);
type Error (line 25) | type Error = FastlyConfigError;
method try_from (line 26) | fn try_from(toml: Table) -> Result<Self, Self::Error> {
function read_json_contents (line 212) | fn read_json_contents(
FILE: src/config/secret_store.rs
type SecretStoreConfig (line 11) | pub struct SecretStoreConfig(pub(crate) SecretStores);
type Error (line 14) | type Error = FastlyConfigError;
method try_from (line 15) | fn try_from(toml: Table) -> Result<Self, Self::Error> {
function is_valid_name (line 184) | fn is_valid_name(name: &str) -> bool {
function read_json_contents (line 192) | fn read_json_contents(filename: &str) -> Result<HashMap<String, String>,...
FILE: src/config/unit_tests.rs
function read_local_server_config (line 12) | fn read_local_server_config(toml: &str) -> Result<LocalServerConfig, Fas...
function error_when_fastly_toml_files_cannot_be_read (line 19) | fn error_when_fastly_toml_files_cannot_be_read() {
function fastly_toml_files_can_be_read (line 27) | fn fastly_toml_files_can_be_read() {
function fastly_toml_files_with_simple_backend_configurations_can_be_read (line 57) | fn fastly_toml_files_with_simple_backend_configurations_can_be_read() {
function fastly_toml_files_with_simple_dictionary_configurations_can_be_read (line 106) | fn fastly_toml_files_with_simple_dictionary_configurations_can_be_read() {
function fastly_toml_files_with_simple_config_store_configurations_can_be_read (line 145) | fn fastly_toml_files_with_simple_config_store_configurations_can_be_read...
function local_server_configs_can_be_deserialized (line 184) | fn local_server_configs_can_be_deserialized() {
function backend_configs_must_use_toml_tables (line 220) | fn backend_configs_must_use_toml_tables() {
function backend_configs_cannot_contain_unrecognized_keys (line 237) | fn backend_configs_cannot_contain_unrecognized_keys() {
function backend_configs_must_provide_a_url (line 254) | fn backend_configs_must_provide_a_url() {
function backend_configs_must_provide_urls_as_a_string (line 270) | fn backend_configs_must_provide_urls_as_a_string() {
function backend_configs_must_provide_a_valid_url (line 286) | fn backend_configs_must_provide_a_valid_url() {
function backend_configs_must_provide_override_host_as_a_string (line 301) | fn backend_configs_must_provide_override_host_as_a_string() {
function backend_configs_must_provide_a_non_empty_override_host (line 317) | fn backend_configs_must_provide_a_non_empty_override_host() {
function backend_configs_must_provide_a_valid_override_host (line 333) | fn backend_configs_must_provide_a_valid_override_host() {
function backend_configs_can_provide_health_status (line 350) | fn backend_configs_can_provide_health_status() {
function backend_configs_health_must_be_valid (line 386) | fn backend_configs_health_must_be_valid() {
function backend_configs_health_must_be_string (line 403) | fn backend_configs_health_must_be_string() {
function dictionary_configs_have_a_valid_format (line 431) | fn dictionary_configs_have_a_valid_format() {
function config_store_configs_have_a_valid_format (line 449) | fn config_store_configs_have_a_valid_format() {
function dictionary_configs_must_use_toml_tables (line 480) | fn dictionary_configs_must_use_toml_tables() {
function config_store_configs_must_use_toml_tables (line 497) | fn config_store_configs_must_use_toml_tables() {
function dictionary_configs_cannot_contain_unrecognized_keys (line 514) | fn dictionary_configs_cannot_contain_unrecognized_keys() {
function config_store_configs_cannot_contain_unrecognized_keys (line 539) | fn config_store_configs_cannot_contain_unrecognized_keys() {
function dictionary_configs_must_provide_a_file (line 564) | fn dictionary_configs_must_provide_a_file() {
function config_store_configs_must_provide_a_file (line 580) | fn config_store_configs_must_provide_a_file() {
function dictionary_configs_must_provide_a_format (line 596) | fn dictionary_configs_must_provide_a_format() {
function config_store_configs_must_provide_a_format (line 620) | fn config_store_configs_must_provide_a_format() {
function dictionary_configs_must_provide_file_as_a_string (line 644) | fn dictionary_configs_must_provide_file_as_a_string() {
function config_store_configs_must_provide_file_as_a_string (line 661) | fn config_store_configs_must_provide_file_as_a_string() {
function dictionary_configs_must_provide_a_non_empty_file (line 678) | fn dictionary_configs_must_provide_a_non_empty_file() {
function config_store_configs_must_provide_a_non_empty_file (line 695) | fn config_store_configs_must_provide_a_non_empty_file() {
function dictionary_configs_must_provide_format_as_a_string (line 712) | fn dictionary_configs_must_provide_format_as_a_string() {
function config_store_configs_must_provide_format_as_a_string (line 729) | fn config_store_configs_must_provide_format_as_a_string() {
function dictionary_configs_must_provide_a_non_empty_format (line 746) | fn dictionary_configs_must_provide_a_non_empty_format() {
function config_store_configs_must_provide_a_non_empty_format (line 763) | fn config_store_configs_must_provide_a_non_empty_format() {
function valid_dictionary_config_with_format_set_to_json (line 780) | fn valid_dictionary_config_with_format_set_to_json() {
function valid_config_store_config_with_format_set_to_json (line 800) | fn valid_config_store_config_with_format_set_to_json() {
function valid_inline_toml_dictionaries_can_be_parsed (line 830) | fn valid_inline_toml_dictionaries_can_be_parsed() {
function valid_inline_toml_config_stores_can_be_parsed (line 842) | fn valid_inline_toml_config_stores_can_be_parsed() {
function dictionary_configs_must_provide_a_format (line 855) | fn dictionary_configs_must_provide_a_format() {
function config_store_configs_must_provide_a_format (line 871) | fn config_store_configs_must_provide_a_format() {
function dictionary_configs_must_provide_contents (line 887) | fn dictionary_configs_must_provide_contents() {
function config_store_configs_must_provide_contents (line 904) | fn config_store_configs_must_provide_contents() {
function device_detection_has_a_valid_format (line 934) | fn device_detection_has_a_valid_format() {
function geolocation_has_a_valid_format (line 964) | fn geolocation_has_a_valid_format() {
function geolocation_must_provide_a_file (line 996) | fn geolocation_must_provide_a_file() {
function geolocation_must_provide_file_as_a_string (line 1012) | fn geolocation_must_provide_file_as_a_string() {
function geolocation_must_provide_a_non_empty_file (line 1030) | fn geolocation_must_provide_a_non_empty_file() {
function geolocation_must_provide_format_as_a_string (line 1048) | fn geolocation_must_provide_format_as_a_string() {
function geolocation_must_provide_a_non_empty_format (line 1065) | fn geolocation_must_provide_a_non_empty_format() {
function valid_geolocation_with_format_set_to_json (line 1082) | fn valid_geolocation_with_format_set_to_json() {
function valid_inline_toml_geolocation_can_be_parsed (line 1113) | fn valid_inline_toml_geolocation_can_be_parsed() {
function geolocation_must_provide_contents (line 1127) | fn geolocation_must_provide_contents() {
function ca_certs_default_to_empty (line 1147) | fn ca_certs_default_to_empty() {
function reads_ca_certs (line 1160) | fn reads_ca_certs() {
function reads_file_path_ca_certs (line 1207) | fn reads_file_path_ca_certs() {
function reads_multiple_ca_certs (line 1234) | fn reads_multiple_ca_certs() {
function fastly_toml_files_with_unsupported_manifest_version (line 1291) | fn fastly_toml_files_with_unsupported_manifest_version() {
function fastly_toml_with_fake_valid_fastly_keys (line 1308) | fn fastly_toml_with_fake_valid_fastly_keys() {
function fastly_toml_without_fake_valid_fastly_keys_defaults_to_empty (line 1328) | fn fastly_toml_without_fake_valid_fastly_keys_defaults_to_empty() {
function fastly_toml_with_empty_fake_valid_fastly_keys (line 1342) | fn fastly_toml_with_empty_fake_valid_fastly_keys() {
FILE: src/downstream.rs
type DownstreamMetadata (line 12) | pub struct DownstreamMetadata {
type DownstreamRequest (line 30) | pub struct DownstreamRequest {
type DownstreamResponse (line 37) | pub enum DownstreamResponse {
function prepare_request (line 47) | pub fn prepare_request(req: Request<hyper::Body>) -> Result<Request<Body...
FILE: src/error.rs
type Error (line 11) | pub enum Error {
method to_fastly_status (line 191) | pub fn to_fastly_status(&self) -> FastlyStatus {
method guest_error_fastly_status (line 279) | fn guest_error_fastly_status(e: &GuestError) -> FastlyStatus {
type HandleError (line 303) | pub enum HandleError {
type ExecutionError (line 381) | pub(crate) enum ExecutionError {
type FastlyConfigError (line 405) | pub enum FastlyConfigError {
type AclConfigError (line 484) | pub enum AclConfigError {
type BackendConfigError (line 502) | pub enum BackendConfigError {
type DictionaryConfigError (line 559) | pub enum DictionaryConfigError {
type DeviceDetectionConfigError (line 633) | pub enum DeviceDetectionConfigError {
type GeolocationConfigError (line 689) | pub enum GeolocationConfigError {
type ObjectStoreConfigError (line 748) | pub enum ObjectStoreConfigError {
type SecretStoreConfigError (line 800) | pub enum SecretStoreConfigError {
type ShieldingSiteConfigError (line 845) | pub enum ShieldingSiteConfigError {
type DownstreamRequestError (line 865) | pub enum DownstreamRequestError {
type NonHttpResponse (line 876) | pub enum NonHttpResponse {
FILE: src/execute.rs
constant DEFAULT_EPOCH_INTERRUPTION_PERIOD (line 59) | pub const DEFAULT_EPOCH_INTERRUPTION_PERIOD: Duration = Duration::from_m...
constant NEXT_REQ_PENDING_MAX (line 61) | const NEXT_REQ_PENDING_MAX: usize = 5;
constant REGION_NONE (line 62) | const REGION_NONE: &str = "none";
type Instance (line 64) | enum Instance {
method unwrap_module (line 73) | fn unwrap_module(&self) -> (&Module, &InstancePre<WasmCtx>) {
type GuestProfileConfig (line 82) | pub struct GuestProfileConfig {
type NextRequest (line 91) | pub struct NextRequest(Option<(Box<DownstreamRequest>, Arc<ExecuteCtx>)>);
method into_request (line 94) | pub fn into_request(mut self) -> Option<DownstreamRequest> {
method fmt (line 100) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
method drop (line 109) | fn drop(&mut self) {
type ExecuteCtx (line 123) | pub struct ExecuteCtx {
method build (line 173) | pub fn build(
method new (line 327) | pub fn new(
method engine (line 349) | pub fn engine(&self) -> &Engine {
method acls (line 354) | pub fn acls(&self) -> &Acls {
method backends (line 359) | pub fn backends(&self) -> &Backends {
method device_detection (line 364) | pub fn device_detection(&self) -> &DeviceDetection {
method geolocation (line 369) | pub fn geolocation(&self) -> &Geolocation {
method dictionaries (line 374) | pub fn dictionaries(&self) -> &Dictionaries {
method capture_logs (line 379) | pub fn capture_logs(&self) -> Arc<Mutex<dyn Write + Send>> {
method log_stdout (line 384) | pub fn log_stdout(&self) -> bool {
method log_stderr (line 389) | pub fn log_stderr(&self) -> bool {
method tls_config (line 394) | pub fn tls_config(&self) -> &TlsConfig {
method maybe_receive_response (line 398) | async fn maybe_receive_response(
method handle_request (line 451) | pub async fn handle_request(
method retry_request (line 622) | pub(crate) fn retry_request(self: Arc<Self>, mut downstream: Downstrea...
method handle_request_with_runtime_error (line 636) | pub async fn handle_request_with_runtime_error(
method reuse_or_spawn_guest (line 648) | async fn reuse_or_spawn_guest(
method spawn_guest (line 686) | async fn spawn_guest(
method run_guest (line 723) | async fn run_guest(
method run_main (line 899) | pub async fn run_main(
method cache (line 980) | pub fn cache(&self) -> &Arc<Cache> {
method config_path (line 984) | pub fn config_path(&self) -> Option<&Path> {
method object_store (line 988) | pub fn object_store(&self) -> &ObjectStores {
method secret_stores (line 992) | pub fn secret_stores(&self) -> &SecretStores {
method shielding_sites (line 996) | pub fn shielding_sites(&self) -> &ShieldingSites {
method fake_valid_fastly_keys (line 1001) | pub fn fake_valid_fastly_keys(&self) -> &FakeValidFastlyKeys {
method register_pending_downstream (line 1005) | pub async fn register_pending_downstream(&self) -> Option<oneshot::Rec...
method is_component (line 1018) | pub fn is_component(&self) -> bool {
type ExecuteCtxBuilder (line 1023) | pub struct ExecuteCtxBuilder {
method finish (line 1028) | pub fn finish(self) -> Result<Arc<ExecuteCtx>, Error> {
method with_acls (line 1033) | pub fn with_acls(mut self, acls: Acls) -> Self {
method with_backends (line 1039) | pub fn with_backends(mut self, backends: Backends) -> Self {
method with_device_detection (line 1045) | pub fn with_device_detection(mut self, device_detection: DeviceDetecti...
method with_geolocation (line 1051) | pub fn with_geolocation(mut self, geolocation: Geolocation) -> Self {
method with_dictionaries (line 1057) | pub fn with_dictionaries(mut self, dictionaries: Dictionaries) -> Self {
method with_object_stores (line 1063) | pub fn with_object_stores(mut self, object_store: ObjectStores) -> Self {
method with_secret_stores (line 1069) | pub fn with_secret_stores(mut self, secret_stores: SecretStores) -> Se...
method with_shielding_sites (line 1074) | pub fn with_shielding_sites(mut self, shielding_sites: ShieldingSites)...
method with_fake_valid_fastly_keys (line 1080) | pub fn with_fake_valid_fastly_keys(
method with_config_path (line 1089) | pub fn with_config_path(mut self, config_path: PathBuf) -> Self {
method with_capture_logs (line 1096) | pub fn with_capture_logs(mut self, capture_logs: Arc<Mutex<dyn Write +...
method with_log_stdout (line 1102) | pub fn with_log_stdout(mut self, log_stdout: bool) -> Self {
method with_log_stderr (line 1108) | pub fn with_log_stderr(mut self, log_stderr: bool) -> Self {
method with_local_pushpin_proxy_port (line 1114) | pub fn with_local_pushpin_proxy_port(mut self, local_pushpin_proxy_por...
function write_profile_to_file (line 1120) | fn write_profile_to_file(profile: Box<GuestProfiler>, path: &PathBuf) {
function write_profile (line 1142) | fn write_profile(store: &mut wasmtime::Store<WasmCtx>, guest_profile_pat...
function write_profile_component (line 1150) | fn write_profile_component(
function guest_result_to_response (line 1161) | fn guest_result_to_response(resp: Response<Body>, err: Option<anyhow::Er...
function exec_err_to_response (line 1165) | fn exec_err_to_response(err: &ExecutionError) -> Response<Body> {
function anyhow_response (line 1173) | fn anyhow_response(err: &anyhow::Error) -> Response<Body> {
method drop (line 1181) | fn drop(&mut self) {
function configure_wasmtime (line 1189) | fn configure_wasmtime(
type CpuTimeTracking (line 1219) | struct CpuTimeTracking<F> {
function new (line 1226) | fn new(time_spent: Arc<AtomicU64>, future: F) -> Self {
type Output (line 1232) | type Output = F::Output;
method poll (line 1234) | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
FILE: src/framing.rs
function content_length_is_valid (line 5) | pub fn content_length_is_valid(headers: &HeaderMap) -> bool {
function transfer_encoding_is_supported (line 14) | pub fn transfer_encoding_is_supported(headers: &HeaderMap) -> bool {
FILE: src/handoff.rs
constant PROTECTED_REQ_HEADERS (line 18) | const PROTECTED_REQ_HEADERS: &[&str] = &[
type HandoffInfo (line 43) | pub struct HandoffInfo {
type HandoffRequestInfo (line 50) | pub struct HandoffRequestInfo {
method from_parts (line 59) | pub fn from_parts(parts: &Parts) -> Self {
type HandoffConfig (line 70) | pub struct HandoffConfig {
type HandoffTlsConfig (line 79) | pub struct HandoffTlsConfig {
type Connection (line 89) | pub enum Connection {
method poll_read (line 95) | fn poll_read(
method poll_write (line 108) | fn poll_write(
method poll_flush (line 118) | fn poll_flush(
method poll_shutdown (line 127) | fn poll_shutdown(
function perform_handoff (line 156) | pub async fn perform_handoff(
function create_request_for_handoff (line 230) | fn create_request_for_handoff(
function execute_handoff (line 289) | async fn execute_handoff(
function proxy_upgraded_connection (line 408) | async fn proxy_upgraded_connection(
function build_error_response (line 453) | fn build_error_response(status: StatusCode, message: impl ToString) -> R...
FILE: src/headers.rs
function filter_outgoing_headers (line 3) | pub fn filter_outgoing_headers(headers: &mut HeaderMap) {
FILE: src/linking.rs
type Limiter (line 15) | pub struct Limiter {
method for_wasip2 (line 23) | pub fn for_wasip2() -> Self {
method for_wasip1 (line 27) | pub fn for_wasip1() -> Self {
method new (line 31) | fn new(max_instances: usize, max_memories: usize, max_tables: usize) -...
method memory_growing (line 46) | fn memory_growing(
method table_growing (line 67) | fn table_growing(
method memory_grow_failed (line 76) | fn memory_grow_failed(&mut self, error: anyhow::Error) -> anyhow::Resu...
method table_grow_failed (line 80) | fn table_grow_failed(&mut self, error: anyhow::Error) -> anyhow::Resul...
method instances (line 84) | fn instances(&self) -> usize {
method tables (line 88) | fn tables(&self) -> usize {
method memories (line 92) | fn memories(&self) -> usize {
type ComponentCtx (line 98) | pub struct ComponentCtx {
method wasi (line 123) | pub fn wasi(&mut self) -> &mut wasmtime_wasi::WasiCtx {
method sandbox (line 127) | pub fn sandbox(&mut self) -> &mut Sandbox {
method take_guest_profiler (line 131) | pub fn take_guest_profiler(&mut self) -> Option<Box<GuestProfiler>> {
method limiter (line 135) | pub fn limiter(&self) -> &Limiter {
method close_downstream_response_sender (line 139) | pub fn close_downstream_response_sender(&mut self, resp: Response<Body...
method create_store (line 147) | pub(crate) fn create_store(
method ctx (line 191) | fn ctx(&mut self) -> wasmtime_wasi::WasiCtxView<'_> {
method table (line 200) | fn table(&mut self) -> &mut wasmtime_wasi::ResourceTable {
type SandboxView (line 107) | pub trait SandboxView {
method sandbox (line 108) | fn sandbox(&self) -> &Sandbox;
method sandbox_mut (line 109) | fn sandbox_mut(&mut self) -> &mut Sandbox;
method sandbox (line 113) | fn sandbox(&self) -> &Sandbox {
method sandbox_mut (line 117) | fn sandbox_mut(&mut self) -> &mut Sandbox {
type WasmCtx (line 205) | pub struct WasmCtx {
method wasi (line 213) | pub fn wasi(&mut self) -> &mut WasiP1Ctx {
method wasi_nn (line 217) | fn wasi_nn(&mut self) -> &mut WasiNnCtx {
method sandbox (line 221) | pub fn sandbox(&mut self) -> &mut Sandbox {
method take_guest_profiler (line 225) | pub fn take_guest_profiler(&mut self) -> Option<Box<GuestProfiler>> {
method limiter (line 229) | pub fn limiter(&self) -> &Limiter {
method close_downstream_response_sender (line 235) | pub fn close_downstream_response_sender(&mut self, resp: Response<Body...
function create_store (line 244) | pub(crate) fn create_store(
function make_wasi_ctx (line 289) | fn make_wasi_ctx(ctx: &ExecuteCtx, sandbox: &Sandbox) -> wasmtime_wasi::...
function link_host_functions (line 325) | pub fn link_host_functions(
function link_legacy_aliases (line 366) | fn link_legacy_aliases(linker: &mut Linker<WasmCtx>) -> Result<(), Error> {
FILE: src/logging.rs
type LogEndpoint (line 11) | pub struct LogEndpoint {
method new (line 19) | pub fn new(name: &[u8], writer: Arc<Mutex<dyn Write + Send>>) -> LogEn...
method write_entry (line 32) | pub fn write_entry(&self, mut msg: &[u8]) -> io::Result<()> {
method p2_stream (line 76) | fn p2_stream(&self) -> Box<dyn wasmtime_wasi::p2::OutputStream> {
method async_stream (line 80) | fn async_stream(&self) -> Box<dyn AsyncWrite + Send + Sync> {
method ready (line 87) | async fn ready(&mut self) {}
method is_terminal (line 91) | fn is_terminal(&self) -> bool {
method write (line 97) | fn write(&mut self, bytes: bytes::Bytes) -> wasmtime_wasi::p2::StreamR...
method flush (line 102) | fn flush(&mut self) -> wasmtime_wasi::p2::StreamResult<()> {
method check_write (line 107) | fn check_write(&mut self) -> wasmtime_wasi::p2::StreamResult<usize> {
method write (line 65) | fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
method flush (line 70) | fn flush(&mut self) -> io::Result<()> {
method poll_write (line 113) | fn poll_write(
method poll_flush (line 122) | fn poll_flush(
method poll_shutdown (line 129) | fn poll_shutdown(
FILE: src/object_store.rs
type ObjectValue (line 13) | pub struct ObjectValue {
type ObjectStores (line 22) | pub struct ObjectStores {
method new (line 28) | pub fn new() -> Self {
method store_exists (line 34) | pub(crate) fn store_exists(&self, obj_store_key: &str) -> Result<bool,...
method lookup (line 43) | pub fn lookup(
method insert_empty_store (line 73) | pub(crate) fn insert_empty_store(
method insert (line 88) | pub fn insert(
method delete (line 186) | pub fn delete(
method list (line 214) | pub fn list(
type ObjectStoreKey (line 316) | pub struct ObjectStoreKey(String);
method new (line 319) | pub fn new(key: impl ToString) -> Self {
type ObjectKey (line 325) | pub struct ObjectKey(String);
method new (line 328) | pub fn new(key: impl ToString) -> Result<Self, KeyValidationError> {
type ObjectStoreError (line 336) | pub enum ObjectStoreError {
method from (line 347) | fn from(e: &ObjectStoreError) -> Self {
type KvStoreError (line 358) | pub enum KvStoreError {
function from (line 378) | fn from(e: &KvError) -> Self {
method from (line 393) | fn from(e: &KvStoreError) -> Self {
method from (line 406) | fn from(e: &KvStoreError) -> Self {
function is_valid_key (line 427) | fn is_valid_key(key: &str) -> Result<(), KeyValidationError> {
type KeyValidationError (line 476) | pub enum KeyValidationError {
constant STORE_NAME (line 495) | const STORE_NAME: &'static str = "test_store";
function test_kv_store_exists (line 498) | fn test_kv_store_exists() {
function test_kv_store_basics (line 513) | fn test_kv_store_basics() {
function test_kv_store_item_404s (line 573) | fn test_kv_store_item_404s() {
function test_kv_store_item_insert_modes (line 601) | fn test_kv_store_item_insert_modes() {
function test_kv_store_item_insert_generation (line 708) | fn test_kv_store_item_insert_generation() {
function test_kv_store_item_list_advanced (line 792) | fn test_kv_store_item_list_advanced() {
FILE: src/sandbox.rs
constant NEXT_REQ_ACCEPT_MAX (line 54) | const NEXT_REQ_ACCEPT_MAX: usize = 5;
constant NEXT_REQ_TIMEOUT (line 55) | const NEXT_REQ_TIMEOUT: Duration = Duration::from_secs(10);
constant NGWAF_ALLOW_VERDICT (line 56) | const NGWAF_ALLOW_VERDICT: &str = "allow";
type RequestParts (line 58) | pub struct RequestParts {
type Sandbox (line 65) | pub struct Sandbox {
method new (line 133) | pub fn new(
method downstream_metadata (line 186) | pub fn downstream_metadata(
method downstream_client_ip (line 197) | pub fn downstream_client_ip(
method downstream_server_ip (line 207) | pub fn downstream_server_ip(
method downstream_compliance_region (line 217) | pub fn downstream_compliance_region(
method downstream_request_id (line 227) | pub fn downstream_request_id(&self, handle: RequestHandle) -> Result<O...
method downstream_request (line 232) | pub fn downstream_request(&self) -> RequestHandle {
method downstream_request_body (line 237) | pub fn downstream_request_body(&self) -> BodyHandle {
method downstream_original_headers (line 242) | pub fn downstream_original_headers(
method send_downstream_response (line 261) | pub fn send_downstream_response(&mut self, resp: Response<Body>) -> Re...
method redirect_downstream_to_pushpin (line 273) | pub fn redirect_downstream_to_pushpin(
method redirect_downstream_to_backend (line 288) | pub fn redirect_downstream_to_backend(
method close_downstream_response_sender (line 297) | pub fn close_downstream_response_sender(&mut self, resp: Response<Body...
method insert_body (line 310) | pub fn insert_body(&mut self, body: Body) -> BodyHandle {
method body (line 321) | pub fn body(&self, handle: BodyHandle) -> Result<&Body, HandleError> {
method body_mut (line 336) | pub fn body_mut(&mut self, handle: BodyHandle) -> Result<&mut Body, Ha...
method take_body (line 351) | pub fn take_body(&mut self, handle: BodyHandle) -> Result<Body, Handle...
method drop_body (line 362) | pub fn drop_body(&mut self, handle: BodyHandle) -> Result<(), HandleEr...
method begin_streaming (line 377) | pub fn begin_streaming(&mut self, handle: BodyHandle) -> Result<Body, ...
method is_streaming_body (line 389) | pub fn is_streaming_body(&self, handle: BodyHandle) -> bool {
method streaming_body_mut (line 406) | pub fn streaming_body_mut(
method take_streaming_body (line 426) | pub fn take_streaming_body(
method insert_request_parts (line 447) | pub fn insert_request_parts(&mut self, parts: request::Parts) -> Reque...
method request_parts (line 464) | pub fn request_parts(&self, handle: RequestHandle) -> Result<&request:...
method request_parts_mut (line 481) | pub fn request_parts_mut(
method take_request_parts (line 501) | pub fn take_request_parts(
method insert_response_parts (line 521) | pub fn insert_response_parts(&mut self, parts: response::Parts) -> Res...
method response_parts (line 535) | pub fn response_parts(&self, handle: ResponseHandle) -> Result<&respon...
method response_parts_mut (line 552) | pub fn response_parts_mut(
method take_response_parts (line 572) | pub fn take_response_parts(
method insert_response (line 582) | pub fn insert_response(&mut self, resp: Response<Body>) -> (ResponseHa...
method log_endpoint_handle (line 597) | pub fn log_endpoint_handle(&mut self, name: &[u8]) -> EndpointHandle {
method log_endpoint (line 615) | pub fn log_endpoint(&self, handle: EndpointHandle) -> Result<&LogEndpo...
method acl_handle_by_name (line 623) | pub fn acl_handle_by_name(&mut self, name: &str) -> Option<AclHandle> {
method acl_by_handle (line 628) | pub fn acl_by_handle(&self, handle: AclHandle) -> Option<Arc<Acl>> {
method backends (line 635) | pub fn backends(&self) -> &Backends {
method backend (line 640) | pub fn backend(&self, name: &str) -> Option<&Arc<Backend>> {
method dynamic_backend (line 649) | pub fn dynamic_backend(&self, name: &str) -> Option<&Arc<Backend>> {
method backend_names (line 654) | pub fn backend_names(&self) -> impl Iterator<Item = &String> {
method add_backend (line 661) | pub fn add_backend(&mut self, name: &str, info: Backend) -> bool {
method tls_config (line 676) | pub fn tls_config(&self) -> &TlsConfig {
method device_detection_lookup (line 682) | pub fn device_detection_lookup(&self, user_agent: &str) -> Option<Stri...
method dictionary_handle (line 692) | pub fn dictionary_handle(&mut self, name: &str) -> Result<DictionaryHa...
method dictionary (line 704) | pub fn dictionary(&self, handle: DictionaryHandle) -> Result<&LoadedDi...
method dictionaries (line 711) | pub fn dictionaries(&self) -> &Dictionaries {
method geolocation_lookup (line 717) | pub fn geolocation_lookup(&self, addr: &IpAddr) -> Option<String> {
method ngwaf_response (line 727) | pub fn ngwaf_response(&self) -> String {
method kv_store (line 736) | pub fn kv_store(&self) -> &ObjectStores {
method kv_store_handle (line 740) | pub fn kv_store_handle(&mut self, key: &str) -> KvStoreHandle {
method get_kv_store_key (line 745) | pub fn get_kv_store_key(&self, handle: KvStoreHandle) -> Option<&Objec...
method kv_insert (line 750) | pub fn kv_insert(
method insert_pending_kv_insert (line 773) | pub fn insert_pending_kv_insert(
method take_pending_kv_insert (line 786) | pub fn take_pending_kv_insert(
method pending_kv_insert (line 804) | pub fn pending_kv_insert(
method kv_delete (line 815) | pub fn kv_delete(
method insert_pending_kv_delete (line 827) | pub fn insert_pending_kv_delete(
method take_pending_kv_delete (line 840) | pub fn take_pending_kv_delete(
method pending_kv_delete (line 858) | pub fn pending_kv_delete(
method obj_lookup (line 869) | pub fn obj_lookup(
method insert_pending_kv_lookup (line 881) | pub fn insert_pending_kv_lookup(
method take_pending_kv_lookup (line 894) | pub fn take_pending_kv_lookup(
method pending_kv_lookup (line 912) | pub fn pending_kv_lookup(
method kv_list (line 923) | pub fn kv_list(
method insert_pending_kv_list (line 939) | pub fn insert_pending_kv_list(&mut self, pending: PendingKvListTask) -...
method take_pending_kv_list (line 949) | pub fn take_pending_kv_list(
method pending_kv_list (line 967) | pub fn pending_kv_list(
method secret_store_handle (line 980) | pub fn secret_store_handle(&mut self, name: &str) -> Option<SecretStor...
method secret_store_name (line 985) | pub fn secret_store_name(&self, handle: SecretStoreHandle) -> Option<S...
method secret_handle (line 989) | pub fn secret_handle(&mut self, store_name: &str, secret_name: &str) -...
method secret_lookup (line 999) | pub fn secret_lookup(&self, handle: SecretHandle) -> Option<SecretLook...
method add_secret (line 1003) | pub fn add_secret(&mut self, plaintext: Vec<u8>) -> SecretHandle {
method secret_stores (line 1008) | pub fn secret_stores(&self) -> &SecretStores {
method insert_pending_request (line 1018) | pub fn insert_pending_request(
method pending_request (line 1031) | pub fn pending_request(
method pending_request_mut (line 1046) | pub fn pending_request_mut(
method take_pending_request (line 1061) | pub fn take_pending_request(
method reinsert_pending_request (line 1075) | pub fn reinsert_pending_request(
method insert_cache_op (line 1091) | pub fn insert_cache_op(&mut self, task: PendingCacheTask) -> AsyncItem...
method cache_entry_mut (line 1097) | pub(crate) async fn cache_entry_mut(
method cache_entry (line 1117) | pub(crate) async fn cache_entry(
method take_cache_entry (line 1138) | pub(crate) fn take_cache_entry(
method cache (line 1150) | pub fn cache(&self) -> &Arc<Cache> {
method prepare_select_targets (line 1160) | pub fn prepare_select_targets(
method reinsert_select_targets (line 1183) | pub fn reinsert_select_targets(&mut self, targets: Vec<SelectTarget>) {
method reinsert_async_handle (line 1189) | pub fn reinsert_async_handle(&mut self, handle: AsyncItemHandle, item:...
method new_ready (line 1195) | pub fn new_ready(&mut self) -> AsyncItemHandle {
method sandbox_id (line 1205) | pub fn sandbox_id(&self) -> u64 {
method config_path (line 1210) | pub fn config_path(&self) -> Option<&Path> {
method async_item_mut (line 1214) | pub fn async_item_mut(
method take_async_item (line 1224) | pub fn take_async_item(&mut self, handle: AsyncItemHandle) -> Result<A...
method select_impl (line 1243) | pub async fn select_impl(
method shielding_sites (line 1256) | pub fn shielding_sites(&self) -> &ShieldingSites {
method fake_valid_fastly_keys (line 1260) | pub fn fake_valid_fastly_keys(&self) -> &crate::config::FakeValidFastl...
method check_fastly_key (line 1268) | pub fn check_fastly_key(&self, handle: RequestHandle) -> Result<bool, ...
method register_pending_downstream_req (line 1279) | pub async fn register_pending_downstream_req(
method take_pending_downstream_req (line 1309) | pub fn take_pending_downstream_req(
method await_downstream_req (line 1337) | pub async fn await_downstream_req(
method abandon_pending_downstream_req (line 1366) | pub fn abandon_pending_downstream_req(
method ctx (line 1373) | pub fn ctx(&self) -> &Arc<ExecuteCtx> {
method get_heap_usage_mib (line 1381) | pub fn get_heap_usage_mib(&self) -> u32 {
method limiter (line 1387) | pub fn limiter(&self) -> &Limiter {
method limiter_mut (line 1391) | pub fn limiter_mut(&mut self) -> &mut Limiter {
type SelectedTargets (line 1396) | pub struct SelectedTargets<'sandbox> {
function new (line 1402) | fn new(sandbox: &'sandbox mut Sandbox, targets: Vec<SelectTarget>) -> Se...
function future (line 1406) | fn future(&mut self) -> Box<dyn Future<Output = usize> + Unpin + Send + ...
method drop (line 1424) | fn drop(&mut self) {
type ViceroyRequestMetadata (line 1432) | pub struct ViceroyRequestMetadata {
method default (line 1438) | fn default() -> Self {
type ViceroyResponseMetadata (line 1448) | pub struct ViceroyResponseMetadata {
method default (line 1453) | fn default() -> Self {
type AsyncItemHandle (line 1462) | pub struct AsyncItemHandle(u32);
method from (line 1472) | fn from(h: BodyHandle) -> AsyncItemHandle {
method from (line 1484) | fn from(h: PendingRequestHandle) -> AsyncItemHandle {
method from (line 1496) | fn from(h: types::AsyncItemHandle) -> AsyncItemHandle {
method from (line 1508) | fn from(h: PendingKvLookupHandle) -> AsyncItemHandle {
method from (line 1520) | fn from(h: PendingKvInsertHandle) -> AsyncItemHandle {
method from (line 1532) | fn from(h: PendingKvDeleteHandle) -> AsyncItemHandle {
method from (line 1544) | fn from(h: PendingKvListHandle) -> AsyncItemHandle {
method from (line 1556) | fn from(h: KvStoreLookupHandle) -> AsyncItemHandle {
method from (line 1568) | fn from(h: KvStoreInsertHandle) -> AsyncItemHandle {
method from (line 1580) | fn from(h: KvStoreDeleteHandle) -> AsyncItemHandle {
method from (line 1592) | fn from(h: KvStoreListHandle) -> AsyncItemHandle {
method from (line 1610) | fn from(h: CacheHandle) -> AsyncItemHandle {
method from (line 1622) | fn from(h: CacheBusyHandle) -> AsyncItemHandle {
method from (line 1634) | fn from(h: RequestPromiseHandle) -> AsyncItemHandle {
method from (line 1478) | fn from(h: AsyncItemHandle) -> BodyHandle {
method from (line 1490) | fn from(h: AsyncItemHandle) -> PendingRequestHandle {
function from (line 1502) | fn from(h: AsyncItemHandle) -> types::AsyncItemHandle {
method from (line 1514) | fn from(h: AsyncItemHandle) -> PendingKvLookupHandle {
method from (line 1526) | fn from(h: AsyncItemHandle) -> PendingKvInsertHandle {
method from (line 1538) | fn from(h: AsyncItemHandle) -> PendingKvDeleteHandle {
method from (line 1550) | fn from(h: AsyncItemHandle) -> PendingKvListHandle {
method from (line 1562) | fn from(h: AsyncItemHandle) -> KvStoreLookupHandle {
method from (line 1574) | fn from(h: AsyncItemHandle) -> KvStoreInsertHandle {
method from (line 1586) | fn from(h: AsyncItemHandle) -> KvStoreDeleteHandle {
method from (line 1598) | fn from(h: AsyncItemHandle) -> KvStoreListHandle {
method from (line 1604) | fn from(h: AsyncItemHandle) -> CacheHandle {
method from (line 1616) | fn from(h: AsyncItemHandle) -> CacheBusyHandle {
method from (line 1628) | fn from(h: AsyncItemHandle) -> RequestPromiseHandle {
method from (line 1641) | fn from(h: CacheBusyHandle) -> CacheHandle {
FILE: src/sandbox/async_item.rs
type PendingKvLookupTask (line 15) | pub struct PendingKvLookupTask(PeekableTask<Result<Option<ObjectValue>, ...
method new (line 17) | pub fn new(t: PeekableTask<Result<Option<ObjectValue>, KvStoreError>>)...
method task (line 20) | pub fn task(self) -> PeekableTask<Result<Option<ObjectValue>, KvStoreE...
type PendingKvInsertTask (line 26) | pub struct PendingKvInsertTask(PeekableTask<Result<(), KvStoreError>>);
method new (line 28) | pub fn new(t: PeekableTask<Result<(), KvStoreError>>) -> PendingKvInse...
method task (line 31) | pub fn task(self) -> PeekableTask<Result<(), KvStoreError>> {
type PendingKvDeleteTask (line 37) | pub struct PendingKvDeleteTask(PeekableTask<Result<bool, KvStoreError>>);
method new (line 39) | pub fn new(t: PeekableTask<Result<bool, KvStoreError>>) -> PendingKvDe...
method task (line 42) | pub fn task(self) -> PeekableTask<Result<bool, KvStoreError>> {
type PendingKvListTask (line 48) | pub struct PendingKvListTask(PeekableTask<Result<Vec<u8>, KvStoreError>>);
method new (line 50) | pub fn new(t: PeekableTask<Result<Vec<u8>, KvStoreError>>) -> PendingK...
method task (line 53) | pub fn task(self) -> PeekableTask<Result<Vec<u8>, KvStoreError>> {
type PendingDownstreamReqTask (line 65) | pub enum PendingDownstreamReqTask {
method new (line 71) | pub fn new(
method recv (line 86) | pub async fn recv(mut self) -> Result<Option<DownstreamRequest>, Error> {
method await_ready (line 110) | pub async fn await_ready(&mut self) {
type PendingCacheTask (line 129) | pub struct PendingCacheTask(PeekableTask<CacheEntry>);
method new (line 131) | pub fn new(t: PeekableTask<CacheEntry>) -> PendingCacheTask {
method task (line 134) | pub fn task(self) -> PeekableTask<CacheEntry> {
method as_mut (line 139) | pub async fn as_mut(&mut self) -> &mut Result<CacheEntry, Error> {
type AsyncItem (line 152) | pub enum AsyncItem {
method is_streaming (line 166) | pub fn is_streaming(&self) -> bool {
method as_body (line 170) | pub fn as_body(&self) -> Option<&Body> {
method as_body_mut (line 177) | pub fn as_body_mut(&mut self) -> Option<&mut Body> {
method into_body (line 184) | pub fn into_body(self) -> Option<Body> {
method as_streaming_mut (line 191) | pub fn as_streaming_mut(&mut self) -> Option<&mut StreamingBody> {
method into_streaming (line 198) | pub fn into_streaming(self) -> Option<StreamingBody> {
method begin_streaming (line 205) | pub fn begin_streaming(&mut self) -> Option<Body> {
method as_pending_kv_lookup (line 222) | pub fn as_pending_kv_lookup(&self) -> Option<&PendingKvLookupTask> {
method into_pending_kv_lookup (line 229) | pub fn into_pending_kv_lookup(self) -> Option<PendingKvLookupTask> {
method as_pending_kv_insert (line 236) | pub fn as_pending_kv_insert(&self) -> Option<&PendingKvInsertTask> {
method into_pending_kv_insert (line 243) | pub fn into_pending_kv_insert(self) -> Option<PendingKvInsertTask> {
method as_pending_kv_delete (line 250) | pub fn as_pending_kv_delete(&self) -> Option<&PendingKvDeleteTask> {
method into_pending_kv_delete (line 257) | pub fn into_pending_kv_delete(self) -> Option<PendingKvDeleteTask> {
method as_pending_kv_list (line 264) | pub fn as_pending_kv_list(&self) -> Option<&PendingKvListTask> {
method into_pending_kv_list (line 271) | pub fn into_pending_kv_list(self) -> Option<PendingKvListTask> {
method as_pending_req (line 278) | pub fn as_pending_req(&self) -> Option<&PeekableTask<Response<Body>>> {
method as_pending_req_mut (line 285) | pub fn as_pending_req_mut(&mut self) -> Option<&mut PeekableTask<Respo...
method as_pending_cache (line 292) | pub fn as_pending_cache(&self) -> Option<&PendingCacheTask> {
method as_pending_cache_mut (line 299) | pub fn as_pending_cache_mut(&mut self) -> Option<&mut PendingCacheTask> {
method into_pending_cache (line 306) | pub fn into_pending_cache(self) -> Option<PendingCacheTask> {
method into_pending_req (line 313) | pub fn into_pending_req(self) -> Option<PeekableTask<Response<Body>>> {
method as_pending_downstream_req_mut (line 320) | pub fn as_pending_downstream_req_mut(&mut self) -> Option<&mut Pending...
method into_pending_downstream_req (line 327) | pub fn into_pending_downstream_req(self) -> Option<PendingDownstreamRe...
method await_ready (line 334) | pub async fn await_ready(&mut self) {
method is_ready (line 349) | pub fn is_ready(&mut self) -> bool {
method from (line 355) | fn from(req: PeekableTask<Response<Body>>) -> Self {
method from (line 361) | fn from(task: PendingKvLookupTask) -> Self {
method from (line 367) | fn from(task: PendingKvInsertTask) -> Self {
method from (line 373) | fn from(task: PendingKvDeleteTask) -> Self {
method from (line 379) | fn from(task: PendingKvListTask) -> Self {
method from (line 385) | fn from(task: PendingCacheTask) -> Self {
method from (line 391) | fn from(task: PendingDownstreamReqTask) -> Self {
type PeekableTask (line 397) | pub enum PeekableTask<T> {
function spawn (line 403) | pub async fn spawn(fut: impl Future<Output = Result<T, Error>> + 'static...
function complete (line 409) | pub fn complete(t: T) -> Self {
function await_ready (line 414) | pub async fn await_ready(&mut self) {
function recv (line 429) | pub async fn recv(self) -> Result<T, Error> {
function get_mut (line 438) | pub fn get_mut(&mut self) -> Option<&mut Result<T, Error>> {
FILE: src/sandbox/downstream.rs
type DownstreamResponseState (line 26) | pub enum DownstreamResponseState {
method new (line 44) | pub fn new(sender: Sender<DownstreamResponse>) -> Self {
method is_unsent (line 48) | pub fn is_unsent(&self) -> bool {
method send (line 61) | pub fn send(&mut self, mut response: Response<Body>) -> Result<(), Err...
method redirect_to_pushpin (line 134) | pub fn redirect_to_pushpin(&mut self, redirect_info: HandoffInfo) -> R...
method redirect_to_backend (line 154) | pub fn redirect_to_backend(&mut self, redirect_info: HandoffInfo) -> R...
method close (line 176) | pub fn close(&mut self) {
FILE: src/secret_store.rs
type SecretStores (line 4) | pub struct SecretStores {
method new (line 9) | pub fn new() -> Self {
method get_store (line 15) | pub fn get_store(&self, name: &str) -> Option<&SecretStore> {
method add_store (line 19) | pub fn add_store(&mut self, name: String, store: SecretStore) {
type SecretStore (line 25) | pub struct SecretStore {
method new (line 30) | pub fn new() -> Self {
method get_secret (line 36) | pub fn get_secret(&self, name: &str) -> Option<&Secret> {
method add_secret (line 40) | pub fn add_secret(&mut self, name: String, secret: Bytes) {
type Secret (line 46) | pub struct Secret {
method plaintext (line 51) | pub fn plaintext(&self) -> &[u8] {
type SecretLookup (line 57) | pub enum SecretLookup {
FILE: src/service.rs
type ViceroyService (line 34) | pub struct ViceroyService {
method new (line 63) | pub fn new(ctx: Arc<ExecuteCtx>) -> Self {
method make_service (line 68) | fn make_service(&self, remote: &AddrStream) -> RequestService {
method serve (line 77) | pub async fn serve(self, addr: SocketAddr) -> Result<(), hyper::Error> {
type Response (line 86) | type Response = RequestService;
type Error (line 87) | type Error = Infallible;
type Future (line 88) | type Future = Ready<Result<Self::Response, Self::Error>>;
method poll_ready (line 90) | fn poll_ready(&mut self, _cx: &mut task::Context<'_>) -> Poll<Result<(...
method call (line 94) | fn call(&mut self, addr: &'addr AddrStream) -> Self::Future {
type RequestService (line 114) | pub struct RequestService {
method new (line 122) | fn new(ctx: Arc<ExecuteCtx>, addr: &AddrStream) -> Self {
type Response (line 137) | type Response = Response<Body>;
type Error (line 138) | type Error = Error;
type Future (line 139) | type Future = Pin<Box<ServiceFuture>>;
method poll_ready (line 141) | fn poll_ready(&mut self, _cx: &mut task::Context<'_>) -> Poll<Result<(...
method call (line 146) | fn call(&mut self, req: Request<hyper::Body>) -> Self::Future {
type ServiceFuture (line 134) | type ServiceFuture = dyn Future<Output = Result<Response<Body>, Error>> ...
FILE: src/shielding_site.rs
type ShieldingSites (line 12) | pub struct ShieldingSites {
type Error (line 23) | type Error = FastlyConfigError;
method try_from (line 25) | fn try_from(value: toml::value::Map<String, Value>) -> Result<Self, Se...
method new (line 120) | pub fn new() -> Self {
method with_local (line 126) | pub fn with_local<S: ToString>(mut self, name: S) -> Self {
method with_remote (line 131) | pub fn with_remote<S: ToString>(mut self, name: S, unencrypted: Url, e...
method is_local (line 142) | pub fn is_local<S: AsRef<str>>(&self, name: S) -> bool {
method get_encrypted (line 149) | pub fn get_encrypted<S: AsRef<str>>(&self, name: S) -> Option<Url> {
method get_unencrypted (line 156) | pub fn get_unencrypted<S: AsRef<str>>(&self, name: S) -> Option<Url> {
method default (line 17) | fn default() -> Self {
type ShieldingSite (line 114) | enum ShieldingSite {
FILE: src/shift_mem.rs
constant OFFSET_PAGES (line 16) | const OFFSET_PAGES: i32 = 2;
constant OFFSET (line 18) | const OFFSET: i32 = OFFSET_PAGES * 64 * 1024;
function shift_func (line 19) | fn shift_func(r#gen: &mut ModuleLocals, func: &mut LocalFunction) {
function get_local (line 173) | fn get_local(r#gen: &mut ModuleLocals, locals: &mut Vec<LocalId>, idx: u...
function shift_main_module (line 184) | pub fn shift_main_module(bytes: &[u8]) -> anyhow::Result<Vec<u8>> {
FILE: src/streaming_body.rs
constant STREAMING_CHANNEL_SIZE (line 12) | const STREAMING_CHANNEL_SIZE: usize = 8;
type StreamingBody (line 19) | pub struct StreamingBody {
method new (line 47) | pub fn new() -> (StreamingBody, mpsc::Receiver<StreamingBodyItem>) {
method send_chunk (line 62) | pub async fn send_chunk(&mut self, chunk: impl Into<Chunk>) -> Result<...
method append_trailer (line 70) | pub fn append_trailer(&mut self, name: HeaderName, value: HeaderValue) {
method await_ready (line 75) | pub async fn await_ready(&mut self) {
method finish (line 83) | pub fn finish(self) -> Result<(), Error> {
type StreamingBodyItem (line 40) | pub enum StreamingBodyItem {
FILE: src/upstream.rs
type TlsConfig (line 42) | pub struct TlsConfig {
method new (line 48) | pub fn new() -> Result<TlsConfig, Error> {
type BackendConnector (line 79) | pub struct BackendConnector {
method new (line 86) | pub fn new(backend: Arc<Backend>, tls_config: TlsConfig) -> Self {
type Response (line 121) | type Response = Connection;
type Error (line 122) | type Error = BoxError;
type Future (line 123) | type Future = Pin<Box<dyn Future<Output = Result<Self::Response, BoxEr...
method poll_ready (line 125) | fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<()...
method call (line 131) | fn call(&mut self, _: Uri) -> Self::Future {
type BoxError (line 98) | type BoxError = Box<dyn std::error::Error + Send + Sync>;
type Connection (line 100) | pub enum Connection {
method metadata (line 106) | fn metadata(&self) -> &ConnMetadata {
method connected (line 461) | fn connected(&self) -> hyper::client::connect::Connected {
type ConnMetadata (line 115) | pub struct ConnMetadata {
function canonical_host_header (line 252) | fn canonical_host_header(
function canonical_uri (line 275) | fn canonical_uri(original_uri: &Uri, canonical_host: &str, backend: &Bac...
function send_request (line 322) | pub fn send_request(
type PendingRequest (line 443) | pub enum PendingRequest {
type SelectTarget (line 453) | pub struct SelectTarget {
method poll_read (line 467) | fn poll_read(
method poll_write (line 480) | fn poll_write(
method poll_flush (line 491) | fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result...
method poll_shutdown (line 498) | fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Res...
FILE: src/wiggle_abi.rs
constant ABI_VERSION (line 28) | pub const ABI_VERSION: u64 = 1;
function from (line 100) | fn from(h: types::ObjectStoreHandle) -> types::KvStoreHandle {
function from (line 107) | fn from(h: types::KvStoreHandle) -> types::ObjectStoreHandle {
function from (line 114) | fn from(h: types::KvStoreLookupHandle) -> types::PendingKvLookupHandle {
function from (line 121) | fn from(h: types::PendingKvLookupHandle) -> types::KvStoreLookupHandle {
function from (line 128) | fn from(h: types::KvStoreInsertHandle) -> types::PendingKvInsertHandle {
function from (line 135) | fn from(h: types::PendingKvInsertHandle) -> types::KvStoreInsertHandle {
function from (line 142) | fn from(h: types::KvStoreDeleteHandle) -> types::PendingKvDeleteHandle {
function from (line 149) | fn from(h: types::PendingKvDeleteHandle) -> types::KvStoreDeleteHandle {
function from (line 156) | fn from(h: types::KvStoreListHandle) -> types::PendingKvListHandle {
function from (line 163) | fn from(h: types::PendingKvListHandle) -> types::KvStoreListHandle {
function from (line 170) | fn from(v: types::HttpVersion) -> http::version::Version {
type Error (line 184) | type Error = &'static str;
function try_from (line 185) | fn try_from(v: http::version::Version) -> Result<Self, Self::Error> {
method init (line 198) | fn init(&mut self, _memory: &mut GuestMemory<'_>, abi_version: u64) -> R...
method fastly_status_from_error (line 208) | fn fastly_status_from_error(&mut self, e: Error) -> Result<FastlyStatus,...
method success (line 259) | fn success() -> Self {
type MultiValueWriter (line 264) | pub(crate) trait MultiValueWriter {
method write_values (line 265) | fn write_values(
method write_values (line 281) | fn write_values(
FILE: src/wiggle_abi/acl.rs
method open (line 8) | fn open(
method lookup (line 25) | async fn lookup(
FILE: src/wiggle_abi/backend_impl.rs
function lookup_backend_definition (line 4) | fn lookup_backend_definition<'sess>(
method exists (line 17) | fn exists(
method is_healthy (line 29) | fn is_healthy(
method is_dynamic (line 42) | fn is_dynamic(
method get_host (line 58) | fn get_host(
method get_override_host (line 84) | fn get_override_host(
method get_port (line 114) | fn get_port(
method get_connect_timeout_ms (line 128) | fn get_connect_timeout_ms(
method get_first_byte_timeout_ms (line 139) | fn get_first_byte_timeout_ms(
method get_between_bytes_timeout_ms (line 150) | fn get_between_bytes_timeout_ms(
method get_ssl_min_version (line 161) | fn get_ssl_min_version(
method get_ssl_max_version (line 172) | fn get_ssl_max_version(
method get_http_keepalive_time (line 183) | fn get_http_keepalive_time(
method get_tcp_keepalive_enable (line 192) | fn get_tcp_keepalive_enable(
method get_tcp_keepalive_interval (line 201) | fn get_tcp_keepalive_interval(
method get_tcp_keepalive_probes (line 210) | fn get_tcp_keepalive_probes(
method get_tcp_keepalive_time (line 219) | fn get_tcp_keepalive_time(
method is_ssl (line 228) | fn is_ssl(
FILE: src/wiggle_abi/body_impl.rs
method append (line 24) | async fn append(
method new (line 49) | fn new(&mut self, _memory: &mut GuestMemory<'_>) -> Result<BodyHandle, E...
method read (line 53) | async fn read(
method write (line 73) | async fn write(
method close (line 106) | fn close(
method abandon (line 120) | fn abandon(
method trailer_append (line 129) | fn trailer_append(
method trailer_names_get (line 151) | fn trailer_names_get<'a>(
method trailer_value_get (line 178) | fn trailer_value_get<'a>(
method trailer_values_get (line 200) | fn trailer_values_get<'a>(
method known_length (line 228) | fn known_length(
FILE: src/wiggle_abi/cache.rs
function load_cache_key (line 16) | fn load_cache_key(
function load_write_options (line 25) | fn load_write_options(
type LookupOptions (line 137) | struct LookupOptions {
function load_lookup_options (line 142) | fn load_lookup_options(
method lookup (line 182) | async fn lookup(
method insert (line 208) | async fn insert(
method replace (line 241) | async fn replace(
method replace_get_age_ns (line 251) | async fn replace_get_age_ns(
method replace_get_body (line 259) | async fn replace_get_body(
method replace_get_hits (line 269) | async fn replace_get_hits(
method replace_get_length (line 277) | async fn replace_get_length(
method replace_get_max_age_ns (line 285) | async fn replace_get_max_age_ns(
method replace_get_stale_while_revalidate_ns (line 293) | async fn replace_get_stale_while_revalidate_ns(
method replace_get_state (line 301) | async fn replace_get_state(
method replace_get_user_metadata (line 309) | async fn replace_get_user_metadata(
method replace_insert (line 320) | async fn replace_insert(
method transaction_lookup (line 330) | async fn transaction_lookup(
method transaction_lookup_async (line 343) | async fn transaction_lookup_async(
method cache_busy_handle_wait (line 382) | async fn cache_busy_handle_wait(
method transaction_insert (line 396) | async fn transaction_insert(
method transaction_insert_and_stream_back (line 411) | async fn transaction_insert_and_stream_back(
method transaction_update (line 440) | async fn transaction_update(
method transaction_cancel (line 463) | async fn transaction_cancel(
method close_busy (line 476) | async fn close_busy(
method close (line 486) | async fn close(
method get_state (line 495) | async fn get_state(
method get_user_metadata (line 523) | async fn get_user_metadata(
method get_body (line 557) | async fn get_body(
method get_length (line 620) | async fn get_length(
method get_max_age_ns (line 635) | async fn get_max_age_ns(
method get_stale_while_revalidate_ns (line 648) | async fn get_stale_while_revalidate_ns(
method get_age_ns (line 656) | async fn get_age_ns(
method get_hits (line 669) | async fn get_hits(
FILE: src/wiggle_abi/compute_runtime.rs
method get_vcpu_ms (line 8) | fn get_vcpu_ms(&mut self, _memory: &mut GuestMemory<'_>) -> Result<u64, ...
method get_heap_mib (line 15) | fn get_heap_mib(&mut self, _memory: &mut GuestMemory<'_>) -> Result<u32,...
FILE: src/wiggle_abi/config_store.rs
method open (line 10) | fn open(
method get (line 19) | fn get(
FILE: src/wiggle_abi/device_detection_impl.rs
type DeviceDetectionError (line 9) | pub enum DeviceDetectionError {
method to_fastly_status (line 17) | pub fn to_fastly_status(&self) -> FastlyStatus {
method lookup (line 26) | fn lookup(
FILE: src/wiggle_abi/dictionary_impl.rs
type DictionaryError (line 16) | pub enum DictionaryError {
method to_fastly_status (line 27) | pub fn to_fastly_status(&self) -> FastlyStatus {
method open (line 37) | fn open(
method get (line 45) | fn get(
FILE: src/wiggle_abi/erl_impl.rs
method check_rate (line 9) | fn check_rate(
method ratecounter_increment (line 23) | fn ratecounter_increment(
method ratecounter_lookup_rate (line 33) | fn ratecounter_lookup_rate(
method ratecounter_lookup_count (line 43) | fn ratecounter_lookup_count(
method penaltybox_add (line 53) | fn penaltybox_add(
method penaltybox_has (line 63) | fn penaltybox_has(
FILE: src/wiggle_abi/fastly_purge_impl.rs
method purge_surrogate_key (line 10) | fn purge_surrogate_key(
FILE: src/wiggle_abi/geo_impl.rs
method lookup (line 15) | fn lookup(
FILE: src/wiggle_abi/headers.rs
constant MAX_HEADER_NAME_LEN (line 9) | pub const MAX_HEADER_NAME_LEN: u32 = (1 << 16) - 1;
type HttpHeaders (line 11) | pub(crate) trait HttpHeaders {
method names_get (line 12) | fn names_get(
method value_get (line 21) | fn value_get(
method values_get (line 30) | fn values_get(
method values_set (line 40) | fn values_set(
method insert (line 47) | fn insert(
method append (line 54) | fn append(
method remove (line 61) | fn remove(&mut self, memory: &GuestMemory<'_>, name: GuestPtr<[u8]>) -...
method names_get (line 65) | fn names_get(
method value_get (line 80) | fn value_get(
method values_get (line 115) | fn values_get(
method values_set (line 136) | fn values_set(
method insert (line 169) | fn insert(
method append (line 185) | fn append(
method remove (line 201) | fn remove(&mut self, memory: &GuestMemory<'_>, name: GuestPtr<[u8]>) -...
FILE: src/wiggle_abi/http_cache.rs
method lookup (line 10) | async fn lookup(
method transaction_lookup (line 20) | async fn transaction_lookup(
method transaction_insert (line 30) | async fn transaction_insert(
method transaction_insert_and_stream_back (line 41) | async fn transaction_insert_and_stream_back(
method transaction_update (line 52) | async fn transaction_update(
method transaction_update_and_return_fresh (line 63) | async fn transaction_update_and_return_fresh(
method transaction_record_not_cacheable (line 74) | async fn transaction_record_not_cacheable(
method transaction_abandon (line 84) | async fn transaction_abandon(
method transaction_choose_stale (line 92) | async fn transaction_choose_stale(
method close (line 100) | async fn close(
method is_request_cacheable (line 108) | fn is_request_cacheable(
method get_suggested_cache_key (line 116) | fn get_suggested_cache_key(
method get_suggested_backend_request (line 127) | async fn get_suggested_backend_request(
method get_suggested_cache_options (line 135) | async fn get_suggested_cache_options(
method prepare_response_for_storage (line 148) | async fn prepare_response_for_storage(
method get_found_response (line 157) | async fn get_found_response(
method get_state (line 166) | async fn get_state(
method get_length (line 174) | async fn get_length(
method get_max_age_ns (line 182) | async fn get_max_age_ns(
method get_stale_while_revalidate_ns (line 190) | async fn get_stale_while_revalidate_ns(
method get_stale_if_error_ns (line 198) | async fn get_stale_if_error_ns(
method get_age_ns (line 206) | async fn get_age_ns(
method get_hits (line 214) | async fn get_hits(
method get_sensitive_data (line 222) | async fn get_sensitive_data(
method get_surrogate_keys (line 230) | async fn get_surrogate_keys(
method get_vary_rule (line 241) | async fn get_vary_rule(
FILE: src/wiggle_abi/http_downstream.rs
method next_request (line 16) | async fn next_request(
method next_request_abandon (line 30) | async fn next_request_abandon(
method next_request_wait (line 40) | async fn next_request_wait(
method downstream_original_header_names (line 52) | fn downstream_original_header_names(
method downstream_original_header_count (line 73) | fn downstream_original_header_count(
method downstream_server_ip_addr (line 88) | fn downstream_server_ip_addr(
method downstream_client_ip_addr (line 117) | fn downstream_client_ip_addr(
method downstream_client_h2_fingerprint (line 146) | fn downstream_client_h2_fingerprint(
method downstream_client_request_id (line 157) | fn downstream_client_request_id(
method downstream_client_oh_fingerprint (line 188) | fn downstream_client_oh_fingerprint(
method downstream_client_ddos_detected (line 199) | fn downstream_client_ddos_detected(
method downstream_tls_cipher_openssl_name (line 207) | fn downstream_tls_cipher_openssl_name(
method downstream_tls_protocol (line 218) | fn downstream_tls_protocol(
method downstream_tls_client_servername (line 229) | fn downstream_tls_client_servername(
method downstream_tls_client_hello (line 240) | fn downstream_tls_client_hello(
method downstream_tls_raw_client_certificate (line 251) | fn downstream_tls_raw_client_certificate(
method downstream_tls_client_cert_verify_result (line 262) | fn downstream_tls_client_cert_verify_result(
method downstream_tls_ja3_md5 (line 270) | fn downstream_tls_ja3_md5(
method downstream_tls_ja4 (line 279) | fn downstream_tls_ja4(
method downstream_compliance_region (line 290) | fn downstream_compliance_region(
method fastly_key_is_valid (line 321) | fn fastly_key_is_valid(
method downstream_bot_analyzed (line 329) | fn downstream_bot_analyzed(
method downstream_bot_detected (line 337) | fn downstream_bot_detected(
method downstream_bot_name (line 345) | fn downstream_bot_name(
method downstream_bot_category (line 356) | fn downstream_bot_category(
method downstream_bot_category_kind (line 367) | fn downstream_bot_category_kind(
method downstream_bot_verified (line 375) | fn downstream_bot_verified(
method downstream_resvpnproxy_is_anonymous (line 383) | fn downstream_resvpnproxy_is_anonymous(
method downstream_resvpnproxy_is_anonymous_vpn (line 391) | fn downstream_resvpnproxy_is_anonymous_vpn(
method downstream_resvpnproxy_is_hosting_provider (line 399) | fn downstream_resvpnproxy_is_hosting_provider(
method downstream_resvpnproxy_is_proxy_over_vpn (line 407) | fn downstream_resvpnproxy_is_proxy_over_vpn(
method downstream_resvpnproxy_is_public_proxy (line 415) | fn downstream_resvpnproxy_is_public_proxy(
method downstream_resvpnproxy_is_relay_proxy (line 423) | fn downstream_resvpnproxy_is_relay_proxy(
method downstream_resvpnproxy_is_residential_proxy (line 431) | fn downstream_resvpnproxy_is_residential_proxy(
method downstream_resvpnproxy_is_smart_dns_proxy (line 439) | fn downstream_resvpnproxy_is_smart_dns_proxy(
method downstream_resvpnproxy_is_tor_exit_node (line 447) | fn downstream_resvpnproxy_is_tor_exit_node(
method downstream_resvpnproxy_is_vpn_datacenter (line 455) | fn downstream_resvpnproxy_is_vpn_datacenter(
method downstream_resvpnproxy_vpn_service_name (line 463) | fn downstream_resvpnproxy_vpn_service_name(
type MetadataView (line 475) | trait MetadataView {
method absent_metadata_value (line 477) | fn absent_metadata_value<T>(&self, handle: RequestHandle) -> Result<T,...
method absent_metadata_value (line 480) | fn absent_metadata_value<T>(&self, handle: RequestHandle) -> Result<T,...
FILE: src/wiggle_abi/image_optimizer.rs
method transform_image_optimizer_request (line 7) | async fn transform_image_optimizer_request(
FILE: src/wiggle_abi/kv_store_impl.rs
method open (line 28) | fn open(
method lookup (line 43) | async fn lookup(
method lookup_wait (line 66) | async fn lookup_wait(
method lookup_wait_v2 (line 121) | async fn lookup_wait_v2(
method insert (line 176) | async fn insert(
method insert_wait (line 245) | async fn insert_wait(
method delete (line 269) | async fn delete(
method delete_wait (line 291) | async fn delete_wait(
method list (line 315) | async fn list(
method list_wait (line 370) | async fn list_wait(
FILE: src/wiggle_abi/log_impl.rs
function is_reserved_endpoint (line 13) | fn is_reserved_endpoint(name: &[u8]) -> bool {
method endpoint_get (line 26) | fn endpoint_get(
method write (line 40) | fn write(
FILE: src/wiggle_abi/obj_store_impl.rs
method open (line 22) | fn open(
method lookup (line 37) | fn lookup(
method lookup_async (line 60) | async fn lookup_async(
method pending_lookup_wait (line 79) | async fn pending_lookup_wait(
method insert (line 102) | async fn insert(
method insert_async (line 117) | async fn insert_async(
method pending_insert_wait (line 138) | async fn pending_insert_wait(
method delete_async (line 150) | async fn delete_async(
method pending_delete_wait (line 168) | async fn pending_delete_wait(
FILE: src/wiggle_abi/req_impl.rs
method body_downstream_get (line 36) | fn body_downstream_get(
method cache_override_set (line 45) | fn cache_override_set(
method cache_override_v2_set (line 63) | fn cache_override_v2_set(
method downstream_server_ip_addr (line 90) | fn downstream_server_ip_addr(
method downstream_client_ip_addr (line 104) | fn downstream_client_ip_addr(
method downstream_client_h2_fingerprint (line 118) | fn downstream_client_h2_fingerprint(
method downstream_client_request_id (line 135) | fn downstream_client_request_id(
method downstream_client_oh_fingerprint (line 152) | fn downstream_client_oh_fingerprint(
method downstream_client_ddos_detected (line 169) | fn downstream_client_ddos_detected(
method downstream_tls_cipher_openssl_name (line 180) | fn downstream_tls_cipher_openssl_name(
method upgrade_websocket (line 198) | fn upgrade_websocket(
method redirect_to_websocket_proxy (line 207) | fn redirect_to_websocket_proxy(
method redirect_to_grip_proxy (line 226) | fn redirect_to_grip_proxy(
method redirect_to_websocket_proxy_v2 (line 244) | fn redirect_to_websocket_proxy_v2(
method redirect_to_grip_proxy_v2 (line 264) | fn redirect_to_grip_proxy_v2(
method downstream_tls_protocol (line 284) | fn downstream_tls_protocol(
method downstream_tls_client_hello (line 301) | fn downstream_tls_client_hello(
method downstream_tls_raw_client_certificate (line 318) | fn downstream_tls_raw_client_certificate(
method downstream_tls_client_cert_verify_result (line 335) | fn downstream_tls_client_cert_verify_result(
method downstream_tls_ja3_md5 (line 346) | fn downstream_tls_ja3_md5(
method downstream_tls_ja4 (line 359) | fn downstream_tls_ja4(
method downstream_compliance_region (line 376) | fn downstream_compliance_region(
method framing_headers_mode_set (line 394) | fn framing_headers_mode_set(
method register_dynamic_backend (line 417) | fn register_dynamic_backend(
method new (line 598) | fn new(&mut self, _memory: &mut GuestMemory<'_>) -> Result<RequestHandle...
method header_names_get (line 603) | fn header_names_get(
method original_header_names_get (line 621) | fn original_header_names_get(
method original_header_count (line 642) | fn original_header_count(&mut self, memory: &mut GuestMemory<'_>) -> Res...
method header_value_get (line 650) | fn header_value_get(
method header_values_get (line 663) | fn header_values_get(
method header_values_set (line 682) | fn header_values_set(
method header_insert (line 693) | fn header_insert(
method header_append (line 704) | fn header_append(
method header_remove (line 715) | fn header_remove(
method method_get (line 725) | fn method_get(
method method_set (line 756) | fn method_set(
method uri_get (line 771) | fn uri_get(
method uri_set (line 800) | fn uri_set(
method version_get (line 815) | fn version_get(
method version_set (line 824) | fn version_set(
method send (line 837) | async fn send(
method send_v2 (line 862) | async fn send_v2(
method send_v3 (line 875) | async fn send_v3(
method send_async (line 887) | async fn send_async(
method send_async_v2 (line 920) | async fn send_async_v2(
method send_async_streaming (line 937) | async fn send_async_streaming(
method pending_req_poll (line 972) | async fn pending_req_poll(
method pending_req_poll_v2 (line 989) | async fn pending_req_poll_v2(
method pending_req_wait (line 999) | async fn pending_req_wait(
method pending_req_wait_v2 (line 1011) | async fn pending_req_wait_v2(
method pending_req_select (line 1022) | async fn pending_req_select(
method pending_req_select_v2 (line 1073) | async fn pending_req_select_v2(
method fastly_key_is_valid (line 1083) | fn fastly_key_is_valid(&mut self, memory: &mut GuestMemory<'_>) -> Resul...
method close (line 1087) | fn close(
method auto_decompress_response_set (line 1098) | fn auto_decompress_response_set(
method inspect (line 1123) | fn inspect(
method on_behalf_of (line 1189) | fn on_behalf_of(
function try_ip_from_bytes (line 1201) | fn try_ip_from_bytes<const N: usize>(bytes: Option<&[u8]>) -> Result<IpA...
function read_guest_ip (line 1211) | fn read_guest_ip(
FILE: src/wiggle_abi/resp_impl.rs
method new (line 24) | fn new(&mut self, _memory: &mut GuestMemory<'_>) -> Result<ResponseHandl...
method header_names_get (line 30) | fn header_names_get(
method header_value_get (line 48) | fn header_value_get(
method header_values_get (line 61) | fn header_values_get(
method header_values_set (line 88) | fn header_values_set(
method header_insert (line 99) | fn header_insert(
method header_append (line 110) | fn header_append<'a>(
method header_remove (line 121) | fn header_remove<'a>(
method version_get (line 131) | fn version_get(
method version_set (line 140) | fn version_set(
method send_downstream (line 153) | fn send_downstream(
method status_get (line 174) | fn status_get(
method status_set (line 182) | fn status_set(
method framing_headers_mode_set (line 194) | fn framing_headers_mode_set(
method close (line 221) | fn close(
method http_keepalive_mode_set (line 232) | fn http_keepalive_mode_set(
method get_addr_dest_ip (line 244) | fn get_addr_dest_ip(
method get_addr_dest_port (line 282) | fn get_addr_dest_port(
FILE: src/wiggle_abi/secret_store_impl.rs
type SecretStoreError (line 16) | pub enum SecretStoreError {
method from (line 35) | fn from(err: &SecretStoreError) -> Self {
method open (line 47) | fn open(
method get (line 59) | fn get(
method plaintext (line 77) | fn plaintext(
method from_bytes (line 129) | fn from_bytes(
FILE: src/wiggle_abi/shielding.rs
method shield_info (line 9) | fn shield_info(
method backend_for_shield (line 58) | fn backend_for_shield(
FILE: src/wiggle_abi/uap_impl.rs
method parse (line 9) | fn parse(
FILE: test-fixtures/src/bin/acl.rs
function main (line 6) | fn main() -> Result<(), Error> {
FILE: test-fixtures/src/bin/args.rs
function main (line 1) | fn main() {
FILE: test-fixtures/src/bin/async_io.rs
function is_ready (line 14) | fn is_ready(handle: u32) -> bool {
function append_header (line 23) | fn append_header(resp: &mut ResponseHandle, header: impl ToString, value...
function test_select (line 30) | fn test_select() -> Result<(), Error> {
function test_empty_select (line 121) | fn test_empty_select(timeout: u32) {
function main (line 144) | fn main() -> Result<(), Error> {
FILE: test-fixtures/src/bin/bad-framing-headers.rs
function main (line 4) | fn main() -> Result<(), Error> {
FILE: test-fixtures/src/bin/cache.rs
function main (line 21) | fn main() {
function new_key (line 74) | fn new_key() -> CacheKey {
function ready_and_pending (line 81) | fn ready_and_pending(
function poll_known_length (line 105) | fn poll_known_length(key: &CacheKey) -> Found {
function test_non_concurrent (line 126) | fn test_non_concurrent() {
function test_concurrent (line 156) | fn test_concurrent() {
function test_single_body (line 192) | fn test_single_body() {
function test_insert_stale (line 237) | fn test_insert_stale() {
function test_edge_expired (line 260) | fn test_edge_expired() {
function test_edge_expires_after_ttl (line 289) | fn test_edge_expires_after_ttl() {
function test_vary (line 301) | fn test_vary() {
function test_vary_multiple (line 336) | fn test_vary_multiple() {
function test_novary_ignore_headers (line 409) | fn test_novary_ignore_headers() {
function test_vary_subtle (line 439) | fn test_vary_subtle() {
function test_vary_combine (line 467) | fn test_vary_combine() {
function test_user_metadata (line 506) | fn test_user_metadata() {
function test_service_id (line 536) | fn test_service_id() {
function test_length_from_body (line 549) | fn test_length_from_body() {
function test_inconsistent_body_length (line 570) | fn test_inconsistent_body_length() {
function test_nonconcurrent_range (line 623) | fn test_nonconcurrent_range() {
function test_concurrent_range (line 671) | fn test_concurrent_range() {
function test_concurrent_range_fixed (line 709) | fn test_concurrent_range_fixed() {
function test_concurrent_range_known_length_fixed (line 742) | fn test_concurrent_range_known_length_fixed() {
function test_transaction_range_fixed (line 770) | fn test_transaction_range_fixed() {
function test_known_length_nonblocking (line 800) | fn test_known_length_nonblocking() {
function test_known_length_invalid_range (line 825) | fn test_known_length_invalid_range() {
function test_unknown_length_invalid_range (line 870) | fn test_unknown_length_invalid_range() {
function test_stale_while_revalidate (line 913) | fn test_stale_while_revalidate() {
function test_keyed_purge (line 959) | fn test_keyed_purge() {
function test_soft_purge (line 984) | fn test_soft_purge() {
function test_purge_variant (line 1021) | fn test_purge_variant() {
function test_racing_transactions (line 1083) | fn test_racing_transactions() {
function test_implicit_cancel_of_fetch (line 1110) | fn test_implicit_cancel_of_fetch() {
function test_implicit_cancel_of_pending (line 1125) | fn test_implicit_cancel_of_pending() {
function test_explicit_cancel (line 1140) | fn test_explicit_cancel() {
function test_collapse_across_vary (line 1156) | fn test_collapse_across_vary() {
function test_stream_back (line 1205) | fn test_stream_back() {
function test_stream_back_fixed (line 1226) | fn test_stream_back_fixed() {
function test_simple_cache_expires (line 1261) | fn test_simple_cache_expires() {
function test_core_cache_expires (line 1273) | fn test_core_cache_expires() {
FILE: test-fixtures/src/bin/config-store-lookup.rs
function main (line 5) | fn main() {
FILE: test-fixtures/src/bin/content-length.rs
function main (line 8) | fn main() -> Result<(), Error> {
FILE: test-fixtures/src/bin/device-detection-lookup.rs
function main (line 5) | fn main() {
FILE: test-fixtures/src/bin/dictionary-lookup.rs
function main (line 5) | fn main() {
FILE: test-fixtures/src/bin/downstream-req.rs
function downstream_compliance_region (line 8) | pub fn downstream_compliance_region(
function main (line 16) | fn main() {
FILE: test-fixtures/src/bin/early-hints.rs
function main (line 9) | fn main(_req: Request) -> Result<Response, Error> {
FILE: test-fixtures/src/bin/edge-rate-limiting.rs
function main (line 7) | fn main() {
FILE: test-fixtures/src/bin/env-vars.rs
function main (line 5) | fn main() {
FILE: test-fixtures/src/bin/expects-hello.rs
function main (line 4) | fn main() {
FILE: test-fixtures/src/bin/fastly-key-is-valid.rs
function main (line 3) | fn main() {
FILE: test-fixtures/src/bin/geolocation-lookup-default.rs
function main (line 14) | fn main() {
FILE: test-fixtures/src/bin/geolocation-lookup.rs
function main (line 14) | fn main() {
FILE: test-fixtures/src/bin/grpc.rs
function main (line 7) | fn main() -> Result<(), Error> {
FILE: test-fixtures/src/bin/gzipped-response.rs
function main (line 9) | fn main() -> Result<(), SendError> {
FILE: test-fixtures/src/bin/inspect.rs
function main (line 6) | fn main(req: Request) -> Result<Response, Error> {
FILE: test-fixtures/src/bin/invalid-status-code.rs
function main (line 4) | fn main(_req: Request) -> Result<Response, Error> {
FILE: test-fixtures/src/bin/kv_store.rs
function main (line 8) | fn main() {
FILE: test-fixtures/src/bin/logging.rs
function main (line 4) | fn main() {
FILE: test-fixtures/src/bin/manual-framing-headers.rs
function main (line 12) | fn main() -> Result<(), Error> {
FILE: test-fixtures/src/bin/mutual-tls.rs
function main (line 9) | fn main() -> Result<(), Error> {
FILE: test-fixtures/src/bin/noop.rs
function main (line 3) | fn main() {}
FILE: test-fixtures/src/bin/panic.rs
function main (line 2) | fn main() {
FILE: test-fixtures/src/bin/request.rs
constant HEADER_LEN_TOO_LONG (line 20) | const HEADER_LEN_TOO_LONG: usize = MAX_HEADER_NAME_LEN + 1;
function test_version_set_and_get (line 22) | fn test_version_set_and_get() {
function test_uri_set_and_get (line 47) | fn test_uri_set_and_get() {
function test_method_set_and_get (line 106) | fn test_method_set_and_get() {
function test_header_value_get_and_insert (line 164) | fn test_header_value_get_and_insert() {
function test_header_append_and_remove (line 267) | fn test_header_append_and_remove() {
function test_header_multi_value_set_and_get (line 352) | fn test_header_multi_value_set_and_get() {
function test_default_decompress_response (line 427) | fn test_default_decompress_response() {
function main (line 433) | fn main() {
FILE: test-fixtures/src/bin/response.rs
constant HEADER_LEN_TOO_LONG (line 21) | const HEADER_LEN_TOO_LONG: usize = MAX_HEADER_NAME_LEN + 1;
function test_status_set_and_get (line 23) | fn test_status_set_and_get() {
function test_version_set_and_get (line 58) | fn test_version_set_and_get() {
function test_header_value_get_and_insert (line 80) | fn test_header_value_get_and_insert() {
function test_header_append_and_remove (line 183) | fn test_header_append_and_remove() {
function test_header_multi_value_set_and_get (line 268) | fn test_header_multi_value_set_and_get() {
function main (line 343) | fn main() {
FILE: test-fixtures/src/bin/reusable-sandboxes.rs
function is_ready (line 8) | fn is_ready(handle: u32) -> bool {
function main (line 17) | fn main() {
FILE: test-fixtures/src/bin/secret-store.rs
function main (line 6) | fn main() {
FILE: test-fixtures/src/bin/shielding.rs
function main (line 5) | fn main(request: Request) -> Result<Response, Error> {
FILE: test-fixtures/src/bin/sleep.rs
function main (line 1) | fn main() {
FILE: test-fixtures/src/bin/streaming-response.rs
function main (line 4) | fn main() {
FILE: test-fixtures/src/bin/teapot-status.rs
function main (line 13) | fn main() {
FILE: test-fixtures/src/bin/unknown-import.rs
function main (line 6) | fn main() {
function unknown_function (line 27) | pub fn unknown_function(arg1: c_int, arg2: c_float) -> c_int;
FILE: test-fixtures/src/bin/upstream-async.rs
function send_async_reqs (line 13) | fn send_async_reqs() -> (PendingRequest, PendingRequest) {
type ResponseTracker (line 24) | struct ResponseTracker {
method new (line 32) | fn new() -> Self {
method process (line 43) | fn process(&mut self, resp: Response) {
method assert_complete (line 56) | fn assert_complete(self) {
function test_wait (line 63) | fn test_wait() {
function test_poll (line 71) | fn test_poll() {
function test_select (line 103) | fn test_select() {
function main (line 117) | fn main() {
FILE: test-fixtures/src/bin/upstream-dynamic.rs
function main (line 6) | fn main() -> Result<(), Error> {
FILE: test-fixtures/src/bin/upstream-streaming.rs
function main (line 4) | fn main() {
FILE: test-fixtures/src/bin/upstream.rs
function main (line 5) | fn main() {
FILE: test-fixtures/src/bin/vcpu_time_test.rs
function get_vcpu_ms (line 11) | pub fn get_vcpu_ms(ms_out: *mut u64) -> FastlyStatus;
function current_vcpu_ms (line 14) | fn current_vcpu_ms() -> Result<u64, anyhow::Error> {
function test_that_waiting_for_servers_increases_only_wall_time (line 23) | fn test_that_waiting_for_servers_increases_only_wall_time(client_req: Re...
function test_that_computing_factorial_increases_vcpu_time (line 39) | fn test_that_computing_factorial_increases_vcpu_time() -> Result<(), Err...
function main (line 62) | fn main() -> Result<(), Error> {
FILE: test-fixtures/src/bin/write-and-read-body.rs
function main (line 4) | fn main() {
FILE: test-fixtures/src/bin/write-body.rs
function main (line 19) | fn main() {
FILE: test-fixtures/src/limits.rs
constant MAX_HEADER_NAME_LEN (line 6) | pub const MAX_HEADER_NAME_LEN: usize = (1 << 16) - 1;
FILE: wasm_abi/adapter/build.rs
function main (line 4) | fn main() {
function build_raw_intrinsics (line 74) | fn build_raw_intrinsics() -> Vec<u8> {
function build_archive (line 251) | fn build_archive(wasm: &[u8]) -> Vec<u8> {
FILE: wasm_abi/adapter/byte-array-literals/src/lib.rs
function str (line 7) | pub fn str(input: TokenStream) -> TokenStream {
function str_nl (line 20) | pub fn str_nl(input: TokenStream) -> TokenStream {
function convert_str (line 33) | fn convert_str(input: TokenStream) -> Vec<TokenTree> {
function to_string (line 51) | fn to_string(lit: Literal) -> String {
FILE: wasm_abi/adapter/src/descriptors.rs
constant MAX_DESCRIPTORS (line 8) | pub const MAX_DESCRIPTORS: usize = 128;
type Descriptor (line 11) | pub enum Descriptor {
type Streams (line 25) | pub struct Streams {
method get_read_stream (line 38) | pub fn get_read_stream(&self) -> Result<&InputStream, Errno> {
method get_write_stream (line 48) | pub fn get_write_stream(&self) -> Result<&OutputStream, Errno> {
type StreamType (line 58) | pub enum StreamType {
type Descriptors (line 64) | pub struct Descriptors {
method new (line 75) | pub fn new(_state: &State) -> Self {
method push (line 110) | fn push(&self, desc: Descriptor) -> Result<Fd, Errno> {
method table (line 123) | fn table(&self) -> &[Descriptor] {
method table_mut (line 132) | fn table_mut(&mut self) -> &mut [Descriptor] {
method open (line 141) | pub fn open(&mut self, d: Descriptor) -> Result<Fd, Errno> {
method get (line 161) | pub fn get(&self, fd: Fd) -> Result<&Descriptor, Errno> {
method get_mut (line 167) | pub fn get_mut(&mut self, fd: Fd) -> Result<&mut Descriptor, Errno> {
method close (line 174) | pub fn close(&mut self, fd: Fd) -> Result<(), Errno> {
method push_closed (line 189) | fn push_closed(&mut self) -> Result<(), Errno> {
method renumber (line 197) | pub fn renumber(&mut self, from_fd: Fd, to_fd: Fd) -> Result<(), Errno> {
method get_read_stream (line 223) | pub fn get_read_stream(&self, fd: Fd) -> Result<&InputStream, Errno> {
method get_write_stream (line 230) | pub fn get_write_stream(&self, fd: Fd) -> Result<&OutputStream, Errno> {
FILE: wasm_abi/adapter/src/fastly/cache.rs
type CacheHandle (line 7) | pub type CacheHandle = u32;
type CacheBusyHandle (line 8) | pub type CacheBusyHandle = u32;
type CacheReplaceHandle (line 9) | pub type CacheReplaceHandle = u32;
type CacheObjectLength (line 11) | pub type CacheObjectLength = u64;
type CacheDurationNs (line 12) | pub type CacheDurationNs = u64;
type CacheHitCount (line 13) | pub type CacheHitCount = u64;
type CacheLookupOptions (line 17) | pub struct CacheLookupOptions {
type CacheReplaceOptions (line 36) | pub struct CacheReplaceOptions {
type CacheReplaceStrategy (line 56) | pub enum CacheReplaceStrategy {
type CacheWriteOptions (line 64) | pub struct CacheWriteOptions {
type CacheGetBodyOptions (line 101) | pub struct CacheGetBodyOptions {
method from (line 132) | fn from(value: cache::LookupState) -> Self {
type Error (line 150) | type Error = FastlyStatus;
function try_from (line 152) | fn try_from(value: u32) -> Result<Self, Self::Error> {
function convert_lookup_options (line 165) | unsafe fn convert_lookup_options<'a>(
function lookup (line 183) | pub fn lookup(
function write_options (line 234) | unsafe fn write_options<'a>(
function insert (line 304) | pub fn insert(
function transaction_lookup (line 352) | pub fn transaction_lookup(
function transaction_lookup_async (line 399) | pub fn transaction_lookup_async(
function cache_busy_handle_wait (line 456) | pub fn cache_busy_handle_wait(
function transaction_insert (line 481) | pub fn transaction_insert(
function transaction_insert_and_stream_back (line 526) | pub fn transaction_insert_and_stream_back(
function transaction_update (line 573) | pub fn transaction_update(
function transaction_cancel (line 609) | pub fn transaction_cancel(handle: CacheHandle) -> FastlyStatus {
function close_busy (line 615) | pub fn close_busy(handle: CacheBusyHandle) -> FastlyStatus {
function close (line 637) | pub fn close(handle: CacheHandle) -> FastlyStatus {
function get_state (line 667) | pub fn get_state(
function get_user_metadata (line 684) | pub fn get_user_metadata(
function from (line 700) | fn from((mask, value): (CacheGetBodyOptionsMask, CacheGetBodyOptions)) -...
function get_body (line 714) | pub fn get_body(
function get_length (line 739) | pub fn get_length(handle: CacheHandle, length_out: *mut CacheObjectLengt...
function get_max_age_ns (line 754) | pub fn get_max_age_ns(handle: CacheHandle, duration_out: *mut CacheDurat...
function get_stale_while_revalidate_ns (line 769) | pub fn get_stale_while_revalidate_ns(
function get_age_ns (line 787) | pub fn get_age_ns(handle: CacheHandle, duration_out: *mut CacheDurationN...
function get_hits (line 802) | pub fn get_hits(handle: CacheHandle, hits_out: *mut CacheHitCount) -> Fa...
function replace (line 817) | pub fn replace(
function replace_insert (line 884) | pub fn replace_insert(
function replace_get_age_ns (line 939) | pub fn replace_get_age_ns(
function replace_get_body (line 959) | pub fn replace_get_body(
function replace_get_hits (line 987) | pub fn replace_get_hits(
function replace_get_length (line 1007) | pub fn replace_get_length(
function replace_get_max_age_ns (line 1027) | pub fn replace_get_max_age_ns(
function replace_get_stale_while_revalidate_ns (line 1047) | pub fn replace_get_stale_while_revalidate_ns(
function replace_get_state (line 1067) | pub fn replace_get_state(
function replace_get_user_metadata (line 1087) | pub fn replace_get_user_metadata(
constant REPLACE_ENTRY_MARKER (line 1112) | const REPLACE_ENTRY_MARKER: u32 = 0x4000_0000;
function encode_replace_entry (line 1116) | fn encode_replace_entry(cache_entry: CacheReplaceHandle) -> CacheHandle {
function decode_replace_entry (line 1123) | fn decode_replace_entry(cache_entry: CacheHandle) -> CacheReplaceHandle {
function is_replace_entry (line 1129) | fn is_replace_entry(cache_entry: CacheHandle) -> bool {
FILE: wasm_abi/adapter/src/fastly/config_store.rs
type ConfigStoreHandle (line 5) | pub type ConfigStoreHandle = u32;
function open (line 8) | pub fn open(
function get (line 32) | pub fn get(
FILE: wasm_abi/adapter/src/fastly/core.rs
function from (line 14) | fn from(value: crate::bindings::fastly::compute::http_types::HttpVersion...
type Error (line 27) | type Error = u32;
function try_from (line 29) | fn try_from(value: u32) -> Result<Self, Self::Error> {
type BodyWriteEnd (line 44) | pub enum BodyWriteEnd {
type FramingHeadersMode (line 53) | pub enum FramingHeadersMode {
type HttpKeepaliveMode (line 85) | pub enum HttpKeepaliveMode {
function from (line 95) | fn from(value: crate::bindings::fastly::compute::http_downstream::BotCat...
type AclHandle (line 117) | pub type AclHandle = u32;
type AsyncItemHandle (line 118) | pub type AsyncItemHandle = u32;
type BodyHandle (line 119) | pub type BodyHandle = u32;
type DictionaryHandle (line 120) | pub type DictionaryHandle = u32;
type KVStoreHandle (line 121) | pub type KVStoreHandle = u32;
type ObjectStoreHandle (line 122) | pub type ObjectStoreHandle = u32;
type PendingObjectStoreDeleteHandle (line 123) | pub type PendingObjectStoreDeleteHandle = u32;
type PendingObjectStoreInsertHandle (line 124) | pub type PendingObjectStoreInsertHandle = u32;
type KVStoreLookupHandle (line 125) | pub type KVStoreLookupHandle = u32;
type KVStoreInsertHandle (line 126) | pub type KVStoreInsertHandle = u32;
type KVStoreDeleteHandle (line 127) | pub type KVStoreDeleteHandle = u32;
type KVStoreListHandle (line 128) | pub type KVStoreListHandle = u32;
type PendingObjectStoreLookupHandle (line 129) | pub type PendingObjectStoreLookupHandle = u32;
type PendingRequestHandle (line 130) | pub type PendingRequestHandle = u32;
type RequestHandle (line 131) | pub type RequestHandle = u32;
type RequestPromiseHandle (line 132) | pub type RequestPromiseHandle = u32;
type ResponseHandle (line 133) | pub type ResponseHandle = u32;
type SecretHandle (line 134) | pub type SecretHandle = u32;
type SecretStoreHandle (line 135) | pub type SecretStoreHandle = u32;
constant INVALID_HANDLE (line 137) | pub const INVALID_HANDLE: u32 = u32::MAX - 1;
type DynamicBackendConfig (line 140) | pub struct DynamicBackendConfig {
method default (line 170) | fn default() -> Self {
function from (line 212) | fn from(value: ContentEncodings) -> Self {
type InspectConfig (line 258) | pub struct InspectConfig {
constant ABI_VERSION (line 270) | pub const ABI_VERSION: u64 = 1;
function init (line 274) | pub fn init(abi_version: u64) -> FastlyStatus {
function get_vcpu_ms (line 287) | pub fn get_vcpu_ms(vcpu_time_ms_out: *mut u64) -> FastlyStatus {
function get_heap_mib (line 296) | pub fn get_heap_mib(heap_mb_out: *mut u32) -> FastlyStatus {
function append (line 311) | pub fn append(dst_handle: BodyHandle, src_handle: BodyHandle) -> FastlyS...
function new (line 318) | pub fn new(handle_out: *mut BodyHandle) -> FastlyStatus {
function read (line 331) | pub fn read(
function write (line 346) | pub fn write(
function close (line 375) | pub fn close(body_handle: BodyHandle) -> FastlyStatus {
function abandon (line 381) | pub fn abandon(body_handle: BodyHandle) -> FastlyStatus {
function trailer_append (line 388) | pub fn trailer_append(
function trailer_names_get (line 402) | pub fn trailer_names_get(
function trailer_value_get (line 447) | pub fn trailer_value_get(
function trailer_values_get (line 490) | pub fn trailer_values_get(
function known_length (line 539) | pub fn known_length(body_handle: BodyHandle, length_out: *mut u64) -> Fa...
function endpoint_get (line 560) | pub fn endpoint_get(
function write (line 583) | pub fn write(
type NextRequestOptions (line 618) | pub struct NextRequestOptions {
function next_request (line 623) | pub fn next_request(
function next_request_wait (line 660) | pub fn next_request_wait(
function next_request_abandon (line 695) | pub fn next_request_abandon(handle: RequestPromiseHandle) -> FastlyStatus {
function downstream_original_header_names (line 702) | pub fn downstream_original_header_names(
function downstream_original_header_count (line 740) | pub fn downstream_original_header_count(
function downstream_client_ip_addr (line 757) | pub fn downstream_client_ip_addr(
function downstream_server_ip_addr (line 777) | pub fn downstream_server_ip_addr(
function downstream_client_h2_fingerprint (line 797) | pub fn downstream_client_h2_fingerprint(
function downstream_client_request_id (line 818) | pub fn downstream_client_request_id(
function downstream_client_oh_fingerprint (line 839) | pub fn downstream_client_oh_fingerprint(
function downstream_client_ddos_detected (line 860) | pub fn downstream_client_ddos_detected(
function downstream_tls_cipher_openssl_name (line 879) | pub fn downstream_tls_cipher_openssl_name(
function downstream_tls_protocol (line 900) | pub fn downstream_tls_protocol(
function downstream_tls_client_hello (line 921) | pub fn downstream_tls_client_hello(
function downstream_tls_client_servername (line 942) | pub fn downstream_tls_client_servername(
function downstream_tls_ja3_md5 (line 963) | pub fn downstream_tls_ja3_md5(
function downstream_tls_ja4 (line 978) | pub fn downstream_tls_ja4(
function downstream_compliance_region (line 999) | pub fn downstream_compliance_region(
function downstream_tls_raw_client_certificate (line 1020) | pub fn downstream_tls_raw_client_certificate(
function downstream_tls_client_cert_verify_result (line 1041) | pub fn downstream_tls_client_cert_verify_result(
function fastly_key_is_valid (line 1062) | pub fn fastly_key_is_valid(req_handle: RequestHandle, is_valid_out: *mut...
function downstream_bot_analyzed (line 1076) | pub fn downstream_bot_analyzed(
function downstream_bot_detected (line 1093) | pub fn downstream_bot_detected(
function downstream_bot_name (line 1110) | pub fn downstream_bot_name(
function downstream_bot_category (line 1131) | pub fn downstream_bot_category(
function downstream_bot_category_kind (line 1152) | pub fn downstream_bot_category_kind(
function downstream_bot_verified (line 1170) | pub fn downstream_bot_verified(
function downstream_resvpnproxy_is_anonymous (line 1188) | pub fn downstream_resvpnproxy_is_anonymous(
function downstream_resvpnproxy_is_anonymous_vpn (line 1206) | pub fn downstream_resvpnproxy_is_anonymous_vpn(
function downstream_resvpnproxy_is_hosting_provider (line 1224) | pub fn downstream_resvpnproxy_is_hosting_provider(
function downstream_resvpnproxy_is_proxy_over_vpn (line 1242) | pub fn downstream_resvpnproxy_is_proxy_over_vpn(
function downstream_resvpnproxy_is_public_proxy (line 1260) | pub fn downstream_resvpnproxy_is_public_proxy(
function downstream_resvpnproxy_is_relay_proxy (line 1278) | pub fn downstream_resvpnproxy_is_relay_proxy(
function downstream_resvpnproxy_is_residential_proxy (line 1296) | pub fn downstream_resvpnproxy_is_residential_proxy(
function downstream_resvpnproxy_is_smart_dns_proxy (line 1314) | pub fn downstream_resvpnproxy_is_smart_dns_proxy(
function downstream_resvpnproxy_is_tor_exit_node (line 1332) | pub fn downstream_resvpnproxy_is_tor_exit_node(
function downstream_resvpnproxy_is_vpn_datacenter (line 1350) | pub fn downstream_resvpnproxy_is_vpn_datacenter(
function downstream_resvpnproxy_vpn_service_name (line 1368) | pub fn downstream_resvpnproxy_vpn_service_name(
type SendErrorDetailTag (line 1416) | pub enum SendErrorDetailTag {
type SendErrorDetail (line 1447) | pub struct SendErrorDetail {
method from (line 1498) | fn from(err: fastly::compute::http_req::SendErrorDetail) -> Self {
method from (line 1570) | fn from(dns_error: http_req::DnsErrorDetail) -> Self {
method from (line 1595) | fn from(tls_alert: http_req::TlsAlertReceivedDetail) -> Self {
method from (line 1615) | fn from(h2_err: http_req::H2ErrorDetail) -> Self {
method from (line 1632) | fn from(_: http_req::ExtraSendErrorDetail) -> Self {
method from (line 1649) | fn from(tag: SendErrorDetailTag) -> Self {
function from (line 1461) | fn from((tag, ttl, swr, sk): (u32, u32, u32, Option<ManuallyDrop<Vec<u8>...
function into (line 1483) | fn into(self) -> u32 {
function encode_tls_version (line 1662) | fn encode_tls_version(val: u32) -> Result<http_types::TlsVersion, ()> {
function body_downstream_get (line 1673) | pub fn body_downstream_get(
function cache_override_set (line 1687) | pub fn cache_override_set(
function cache_override_v2_set (line 1701) | pub fn cache_override_v2_set(
function framing_headers_mode_set (line 1721) | pub fn framing_headers_mode_set(
function downstream_tls_cipher_openssl_name (line 1739) | pub fn downstream_tls_cipher_openssl_name(
function downstream_tls_protocol (line 1757) | pub fn downstream_tls_protocol(
function downstream_tls_raw_client_certificate (line 1775) | pub fn downstream_tls_raw_client_certificate(
function header_append (line 1793) | pub fn header_append(
function header_insert (line 1807) | pub fn header_insert(
function original_header_names_get (line 1821) | pub fn original_header_names_get(
function original_header_count (line 1856) | pub fn original_header_count(count_out: *mut u32) -> FastlyStatus {
function header_names_get (line 1869) | pub fn header_names_get(
function header_values_get (line 1901) | pub fn header_values_get(
function header_values_set (line 1941) | pub fn header_values_set(
function header_value_get (line 1956) | pub fn header_value_get(
function header_remove (line 1983) | pub fn header_remove(
function method_get (line 1994) | pub fn method_get(
function method_set (line 2010) | pub fn method_set(
function new (line 2021) | pub fn new(req_handle_out: *mut RequestHandle) -> FastlyStatus {
function send (line 2034) | pub fn send(
function send_v2 (line 2063) | pub fn send_v2(
function send_v3 (line 2112) | pub fn send_v3(
function send_async (line 2161) | pub fn send_async(
function send_async_v2 (line 2188) | pub fn send_async_v2(
function send_async_streaming (line 2224) | pub fn send_async_streaming(
function upgrade_websocket (line 2252) | pub fn upgrade_websocket(backend: *const u8, backend_len: usize) -> Fast...
function redirect_to_websocket_proxy_v2 (line 2262) | pub fn redirect_to_websocket_proxy_v2(
function redirect_to_grip_proxy_v2 (line 2277) | pub fn redirect_to_grip_proxy_v2(
function register_dynamic_backend (line 2292) | pub fn register_dynamic_backend(
function uri_get (line 2395) | pub fn uri_get(
function uri_set (line 2408) | pub fn uri_set(req_handle: RequestHandle, uri: *const u8, uri_len: usize...
function version_get (line 2415) | pub fn version_get(req_handle: RequestHandle, version: *mut u32) -> Fast...
function version_set (line 2429) | pub fn version_set(req_handle: RequestHandle, version: u32) -> FastlySta...
function pending_req_poll (line 2439) | pub fn pending_req_poll(
function pending_req_poll_v2 (line 2464) | pub fn pending_req_poll_v2(
function pending_req_select (line 2497) | pub fn pending_req_select(
function pending_req_select_v2 (line 2526) | pub fn pending_req_select_v2(
function pending_req_wait (line 2557) | pub fn pending_req_wait(
function pending_req_wait_v2 (line 2580) | pub fn pending_req_wait_v2(
function close (line 2609) | pub fn close(req_handle: RequestHandle) -> FastlyStatus {
function auto_decompress_response_set (line 2615) | pub fn auto_decompress_response_set(
function inspect (line 2624) | pub fn inspect(
function on_behalf_of (line 2689) | pub fn on_behalf_of(
function header_append (line 2706) | pub fn header_append(
function header_insert (line 2721) | pub fn header_insert(
function header_names_get (line 2736) | pub fn header_names_get(
function header_value_get (line 2769) | pub fn header_value_get(
function header_values_get (line 2797) | pub fn header_values_get(
function header_values_set (line 2839) | pub fn header_values_set(
function header_remove (line 2854) | pub fn header_remove(
function new (line 2866) | pub fn new(handle_out: *mut ResponseHandle) -> FastlyStatus {
function send_downstream (line 2879) | pub fn send_downstream(
function status_get (line 2898) | pub fn status_get(resp_handle: ResponseHandle, status: *mut u16) -> Fast...
function status_set (line 2915) | pub fn status_set(resp_handle: ResponseHandle, status: u16) -> FastlySta...
function version_get (line 2922) | pub fn version_get(resp_handle: ResponseHandle, version: *mut u32) -> Fa...
function version_set (line 2937) | pub fn version_set(resp_handle: ResponseHandle, version: u32) -> FastlyS...
function framing_headers_mode_set (line 2948) | pub fn framing_headers_mode_set(
function http_keepalive_mode_set (line 2968) | pub fn http_keepalive_mode_set(
function close (line 2985) | pub fn close(resp_handle: ResponseHandle) -> FastlyStatus {
function get_addr_dest_ip (line 2991) | pub fn get_addr_dest_ip(
function get_addr_dest_port (line 3011) | pub fn get_addr_dest_port(resp_handle: ResponseHandle, port_out: *mut u1...
function open (line 3031) | pub fn open(
function get (line 3056) | pub fn get(
function lookup (line 3082) | pub fn lookup(
function lookup (line 3104) | pub fn lookup(
function check_rate (line 3123) | pub fn check_rate(
function ratecounter_increment (line 3159) | pub fn ratecounter_increment(
function ratecounter_lookup_rate (line 3176) | pub fn ratecounter_lookup_rate(
function ratecounter_lookup_count (line 3202) | pub fn ratecounter_lookup_count(
function penaltybox_add (line 3228) | pub fn penaltybox_add(
function penaltybox_has (line 3245) | pub fn penaltybox_has(
function open (line 3269) | pub fn open(
function lookup (line 3298) | pub fn lookup(
function lookup_async (line 3331) | pub fn lookup_async(
function await_pending_lookup (line 3352) | pub fn await_pending_lookup(
function insert (line 3382) | pub fn insert(
function insert_async (line 3410) | pub fn insert_async(
function await_pending_insert (line 3450) | pub fn await_pending_insert(
function delete_async (line 3459) | pub fn delete_async(
function pending_delete_wait (line 3480) | pub fn pending_delete_wait(
type InsertMode (line 3499) | pub enum InsertMode {
function from (line 3508) | fn from(value: InsertMode) -> Self {
type InsertConfig (line 3519) | pub struct InsertConfig {
method default (line 3529) | fn default() -> Self {
type ListModeInternal (line 3543) | pub enum ListModeInternal {
function from (line 3550) | fn from(value: ListModeInternal) -> Self {
type ListConfig (line 3559) | pub struct ListConfig {
method default (line 3569) | fn default() -> Self {
type LookupConfig (line 3582) | pub struct LookupConfig {
method default (line 3589) | fn default() -> Self {
type DeleteConfig (line 3595) | pub struct DeleteConfig {
method default (line 3602) | fn default() -> Self {
type KvError (line 3644) | pub enum KvError {
method from (line 3656) | fn from(value: kv_store::KvError) -> Self {
function open_v2 (line 3671) | pub fn open_v2(
function lookup (line 3706) | pub fn lookup(
function lookup_wait (line 3731) | pub fn lookup_wait(
function lookup_wait_v2 (line 3799) | pub fn lookup_wait_v2(
function insert (line 3867) | pub fn insert(
function insert_wait (line 3927) | pub fn insert_wait(
function delete (line 3960) | pub fn delete(
function delete_wait (line 3987) | pub fn delete_wait(
function list (line 4027) | pub fn list(
function list_wait (line 4087) | pub fn list_wait(
function open (line 4129) | pub fn open(
function get (line 4150) | pub fn get(
function plaintext (line 4174) | pub fn plaintext(
function from_bytes (line 4191) | pub fn from_bytes(
type BackendHealth (line 4215) | pub enum BackendHealth {
method from (line 4222) | fn from(value: backend::BackendHealth) -> Self {
function decode_tls_version (line 4231) | fn decode_tls_version(val: http_types::TlsVersion) -> Result<u32, ()> {
function exists (line 4242) | pub fn exists(
function is_healthy (line 4266) | pub fn is_healthy(
function is_dynamic (line 4288) | pub fn is_dynamic(backend_ptr: *const u8, backend_len: usize, value: *mu...
function get_host (line 4306) | pub fn get_host(
function get_override_host (line 4327) | pub fn get_override_host(
function get_port (line 4348) | pub fn get_port(backend_ptr: *const u8, backend_len: usize, value: *mut ...
function get_connect_timeout_ms (line 4366) | pub fn get_connect_timeout_ms(
function get_first_byte_timeout_ms (line 4388) | pub fn get_first_byte_timeout_ms(
function get_between_bytes_timeout_ms (line 4410) | pub fn get_between_bytes_timeout_ms(
function is_ssl (line 4432) | pub fn is_ssl(backend_ptr: *const u8, backend_len: usize, value: *mut u3...
function get_ssl_min_version (line 4450) | pub fn get_ssl_min_version(
function get_ssl_max_version (line 4476) | pub fn get_ssl_max_version(
function get_http_keepalive_time (line 4502) | pub fn get_http_keepalive_time(
function get_tcp_keepalive_enable (line 4526) | pub fn get_tcp_keepalive_enable(
function get_tcp_keepalive_interval (line 4550) | pub fn get_tcp_keepalive_interval(
function get_tcp_keepalive_probes (line 4574) | pub fn get_tcp_keepalive_probes(
function get_tcp_keepalive_time (line 4598) | pub fn get_tcp_keepalive_time(
type AclError (line 4629) | pub enum AclError {
function open (line 4637) | pub fn open(
function lookup (line 4655) | pub fn lookup(
function select (line 4702) | pub fn select(
function is_ready (line 4723) | pub fn is_ready(async_item_handle: AsyncItemHandle, ready_out: *mut u32)...
function from (line 4747) | fn from(value: PurgeOptionsMask) -> Self {
type PurgeOptions (line 4757) | pub struct PurgeOptions {
function purge_surrogate_key (line 4764) | pub fn purge_surrogate_key(
type ShieldBackendConfig (line 4826) | pub struct ShieldBackendConfig {
method default (line 4833) | fn default() -> Self {
function shield_info (line 4851) | pub fn shield_info(
function backend_for_shield (line 4888) | pub fn backend_for_shield(
function init (line 4954) | pub fn init(abi_version: u64) -> FastlyStatus {
function get_secret (line 4963) | pub fn get_secret(
type ImageOptimizerErrorTag (line 4976) | pub enum ImageOptimizerErrorTag {
type ImageOptimizerErrorDetail (line 4999) | pub struct ImageOptimizerErrorDetail {
type ImageOptimizerTransformConfig (line 5007) | pub struct ImageOptimizerTransformConfig {
function transform_image_optimizer_request (line 5013) | pub fn transform_image_optimizer_request(
function select_wrapper (line 5099) | fn select_wrapper(hs: &[u32]) -> u32 {
function select_with_timeout_wrapper (line 5114) | fn select_with_timeout_wrapper(hs: &[u32], timeout_ms: u32) -> Option<u3...
FILE: wasm_abi/adapter/src/fastly/error.rs
type FastlyStatus (line 5) | pub struct FastlyStatus(i32);
constant OK (line 12) | pub const OK: Self = FastlyStatus(0);
constant UNKNOWN_ERROR (line 13) | pub const UNKNOWN_ERROR: Self = FastlyStatus(1);
constant INVALID_ARGUMENT (line 14) | pub const INVALID_ARGUMENT: Self = Self(2);
constant BADF (line 15) | pub const BADF: Self = Self(3);
constant BUFFER_LEN (line 16) | pub const BUFFER_LEN: Self = Self(4);
constant UNSUPPORTED (line 17) | pub const UNSUPPORTED: Self = FastlyStatus(5);
constant HTTPINVALID (line 18) | pub const HTTPINVALID: Self = FastlyStatus(7);
constant HTTPUSER (line 19) | pub const HTTPUSER: Self = FastlyStatus(8);
constant HTTPINCOMPLETE (line 20) | pub const HTTPINCOMPLETE: Self = FastlyStatus(9);
constant NONE (line 21) | pub const NONE: Self = FastlyStatus(10);
constant HTTPHEADTOOLARGE (line 22) | pub const HTTPHEADTOOLARGE: Self = FastlyStatus(11);
constant HTTPINVALIDSTATUS (line 23) | pub const HTTPINVALIDSTATUS: Self = FastlyStatus(12);
constant LIMITEXCEEDED (line 24) | pub const LIMITEXCEEDED: Self = FastlyStatus(13);
constant AGAIN (line 25) | pub const AGAIN: Self = FastlyStatus(14);
method from (line 29) | fn from(err: crate::bindings::fastly::compute::types::Error) -> Self {
method from (line 50) | fn from(err: crate::bindings::fastly::compute::types::OpenError) -> Se...
method from (line 69) | fn from(err: crate::bindings::fastly::compute::kv_store::KvError) -> S...
constant SUCCESS (line 8) | const SUCCESS: Self = Self::OK;
function convert_result (line 84) | pub(crate) fn convert_result<T: Into<FastlyStatus>>(res: Result<(), T>) ...
FILE: wasm_abi/adapter/src/fastly/http_cache.rs
type HttpCacheHandle (line 12) | pub type HttpCacheHandle = u32;
type IsCacheable (line 13) | pub type IsCacheable = u32;
type IsSensitive (line 14) | pub type IsSensitive = u32;
constant INVALID_HTTP_CACHE_HANDLE (line 16) | pub const INVALID_HTTP_CACHE_HANDLE: HttpCacheHandle = HttpCacheHandle::...
type HttpStorageAction (line 21) | pub enum HttpStorageAction {
method from (line 161) | fn from(value: host::StorageAction) -> Self {
type HttpCacheLookupOptions (line 30) | pub struct HttpCacheLookupOptions {
type HttpCacheWriteOptions (line 48) | pub struct HttpCacheWriteOptions {
function cache_lookup_options (line 81) | fn cache_lookup_options(
function cache_write_options (line 111) | fn cache_write_options(
function is_request_cacheable (line 172) | pub fn is_request_cacheable(
function get_suggested_cache_key (line 183) | pub fn get_suggested_cache_key(
function lookup (line 202) | pub fn lookup(
function transaction_lookup (line 244) | pub fn transaction_lookup(
function transaction_insert (line 286) | pub fn transaction_insert(
function transaction_insert_and_stream_back (line 308) | pub fn transaction_insert_and_stream_back(
function transaction_update (line 341) | pub fn transaction_update(
function transaction_update_and_return_fresh (line 362) | pub fn transaction_update_and_return_fresh(
function transaction_record_not_cacheable (line 385) | pub fn transaction_record_not_cacheable(
function transaction_choose_stale (line 404) | pub fn transaction_choose_stale(handle: HttpCacheHandle) -> FastlyStatus {
function transaction_abandon (line 410) | pub fn transaction_abandon(handle: HttpCacheHandle) -> FastlyStatus {
function close (line 416) | pub fn close(handle: HttpCacheHandle) -> FastlyStatus {
function get_suggested_backend_request (line 422) | pub fn get_suggested_backend_request(
function get_suggested_cache_options (line 432) | pub fn get_suggested_cache_options(
function prepare_response_for_storage (line 563) | pub fn prepare_response_for_storage(
function get_found_response (line 587) | pub fn get_found_response(
function get_state (line 611) | pub fn get_state(
function get_length (line 629) | pub fn get_length(handle: HttpCacheHandle, length_out: *mut CacheObjectL...
function get_max_age_ns (line 636) | pub fn get_max_age_ns(
function get_stale_while_revalidate_ns (line 646) | pub fn get_stale_while_revalidate_ns(
function get_stale_if_error_ns (line 656) | pub fn get_stale_if_error_ns(
function get_age_ns (line 666) | pub fn get_age_ns(handle: HttpCacheHandle, duration_out: *mut CacheDurat...
function get_hits (line 673) | pub fn get_hits(handle: HttpCacheHandle, hits_out: *mut CacheHitCount) -...
function get_sensitive_data (line 680) | pub fn get_sensitive_data(
function get_surrogate_keys (line 690) | pub fn get_surrogate_keys(
function get_vary_rule (line 706) | pub fn get_vary_rule(
FILE: wasm_abi/adapter/src/fastly/mod.rs
function decode_ip_address (line 16) | pub(crate) unsafe fn decode_ip_address(
function encode_ip_address (line 35) | pub(crate) unsafe fn encode_ip_address(
FILE: wasm_abi/adapter/src/lib.rs
constant OFFSET (line 49) | pub const OFFSET: usize = 2 * PAGE_SIZE;
function maybe_link_cabi_realloc (line 85) | pub fn maybe_link_cabi_realloc() {}
type ComponentAdapter (line 89) | pub struct ComponentAdapter;
method handle (line 93) | fn handle(
type TrappingUnwrap (line 136) | trait TrappingUnwrap<T> {
method trapping_unwrap (line 137) | fn trapping_unwrap(self) -> T;
function trapping_unwrap (line 141) | fn trapping_unwrap(self) -> T {
function trapping_unwrap (line 150) | fn trapping_unwrap(self) -> T {
function adapter_open_badfd (line 165) | pub unsafe extern "C" fn adapter_open_badfd(fd: *mut u32) -> Errno {
function adapter_close_badfd (line 174) | pub unsafe extern "C" fn adapter_close_badfd(fd: u32) -> Errno {
function reset_adapter_state (line 179) | pub unsafe extern "C" fn reset_adapter_state() {
function cabi_import_realloc (line 187) | pub unsafe extern "C" fn cabi_import_realloc(
type ImportAlloc (line 243) | enum ImportAlloc {
method alloc (line 286) | unsafe fn alloc(
type BumpAlloc (line 388) | struct BumpAlloc {
method alloc (line 394) | unsafe fn alloc(&mut self, align: usize, size: usize) -> *mut u8 {
method align_to (line 405) | unsafe fn align_to(&mut self, align: usize) {
function wasi_cli_get_arguments (line 421) | fn wasi_cli_get_arguments(rval: *mut WasmStrList);
function wasi_cli_get_environment (line 423) | fn wasi_cli_get_environment(rval: *mut StrTupleList);
function args_get (line 429) | pub unsafe extern "C" fn args_get(argv: *mut *mut u8, argv_buf: *mut u8)...
function args_sizes_get (line 463) | pub unsafe extern "C" fn args_sizes_get(argc: *mut Size, argv_buf_size: ...
function environ_get (line 496) | pub unsafe extern "C" fn environ_get(environ: *mut *const u8, environ_bu...
function environ_sizes_get (line 531) | pub unsafe extern "C" fn environ_sizes_get(
function clock_res_get (line 579) | pub extern "C" fn clock_res_get(id: Clockid, resolution: &mut Timestamp)...
function clock_time_get (line 606) | pub unsafe extern "C" fn clock_time_get(
function fd_advise (line 635) | pub unsafe extern "C" fn fd_advise(
function fd_allocate (line 647) | pub unsafe extern "C" fn fd_allocate(_fd: Fd, _offset: Filesize, _len: F...
function fd_close (line 654) | pub unsafe extern "C" fn fd_close(fd: Fd) -> Errno {
function fd_datasync (line 668) | pub unsafe extern "C" fn fd_datasync(_fd: Fd) -> Errno {
function fd_fdstat_get (line 675) | pub unsafe extern "C" fn fd_fdstat_get(_fd: Fd, _stat: *mut Fdstat) -> E...
function fd_fdstat_set_flags (line 682) | pub unsafe extern "C" fn fd_fdstat_set_flags(_fd: Fd, _flags: Fdflags) -...
function fd_fdstat_set_rights (line 688) | pub unsafe extern "C" fn fd_fdstat_set_rights(
function fd_filestat_get (line 704) | pub unsafe extern "C" fn fd_filestat_get(_fd: Fd, _buf: *mut Filestat) -...
function fd_filestat_set_size (line 711) | pub unsafe extern "C" fn fd_filestat_set_size(_fd: Fd, _size: Filesize) ...
function fd_filestat_set_times (line 718) | pub unsafe extern "C" fn fd_filestat_set_times(
function fd_pread (line 730) | pub unsafe extern "C" fn fd_pread(
function fd_prestat_get (line 742) | pub unsafe extern "C" fn fd_prestat_get(_fd: Fd, _buf: *mut Prestat) -> ...
function fd_prestat_dir_name (line 748) | pub unsafe extern "C" fn fd_prestat_dir_name(
function fd_pwrite (line 759) | pub unsafe extern "C" fn fd_pwrite(
function fd_read (line 772) | pub unsafe extern "C" fn fd_read(
function stream_error_to_errno (line 825) | fn stream_error_to_errno(_err: streams::Error) -> Errno {
function fd_readdir (line 839) | pub unsafe extern "C" fn fd_readdir(
function fd_renumber (line 858) | pub unsafe extern "C" fn fd_renumber(fd: Fd, to: Fd) -> Errno {
function fd_seek (line 865) | pub unsafe extern "C" fn fd_seek(
function fd_sync (line 877) | pub unsafe extern "C" fn fd_sync(_fd: Fd) -> Errno {
function fd_tell (line 884) | pub unsafe extern "C" fn fd_tell(_fd: Fd, _offset: *mut Filesize) -> Err...
function fd_write (line 891) | pub unsafe extern "C" fn fd_write(
function path_create_directory (line 938) | pub unsafe extern "C" fn path_create_directory(
function path_filestat_get (line 949) | pub unsafe extern "C" fn path_filestat_get(
function path_filestat_set_times (line 962) | pub unsafe extern "C" fn path_filestat_set_times(
function path_link (line 977) | pub unsafe extern "C" fn path_link(
function path_open (line 997) | pub unsafe extern "C" fn path_open(
function path_readlink (line 1014) | pub unsafe extern "C" fn path_readlink(
function path_remove_directory (line 1029) | pub unsafe extern "C" fn path_remove_directory(
function path_rename (line 1040) | pub unsafe extern "C" fn path_rename(
function path_symlink (line 1054) | pub unsafe extern "C" fn path_symlink(
function path_unlink_file (line 1068) | pub unsafe extern "C" fn path_unlink_file(
type Pollables (line 1076) | struct Pollables {
method push (line 1083) | unsafe fn push(&mut self, pollable: Pollable) {
method drop (line 1095) | fn drop(&mut self) {
function poll_oneoff (line 1107) | pub unsafe extern "C" fn poll_oneoff(
function proc_exit (line 1319) | pub unsafe extern "C" fn proc_exit(rval: Exitcode) -> ! {
function proc_raise (line 1328) | pub unsafe extern "C" fn proc_raise(_sig: Signal) -> Errno {
function sched_yield (line 1335) | pub unsafe extern "C" fn sched_yield() -> Errno {
function random_get (line 1348) | pub unsafe extern "C" fn random_get(buf: *mut u8, buf_len: Size) -> Errno {
function sock_accept (line 1374) | pub unsafe extern "C" fn sock_accept(_fd: Fd, _flags: Fdflags, _connecti...
function sock_recv (line 1382) | pub unsafe extern "C" fn sock_recv(
function sock_send (line 1397) | pub unsafe extern "C" fn sock_send(
function sock_shutdown (line 1410) | pub unsafe extern "C" fn sock_shutdown(_fd: Fd, _how: Sdflags) -> Errno {
type BlockingMode (line 1415) | pub enum BlockingMode {
method read (line 1424) | fn read(
method write (line 1434) | fn write(
constant PAGE_SIZE (line 1493) | const PAGE_SIZE: usize = 65536;
constant MAGIC (line 1496) | const MAGIC: u32 = u32::from_le_bytes(*b"ugh!");
type State (line 1499) | pub(crate) struct State {
method with (line 1631) | pub(crate) fn with<E: StateError>(f: impl FnOnce(&State) -> Result<(),...
method ptr (line 1642) | fn ptr() -> &'static State {
method new (line 1654) | fn new() -> *mut State {
method init (line 1697) | unsafe fn init(state: *mut State) {
method descriptors (line 1712) | fn descriptors<'a>(&'a self) -> impl Deref<Target = Descriptors> + 'a {
method descriptors_mut (line 1724) | fn descriptors_mut<'a>(&'a self) -> impl DerefMut + Deref<Target = Des...
method temporary_alloc (line 1735) | unsafe fn temporary_alloc(&self) -> BumpAlloc {
method with_one_import_alloc (line 1746) | fn with_one_import_alloc<T>(&self, base: *mut u8, len: usize, f: impl ...
method with_import_alloc (line 1755) | fn with_import_alloc<T>(&self, alloc: ImportAlloc, f: impl FnOnce() ->...
type WasmStr (line 1550) | pub struct WasmStr {
type WasmStrList (line 1556) | pub struct WasmStrList {
type StrTuple (line 1562) | pub struct StrTuple {
type StrTupleList (line 1569) | pub struct StrTupleList {
type ReadyList (line 1576) | pub struct ReadyList {
function temporary_data_size (line 1581) | const fn temporary_data_size() -> usize {
constant _ (line 1600) | const _: () = {
type AllocationState (line 1606) | enum AllocationState {
function get_state_ptr (line 1616) | fn get_state_ptr() -> *mut State;
function set_state_ptr (line 1617) | fn set_state_ptr(state: *mut State);
function get_allocation_state (line 1618) | fn get_allocation_state() -> AllocationState;
function set_allocation_state (line 1619) | fn set_allocation_state(state: AllocationState);
type StateError (line 1622) | pub(crate) trait StateError {
constant SUCCESS (line 1623) | const SUCCESS: Self;
constant SUCCESS (line 1627) | const SUCCESS: Self = ERRNO_SUCCESS;
FILE: wasm_abi/adapter/src/macros.rs
function print (line 57) | pub(crate) fn print(message: &[u8]) {
function eprint_u32 (line 84) | fn eprint_u32(x: u32) {
function unreachable (line 104) | pub(crate) fn unreachable(line: u32, message: &[u8]) -> ! {
Condensed preview — 304 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (2,152K chars).
[
{
"path": ".github/workflows/changelog.yml",
"chars": 1558,
"preview": "name: Changelog\non:\n pull_request:\n types: [opened, synchronize, reopened, labeled, unlabeled]\n\njobs:\n validate:\n "
},
{
"path": ".github/workflows/release.yml",
"chars": 3871,
"preview": "name: Main\n\non:\n push:\n tags:\n - \"v*.*.*\"\n\njobs:\n build:\n strategy:\n matrix:\n os: [ubuntu-24.04"
},
{
"path": ".github/workflows/rust.yml",
"chars": 391,
"preview": "name: Test Rust versions\n\non:\n schedule:\n - cron: \"2 13 * * 1\"\n workflow_dispatch:\n\njobs:\n test:\n strategy:\n "
},
{
"path": ".github/workflows/test.yml",
"chars": 2194,
"preview": "name: Test\n\non: [pull_request]\n\nenv:\n CACHE_GENERATION: 0\njobs:\n test:\n strategy:\n matrix:\n platform: ["
},
{
"path": ".gitignore",
"chars": 55,
"preview": "**/target/\npublish\nvendor/\nverify-publishable/\n.vscode\n"
},
{
"path": "CHANGELOG.md",
"chars": 31069,
"preview": "## Unreleased\n\n- Rename 'session' to 'sandbox' since that is the preferred term in public documentation. ([#617](https:/"
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 5509,
"preview": "\n# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make particip"
},
{
"path": "CONTRIBUTING.md",
"chars": 3282,
"preview": "# Contributing to Viceroy\n\nFirst off thank you for wanting to contribute to making Viceroy better! We\nappreciate you tak"
},
{
"path": "Cargo.toml",
"chars": 3508,
"preview": "[package]\nname = \"viceroy-lib\"\nversion = \"0.17.1\"\ndescription = \"Viceroy implementation details.\"\nauthors = [\"Fastly\"]\ne"
},
{
"path": "Dockerfile",
"chars": 576,
"preview": "FROM ubuntu:bionic\n\nARG VICEROY_SRC=/Viceroy\n\nENV DEBIAN_FRONTEND=noninteractive\n\nRUN apt-get update \\\n\t&& apt-get insta"
},
{
"path": "LICENSE",
"chars": 12243,
"preview": "\n Apache License\n Version 2.0, January 2004\n "
},
{
"path": "Makefile",
"chars": 4278,
"preview": "# Default to using regular `cargo`. CI targets may override this.\nVICEROY_CARGO=cargo\n\n.PHONY: format\nformat: ## Apply "
},
{
"path": "README.md",
"chars": 5763,
"preview": "# Viceroy\n\nViceroy provides local testing for developers working with Fastly Compute. It\nallows you to run services writ"
},
{
"path": "SECURITY.md",
"chars": 865,
"preview": "## Report a security issue\n\nThe fastly/Viceroy project team welcomes security reports and is committed to providing prom"
},
{
"path": "cli/Cargo.toml",
"chars": 1592,
"preview": "[package]\nname = \"viceroy\"\ndescription = \"Viceroy is a local testing daemon for Fastly Compute.\"\nversion = \"0.17.1\"\nauth"
},
{
"path": "cli/src/execute_ctx.rs",
"chars": 5579,
"preview": "use crate::opts::SharedArgs;\nuse hyper::{Body, Request, client::Client};\nuse std::io::{self, Stderr, Stdout};\nuse std::s"
},
{
"path": "cli/src/main.rs",
"chars": 3219,
"preview": "//! Fastly's local testing daemon for Compute.\n\n// When building the project in release mode:\n// (1): Promote warnings"
},
{
"path": "cli/src/opts.rs",
"chars": 22950,
"preview": "//! Command line arguments.\n\nuse std::time::Duration;\n\nuse viceroy_lib::{GuestProfileConfig, config::UnknownImportBehavi"
},
{
"path": "cli/src/subcommands/adapt.rs",
"chars": 1985,
"preview": "use crate::install_tracing_subscriber;\nuse crate::opts::AdaptArgs;\nuse std::process::ExitCode;\nuse tracing::{Level, even"
},
{
"path": "cli/src/subcommands/run.rs",
"chars": 2572,
"preview": "use crate::execute_ctx::create_execution_context;\nuse crate::install_tracing_subscriber;\nuse crate::opts::RunArgs;\nuse s"
},
{
"path": "cli/src/subcommands/serve.rs",
"chars": 1382,
"preview": "use crate::opts::ServeArgs;\nuse crate::{create_execution_context, install_tracing_subscriber};\nuse std::process::ExitCod"
},
{
"path": "cli/src/subcommands.rs",
"chars": 83,
"preview": "//! Module for `viceroy` CLI commands.\n\npub mod adapt;\npub mod run;\npub mod serve;\n"
},
{
"path": "cli/tests/integration/acl.rs",
"chars": 3487,
"preview": "use crate::{common::Test, common::TestResult, viceroy_test};\nuse hyper::{StatusCode, body::to_bytes};\nuse viceroy_lib::c"
},
{
"path": "cli/tests/integration/args.rs",
"chars": 1446,
"preview": "use crate::common::{Test, TestResult};\nuse hyper::{StatusCode, body::to_bytes};\n\n/// Run a program that tests its args. "
},
{
"path": "cli/tests/integration/async_io.rs",
"chars": 8835,
"preview": "// On Windows, streaming body backpressure doesn't seem to work as expected, either\n// due to the Hyper client or server"
},
{
"path": "cli/tests/integration/body.rs",
"chars": 4451,
"preview": "//! Tests related to HTTP request and response bodies.\n\nuse {\n crate::{\n common::{Test, TestResult},\n v"
},
{
"path": "cli/tests/integration/cache.rs",
"chars": 341,
"preview": "use {\n crate::{\n common::{Test, TestResult},\n viceroy_test,\n },\n hyper::StatusCode,\n};\n\nviceroy_t"
},
{
"path": "cli/tests/integration/client_certs.rs",
"chars": 10315,
"preview": "use crate::{\n common::{Test, TestResult},\n viceroy_test,\n};\nuse base64::engine::{Engine, general_purpose};\nuse hyp"
},
{
"path": "cli/tests/integration/common/backends.rs",
"chars": 11173,
"preview": "use std::collections::HashMap;\nuse std::sync::{Arc, Weak};\n\nuse hyper::http::HeaderValue;\nuse hyper::http::uri::PathAndQ"
},
{
"path": "cli/tests/integration/common.rs",
"chars": 24201,
"preview": "//! Common values and types used by test fixtures\n\nuse futures::stream::StreamExt;\nuse hyper::{Body as HyperBody, Reques"
},
{
"path": "cli/tests/integration/config_store_lookup.rs",
"chars": 2383,
"preview": "use crate::{\n common::{Test, TestResult},\n viceroy_test,\n};\nuse hyper::{StatusCode, body::to_bytes};\n\nviceroy_test"
},
{
"path": "cli/tests/integration/device_detection_lookup.rs",
"chars": 2701,
"preview": "use crate::{\n common::{Test, TestResult},\n viceroy_test,\n};\nuse hyper::{StatusCode, body::to_bytes};\n\nviceroy_test"
},
{
"path": "cli/tests/integration/dictionary_lookup.rs",
"chars": 2472,
"preview": "use crate::{\n common::{Test, TestResult},\n viceroy_test,\n};\nuse hyper::{StatusCode, body::to_bytes};\n\nviceroy_test"
},
{
"path": "cli/tests/integration/downstream_req.rs",
"chars": 525,
"preview": "use {\n crate::{\n common::{Test, TestResult},\n viceroy_test,\n },\n hyper::{Request, StatusCode},\n};"
},
{
"path": "cli/tests/integration/early_hints.rs",
"chars": 388,
"preview": "// A test to ensure that early hints (103 responses) don't cause errors in Viceroy.\n\nuse crate::{\n common::{Test, Tes"
},
{
"path": "cli/tests/integration/edge_rate_limiting.rs",
"chars": 432,
"preview": "//! Tests related to HTTP request and response bodies.\n\nuse {\n crate::{\n common::{Test, TestResult},\n v"
},
{
"path": "cli/tests/integration/env_vars.rs",
"chars": 305,
"preview": "use crate::{\n common::{Test, TestResult},\n viceroy_test,\n};\n\nviceroy_test!(env_vars_are_set, |is_component| {\n "
},
{
"path": "cli/tests/integration/fastly_key_is_valid.rs",
"chars": 3079,
"preview": "use {\n crate::{\n common::{Test, TestResult},\n viceroy_test,\n },\n hyper::{Request, StatusCode},\n};"
},
{
"path": "cli/tests/integration/geolocation_lookup.rs",
"chars": 3805,
"preview": "use crate::{\n common::{Test, TestResult},\n viceroy_test,\n};\nuse hyper::{StatusCode, body::to_bytes};\n\nviceroy_test"
},
{
"path": "cli/tests/integration/grpc.rs",
"chars": 1628,
"preview": "use crate::{\n common::{Test, TestResult},\n viceroy_test,\n};\nuse hyper::http::response;\nuse hyper::server::conn::Ad"
},
{
"path": "cli/tests/integration/http_semantics.rs",
"chars": 2980,
"preview": "//! Tests related to HTTP semantics (e.g. framing headers, status codes).\n\nuse {\n crate::{\n common::{Test, Tes"
},
{
"path": "cli/tests/integration/inspect.rs",
"chars": 665,
"preview": "use {\n crate::{\n common::{Test, TestResult},\n viceroy_test,\n },\n hyper::{Request, StatusCode},\n};"
},
{
"path": "cli/tests/integration/invalid_status_code.rs",
"chars": 474,
"preview": "// A test to ensure that invalid status codes (1xx other than 103 Early Hunts) return errors in Viceroy.\n\nuse crate::{\n "
},
{
"path": "cli/tests/integration/kv_store.rs",
"chars": 27045,
"preview": "use crate::{\n common::{Test, TestResult},\n viceroy_test,\n};\nuse hyper::{StatusCode, body::to_bytes};\n\nviceroy_test"
},
{
"path": "cli/tests/integration/logging.rs",
"chars": 2130,
"preview": "use {\n crate::{\n common::{Test, TestResult},\n viceroy_test,\n },\n hyper::StatusCode,\n std::{\n "
},
{
"path": "cli/tests/integration/main.rs",
"chars": 648,
"preview": "mod acl;\nmod args;\nmod async_io;\nmod body;\nmod cache;\nmod client_certs;\nmod common;\nmod config_store_lookup;\nmod device_"
},
{
"path": "cli/tests/integration/memory.rs",
"chars": 1658,
"preview": "use crate::{\n common::{Test, TestResult},\n viceroy_test,\n};\nuse hyper::body::to_bytes;\nuse hyper::{Request, Status"
},
{
"path": "cli/tests/integration/profiling.rs",
"chars": 1650,
"preview": "//! Tests for guest profiling functionality.\n\nuse {\n crate::{\n common::{Test, TestResult},\n viceroy_tes"
},
{
"path": "cli/tests/integration/request.rs",
"chars": 351,
"preview": "use {\n crate::{\n common::{Test, TestResult},\n viceroy_test,\n },\n hyper::StatusCode,\n};\n\nviceroy_t"
},
{
"path": "cli/tests/integration/response.rs",
"chars": 353,
"preview": "use {\n crate::{\n common::{Test, TestResult},\n viceroy_test,\n },\n hyper::StatusCode,\n};\n\nviceroy_t"
},
{
"path": "cli/tests/integration/reusable_sandboxes.rs",
"chars": 1896,
"preview": "//! Tests related to HTTP request and response bodies.\n\nuse crate::common::{Test, TestResult};\nuse crate::viceroy_test;\n"
},
{
"path": "cli/tests/integration/secret_store.rs",
"chars": 11146,
"preview": "use crate::{\n common::{Test, TestResult},\n viceroy_test,\n};\nuse hyper::{StatusCode, body::to_bytes};\nuse viceroy_l"
},
{
"path": "cli/tests/integration/sending_response.rs",
"chars": 3089,
"preview": "//! Tests related to sending HTTP responses downstream.\n\nuse {\n crate::{\n common::{Test, TestResult},\n "
},
{
"path": "cli/tests/integration/shielding.rs",
"chars": 4281,
"preview": "use crate::common::{Test, TestResult};\nuse crate::viceroy_test;\nuse hyper::service::{make_service_fn, service_fn};\nuse h"
},
{
"path": "cli/tests/integration/sleep.rs",
"chars": 760,
"preview": "use crate::{\n common::{Test, TestResult},\n viceroy_test,\n};\nuse hyper::{StatusCode, body::to_bytes};\n\n// Run a pro"
},
{
"path": "cli/tests/integration/unknown_import_behavior.rs",
"chars": 2444,
"preview": "use hyper::{Request, Response, StatusCode};\nuse viceroy_lib::config::UnknownImportBehavior;\n\nuse crate::common::{Test, T"
},
{
"path": "cli/tests/integration/upstream.rs",
"chars": 5683,
"preview": "use {\n crate::{\n common::{Test, TestResult},\n viceroy_test,\n },\n hyper::{\n Request, Respon"
},
{
"path": "cli/tests/integration/upstream_async.rs",
"chars": 1982,
"preview": "use std::sync::Arc;\n\nuse tokio::sync::Semaphore;\n\nuse {\n crate::{\n common::{Test, TestResult},\n viceroy"
},
{
"path": "cli/tests/integration/upstream_dynamic.rs",
"chars": 4604,
"preview": "use {\n crate::{\n common::{Test, TestResult},\n viceroy_test,\n },\n hyper::{\n Request, Respon"
},
{
"path": "cli/tests/integration/upstream_streaming.rs",
"chars": 1122,
"preview": "use {\n crate::{\n common::{Test, TestResult},\n viceroy_test,\n },\n hyper::{Response, StatusCode, bo"
},
{
"path": "cli/tests/integration/vcpu_time.rs",
"chars": 762,
"preview": "use crate::{\n common::{Test, TestResult},\n viceroy_test,\n};\nuse hyper::{Request, Response, StatusCode};\n\nviceroy_t"
},
{
"path": "cli/tests/trap-test/Cargo.toml",
"chars": 704,
"preview": "[package]\nname = \"trap-test\"\ndescription = \"A test to exercise the Viceroy functionality in which a hostcall experiences"
},
{
"path": "cli/tests/trap-test/src/main.rs",
"chars": 1968,
"preview": "use std::collections::HashSet;\nuse {\n hyper::{Body, Request, StatusCode},\n viceroy_lib::{ExecuteCtx, ProfilingStra"
},
{
"path": "cli/tests/wasm/exit_code_4.wat",
"chars": 226,
"preview": "(module\n (import \"wasi_snapshot_preview1\" \"proc_exit\"\n (func $proc_exit (param i32)))\n (export \"_start\" (func $_start"
},
{
"path": "cli/tests/wasm/invalid.wat",
"chars": 29,
"preview": "This is not a valid wat file\n"
},
{
"path": "cli/tests/wasm/minimal.wat",
"chars": 9,
"preview": "(module)\n"
},
{
"path": "cli/tests/wasm/trapping.wat",
"chars": 80,
"preview": "(module\n (export \"_start\" (func $_start))\n (func $_start\n unreachable\n )\n)"
},
{
"path": "doc/RELEASING.md",
"chars": 1649,
"preview": "# Releasing Viceroy\n\nBelow are the steps needed to do a Viceroy release:\n\n1. Make sure the Viceroy version has been bump"
},
{
"path": "proptest-regressions/body.txt",
"chars": 749,
"preview": "# Seeds for failure cases proptest has generated in the past. It is\n# automatically read and these particular cases re-r"
},
{
"path": "proptest-regressions/cache.txt",
"chars": 468,
"preview": "# Seeds for failure cases proptest has generated in the past. It is\n# automatically read and these particular cases re-r"
},
{
"path": "proptest-regressions/collecting_body.txt",
"chars": 405,
"preview": "# Seeds for failure cases proptest has generated in the past. It is\n# automatically read and these particular cases re-r"
},
{
"path": "rust-toolchain.toml",
"chars": 139,
"preview": "[toolchain]\nchannel = \"1.95\"\ncomponents = [ \"rustfmt\", \"clippy\" ]\ntargets = [ \"wasm32-wasip1\", \"wasm32-wasip2\", \"wasm32-"
},
{
"path": "rustfmt.toml",
"chars": 48,
"preview": "# Viceroy uses the default formatting settings.\n"
},
{
"path": "src/acl.rs",
"chars": 12164,
"preview": "use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error};\nuse std::collections::HashMap;\nuse std::fmt::D"
},
{
"path": "src/adapt.rs",
"chars": 7396,
"preview": "use anyhow::Context;\n\n/// The full adapter.\nconst ADAPTER_BYTES: &[u8] = include_bytes!(\"../wasm_abi/data/viceroy-compon"
},
{
"path": "src/async_io.rs",
"chars": 1989,
"preview": "use {\n crate::{\n error::Error,\n sandbox::Sandbox,\n wiggle_abi::{fastly_async_io::FastlyAsyncIo, "
},
{
"path": "src/body.rs",
"chars": 20042,
"preview": "//! Body type, for request and response bodies.\n\nuse futures::FutureExt;\n\nuse {\n crate::{Error, error, streaming_body"
},
{
"path": "src/body_tee.rs",
"chars": 10306,
"preview": "use futures::stream::{Stream, StreamExt};\nuse hyper::body::{Body, Bytes, HttpBody};\nuse std::collections::VecDeque;\nuse "
},
{
"path": "src/cache/store.rs",
"chars": 34613,
"preview": "//! Data structures & implementation details for the Viceroy cache.\n\nuse crate::cache::{Error, variance::VaryRule};\nuse "
},
{
"path": "src/cache/variance.rs",
"chars": 3794,
"preview": "//! Support for request- and response-keyed variance, per HTTP's vary rules\n//!\n//! HTTP caching as described in RFC 911"
},
{
"path": "src/cache.rs",
"chars": 28390,
"preview": "use core::str;\nuse std::{collections::HashSet, sync::Arc, time::Duration};\n\nuse bytes::Bytes;\n#[cfg(test)]\nuse proptest_"
},
{
"path": "src/collecting_body.rs",
"chars": 27084,
"preview": "//! Provides `CollectingBody`, a body that can be concurrently written-to (via a `StreamingBody`\n//! handle) and read-fr"
},
{
"path": "src/component/adapter/http_req.rs",
"chars": 1958,
"preview": "use {\n crate::component::bindings::{\n fastly::adapter::adapter_http_req,\n fastly::compute::http_downstr"
},
{
"path": "src/component/adapter.rs",
"chars": 72,
"preview": "//! Implementations for `fastly:adapter` interfaces.\n\npub mod http_req;\n"
},
{
"path": "src/component/backend.rs",
"chars": 10464,
"preview": "use {\n crate::component::bindings::fastly::compute::{backend, http_types, types},\n crate::config::{Backend, Client"
},
{
"path": "src/component/compute/acl.rs",
"chars": 1291,
"preview": "use crate::component::bindings::fastly::compute::{acl, http_body, types};\nuse crate::linking::{ComponentCtx, SandboxView"
},
{
"path": "src/component/compute/async_io.rs",
"chars": 2237,
"preview": "use {\n crate::component::bindings::fastly::compute::async_io,\n crate::{\n linking::{ComponentCtx, SandboxVie"
},
{
"path": "src/component/compute/backend.rs",
"chars": 13084,
"preview": "use std::num::NonZeroUsize;\nuse std::time::Duration;\n\nuse {\n crate::component::bindings::fastly::compute::{backend, h"
},
{
"path": "src/component/compute/cache.rs",
"chars": 20349,
"preview": "use {\n crate::component::bindings::fastly::compute::{cache as api, http_body, types},\n crate::{\n body::Body"
},
{
"path": "src/component/compute/compute_runtime.rs",
"chars": 1213,
"preview": "use crate::component::bindings::fastly::compute::compute_runtime;\nuse crate::linking::ComponentCtx;\nuse std::sync::atomi"
},
{
"path": "src/component/compute/config_store.rs",
"chars": 1329,
"preview": "use {\n crate::component::bindings::fastly::compute::{config_store, types},\n crate::linking::{ComponentCtx, Sandbox"
},
{
"path": "src/component/compute/device_detection.rs",
"chars": 635,
"preview": "use {\n crate::component::bindings::fastly::compute::{device_detection, types},\n crate::linking::ComponentCtx,\n};\n\n"
},
{
"path": "src/component/compute/dictionary.rs",
"chars": 1161,
"preview": "use {\n crate::component::bindings::fastly::compute::{dictionary, types},\n crate::linking::{ComponentCtx, SandboxVi"
},
{
"path": "src/component/compute/erl.rs",
"chars": 3060,
"preview": "use {\n crate::component::bindings::fastly::compute::{erl, types},\n crate::linking::ComponentCtx,\n};\n\nuse wasmtime:"
},
{
"path": "src/component/compute/error.rs",
"chars": 10556,
"preview": "use {\n crate::component::bindings::fastly::compute::{http_req, kv_store::KvError, types},\n crate::{\n config"
},
{
"path": "src/component/compute/geo.rs",
"chars": 707,
"preview": "use {\n crate::component::bindings::fastly::compute::{geo, types},\n crate::{error, linking::ComponentCtx},\n std:"
},
{
"path": "src/component/compute/headers.rs",
"chars": 4086,
"preview": "use crate::component::bindings::fastly::compute::types;\nuse crate::error::Error;\nuse http::{HeaderMap, HeaderName};\nuse "
},
{
"path": "src/component/compute/http_body.rs",
"chars": 7782,
"preview": "use {\n crate::component::{\n bindings::fastly::compute::{http_body, types},\n compute::headers,\n },\n "
},
{
"path": "src/component/compute/http_cache.rs",
"chars": 10603,
"preview": "use {\n crate::component::bindings::fastly::compute::{http_body, http_cache, types},\n crate::{error::Error, linking"
},
{
"path": "src/component/compute/http_downstream.rs",
"chars": 10997,
"preview": "use std::time::Duration;\n\nuse crate::component::bindings::fastly::compute::{http_body, http_downstream, http_req, types}"
},
{
"path": "src/component/compute/http_req.rs",
"chars": 15338,
"preview": "use {\n crate::{\n component::{\n bindings::fastly::compute::{http_body, http_req, http_resp, http_typ"
},
{
"path": "src/component/compute/http_resp.rs",
"chars": 11469,
"preview": "use {\n crate::{\n component::{\n bindings::fastly::compute::{http_body, http_resp, http_types, types}"
},
{
"path": "src/component/compute/http_types.rs",
"chars": 1518,
"preview": "use {\n crate::component::bindings::fastly::compute::{http_types, types},\n crate::linking::ComponentCtx,\n};\n\nimpl h"
},
{
"path": "src/component/compute/image_optimizer.rs",
"chars": 1257,
"preview": "use crate::component::bindings::fastly::compute::{\n http_body, http_req, http_resp, image_optimizer, types,\n};\nuse cr"
},
{
"path": "src/component/compute/kv_store.rs",
"chars": 10225,
"preview": "use {\n crate::component::bindings::fastly::compute::{\n http_body,\n kv_store::{self, InsertMode},\n "
},
{
"path": "src/component/compute/log.rs",
"chars": 1539,
"preview": "use {\n crate::component::bindings::fastly::compute::{log, types},\n crate::linking::{ComponentCtx, SandboxView},\n "
},
{
"path": "src/component/compute/purge.rs",
"chars": 1111,
"preview": "use {\n crate::Error,\n crate::component::bindings::fastly::compute::{purge, types},\n crate::linking::ComponentCt"
},
{
"path": "src/component/compute/secret_store.rs",
"chars": 2980,
"preview": "use {\n crate::component::bindings::fastly::compute::{secret_store, types},\n crate::{\n error::Error,\n "
},
{
"path": "src/component/compute/security.rs",
"chars": 1738,
"preview": "use {\n crate::component::bindings::fastly::compute::{http_body, http_req, security, types},\n crate::{error::Error,"
},
{
"path": "src/component/compute/shielding.rs",
"chars": 2745,
"preview": "use crate::component::bindings::fastly::compute::{shielding, types};\nuse crate::error::Error;\nuse crate::linking::Compon"
},
{
"path": "src/component/compute/types.rs",
"chars": 731,
"preview": "use {crate::component::bindings::fastly::compute::types, crate::linking::ComponentCtx};\n\nimpl types::Host for ComponentC"
},
{
"path": "src/component/compute.rs",
"chars": 531,
"preview": "//! Implementations for `fastly:compute` interfaces.\n\npub mod acl;\npub mod async_io;\npub mod backend;\npub mod cache;\npub"
},
{
"path": "src/component/erl.rs",
"chars": 1138,
"preview": "use {crate::component::bindings::fastly::compute::types, crate::sandbox::Sandbox};\n\n#[allow(clippy::too_many_arguments)]"
},
{
"path": "src/component/handles.rs",
"chars": 3120,
"preview": "use crate::wiggle_abi::types::*;\n\n/// Macro which provides the common implementation of a resource type.\nmacro_rules! re"
},
{
"path": "src/component/http_req.rs",
"chars": 5755,
"preview": "use {\n crate::component::bindings::fastly::compute::{http_body, http_req, http_resp, types},\n crate::handoff::{Han"
},
{
"path": "src/component/image_optimizer.rs",
"chars": 589,
"preview": "use crate::component::bindings::fastly::compute::{\n http_body, http_req, http_resp, image_optimizer, types,\n};\nuse cr"
},
{
"path": "src/component/shielding.rs",
"chars": 1295,
"preview": "use crate::component::bindings::fastly::compute::{shielding, types};\nuse crate::config::Backend;\nuse crate::error::Error"
},
{
"path": "src/component/wasi.rs",
"chars": 13138,
"preview": "//! Trivial wrappers around wasmtime-wasi implementations.\n//!\n//! This exists because Wasmtime's bindgen system doesn't"
},
{
"path": "src/component.rs",
"chars": 8528,
"preview": "use {\n crate::linking::ComponentCtx,\n wasmtime::component::{self, HasSelf},\n};\n\npub(crate) mod bindings {\n wasm"
},
{
"path": "src/config/acl.rs",
"chars": 2485,
"preview": "use crate::acl;\n\n#[derive(Clone, Debug, Default)]\npub struct AclConfig(pub(crate) acl::Acls);\n\nmod deserialization {\n "
},
{
"path": "src/config/backends/client_cert_info.rs",
"chars": 10478,
"preview": "use rustls::{Certificate, PrivateKey};\nuse std::fmt;\nuse std::io::{BufReader, Cursor};\n\n#[derive(Clone, PartialEq)]\npub "
},
{
"path": "src/config/backends.rs",
"chars": 9889,
"preview": "mod client_cert_info;\n\nuse {\n hyper::{Uri, header::HeaderValue},\n std::{collections::HashMap, sync::Arc},\n};\n\npub "
},
{
"path": "src/config/device_detection.rs",
"chars": 8455,
"preview": "use {\n crate::error::DeviceDetectionConfigError,\n serde_json::{Map, Value as SerdeValue},\n std::{collections::H"
},
{
"path": "src/config/dictionaries.rs",
"chars": 8750,
"preview": "use {\n crate::error::DictionaryConfigError,\n std::{\n collections::HashMap,\n fs,\n path::{Path,"
},
{
"path": "src/config/geolocation.rs",
"chars": 10316,
"preview": "use {\n crate::error::GeolocationConfigError,\n serde_json::{\n Map, Number, Value as SerdeValue, Value::Numbe"
},
{
"path": "src/config/limits.rs",
"chars": 194,
"preview": "// From https://docs.fastly.com/en/guides/resource-limits#vcl-and-configuration-limits\npub const DICTIONARY_ITEM_KEY_MAX"
},
{
"path": "src/config/object_store.rs",
"chars": 12245,
"preview": "use std::collections::HashMap;\nuse std::path::{Path, PathBuf};\nuse toml::Value;\nuse {\n crate::{\n error::{Fastl"
},
{
"path": "src/config/secret_store.rs",
"chars": 8756,
"preview": "use {\n crate::{\n error::{FastlyConfigError, SecretStoreConfigError},\n secret_store::{SecretStore, Secre"
},
{
"path": "src/config/unit_tests.rs",
"chars": 47275,
"preview": "use {\n super::{FastlyConfig, LocalServerConfig, RawLocalServerConfig},\n crate::error::FastlyConfigError,\n std::"
},
{
"path": "src/config.rs",
"chars": 11037,
"preview": "//! Fastly-specific configuration utilities.\n\nuse {\n self::{\n acl::AclConfig, backends::BackendsConfig, dictio"
},
{
"path": "src/downstream.rs",
"chars": 2716,
"preview": "//! Operations related to handling the \"downstream\" (end-client) request\nuse std::net::SocketAddr;\n\nuse crate::body::Bod"
},
{
"path": "src/error.rs",
"chars": 29970,
"preview": "//! Error types.\n\nuse crate::{handoff::HandoffInfo, wiggle_abi::types::FastlyStatus};\nuse std::error::Error as StdError;"
},
{
"path": "src/execute.rs",
"chars": 46527,
"preview": "//! Guest code execution.\n\nuse {\n crate::{\n Error,\n acl::Acls,\n adapt,\n body::Body,\n "
},
{
"path": "src/framing.rs",
"chars": 819,
"preview": "//! Utilities for validating \"framing headers\" (Content-Length and Transfer-Encoding) for HTTP messages.\n\nuse http::{Hea"
},
{
"path": "src/handoff.rs",
"chars": 15912,
"preview": "use {\n crate::{config::ClientCertInfo, upstream::TlsConfig},\n http::{\n HeaderMap, HeaderName, HeaderValue, "
},
{
"path": "src/headers.rs",
"chars": 345,
"preview": "use hyper::{HeaderMap, header};\n\npub fn filter_outgoing_headers(headers: &mut HeaderMap) {\n // Remove framing-related"
},
{
"path": "src/lib.rs",
"chars": 1370,
"preview": "//! Viceroy implementation details.\n\n// When building the project in release mode:\n// (1): Promote warnings into error"
},
{
"path": "src/linking.rs",
"chars": 16721,
"preview": "//! Linking and name resolution.\n\nuse {\n crate::{\n Error, body::Body, config::ExperimentalModule, execute::Exe"
},
{
"path": "src/logging.rs",
"chars": 3818,
"preview": "use std::{\n io::{self, Write},\n pin::Pin,\n sync::{Arc, Mutex},\n task::{Context, Poll},\n};\nuse tokio::io::Asy"
},
{
"path": "src/object_store.rs",
"chars": 30276,
"preview": "use {\n crate::wiggle_abi::types::{FastlyStatus, KvError, KvInsertMode},\n base64::prelude::*,\n serde::Serialize,"
},
{
"path": "src/sandbox/async_item.rs",
"chars": 13085,
"preview": "use std::time::{Duration, Instant};\n\nuse crate::cache::CacheEntry;\nuse crate::downstream::DownstreamRequest;\nuse crate::"
},
{
"path": "src/sandbox/downstream.rs",
"chars": 7293,
"preview": "//! Downstream response.\n\nuse {\n crate::{\n body::Body,\n downstream::DownstreamResponse,\n error::"
},
{
"path": "src/sandbox.rs",
"chars": 59317,
"preview": "//! Sandbox type and related facilities.\n\nmod async_item;\nmod downstream;\n\npub use async_item::{\n AsyncItem, Peekable"
},
{
"path": "src/secret_store.rs",
"chars": 1283,
"preview": "use {bytes::Bytes, std::collections::HashMap};\n\n#[derive(Clone, Debug, Default)]\npub struct SecretStores {\n stores: H"
},
{
"path": "src/service.rs",
"chars": 5476,
"preview": "//! Service types.\n\nuse {\n crate::{Error, body::Body, execute::ExecuteCtx},\n futures::future::{self, Ready},\n h"
},
{
"path": "src/shielding_site.rs",
"chars": 6055,
"preview": "use crate::error::{FastlyConfigError, ShieldingSiteConfigError};\nuse std::collections::HashMap;\nuse toml::Value;\nuse url"
},
{
"path": "src/shift_mem.rs",
"chars": 8910,
"preview": "/// This module takes the user wasm module (main module) and pushes the memory address\n/// by 2 pages. Concretely, we pe"
},
{
"path": "src/streaming_body.rs",
"chars": 4431,
"preview": "//! Provides `StreamingBody`, an asynchronously-written body.\n//! See `Body` for a body that is asynchronously read.\n\nus"
},
{
"path": "src/upstream.rs",
"chars": 17563,
"preview": "use crate::{\n body::{Body, Chunk},\n cache::CacheOverride,\n config::Backend,\n error::Error,\n framing::{con"
},
{
"path": "src/wiggle_abi/acl.rs",
"chars": 2550,
"preview": "use crate::error::{Error, HandleError};\nuse crate::sandbox::Sandbox;\nuse crate::wiggle_abi::{fastly_acl, types};\nuse std"
},
{
"path": "src/wiggle_abi/backend_impl.rs",
"chars": 8258,
"preview": "use super::fastly_backend::FastlyBackend;\nuse crate::{config::Backend, error::Error, sandbox::Sandbox};\n\nfn lookup_backe"
},
{
"path": "src/wiggle_abi/body_impl.rs",
"chars": 7691,
"preview": "//! fastly_body` hostcall implementations.\n\nuse http::{HeaderName, HeaderValue};\n\nuse crate::wiggle_abi::headers::HttpHe"
},
{
"path": "src/wiggle_abi/cache.rs",
"chars": 24058,
"preview": "use core::str;\nuse std::sync::Arc;\nuse std::time::Duration;\n\nuse bytes::Bytes;\nuse http::HeaderMap;\n\nuse crate::body::Bo"
},
{
"path": "src/wiggle_abi/compute_runtime.rs",
"chars": 709,
"preview": "use crate::error::Error;\nuse crate::sandbox::Sandbox;\nuse crate::wiggle_abi::fastly_compute_runtime::FastlyComputeRuntim"
},
{
"path": "src/wiggle_abi/config_store.rs",
"chars": 1007,
"preview": "use super::{\n fastly_config_store::FastlyConfigStore,\n fastly_dictionary::FastlyDictionary,\n types::{ConfigStor"
},
{
"path": "src/wiggle_abi/device_detection_impl.rs",
"chars": 2055,
"preview": "//! fastly_device_detection` hostcall implementations.\n\nuse crate::error::Error;\nuse crate::wiggle_abi::{FastlyStatus, S"
},
{
"path": "src/wiggle_abi/dictionary_impl.rs",
"chars": 2715,
"preview": "//! fastly_dictionary` hostcall implementations.\n\nuse {\n crate::{\n error::Error,\n sandbox::Sandbox,\n "
},
{
"path": "src/wiggle_abi/entity.rs",
"chars": 2458,
"preview": "//! [`cranelift_entity::EntityRef`][ref] implementations for ABI types.\n//!\n//! [ref]: https://docs.rs/cranelift-entity/"
},
{
"path": "src/wiggle_abi/erl_impl.rs",
"chars": 1610,
"preview": "use crate::{\n error::Error,\n sandbox::Sandbox,\n wiggle_abi::fastly_erl::FastlyErl,\n wiggle_abi::{GuestMemory"
},
{
"path": "src/wiggle_abi/fastly_purge_impl.rs",
"chars": 1065,
"preview": "//! fastly_purge` hostcall implementations.\n\nuse {\n super::types::{PurgeOptions, PurgeOptionsMask},\n crate::{error"
},
{
"path": "src/wiggle_abi/geo_impl.rs",
"chars": 1625,
"preview": "//! fastly_geo` hostcall implementations.\n\nuse std::{\n convert::TryInto,\n net::{IpAddr, Ipv4Addr, Ipv6Addr},\n};\n\nu"
},
{
"path": "src/wiggle_abi/headers.rs",
"chars": 6772,
"preview": "use {\n crate::{error::Error, wiggle_abi::MultiValueWriter, wiggle_abi::types},\n http::{HeaderMap, HeaderValue, hea"
},
{
"path": "src/wiggle_abi/http_cache.rs",
"chars": 8407,
"preview": "use crate::sandbox::Sandbox;\n\nuse super::fastly_http_cache::FastlyHttpCache;\nuse super::{Error, types};\n\nuse wiggle::{Gu"
},
{
"path": "src/wiggle_abi/http_downstream.rs",
"chars": 14760,
"preview": "use std::net::IpAddr;\nuse std::time::Duration;\n\nuse crate::error::Error;\nuse crate::sandbox::{AsyncItemHandle, Sandbox};"
},
{
"path": "src/wiggle_abi/image_optimizer.rs",
"chars": 888,
"preview": "use crate::error::Error;\nuse crate::sandbox::Sandbox;\nuse crate::wiggle_abi::{fastly_image_optimizer, types};\nuse wiggle"
},
{
"path": "src/wiggle_abi/kv_store_impl.rs",
"chars": 13284,
"preview": "//! fastly_obj_store` hostcall implementations.\n\nuse crate::object_store::KvStoreError;\nuse crate::sandbox::PeekableTask"
},
{
"path": "src/wiggle_abi/log_impl.rs",
"chars": 1722,
"preview": "//! fastly_log` hostcall implementations.\n\nuse {\n crate::{\n error::Error,\n sandbox::Sandbox,\n wi"
},
{
"path": "src/wiggle_abi/obj_store_impl.rs",
"chars": 6406,
"preview": "//! fastly_obj_store` hostcall implementations.\n\nuse super::types::{PendingKvDeleteHandle, PendingKvInsertHandle, Pendin"
},
{
"path": "src/wiggle_abi/req_impl.rs",
"chars": 39930,
"preview": "//! fastly_req` hostcall implementations.\nuse std::net::IpAddr;\n\nuse super::SecretStoreError;\nuse super::types::SendErro"
},
{
"path": "src/wiggle_abi/resp_impl.rs",
"chars": 10159,
"preview": "//! fastly_resp` hostcall implementations.\n\nuse {\n crate::{\n error::Error,\n sandbox::{Sandbox, ViceroyR"
},
{
"path": "src/wiggle_abi/secret_store_impl.rs",
"chars": 4605,
"preview": "use {\n crate::{\n error::Error,\n sandbox::Sandbox,\n secret_store::SecretLookup,\n wiggle_ab"
},
{
"path": "src/wiggle_abi/shielding.rs",
"chars": 3950,
"preview": "use crate::config::Backend;\nuse crate::error::Error;\nuse crate::sandbox::Sandbox;\nuse crate::wiggle_abi::{fastly_shieldi"
},
{
"path": "src/wiggle_abi/uap_impl.rs",
"chars": 797,
"preview": "//! fastly_uap` hostcall implementations.\n\nuse {\n crate::{error::Error, sandbox::Sandbox, wiggle_abi::fastly_uap::Fas"
},
{
"path": "src/wiggle_abi.rs",
"chars": 14322,
"preview": "// a few things to ignore from the `from_witx!` macro-generated code:\n#![allow(clippy::too_many_arguments)]\n#![allow(cli"
},
{
"path": "test-fixtures/Cargo.toml",
"chars": 518,
"preview": "[package]\nname = \"test-fixtures\"\nversion = \"0.1.0\"\ndescription = \"Guest wasm programs intended for integration testing.\""
},
{
"path": "test-fixtures/combined_heap_limits.wat",
"chars": 21648,
"preview": "(module\n\n (import \"fastly_http_req\" \"body_downstream_get\"\n (func $request_get\n (param i32) (param i32)\n (r"
},
{
"path": "test-fixtures/data/ca.key",
"chars": 1743,
"preview": "-----BEGIN RSA PRIVATE KEY-----\nProc-Type: 4,ENCRYPTED\nDEK-Info: DES-EDE3-CBC,6403E194E2FD15C4\n\nJXGAIQ6/3eVUy7R7PulfsnuN"
},
{
"path": "test-fixtures/data/ca.pem",
"chars": 1330,
"preview": "-----BEGIN CERTIFICATE-----\nMIIDqTCCApGgAwIBAgIUDXDr/2fouphqlB8iJASenWOr/XwwDQYJKoZIhvcNAQEL\nBQAwZDELMAkGA1UEBhMCVVMxDzA"
},
{
"path": "test-fixtures/data/ca.srl",
"chars": 41,
"preview": "3A9F7B82F32561D05823FDF2AE90DE1DB771E518\n"
},
{
"path": "test-fixtures/data/client.crt",
"chars": 1359,
"preview": "-----BEGIN CERTIFICATE-----\nMIIDvjCCAqagAwIBAgIUOp97gvMlYdBYI/3yrpDeHbdx5RgwDQYJKoZIhvcNAQEL\nBQAwZDELMAkGA1UEBhMCVVMxDzA"
},
{
"path": "test-fixtures/data/client.csr",
"chars": 1021,
"preview": "-----BEGIN CERTIFICATE REQUEST-----\nMIICujCCAaICAQAwdTELMAkGA1UEBhMCVVMxDzANBgNVBAgMBk9yZWdvbjERMA8G\nA1UEBwwIUG9ydGxhbmQ"
},
{
"path": "test-fixtures/data/client.key",
"chars": 1679,
"preview": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAKCAQEAz27x1GpD46K6b9/3PNyZYKgTL9GBbpLAVF8Uebd34ftUfnWZ\n3ER+x6A1YbacHnL112diPPe"
},
{
"path": "test-fixtures/data/device-detection-mapping.json",
"chars": 1030,
"preview": "{\n \"Mozilla/5.0 (X11; Linux x86_64; rv:10.0) Gecko/20100101 Firefox/10.0 [FBAN/FBIOS;FBAV/8.0.0.28.18;FBBV/1665515;FB"
},
{
"path": "test-fixtures/data/geolocation-mapping.json",
"chars": 1156,
"preview": "{\n \"127.0.0.1\": {\n \"as_name\": \"Fastly Test\",\n \"as_number\": 12345,\n \"area_code\": 123,\n \"ci"
},
{
"path": "test-fixtures/data/json-config_store.json",
"chars": 41,
"preview": "{\n \"cat\": \"meow\",\n \"dog\": \"woof\"\n}\n"
},
{
"path": "test-fixtures/data/json-dictionary.json",
"chars": 41,
"preview": "{\n \"cat\": \"meow\",\n \"dog\": \"woof\"\n}\n"
},
{
"path": "test-fixtures/data/json-kv_store-invalid_1.json",
"chars": 25,
"preview": "{\n \"first\": {\n }\n}\n"
},
{
"path": "test-fixtures/data/json-kv_store-invalid_2.json",
"chars": 147,
"preview": "{\n \"first\": {\n \"data\": \"this is invalid because it has both data and file\",\n \"file\": \"../test-fixtures/"
},
{
"path": "test-fixtures/data/json-kv_store.json",
"chars": 196,
"preview": "{\n \"first\": \"This is some data\",\n \"second\": {\n \"file\": \"../test-fixtures/data/kv-store.txt\"\n },\n \"thi"
},
{
"path": "test-fixtures/data/json-secret_store.json",
"chars": 64,
"preview": "{\n \"first\": \"first secret\",\n \"second\": \"another secret\"\n}\n"
},
{
"path": "test-fixtures/data/kv-store.txt",
"chars": 9,
"preview": "More data"
},
{
"path": "test-fixtures/data/my-acl-1.json",
"chars": 298,
"preview": "{\n \"entries\": [\n { \"op\": \"update\", \"prefix\": \"1.2.3.0/24\", \"action\": \"BLOCK\" },\n { \"op\": \"create\", \"prefix\": \"192"
},
{
"path": "test-fixtures/data/my-acl-2.json",
"chars": 154,
"preview": "{\n \"entries\": [\n { \"op\": \"update\", \"prefix\": \"2000::/24\", \"action\": \"BLOCK\" },\n { \"op\": \"create\", \"prefix\": \"FACE"
},
{
"path": "test-fixtures/data/server.crt",
"chars": 1359,
"preview": "-----BEGIN CERTIFICATE-----\nMIIDvjCCAqagAwIBAgIUOp97gvMlYdBYI/3yrpDeHbdx5RcwDQYJKoZIhvcNAQEL\nBQAwZDELMAkGA1UEBhMCVVMxDzA"
},
{
"path": "test-fixtures/data/server.csr",
"chars": 1021,
"preview": "-----BEGIN CERTIFICATE REQUEST-----\nMIICujCCAaICAQAwdTELMAkGA1UEBhMCVVMxDzANBgNVBAgMBk9yZWdvbjERMA8G\nA1UEBwwIUG9ydGxhbmQ"
},
{
"path": "test-fixtures/data/server.ext",
"chars": 219,
"preview": "authorityKeyIdentifier=keyid,issuer\nbasicConstraints=CA:FALSE \nkeyUsage = digitalSignature, nonRepudiation, keyEncipherm"
},
{
"path": "test-fixtures/data/server.key",
"chars": 1675,
"preview": "-----BEGIN RSA PRIVATE KEY-----\nMIIEogIBAAKCAQEAvaJbeui08EYihCfktu3Ary6CnxNmsg8kCXPddRdGa9+QJGGk\nSNBf4AseYI/jXPpO/eMixAn"
},
{
"path": "test-fixtures/return_ok.wat",
"chars": 2591,
"preview": "(module\n (import \"fastly_http_resp\" \"new\"\n (func $response_new\n (param i32)\n (result i32)))\n (import \"fas"
},
{
"path": "test-fixtures/src/bin/acl.rs",
"chars": 1971,
"preview": "//! A guest program to test that acls works properly.\nuse fastly::acl::Acl;\nuse fastly::Error;\nuse std::net::{Ipv4Addr, "
},
{
"path": "test-fixtures/src/bin/args.rs",
"chars": 135,
"preview": "fn main() {\n let args = Vec::from_iter(std::env::args());\n\n assert_eq!(args.len(), 1);\n assert_eq!(args[0], \"co"
}
]
// ... and 104 more files (download for full content)
About this extraction
This page contains the full source code of the fastly/Viceroy GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 304 files (2.0 MB), approximately 530.4k tokens, and a symbol index with 2373 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.