diff --git a/.github/BRANCH-PROTECTION.md b/.github/BRANCH-PROTECTION.md new file mode 100644 index 000000000..7209898a1 --- /dev/null +++ b/.github/BRANCH-PROTECTION.md @@ -0,0 +1,30 @@ +# Branch protection (beta / stable) + +Configure in GitHub **Settings → Rules → Rulesets** (or classic branch protection). + +## Ruleset: `release-lines` (`beta`, `stable`) + +| Rule | Value | +|------|-------| +| Restrict creations | optional | +| Restrict updates / deletions | yes | +| Block force pushes | yes | +| Require a pull request before merging | **yes** | +| Require approvals | recommended (≥1 maintainer) | +| Require conversation resolution | recommended | +| Require status checks to pass | **yes** | +| Required checks | `.NET / build`, `.NET / ui-portable` (all matrix legs), `RPS saturation / rps` | +| Allow bypass | admins only for emergencies | + +## `develop` + +Keep lighter rules for velocity (direct push OK if that is current practice). Do **not** require full `compare-product` on every feature PR. + +## Applying via `gh` (optional) + +```bash +# Example — adjust org/repo and exact check names from Actions UI after first green run +gh api repos/{owner}/{repo}/rulesets --input .github/branch-ruleset-beta-stable.json +``` + +Exact check names must match the Actions job names as shown on a PR (including matrix suffixes for `ui-portable`). diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 000000000..de880242e --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,8 @@ +# Default +* @justcoding121 + +# PolyForm Noncommercial products — maintainer only +/src/Titanium.Plus/ @justcoding121 +/tests/Titanium.Plus.Tests/ @justcoding121 +/src/Titanium.Inspector/ @justcoding121 +/tests/Titanium.Inspector.Tests/ @justcoding121 diff --git a/.github/dns/README.md b/.github/dns/README.md new file mode 100644 index 000000000..2e769fae6 --- /dev/null +++ b/.github/dns/README.md @@ -0,0 +1,12 @@ +# DNS / CloudFront helpers for titaniumproxy.com + +Public hostnames only — **no AWS credentials or certificate private keys**. + +Live edge (maintainer machine, profile `jthomas`): + +1. ACM cert in `us-east-1` for `titaniumproxy.com` + `www` (DNS validation into zone `Z08516571F59U4HNOJXAT`) +2. CloudFront distribution aliases those names; origin `justcoding121.github.io` (HTTPS) +3. CloudFront Function [`cloudfront-path-rewrite.js`](cloudfront-path-rewrite.js) (`titaniumproxy-path-rewrite`) prepends `/titanium-web-proxy` so project Pages works with VitePress `base: '/'`. Do **not** attach an origin-request policy that forwards the viewer `Host` — GitHub Pages returns “Site not found” unless the origin Host is `justcoding121.github.io`. +4. Route53 A/AAAA aliases → CloudFront ([`route53-alias.json`](route53-alias.json)) + +Template: [`cloudfront-distribution.json`](cloudfront-distribution.json) (substitute ACM ARN; function ARN uses your account). diff --git a/.github/dns/cloudfront-distribution.json b/.github/dns/cloudfront-distribution.json new file mode 100644 index 000000000..fea673137 --- /dev/null +++ b/.github/dns/cloudfront-distribution.json @@ -0,0 +1,71 @@ +{ + "CallerReference": "titaniumproxy-website-v1", + "Comment": "titaniumproxy.com → GitHub Pages origin (path rewrite via CloudFront Function titaniumproxy-path-rewrite)", + "Enabled": true, + "Aliases": { + "Quantity": 2, + "Items": ["titaniumproxy.com", "www.titaniumproxy.com"] + }, + "DefaultRootObject": "index.html", + "Origins": { + "Quantity": 1, + "Items": [ + { + "Id": "github-pages", + "DomainName": "justcoding121.github.io", + "OriginPath": "", + "CustomOriginConfig": { + "HTTPPort": 80, + "HTTPSPort": 443, + "OriginProtocolPolicy": "https-only", + "OriginSslProtocols": { + "Quantity": 1, + "Items": ["TLSv1.2"] + } + }, + "CustomHeaders": { + "Quantity": 0 + }, + "ConnectionAttempts": 3, + "ConnectionTimeout": 10, + "OriginShield": { + "Enabled": false + } + } + ] + }, + "DefaultCacheBehavior": { + "TargetOriginId": "github-pages", + "ViewerProtocolPolicy": "redirect-to-https", + "AllowedMethods": { + "Quantity": 3, + "Items": ["GET", "HEAD", "OPTIONS"], + "CachedMethods": { + "Quantity": 2, + "Items": ["GET", "HEAD"] + } + }, + "Compress": true, + "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", + "FunctionAssociations": { + "Quantity": 1, + "Items": [ + { + "EventType": "viewer-request", + "FunctionARN": "arn:aws:cloudfront::ACCOUNT_ID:function/titaniumproxy-path-rewrite" + } + ] + } + }, + "CustomErrorResponses": { + "Quantity": 0 + }, + "ViewerCertificate": { + "ACMCertificateArn": "REPLACE_WITH_ACM_CERTIFICATE_ARN", + "SSLSupportMethod": "sni-only", + "MinimumProtocolVersion": "TLSv1.2_2021" + }, + "HttpVersion": "http2and3", + "IsIPV6Enabled": true, + "PriceClass": "PriceClass_100" +} diff --git a/.github/dns/cloudfront-path-rewrite.js b/.github/dns/cloudfront-path-rewrite.js new file mode 100644 index 000000000..acbef1474 --- /dev/null +++ b/.github/dns/cloudfront-path-rewrite.js @@ -0,0 +1,12 @@ +function handler(event) { + const request = event.request; + const uri = request.uri; + if (uri.indexOf('/titanium-web-proxy') !== 0) { + if (uri === '/') { + request.uri = '/titanium-web-proxy/'; + } else { + request.uri = '/titanium-web-proxy' + uri; + } + } + return request; +} diff --git a/.github/dns/route53-alias.json b/.github/dns/route53-alias.json new file mode 100644 index 000000000..e51d82969 --- /dev/null +++ b/.github/dns/route53-alias.json @@ -0,0 +1,53 @@ +{ + "Comment": "Alias titaniumproxy.com and www to CloudFront (public CF domain only — no secrets)", + "Changes": [ + { + "Action": "UPSERT", + "ResourceRecordSet": { + "Name": "titaniumproxy.com.", + "Type": "A", + "AliasTarget": { + "HostedZoneId": "Z2FDTNDATAQYW2", + "DNSName": "d19r96hj1fsq1c.cloudfront.net.", + "EvaluateTargetHealth": false + } + } + }, + { + "Action": "UPSERT", + "ResourceRecordSet": { + "Name": "titaniumproxy.com.", + "Type": "AAAA", + "AliasTarget": { + "HostedZoneId": "Z2FDTNDATAQYW2", + "DNSName": "d19r96hj1fsq1c.cloudfront.net.", + "EvaluateTargetHealth": false + } + } + }, + { + "Action": "UPSERT", + "ResourceRecordSet": { + "Name": "www.titaniumproxy.com.", + "Type": "A", + "AliasTarget": { + "HostedZoneId": "Z2FDTNDATAQYW2", + "DNSName": "d19r96hj1fsq1c.cloudfront.net.", + "EvaluateTargetHealth": false + } + } + }, + { + "Action": "UPSERT", + "ResourceRecordSet": { + "Name": "www.titaniumproxy.com.", + "Type": "AAAA", + "AliasTarget": { + "HostedZoneId": "Z2FDTNDATAQYW2", + "DNSName": "d19r96hj1fsq1c.cloudfront.net.", + "EvaluateTargetHealth": false + } + } + } + ] +} diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml new file mode 100644 index 000000000..3abcd5b57 --- /dev/null +++ b/.github/workflows/cla.yml @@ -0,0 +1,34 @@ +name: CLA + +on: + pull_request_target: + types: [opened, synchronize, reopened] + issue_comment: + types: [created] + +permissions: + contents: write + pull-requests: write + statuses: write + +jobs: + cla: + runs-on: ubuntu-latest + steps: + - name: CLA Assistant + if: > + (github.event.issue.pull_request && + contains(github.event.comment.body, 'I have read the CLA and I hereby sign the CLA')) || + github.event_name == 'pull_request_target' + uses: contributor-assistant/github-action@ca4a40a7d1004f18d9960b404b97e5f30a505a08 # v2.6.1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PERSONAL_ACCESS_TOKEN: ${{ secrets.CLA_ASSISTANT_PAT || secrets.GITHUB_TOKEN }} + with: + path-to-document: https://github.com/justcoding121/titanium-web-proxy/blob/develop/CLA.md + path-to-signatures: signatures/version1/cla.json + branch: cla-signatures + allowlist: justcoding121,bot* + custom-notsigned-prcomment: > + Thanks for your contribution. Please read [CLA.md](https://github.com/justcoding121/titanium-web-proxy/blob/develop/CLA.md) + and reply with: I have read the CLA and I hereby sign the CLA. diff --git a/.github/workflows/deploy-website.yml b/.github/workflows/deploy-website.yml new file mode 100644 index 000000000..22c510ba3 --- /dev/null +++ b/.github/workflows/deploy-website.yml @@ -0,0 +1,99 @@ +name: Deploy website + +on: + push: + branches: + - develop + paths: + - 'website/**' + - 'wiki/images/**' + - 'docs/api/**' + - 'docs/styles/**' + - 'docs/fonts/**' + - '.github/workflows/deploy-website.yml' + pull_request: + branches: + - develop + paths: + - 'website/**' + - 'wiki/images/**' + - 'docs/api/**' + - 'docs/styles/**' + - 'docs/fonts/**' + - '.github/workflows/deploy-website.yml' + release: + types: [published] + workflow_dispatch: + +concurrency: + group: pages + cancel-in-progress: false + +jobs: + build: + # NuGet-only GitHub Releases must not redeploy Pages; only v* product tags. + if: github.event_name != 'release' || startsWith(github.event.release.tag_name, 'v') + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - uses: actions/checkout@v6 + + - uses: actions/setup-node@v4 + with: + node-version: '22' + cache: npm + cache-dependency-path: website/package-lock.json + + - name: Install and build + working-directory: website + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + npm ci --ignore-scripts + npm run docs:build + + - name: Copy DocFX API into site + shell: bash + run: | + mkdir -p website/.vitepress/dist/api + if [ -d docs/api ]; then + cp -a docs/api/. website/.vitepress/dist/api/ + # DocFX HTML references ../styles and ../fonts from /api/*.html + if [ -d docs/styles ]; then + cp -a docs/styles website/.vitepress/dist/styles + fi + if [ -d docs/fonts ]; then + cp -a docs/fonts website/.vitepress/dist/fonts + fi + # Prefer DocFX logo only if VitePress did not already emit one + if [ -f docs/logo.svg ] && [ ! -f website/.vitepress/dist/logo.svg ]; then + cp docs/logo.svg website/.vitepress/dist/logo.svg + fi + if [ -f docs/favicon.ico ]; then + cp docs/favicon.ico website/.vitepress/dist/favicon.ico + fi + else + echo "Warning: docs/api missing; API pages will not be published" + fi + + - name: Upload Pages artifact + if: github.event_name != 'pull_request' + uses: actions/upload-pages-artifact@v3 + with: + path: website/.vitepress/dist + + deploy: + if: github.event_name != 'pull_request' && (github.ref == 'refs/heads/develop' || github.event_name == 'release' || github.event_name == 'workflow_dispatch') + needs: build + runs-on: ubuntu-latest + permissions: + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/dotnetcore.yml b/.github/workflows/dotnetcore.yml index 8b2e2609b..1a447a69b 100644 --- a/.github/workflows/dotnetcore.yml +++ b/.github/workflows/dotnetcore.yml @@ -6,16 +6,38 @@ on: - develop - beta - stable + paths-ignore: + - 'website/**' + - 'wiki/**' + - 'docs/**' + - '*.md' + - '.github/workflows/deploy-website.yml' + - '.github/dns/**' pull_request: branches: - develop - beta - stable - + paths-ignore: + - 'website/**' + - 'wiki/**' + - 'docs/**' + - '*.md' + - '.github/workflows/deploy-website.yml' + - '.github/dns/**' + +permissions: + contents: read + jobs: build: runs-on: windows-latest timeout-minutes: 60 + permissions: + contents: read + # SonarCloud / PR decoration when token is present + pull-requests: write + checks: write env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} steps: @@ -62,8 +84,8 @@ jobs: /o:"justcoding121" /d:sonar.token="$env:SONAR_TOKEN" /d:sonar.cs.vscoveragexml.reportsPaths="coverage/coverage.xml" - /d:sonar.exclusions="**/docs/**,**/examples/**,**/benchmarks/**,**/tools/**" - /d:sonar.coverage.exclusions="**/examples/**,**/benchmarks/**,**/docs/**,**/Http3/Http3OriginBridge.cs,**/Http3/Http3OriginClientSession.cs" + /d:sonar.exclusions="**/docs/**,**/examples/**,**/benchmarks/**,**/tools/**,**/*.axaml,**/website/**,**/.github/**" + /d:sonar.coverage.exclusions="**/examples/**,**/benchmarks/**,**/docs/**,**/Http3/Http3OriginBridge.cs,**/Http3/Http3OriginClientSession.cs,**/Titanium.Plus/Dashboard/**,**/Titanium.Inspector/Views/**,**/Titanium.Inspector/Services/AppContainerLoopback.cs,**/Titanium.Inspector/App.axaml.cs,**/Titanium.Inspector/Program.cs,**/Titanium.Inspector/InspectorAppFactory.cs,**/Titanium.Inspector/Services/UpdateService.cs,**/Titanium.Cli/Program.cs,**/Titanium.Cli/AsyncConsole.cs,**/Titanium.Cli/Http3/Http3DepsCommand.cs,**/Titanium.Cli/Updates/VersionAndUpdateCommands.cs,**/Titanium.Cli/Certificates/CertificateBootstrap.cs,**/Titanium.Plus/Discovery/**,**/Titanium.Plus/Security/**,**/Titanium.Plus/State/**,**/Titanium.Plus/Resilience/**,**/Titanium.Plus/PlusLog.cs,**/Titanium.Web.Proxy/Helpers/LinuxSystemProxyBackend.cs,**/Titanium.Web.Proxy/Helpers/MacOsSystemProxyBackend.cs,**/Titanium.Web.Proxy/Helpers/IElevationPrompt.cs,**/Titanium.Web.Proxy/Helpers/IProcessRunner.cs" - name: Build for SonarCloud analysis if: env.SONAR_TOKEN != '' @@ -75,6 +97,18 @@ jobs: dotnet test tests/Titanium.Web.Proxy.UnitTests/Titanium.Web.Proxy.UnitTests.csproj --configuration Release --no-build --no-restore --collect:"Code Coverage" --results-directory coverage/unit if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + # Additional MIT + NC unit suites (coverage merged below) + dotnet test tests/Titanium.Web.Proxy.Configuration.Tests/Titanium.Web.Proxy.Configuration.Tests.csproj --configuration Release --no-build --no-restore --collect:"Code Coverage" --results-directory coverage/configuration + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + dotnet test tests/Titanium.Plus.Tests/Titanium.Plus.Tests.csproj --configuration Release --no-build --no-restore --collect:"Code Coverage" --results-directory coverage/plus + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + dotnet test tests/Titanium.Inspector.Tests/Titanium.Inspector.Tests.csproj --configuration Release --no-build --no-restore --collect:"Code Coverage" --results-directory coverage/inspector + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + dotnet test tests/Titanium.Cli.Tests/Titanium.Cli.Tests.csproj --configuration Release --no-build --no-restore --collect:"Code Coverage" --results-directory coverage/cli + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + dotnet test tests/Titanium.E2E.Tests/Titanium.E2E.Tests.csproj --configuration Release --no-build --no-restore --filter "TestCategory=E2E|TestCategory=E2E-UI" --collect:"Code Coverage" --results-directory coverage/e2e + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + # The integration suite spins up real listening sockets and TLS handshakes, which # occasionally hang or get "connection refused" on shared, resource-constrained CI # runners under connection bursts (a pre-existing, environment-dependent flake, not @@ -110,14 +144,114 @@ jobs: message: Update documentation committer_name: GitHub Actions committer_email: actions@github.com - # Only commit DocFX output — never Sonar/coverage/tool install artifacts + # Only commit DocFX output -- never Sonar/coverage/tool install artifacts add: 'docs' # DocFX often races another develop push; rebase instead of failing the job. pull: '--rebase --autostash' + # Cross-OS Inspector + Plus dashboard UI gates (Headless / Visual / Playwright). + # Inspector unit suite stays on Windows `build` only - do not re-run it here. + ui-portable: + runs-on: ${{ matrix.os }} + timeout-minutes: 35 + permissions: + contents: read + strategy: + fail-fast: false + matrix: + os: [windows-latest, ubuntu-latest, macos-latest] + steps: + - uses: actions/checkout@v6 + - name: Setup .NET + uses: actions/setup-dotnet@v5 + with: + dotnet-version: | + 10.0.x + - name: Linux UI fonts + Playwright OS deps + if: runner.os == 'Linux' + run: | + sudo apt-get update + sudo apt-get install -y fonts-liberation libnss3 libatk-bridge2.0-0 libdrm2 libxkbcommon0 libgbm1 libasound2t64 || sudo apt-get install -y fonts-liberation libnss3 libatk-bridge2.0-0 libdrm2 libxkbcommon0 libgbm1 libasound2 + - name: Restore + run: dotnet restore src/Titanium.Web.Proxy.sln + - name: Build + run: dotnet build src/Titanium.Web.Proxy.sln --configuration Release --no-restore + - name: Install Playwright Chromium + shell: pwsh + run: | + $pw = Join-Path (Resolve-Path "tests/Titanium.E2E.Tests/bin/Release/net10.0") "playwright.ps1" + if (-not (Test-Path $pw)) { + # Ensure test project is built so playwright.ps1 is in output + dotnet build tests/Titanium.E2E.Tests/Titanium.E2E.Tests.csproj -c Release --no-restore + $pw = Join-Path (Resolve-Path "tests/Titanium.E2E.Tests/bin/Release/net10.0") "playwright.ps1" + } + & $pw install chromium + - name: E2E-UI ViewModel smoke + run: | + dotnet test tests/Titanium.E2E.Tests/Titanium.E2E.Tests.csproj --configuration Release --no-build --no-restore --filter "TestCategory=E2E-UI" + - name: Inspector Headless + Visual + Plus Playwright + run: | + dotnet test tests/Titanium.E2E.Tests/Titanium.E2E.Tests.csproj --configuration Release --no-build --no-restore --filter "TestCategory=E2E-UI-Headless|TestCategory=E2E-UI-Visual|TestCategory=E2E-UI-Plus-Dashboard" + - name: OS proxy-backend filters + run: | + dotnet test tests/Titanium.Web.Proxy.UnitTests/Titanium.Web.Proxy.UnitTests.csproj --configuration Release --no-build --no-restore --filter "FullyQualifiedName~UnixProxyBypassMapperTests|FullyQualifiedName~MacOsSystemProxyBackendTests|FullyQualifiedName~LinuxSystemProxyBackendTests|FullyQualifiedName~ElevationPromptCancelTests|FullyQualifiedName~SystemProxyBackendFactoryPlatformTests" + - name: Inspector E2E-UI Linux platform + if: runner.os == 'Linux' + run: | + dotnet test tests/Titanium.Web.Proxy.UnitTests/Titanium.Web.Proxy.UnitTests.csproj --configuration Release --no-build --no-restore --filter "TestCategory=E2E-UI-Linux" + - name: Inspector E2E-UI macOS platform + publish smoke + if: runner.os == 'macOS' + run: | + dotnet test tests/Titanium.Web.Proxy.UnitTests/Titanium.Web.Proxy.UnitTests.csproj --configuration Release --no-build --no-restore --filter "TestCategory=E2E-UI-Mac|FullyQualifiedName~MacOsSystemProxyBackendTests|FullyQualifiedName~UnixProxyBypassMapperTests" + rid=$(dotnet --info | awk '/RID:/ {print $2; exit}') + if [ -z "$rid" ]; then rid=osx-arm64; fi + dotnet publish src/Titanium.Inspector/Titanium.Inspector.csproj -c Release -r "$rid" --self-contained true -o "./artifacts/inspector-$rid" + test -f "./artifacts/inspector-$rid/TitaniumInspector" || test -f "./artifacts/inspector-$rid/Titanium.Inspector" + - name: Upload UI failure artifacts + if: failure() + uses: actions/upload-artifact@v4 + with: + name: ui-portable-${{ matrix.os }} + path: | + tests/Titanium.E2E.Tests/TestResults/** + **/test-results/** + **/playwright-report/** + if-no-files-found: ignore + + # Tiered RPS gate for beta/stable publish (editions). Spot runs on PRs via rps-saturation.yml. + rps-publish-gate: + if: github.event_name == 'push' && (github.ref == 'refs/heads/beta' || github.ref == 'refs/heads/stable') + runs-on: ubuntu-latest + timeout-minutes: 120 + permissions: + contents: read + steps: + - uses: actions/checkout@v6 + - name: Setup .NET + uses: actions/setup-dotnet@v5 + with: + dotnet-version: | + 10.0.x + - name: compare-editions (publish gate) + shell: pwsh + run: | + # Stable tags additionally require compare-product PASS via release.yml on that SHA. + pwsh tools/RpsLoadProbe/run-rps.ps1 ` + -Mode compare-editions ` + -Concurrency '8,16,32,64' ` + -WarmupSec 2 ` + -DurationSec 8 ` + -Repeats 1 ` + -ResultsDir tools/RpsLoadProbe/results ` + -BombardierCheck + $csv = Get-ChildItem tools/RpsLoadProbe/results -Filter 'rps-ramp-*.csv' | + Sort-Object LastWriteTime -Descending | Select-Object -First 1 + if (-not $csv) { throw 'No CSV found for edition gate validation' } + pwsh tools/RpsLoadProbe/validate-edition-gates.ps1 -CsvPath $csv.FullName + publish: if: github.event_name == 'push' && (github.ref == 'refs/heads/beta' || github.ref == 'refs/heads/stable') - needs: build + needs: [build, ui-portable, rps-publish-gate] runs-on: windows-latest environment: nuget-publish permissions: @@ -136,11 +270,17 @@ jobs: - name: Pack Beta if: github.ref == 'refs/heads/beta' - run: dotnet pack src/Titanium.Web.Proxy/Titanium.Web.Proxy.csproj --configuration Release --version-suffix "beta" + run: | + dotnet pack src/Titanium.Web.Proxy.Abstractions/Titanium.Web.Proxy.Abstractions.csproj --configuration Release --version-suffix "beta" + dotnet pack src/Titanium.Web.Proxy.Configuration/Titanium.Web.Proxy.Configuration.csproj --configuration Release --version-suffix "beta" + dotnet pack src/Titanium.Web.Proxy/Titanium.Web.Proxy.csproj --configuration Release --version-suffix "beta" - name: Pack Stable if: github.ref == 'refs/heads/stable' - run: dotnet pack src/Titanium.Web.Proxy/Titanium.Web.Proxy.csproj --configuration Release + run: | + dotnet pack src/Titanium.Web.Proxy.Abstractions/Titanium.Web.Proxy.Abstractions.csproj --configuration Release + dotnet pack src/Titanium.Web.Proxy.Configuration/Titanium.Web.Proxy.Configuration.csproj --configuration Release + dotnet pack src/Titanium.Web.Proxy/Titanium.Web.Proxy.csproj --configuration Release - name: Log in to NuGet uses: NuGet/login@8d196754b4036150537f80ac539e15c2f1028841 # v1 @@ -149,34 +289,48 @@ jobs: user: ${{ secrets.NUGET_USER }} - name: Publish Package - run: dotnet nuget push **/*.nupkg --source https://api.nuget.org/v3/index.json --api-key "${{ steps.login.outputs.NUGET_API_KEY }}" + # MIT packages only -- never push Titanium.Plus or Titanium.Inspector + run: | + Get-ChildItem -Recurse -Filter *.nupkg | + Where-Object { $_.Name -notlike '*Plus*' -and $_.Name -notlike '*Inspector*' -and $_.Name -notlike '*.symbols.nupkg' } | + ForEach-Object { + dotnet nuget push $_.FullName ` + --source https://api.nuget.org/v3/index.json ` + --api-key "${{ steps.login.outputs.NUGET_API_KEY }}" ` + --skip-duplicate + } - - name: Create GitHub Release + # Product zips stay on release.yml (v* tags). After beta/stable merge, create/move the + # version tag and dispatch release.yml (GITHUB_TOKEN tag pushes do not re-trigger workflows). + cut-product-tag: + if: github.event_name == 'push' && (github.ref == 'refs/heads/beta' || github.ref == 'refs/heads/stable') + needs: [build, ui-portable, rps-publish-gate] + runs-on: ubuntu-latest + permissions: + contents: write + actions: write + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + - name: Create/move product tag and dispatch release env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - shell: pwsh + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - $nupkg = Get-ChildItem -Recurse -Filter *.nupkg | - Where-Object { $_.Name -notlike '*.symbols.nupkg' } | - Select-Object -First 1 - if (-not $nupkg) { throw "No nupkg found to attach to the GitHub release." } - - # Titanium.Web.Proxy.3.2.3-beta.nupkg -> 3.2.3-beta - $version = $nupkg.BaseName -replace '^Titanium\.Web\.Proxy\.', '' - $isPrerelease = $version -match '-' - - gh release view $version 2>$null - if ($LASTEXITCODE -eq 0) { - Write-Output "Release $version already exists; uploading package." - gh release upload $version $nupkg.FullName --clobber - } - else { - $createArgs = @( - 'release', 'create', $version, $nupkg.FullName, - '--title', $version, - '--generate-notes', - '--target', $env:GITHUB_SHA - ) - if ($isPrerelease) { $createArgs += '--prerelease' } - gh @createArgs - } + set -euo pipefail + PREFIX=$(grep -oP '(?<=)[^<]+' src/Titanium.Web.Proxy/Titanium.Web.Proxy.csproj | head -n1) + if [[ -z "$PREFIX" ]]; then echo "VersionPrefix not found"; exit 1; fi + CHANNEL=stable + VERSION="$PREFIX" + if [[ "${{ github.ref }}" == "refs/heads/beta" ]]; then + CHANNEL=beta + VERSION="${PREFIX}-beta" + fi + TAG="v${VERSION}" + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git tag -f -a "$TAG" -m "$TAG" "$GITHUB_SHA" + git push origin "refs/tags/$TAG" --force + echo "Dispatching product release for $TAG (channel=$CHANNEL) at $GITHUB_SHA" + gh workflow run release.yml --ref "$GITHUB_REF_NAME" -f channel="$CHANNEL" + diff --git a/.github/workflows/pr-path-guard.yml b/.github/workflows/pr-path-guard.yml new file mode 100644 index 000000000..0ab431024 --- /dev/null +++ b/.github/workflows/pr-path-guard.yml @@ -0,0 +1,58 @@ +name: PR path guard + +on: + pull_request: + branches: + - develop + - beta + - stable + +permissions: + contents: read + pull-requests: read + +jobs: + guard-nc-paths: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: Block external changes to PolyForm NC paths + env: + TWP_NC_MAINTAINERS: ${{ vars.TWP_NC_MAINTAINERS }} + ACTOR: ${{ github.actor }} + shell: bash + run: | + set -euo pipefail + ALLOW="${TWP_NC_MAINTAINERS:-justcoding121}" + IFS=',' read -ra MAINTAINERS <<< "$ALLOW" + is_maintainer=false + for m in "${MAINTAINERS[@]}"; do + m="$(echo "$m" | xargs)" + if [[ "$ACTOR" == "$m" ]]; then + is_maintainer=true + break + fi + done + + BASE="${{ github.event.pull_request.base.sha }}" + HEAD="${{ github.event.pull_request.head.sha }}" + CHANGED="$(git diff --name-only "$BASE"..."$HEAD" || true)" + NC_HIT=false + while IFS= read -r path; do + [[ -z "$path" ]] && continue + case "$path" in + src/Titanium.Plus/*|tests/Titanium.Plus.Tests/*|src/Titanium.Inspector/*|tests/Titanium.Inspector.Tests/*) + NC_HIT=true + echo "NC path touched: $path" + ;; + esac + done <<< "$CHANGED" + + if [[ "$NC_HIT" == "true" && "$is_maintainer" != "true" ]]; then + echo "::error::Changes to Titanium.Plus or Titanium.Inspector require a maintainer listed in TWP_NC_MAINTAINERS (actor=$ACTOR)." + exit 1 + fi + echo "Path guard passed (actor=$ACTOR, nc_hit=$NC_HIT)." diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..15b920976 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,397 @@ +name: release + +on: + push: + tags: + - 'v*.*.*' + workflow_dispatch: + inputs: + channel: + description: 'stable or beta' + required: true + default: 'stable' + +permissions: + contents: read + +jobs: + resolve-version: + runs-on: ubuntu-latest + permissions: + contents: read + outputs: + release_tag: ${{ steps.v.outputs.tag }} + version: ${{ steps.v.outputs.version }} + channel: ${{ steps.v.outputs.channel }} + steps: + - uses: actions/checkout@v6 + - id: v + name: Resolve release tag / channel + run: | + set -euo pipefail + if [[ "$GITHUB_REF" == refs/tags/* ]]; then + TAG="${GITHUB_REF_NAME}" + VERSION="${TAG#v}" + CHANNEL=stable + if [[ "$VERSION" == *beta* || "$VERSION" == *-* ]]; then CHANNEL=beta; fi + else + CHANNEL="${{ github.event.inputs.channel || 'stable' }}" + PREFIX=$(grep -oP '(?<=)[^<]+' src/Titanium.Web.Proxy/Titanium.Web.Proxy.csproj | head -n1) + if [[ -z "$PREFIX" ]]; then echo "VersionPrefix not found"; exit 1; fi + if [[ "$CHANNEL" == "beta" ]]; then + VERSION="${PREFIX}-beta" + else + VERSION="$PREFIX" + fi + TAG="v${VERSION}" + fi + echo "tag=$TAG" >> "$GITHUB_OUTPUT" + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + echo "channel=$CHANNEL" >> "$GITHUB_OUTPUT" + echo "Resolved tag=$TAG version=$VERSION channel=$CHANNEL" + + test: + needs: resolve-version + runs-on: windows-latest + permissions: + contents: read + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-dotnet@v5 + with: + dotnet-version: '10.0.x' + cache: true + - name: Test + run: | + dotnet test src/Titanium.Web.Proxy.sln -c Release --nologo --filter "TestCategory!=Slow&TestCategory!=E2E-UI-Window" + # Product release also requires Headless/Visual/Plus dashboard (same gates as ui-portable). + dotnet build tests/Titanium.E2E.Tests/Titanium.E2E.Tests.csproj -c Release + pwsh tests/Titanium.E2E.Tests/bin/Release/net10.0/playwright.ps1 install chromium + dotnet test tests/Titanium.E2E.Tests/Titanium.E2E.Tests.csproj -c Release --no-build --filter "TestCategory=E2E-UI-Headless|TestCategory=E2E-UI-Visual|TestCategory=E2E-UI-Plus-Dashboard" + + + build-cli: + needs: [resolve-version, test] + runs-on: ${{ matrix.os }} + permissions: + contents: read + strategy: + fail-fast: false + matrix: + include: + - rid: linux-x64 + os: ubuntu-latest + - rid: linux-arm64 + os: ubuntu-latest + - rid: linux-musl-x64 + os: ubuntu-latest + - rid: linux-musl-arm64 + os: ubuntu-latest + - rid: win-x64 + os: ubuntu-latest + - rid: osx-x64 + os: macos-latest + - rid: osx-arm64 + os: macos-latest + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-dotnet@v5 + with: + dotnet-version: '10.0.x' + cache: true + - uses: actions/cache@v4 + with: + path: tools/packaging/.cache/http3-natives + key: http3-natives-${{ hashFiles('tools/packaging/http3-native.lock.json') }}-${{ matrix.rid }} + restore-keys: | + http3-natives-${{ hashFiles('tools/packaging/http3-native.lock.json') }}- + - name: Publish Cli + shell: pwsh + run: | + $rid = "${{ matrix.rid }}" + $out = "artifacts/cli/$rid" + dotnet publish src/Titanium.Cli/Titanium.Cli.csproj -c Release -r $rid --self-contained true -o $out + if (Test-Path "$out/titanium.exe") { + Copy-Item "$out/titanium.exe" "$out/twp.exe" + } elseif (Test-Path "$out/titanium") { + Copy-Item "$out/titanium" "$out/twp" + } + ./tools/packaging/bundle-http3-native.ps1 -Rid $rid -PublishDir $out + if ($IsWindows) { + Compress-Archive -Path "$out/*" -DestinationPath "Titanium.Cli-$rid.zip" + } else { + Push-Location $out + try { zip -r "../../../Titanium.Cli-$rid.zip" . } finally { Pop-Location } + } + - uses: actions/upload-artifact@v4 + with: + name: cli-${{ matrix.rid }} + path: Titanium.Cli-${{ matrix.rid }}.zip + + build-plus: + needs: [resolve-version, test] + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-dotnet@v5 + with: + dotnet-version: '10.0.x' + cache: true + - name: Build Plus + env: + RELEASE_TAG: ${{ needs.resolve-version.outputs.release_tag }} + run: | + dotnet build src/Titanium.Plus/Titanium.Plus.csproj -c Release -o artifacts/plus + cp artifacts/plus/Titanium.Plus.dll "Titanium.Plus-${RELEASE_TAG}.dll" + - uses: actions/upload-artifact@v4 + with: + name: plus + path: Titanium.Plus-*.dll + + build-inspector: + needs: [resolve-version, test] + runs-on: ${{ matrix.os }} + permissions: + contents: read + strategy: + fail-fast: false + matrix: + include: + - rid: win-x64 + os: windows-latest + msi: true + - rid: linux-x64 + os: ubuntu-latest + msi: false + - rid: linux-arm64 + os: ubuntu-latest + msi: false + - rid: linux-musl-x64 + os: ubuntu-latest + msi: false + - rid: linux-musl-arm64 + os: ubuntu-latest + msi: false + - rid: osx-x64 + os: macos-latest + msi: false + - rid: osx-arm64 + os: macos-latest + msi: false + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-dotnet@v5 + with: + dotnet-version: '10.0.x' + cache: true + - uses: actions/cache@v4 + with: + path: tools/packaging/.cache/http3-natives + key: http3-natives-${{ hashFiles('tools/packaging/http3-native.lock.json') }}-${{ matrix.rid }} + restore-keys: | + http3-natives-${{ hashFiles('tools/packaging/http3-native.lock.json') }}- + - name: Publish Inspector + shell: pwsh + run: | + $rid = "${{ matrix.rid }}" + $out = "artifacts/inspector/$rid" + dotnet publish src/Titanium.Inspector/Titanium.Inspector.csproj -c Release -r $rid --self-contained true -o $out + ./tools/packaging/bundle-http3-native.ps1 -Rid $rid -PublishDir $out + Copy-Item -Force tools/packaging/THIRD-PARTY-INSPECTOR.txt (Join-Path $out "THIRD-PARTY-INSPECTOR.txt") + if ($IsWindows) { + Compress-Archive -Path "$out/*" -DestinationPath "TitaniumInspector-$rid.zip" + } else { + Push-Location $out + try { zip -r "../../../TitaniumInspector-$rid.zip" . } finally { Pop-Location } + } + - name: Build MSI (WiX) + if: matrix.msi + shell: pwsh + env: + RELEASE_VERSION: ${{ needs.resolve-version.outputs.version }} + run: | + $ver = $env:RELEASE_VERSION + if ($ver -notmatch '^\d+\.\d+\.\d+') { $ver = "7.0.0" } + $ver = ($ver -split "-")[0] + ./tools/packaging/build-inspector-msi.ps1 ` + -PayloadDir artifacts/inspector/win-x64 ` + -OutputMsi TitaniumInspector-win-x64.msi ` + -Version $ver + - uses: actions/upload-artifact@v4 + with: + name: inspector-${{ matrix.rid }} + if-no-files-found: error + path: | + TitaniumInspector-${{ matrix.rid }}.zip + - uses: actions/upload-artifact@v4 + if: matrix.msi + with: + name: inspector-${{ matrix.rid }}-msi + path: TitaniumInspector-${{ matrix.rid }}.msi + + smoke-http3: + needs: build-cli + runs-on: ubuntu-latest + permissions: + contents: read + strategy: + fail-fast: false + matrix: + include: + - rid: linux-x64 + container: "" + - rid: linux-musl-x64 + container: alpine:3.24 + steps: + - uses: actions/download-artifact@v4 + with: + name: cli-${{ matrix.rid }} + path: dist + - name: Smoke QuicListener (host ubuntu / glibc) + if: matrix.container == '' + run: | + set -euo pipefail + unzip -q dist/Titanium.Cli-${{ matrix.rid }}.zip -d cli + chmod +x cli/titanium + # Soft probe: http3-deps status exits 0 and prints IsSupported + ./cli/titanium http3-deps status | tee smoke-out.txt + grep -qi 'IsSupported' smoke-out.txt + # Bundled natives must be present for glibc zip + test -e cli/libmsquic.so -o -e cli/libmsquic.so.2 -o -e cli/libmsquic.so.2.6.0 + - name: Smoke QuicListener (Alpine musl container) + if: matrix.container != '' + uses: addnab/docker-run-action@4f65fabd2431ebc8d299f8e5a018d79a769ae185 # v3 + with: + image: ${{ matrix.container }} + options: -v ${{ github.workspace }}/dist:/dist + run: | + set -euo pipefail + apk add --no-cache unzip libstdc++ libgcc icu-libs + unzip -q /dist/Titanium.Cli-${{ matrix.rid }}.zip -d /cli + chmod +x /cli/titanium + /cli/titanium http3-deps status | tee /cli/smoke-out.txt + grep -qi 'IsSupported' /cli/smoke-out.txt + test -e /cli/libmsquic.so -o -e /cli/libmsquic.so.2 -o -e /cli/libmsquic.so.2.5.7 + + publish-release: + needs: [resolve-version, build-cli, build-plus, build-inspector, smoke-http3] + if: startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch' + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + - uses: actions/download-artifact@v4 + with: + path: artifacts + - name: Build release-manifest and create GitHub Release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + RELEASE_TAG: ${{ needs.resolve-version.outputs.release_tag }} + RELEASE_VERSION: ${{ needs.resolve-version.outputs.version }} + RELEASE_CHANNEL: ${{ needs.resolve-version.outputs.channel }} + run: | + set -euo pipefail + TAG="$RELEASE_TAG" + VERSION="$RELEASE_VERSION" + CHANNEL="$RELEASE_CHANNEL" + export RELEASE_TAG VERSION + mkdir -p dist + find artifacts -type f \( -name '*.zip' -o -name '*.dll' -o -name '*.msi' \) -exec cp {} dist/ \; + python3 - <<'PY' + import hashlib, json, os, pathlib, datetime + tag = os.environ["RELEASE_TAG"] + version = os.environ["VERSION"] + channel = "beta" if ("-" in version or "beta" in version.lower()) else "stable" + dist = pathlib.Path("dist") + def sha(p): + h = hashlib.sha256() + h.update(p.read_bytes()) + return h.hexdigest() + assets = {} + for p in dist.iterdir(): + assets[p.name] = {"path": str(p), "sha256": sha(p)} + manifest = { + "version": version, + "channel": channel, + "releasedUtc": datetime.datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ"), + "abstractionsVersion": version.split("-")[0], + "products": { + "cli": {"assets": {}}, + "plus": {"requiredAbstractions": "7.0.0", "asset": None}, + "inspector": {"assets": {}}, + }, + "nuget": { + "Titanium.Web.Proxy": version.split("-")[0], + "Titanium.Web.Proxy.Abstractions": version.split("-")[0], + "Titanium.Web.Proxy.Configuration": version.split("-")[0], + }, + } + for name, meta in assets.items(): + url = f"https://github.com/{os.environ['GITHUB_REPOSITORY']}/releases/download/{tag}/{name}" + entry = {"url": url, "sha256": meta["sha256"]} + if name.startswith("Titanium.Cli-"): + rid = name.removeprefix("Titanium.Cli-").removesuffix(".zip") + manifest["products"]["cli"]["assets"][rid] = entry + elif name.startswith("TitaniumInspector-") and name.endswith(".msi"): + manifest["products"]["inspector"]["assets"]["win-x64-msi"] = entry + elif name.startswith("TitaniumInspector-"): + rid = name.removeprefix("TitaniumInspector-").removesuffix(".zip") + manifest["products"]["inspector"]["assets"][rid] = entry + elif name.startswith("Titanium.Plus"): + manifest["products"]["plus"]["asset"] = entry + pathlib.Path("dist/release-manifest.json").write_text(json.dumps(manifest, indent=2)) + print(json.dumps(manifest, indent=2)) + PY + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git tag -f -a "$TAG" -m "$TAG" "$GITHUB_SHA" + git push origin "refs/tags/$TAG" --force + if gh release view "$TAG" >/dev/null 2>&1; then + gh release delete "$TAG" --yes --cleanup-tag || true + git tag -f -a "$TAG" -m "$TAG" "$GITHUB_SHA" + git push origin "refs/tags/$TAG" --force + fi + PRE="" + if [[ "$CHANNEL" == "beta" ]]; then PRE="--prerelease"; fi + gh release create "$TAG" dist/* \ + --title "$TAG" \ + --generate-notes \ + --target "$GITHUB_SHA" \ + $PRE + # When GitHub finds no PR merges, --generate-notes is only a compare link. + # Fall back to commit-subject bullets from the previous different-SHA release tag. + BODY="$(gh release view "$TAG" --json body -q .body 2>/dev/null || true)" + if [[ "$BODY" != *"What's Changed"* ]]; then + CUR_SHA="$(git rev-parse "${TAG}^{commit}" 2>/dev/null || echo "$GITHUB_SHA")" + RANGE_PREV="" + while read -r cand; do + [[ -z "$cand" || "$cand" == "$TAG" ]] && continue + cs="$(git rev-parse "${cand}^{commit}" 2>/dev/null || true)" + [[ -n "$cs" && "$cs" != "$CUR_SHA" ]] || continue + if git merge-base --is-ancestor "$cs" "$CUR_SHA" 2>/dev/null; then + RANGE_PREV="$cand" + break + fi + done < <(gh release list --limit 100 --json tagName,createdAt --jq 'sort_by(.createdAt) | reverse | .[].tagName') + NOTES_FILE="$(mktemp)" + { + echo "## What's Changed" + if [[ -n "$RANGE_PREV" ]]; then + git log --no-merges --pretty=format:'* %s' "${RANGE_PREV}..${TAG}" + echo "" + echo "" + echo "**Full Changelog**: https://github.com/${GITHUB_REPOSITORY}/compare/${RANGE_PREV}...${TAG}" + else + echo "* See repository history for this tag." + fi + } > "$NOTES_FILE" + if grep -q '^\* ' "$NOTES_FILE"; then + gh release edit "$TAG" --notes-file "$NOTES_FILE" + fi + rm -f "$NOTES_FILE" + fi diff --git a/.github/workflows/rps-saturation.yml b/.github/workflows/rps-saturation.yml index b224aed70..e24a885db 100644 --- a/.github/workflows/rps-saturation.yml +++ b/.github/workflows/rps-saturation.yml @@ -1,4 +1,4 @@ -# Manual saturation RPS lab on GitHub-hosted VMs (not a job container). +# Manual saturation RPS lab on GitHub-hosted VMs (not a job container). # Maintainers run this, then paste median numbers into wiki/Performance.md. # Not a per-PR gate; not comparable to dedicated-server blog posts. # @@ -11,6 +11,10 @@ name: RPS saturation on: + pull_request: + branches: [beta, stable] + push: + branches: [beta, stable] workflow_dispatch: inputs: mode: @@ -26,6 +30,8 @@ on: - compare-mitm - compare-matrix - compare-product + - compare-editions + - compare-cross-version - compare-ceiling - compare-bodies - compare-post @@ -33,6 +39,7 @@ on: - compare-tls-cost - compare-arch - compare-saturation + - compare-spot - origin-direct - compare - compare-tls @@ -89,6 +96,12 @@ on: - nginx-reverse-http3-cleartext - yarp-reverse-http2 - yarp-reverse-http2-to-https + - twp-cli-reverse-http1 + - twp-cli-reverse-http1-tls + - twp-cli-reverse-http1-route + - twp-cli-plus-base-http1 + - twp-cli-plus-cache-http1 + - twp-cli-intercept-http1 concurrency: description: 'Comma-separated concurrency steps' required: true @@ -106,16 +119,29 @@ on: required: true default: '3' +permissions: + contents: read + jobs: rps: + # PR → beta/stable: compare-spot; push → beta/stable: compare-editions; dispatch: inputs.mode + permissions: + contents: read + env: + RPS_MODE: ${{ github.event_name == 'workflow_dispatch' && inputs.mode || (github.event_name == 'pull_request' && 'compare-spot' || 'compare-editions') }} + RPS_CONCURRENCY: ${{ github.event_name == 'workflow_dispatch' && inputs.concurrency || '8,16,32,64' }} + RPS_WARMUP_SEC: ${{ github.event_name == 'workflow_dispatch' && inputs.warmup_sec || 2 }} + RPS_DURATION_SEC: ${{ github.event_name == 'workflow_dispatch' && inputs.duration_sec || 8 }} + RPS_REPEATS: ${{ github.event_name == 'workflow_dispatch' && inputs.repeats || 1 }} strategy: fail-fast: false matrix: os: [ubuntu-latest, windows-latest] runs-on: ${{ matrix.os }} - # Intentionally no jobs.*.container — saturation RPS on a container network measures the wrong thing. + # Intentionally no jobs.*.container — saturation RPS on a container network measures the wrong thing. # compare-product with MITM Lite+Full can exceed 3.5h per OS on hosted runners. - timeout-minutes: 420 + # compare-editions (expanded Plus/CLI stress arms) needs ~60m; other modes keep the long ceiling. + timeout-minutes: ${{ github.event_name == 'pull_request' && 45 || (github.event_name == 'push' && 90 || (inputs.mode == 'compare-editions' && 90 || 420)) }} steps: - uses: actions/checkout@v6 @@ -252,13 +278,14 @@ jobs: # Pass workflow_dispatch inputs via env (not ${{ }} in the script) to avoid # githubactions:S7630 script-injection findings on user-controlled values. - name: Run saturation ramp + timeout-minutes: ${{ github.event_name == 'pull_request' && 40 || (github.event_name == 'push' && 60 || (inputs.mode == 'compare-editions' && 60 || 400)) }} shell: pwsh env: - RPS_MODE: ${{ inputs.mode }} - RPS_CONCURRENCY: ${{ inputs.concurrency }} - RPS_WARMUP_SEC: ${{ inputs.warmup_sec }} - RPS_DURATION_SEC: ${{ inputs.duration_sec }} - RPS_REPEATS: ${{ inputs.repeats }} + RPS_MODE: ${{ env.RPS_MODE }} + RPS_CONCURRENCY: ${{ env.RPS_CONCURRENCY }} + RPS_WARMUP_SEC: ${{ env.RPS_WARMUP_SEC }} + RPS_DURATION_SEC: ${{ env.RPS_DURATION_SEC }} + RPS_REPEATS: ${{ env.RPS_REPEATS }} run: | pwsh tools/RpsLoadProbe/run-rps.ps1 ` -Mode $env:RPS_MODE ` @@ -269,7 +296,43 @@ jobs: -ResultsDir tools/RpsLoadProbe/results ` -BombardierCheck + - name: Validate edition gates + if: env.RPS_MODE == 'compare-editions' + shell: pwsh + run: | + $csv = Get-ChildItem tools/RpsLoadProbe/results -Filter 'rps-ramp-*.csv' | + Sort-Object LastWriteTime -Descending | Select-Object -First 1 + if (-not $csv) { throw 'No CSV found for edition gate validation' } + pwsh tools/RpsLoadProbe/validate-edition-gates.ps1 -CsvPath $csv.FullName + + - name: Validate compare-product gates + if: env.RPS_MODE == 'compare-product' + shell: pwsh + run: | + $csv = Get-ChildItem tools/RpsLoadProbe/results -Filter 'rps-ramp-*.csv' | + Sort-Object LastWriteTime -Descending | Select-Object -First 1 + if (-not $csv) { throw 'No CSV found for compare-product gate validation' } + pwsh tools/RpsLoadProbe/validate-compare-product-gates.ps1 -CsvPath $csv.FullName + + - name: Validate cross-version gates + if: env.RPS_MODE == 'compare-cross-version' + shell: pwsh + run: | + $csv = Get-ChildItem tools/RpsLoadProbe/results -Filter 'rps-ramp-*.csv' | + Sort-Object LastWriteTime -Descending | Select-Object -First 1 + if (-not $csv) { throw 'No CSV found for cross-version gate validation' } + $baseline = if ($env:RUNNER_OS -eq 'Windows') { + 'tools/RpsLoadProbe/results/baseline-6.0-win.csv' + } else { + 'tools/RpsLoadProbe/results/baseline-6.0-linux.csv' + } + if (-not (Test-Path $baseline)) { throw "Missing baseline: $baseline" } + pwsh tools/RpsLoadProbe/validate-cross-version.ps1 ` + -BaselineCsv $baseline ` + -CurrentCsv $csv.FullName + - name: Upload CSV artifact + if: always() uses: actions/upload-artifact@v4 with: name: rps-csv-${{ matrix.os }} diff --git a/.gitignore b/.gitignore index ab43d6fcd..f6b9e9ab1 100644 --- a/.gitignore +++ b/.gitignore @@ -225,3 +225,10 @@ tools/ChromeLoadProbe/results/ .tmp-rps/ tmp/ +# VitePress site (website/) +website/.vitepress/dist/ +website/.vitepress/cache/ + +# HTTP/3 native download cache (CI / local packaging) +tools/packaging/.cache/ + diff --git a/CLA.md b/CLA.md new file mode 100644 index 000000000..90f2e9a2c --- /dev/null +++ b/CLA.md @@ -0,0 +1,28 @@ +# Contributor License Agreement (CLA) + +Thank you for your interest in contributing to Titanium Web Proxy and related projects maintained in this repository. + +## Agreement + +By submitting a contribution (including a pull request, patch, or other submission) to this repository, you agree that: + +1. **You own the contribution or have the right to submit it.** You represent that each contribution is your original work, or that you have the necessary rights to submit it under the terms below. +2. **MIT-licensed areas.** Contributions to MIT-licensed paths (including `src/Titanium.Web.Proxy/`, `src/Titanium.Web.Proxy.Abstractions/`, `src/Titanium.Web.Proxy.Configuration/`, `src/Titanium.Cli/`, tests under those products, examples, tools, and documentation for MIT editions) are licensed to the project under the MIT License (see [LICENSE](LICENSE)). +3. **PolyForm Noncommercial areas.** Contributions to PolyForm Noncommercial paths (`src/Titanium.Plus/`, `src/Titanium.Inspector/`, and their dedicated test projects) are licensed to the project under the [PolyForm Noncommercial License 1.0.0](licenses/PolyForm-Noncommercial-1.0.0.txt). External contributors may only submit to those paths if they are listed in the `TWP_NC_MAINTAINERS` allowlist; otherwise such PRs are rejected by CI. +4. **No additional terms.** You grant the project maintainers a perpetual, worldwide, non-exclusive, royalty-free, irrevocable license to use, reproduce, modify, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute your contributions under the applicable project license for each path. +5. **Patent grant.** You grant a patent license covering claims you can license that would be infringed by your contribution alone or by combination of your contribution with the work to which it was submitted. +6. **No expectation of compensation.** Contributions are provided without expectation of payment. + +## How to sign + +On your first pull request, reply with: + +```text +I have read the CLA and I hereby sign the CLA. +``` + +The CLA bot (or maintainer) records your signature. Subsequent contributions from the same GitHub account are covered unless you revoke in writing to the maintainers. + +## Questions + +Open a discussion or contact the repository owner `@justcoding121`. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..c315976a2 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,28 @@ +# Contributing + +Thanks for contributing to Titanium Web Proxy. + +## Editions + +| Paths | License | External PRs | +|-------|---------|--------------| +| `src/Titanium.Web.Proxy/`, `src/Titanium.Web.Proxy.Abstractions/`, `src/Titanium.Web.Proxy.Configuration/`, `src/Titanium.Cli/`, related MIT tests/examples/tools/docs, `website/` | MIT | Welcome after CLA | +| `src/Titanium.Plus/`, `src/Titanium.Inspector/`, `tests/Titanium.Plus.Tests/`, `tests/Titanium.Inspector.Tests/` | PolyForm Noncommercial | Maintainer allowlist only | + +See [CLA.md](CLA.md) and [README.md](README.md) Editions section. + +## Before you open a PR + +1. Sign the [CLA](CLA.md) if you have not already. +2. Target the `develop` branch (unless a maintainer directs otherwise). +3. Run `dotnet build src/Titanium.Web.Proxy.sln -c Release` and `dotnet test` for affected test projects. +4. Do not introduce third-party product names of other proxies or traffic debuggers into source, tests, CLI help, or docs. +5. Keep hot-path changes minimal; preserve `ForwardHost` terminate-lite eligibility when routes are unset or equivalent to a single sticky destination. + +## PR checklist + +Use the pull request template. Include tests for behavior changes. Do not weaken performance gates or skip PublicAPI analyzer updates for intentional API surface changes. + +## Code owners + +PolyForm Noncommercial paths are owned by `@justcoding121`. See [`.github/CODEOWNERS`](.github/CODEOWNERS). diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md index 8eb4b8a5c..9c87de46c 100644 --- a/PULL_REQUEST_TEMPLATE.md +++ b/PULL_REQUEST_TEMPLATE.md @@ -1,4 +1,18 @@ -Doneness: -- [ ] Build is okay - I made sure that this change is building successfully. -- [ ] No Bugs - I made sure that this change is working properly as expected. It doesn't have any bugs that you are aware of. -- [ ] Branching - If this is not a hotfix, I am making this request against the develop branch +## Summary + + + +## Edition impact + +- [ ] MIT only (`Titanium.Web.Proxy` / Abstractions / Configuration / Cli) +- [ ] PolyForm NC (`Titanium.Plus` / `Titanium.Inspector`) — maintainers only + +## Checklist + +- [ ] Build succeeds (`dotnet build src/Titanium.Web.Proxy.sln -c Release`) +- [ ] Tests updated / passing for affected projects +- [ ] CLA signed (first-time contributors) +- [ ] No third-party proxy/debugger product names in new/edited public tree text +- [ ] Hot-path / terminate-lite behavior preserved when routes unset or ForwardHost-equivalent +- [ ] PublicAPI.Shipped.txt / Unshipped.txt updated if public surface changed +- [ ] Target branch is `develop` (unless directed otherwise) diff --git a/README.md b/README.md index 540101075..5ced78d48 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,12 @@ # Titanium Web Proxy -A lightweight, high performing HTTP(S) proxy server for .NET. It acts as a man in the middle (MITM) proxy and/or as a reverse proxy. Designed for high-performance. Works in Windows, Linux & Apple devices. +A lightweight, high-performance HTTP(S) proxy — reverse / edge CLI, desktop Inspector, and optional Plus ops on Windows, Linux, and macOS. Embed the same engine in .NET via NuGet when you need a library. + +**[Website](https://titaniumproxy.com)** · [Download](https://titaniumproxy.com/download) · [Docs](https://titaniumproxy.com/docs/getting-started) · [Releases](https://titaniumproxy.com/releases) [![Build](https://github.com/justcoding121/titanium-web-proxy/actions/workflows/dotnetcore.yml/badge.svg?branch=develop)](https://github.com/justcoding121/titanium-web-proxy/actions/workflows/dotnetcore.yml) [![NuGet](https://img.shields.io/nuget/v/Titanium.Web.Proxy.svg)](https://www.nuget.org/packages/Titanium.Web.Proxy) [![NuGet downloads](https://img.shields.io/nuget/dt/Titanium.Web.Proxy.svg)](https://www.nuget.org/packages/Titanium.Web.Proxy) -[![License](https://img.shields.io/github/license/justcoding121/Titanium-Web-Proxy.svg)](LICENSE) ## Code Quality @@ -27,11 +28,22 @@ A lightweight, high performing HTTP(S) proxy server for .NET. It acts as a man i - Explicit, transparent, and SOCKS4/5 proxy endpoints - Request and response body streaming across HTTP/1.x (plain and TLS), HTTP/2, and HTTP/3 (see the [protocol support matrix](https://github.com/justcoding121/titanium-web-proxy/wiki/Protocol-Support)) - HTTP/2 support, on by default, opt-out via `ProxyServer.EnableHttp2` (see the [protocol support matrix](https://github.com/justcoding121/titanium-web-proxy/wiki/Protocol-Support) for exact coverage) -- HTTP/3 (QUIC) support, opt-in via `ProxyServer.EnableHttp3 = true` (requires MsQuic; 1xx interim responses, per-chunk body streaming hooks, upstream proxy chaining with TCP fallback, HTTPS/SVCB DNS discovery, and QPACK dynamic table; see the [HTTP/3 wiki](https://github.com/justcoding121/titanium-web-proxy/wiki/HTTP-3) for setup and the [protocol bridge matrix](https://github.com/justcoding121/titanium-web-proxy/wiki/Protocol-Support#protocol-bridges) for every client→origin direction) +- HTTP/3 (QUIC) support, opt-in via `ProxyServer.EnableHttp3 = true` (requires MsQuic; CLI/Inspector Release zips bundle natives per RID — see the [HTTP/3 wiki](https://github.com/justcoding121/titanium-web-proxy/wiki/HTTP-3) for packaging and the [protocol bridge matrix](https://github.com/justcoding121/titanium-web-proxy/wiki/Protocol-Support#protocol-bridges) for every client→origin direction) - Upstream HTTP, HTTPS, and SOCKS proxies with automatic system proxy detection - Proxy authentication, mutual TLS, Kerberos, and NTLM support - Connection, certificate, and buffer pooling -- Built-in, zero-overhead-when-disabled logging (every caught exception, optionally to console/file or your own `ILoggerFactory`) and opt-in structured request/connection timing — see [Logging and diagnostics](https://github.com/justcoding121/titanium-web-proxy/wiki/Home#logging-and-diagnostics) in the wiki +- Built-in, zero-overhead-when-disabled logging (every caught exception, optionally to console/file or your own `ILoggerFactory`) and opt-in structured request/connection timing. See [Logging and diagnostics](https://github.com/justcoding121/titanium-web-proxy/wiki/Home#logging-and-diagnostics) in the wiki. + +## Editions + +| Product | What it is | How you get it | +|---------|------------|----------------| +| **Titanium.Cli** (`titanium` / `twp`) | Standalone reverse / edge proxy for any stack: `run`, `test`, `version`, `update` | GitHub Releases, winget, or `dotnet tool` | +| **Titanium Inspector** | Desktop MITM debugger (session grid, inspectors, AutoResponder, breakpoints, HAR) | Windows MSI, winget, or GitHub Releases | +| **Titanium.Plus** | Optional advanced features: control plane, ops, observability, and dashboard | `titanium update --plus` | +| **Titanium.Web.Proxy** | Core library. Embed a MITM and/or reverse proxy in a .NET app | NuGet | + +CLI and Plus target reverse-proxy / edge workloads (routing, load balancing, health, discovery) on Windows, Linux, and macOS. Inspector is the MITM debugging product. The Core library is the embed path for .NET. Requires .NET 10 or later. ## Installation @@ -47,17 +59,30 @@ To use the latest prerelease: dotnet add package Titanium.Web.Proxy --prerelease ``` -## Supported frameworks +### CLI (`titanium` / `twp`) -- .NET 10 +On Windows, **winget is stable-only**: -> Versions prior to 4.0 also supported .NET Framework 4.6.2 and .NET 8; starting with 4.0, the package -> targets .NET 10 only so the codebase can take full advantage of modern APIs. +```shell +winget install justcoding121.TitaniumCli +``` + +For **beta**, download self-contained zips from [Download](https://titaniumproxy.com/download) / [GitHub Releases](https://github.com/justcoding121/titanium-web-proxy/releases) when a product release includes `Titanium.Cli-*.zip` assets (e.g. `v7.0.0-beta`). Extract and run: -> **Breaking change:** `ProxyServer.ExceptionFunc` and `SessionEventArgsBase.TimeLine` were removed in -> favor of the unified `ProxyServer.Logging`/`EnableRequestTimingCapture` APIs described in -> [Logging and diagnostics](https://github.com/justcoding121/titanium-web-proxy/wiki/Home#logging-and-diagnostics) -> and [Breaking changes: unified logging and timing](https://github.com/justcoding121/titanium-web-proxy/wiki/Home#breaking-changes-unified-logging-and-timing). +```shell +titanium run -c twp.yaml +titanium test -c twp.yaml +titanium version --check +titanium update +``` + +Each CLI zip also includes a `twp` alias binary. + +Optional Plus: run `titanium update --plus` (add `--channel beta` for prereleases), then enable Plus in config (`plus.enabled: true` with `plus.controlPlane.sharedSecret`). Check with `titanium version --check --plus`. + +### Titanium Inspector + +Prefer [Download](https://titaniumproxy.com/download). On Windows, winget id `justcoding121.TitaniumInspector` is **stable-only**; MSI / portable zip for beta come from the product `v*` release (e.g. `v7.0.0-beta`). Start interception from the Capture menu, install the root CA, then toggle system proxy. ## Quick start @@ -102,31 +127,36 @@ Task OnRequest(object sender, SessionEventArgs e) Configure your client to use `127.0.0.1:8000` as its HTTP and HTTPS proxy. Trusting a generated root certificate changes the current user's certificate store; only do this on a machine you control. +## Performance + +Typically at or above **YARP**; ahead of **nginx** on H2/H3→H1 reverse, near parity for the rest (nginx still edges tiny keep-alive). Details: [Performance](https://github.com/justcoding121/titanium-web-proxy/wiki/Performance). + ## Examples and documentation -- [Wiki](https://github.com/justcoding121/titanium-web-proxy/wiki) — feature guides, including [performance measurements](https://github.com/justcoding121/titanium-web-proxy/wiki/Performance), [streaming request/response bodies](https://github.com/justcoding121/titanium-web-proxy/wiki/Streaming-Bodies), the [HTTP/3 setup guide](https://github.com/justcoding121/titanium-web-proxy/wiki/HTTP-3), and a [protocol feature support matrix](https://github.com/justcoding121/titanium-web-proxy/wiki/Protocol-Support) (what's supported for HTTP/1.x, HTTP/2, and HTTP/3, including [protocol bridges](https://github.com/justcoding121/titanium-web-proxy/wiki/Protocol-Support#protocol-bridges)) +- **[Website](https://titaniumproxy.com)**: product docs, [download](https://titaniumproxy.com/download), and [release notes](https://titaniumproxy.com/releases) +- [Wiki](https://github.com/justcoding121/titanium-web-proxy/wiki): additional feature guides (also mirrored on the website), including [performance measurements](https://github.com/justcoding121/titanium-web-proxy/wiki/Performance), [streaming request/response bodies](https://github.com/justcoding121/titanium-web-proxy/wiki/Streaming-Bodies), the [HTTP/3 setup guide](https://github.com/justcoding121/titanium-web-proxy/wiki/HTTP-3), and a [protocol feature support matrix](https://github.com/justcoding121/titanium-web-proxy/wiki/Protocol-Support) (what's supported for HTTP/1.x, HTTP/2, and HTTP/3, including [protocol bridges](https://github.com/justcoding121/titanium-web-proxy/wiki/Protocol-Support#protocol-bridges)) - [Basic console proxy](examples/Titanium.Web.Proxy.Examples.Basic) - [WPF proxy application](examples/Titanium.Web.Proxy.Examples.Wpf) - [Windows service](examples/Titanium.Web.Proxy.Examples.WindowsService) -- [Benchmarks](benchmarks/Titanium.Web.Proxy.Benchmarks) — loopback throughput and allocation (BenchmarkDotNet) -- [RPS saturation probe](tools/RpsLoadProbe) — concurrent breaking-point RPS (local cool lab + manual GitHub Linux/Windows VMs) -- [API documentation](https://justcoding121.github.io/titanium-web-proxy/docs/api/Titanium.Web.Proxy.ProxyServer.html) +- [Benchmarks](benchmarks/Titanium.Web.Proxy.Benchmarks): loopback throughput and allocation (BenchmarkDotNet) +- [RPS saturation probe](tools/RpsLoadProbe): concurrent breaking-point RPS +- [API documentation](https://titaniumproxy.com/api/Titanium.Web.Proxy.ProxyServer.html) ### Screenshots -**Basic console example** — compact per-request traffic tape: +**Titanium Inspector:** session grid with request/response details: -Basic console proxy screenshot +Titanium Inspector screenshot -**WPF example** — session list with request/response inspection: +**Basic console example:** compact per-request traffic tape: -WPF proxy application screenshot +Basic console proxy screenshot ## Support and contributing - Report reproducible bugs and feature requests through [GitHub Issues](https://github.com/justcoding121/Titanium-Web-Proxy/issues). - Ask programming questions on [Stack Overflow](https://stackoverflow.com/questions/tagged/titanium-web-proxy) using the `titanium-web-proxy` tag. -- Pull requests are welcome. Please include tests for behavior changes when practical. +- Pull requests are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md). ## Maintainers @@ -140,4 +170,4 @@ Past contributors: ## License -Titanium Web Proxy is available under the [MIT License](LICENSE). +Titanium.Web.Proxy and Titanium.Cli are available under the [MIT License](LICENSE). Titanium Inspector and Titanium.Plus are licensed under [PolyForm Noncommercial 1.0.0](licenses/PolyForm-Noncommercial-1.0.0.txt). diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..4e1bd0f6f --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,17 @@ +# Security Policy + +## Supported versions + +Security fixes are applied to the latest released major version on the default branch (`develop` / published releases). Older majors may not receive patches. + +## Reporting a vulnerability + +Please **do not** open a public GitHub issue for unfixed security vulnerabilities. + +Use GitHub’s private vulnerability reporting for this repository: + +1. Open the repository **Security** tab +2. Choose **Report a vulnerability** +3. Include steps to reproduce, impact, and affected versions when possible + +We will acknowledge the report, triage it privately, and coordinate disclosure through a security advisory when appropriate. diff --git a/docs/BRANCH-PROTECTION.html b/docs/BRANCH-PROTECTION.html new file mode 100644 index 000000000..3f3f30e7f --- /dev/null +++ b/docs/BRANCH-PROTECTION.html @@ -0,0 +1,170 @@ + + + + + + + + Branch protection (beta / stable) | Titanium Web Proxy + + + + + + + + + + + + + + + +
+
+ + + + +
+
+ +
+
Search Results for
+
+

+
+
    +
    +
    + + + +
    + + + + + + diff --git a/docs/api/Titanium.Web.Proxy.Caching.HttpResponseCacheMiddleware.html b/docs/api/Titanium.Web.Proxy.Caching.HttpResponseCacheMiddleware.html new file mode 100644 index 000000000..166f41ac3 --- /dev/null +++ b/docs/api/Titanium.Web.Proxy.Caching.HttpResponseCacheMiddleware.html @@ -0,0 +1,302 @@ + + + + + + + + Class HttpResponseCacheMiddleware | Titanium Web Proxy + + + + + + + + + + + + + + + +
    +
    + + + + +
    +
    + +
    +
    Search Results for
    +
    +

    +
    +
      +
      +
      + + + +
      + + + + + + diff --git a/docs/api/Titanium.Web.Proxy.Caching.MemoryHttpResponseCache.html b/docs/api/Titanium.Web.Proxy.Caching.MemoryHttpResponseCache.html new file mode 100644 index 000000000..a65f152ba --- /dev/null +++ b/docs/api/Titanium.Web.Proxy.Caching.MemoryHttpResponseCache.html @@ -0,0 +1,345 @@ + + + + + + + + Class MemoryHttpResponseCache | Titanium Web Proxy + + + + + + + + + + + + + + + +
      +
      + + + + +
      +
      + +
      +
      Search Results for
      +
      +

      +
      +
        +
        +
        + + + +
        + + + + + + diff --git a/docs/api/Titanium.Web.Proxy.Caching.html b/docs/api/Titanium.Web.Proxy.Caching.html new file mode 100644 index 000000000..7a18880f2 --- /dev/null +++ b/docs/api/Titanium.Web.Proxy.Caching.html @@ -0,0 +1,133 @@ + + + + + + + + Namespace Titanium.Web.Proxy.Caching | Titanium Web Proxy + + + + + + + + + + + + + + + +
        +
        + + + + +
        +
        + +
        +
        Search Results for
        +
        +

        +
        +
          +
          +
          + + + +
          + + + + + + diff --git a/docs/api/Titanium.Web.Proxy.Clusters.ClusterManager.html b/docs/api/Titanium.Web.Proxy.Clusters.ClusterManager.html new file mode 100644 index 000000000..7cce493a7 --- /dev/null +++ b/docs/api/Titanium.Web.Proxy.Clusters.ClusterManager.html @@ -0,0 +1,341 @@ + + + + + + + + Class ClusterManager | Titanium Web Proxy + + + + + + + + + + + + + + + +
          +
          + + + + +
          +
          + +
          +
          Search Results for
          +
          +

          +
          +
            +
            +
            + + + +
            + + + + + + diff --git a/docs/api/Titanium.Web.Proxy.Clusters.DestinationHealthTracker.html b/docs/api/Titanium.Web.Proxy.Clusters.DestinationHealthTracker.html new file mode 100644 index 000000000..817a15531 --- /dev/null +++ b/docs/api/Titanium.Web.Proxy.Clusters.DestinationHealthTracker.html @@ -0,0 +1,332 @@ + + + + + + + + Class DestinationHealthTracker | Titanium Web Proxy + + + + + + + + + + + + + + + +
            +
            + + + + +
            +
            + +
            +
            Search Results for
            +
            +

            +
            +
              +
              +
              + + + +
              + + + + + + diff --git a/docs/api/Titanium.Web.Proxy.Clusters.LoadBalancer.html b/docs/api/Titanium.Web.Proxy.Clusters.LoadBalancer.html new file mode 100644 index 000000000..ffd2c4341 --- /dev/null +++ b/docs/api/Titanium.Web.Proxy.Clusters.LoadBalancer.html @@ -0,0 +1,475 @@ + + + + + + + + Class LoadBalancer | Titanium Web Proxy + + + + + + + + + + + + + + + +
              +
              + + + + +
              +
              + +
              +
              Search Results for
              +
              +

              +
              +
                +
                +
                + + + +
                + + + + + + diff --git a/docs/api/Titanium.Web.Proxy.Clusters.html b/docs/api/Titanium.Web.Proxy.Clusters.html new file mode 100644 index 000000000..40156b23b --- /dev/null +++ b/docs/api/Titanium.Web.Proxy.Clusters.html @@ -0,0 +1,136 @@ + + + + + + + + Namespace Titanium.Web.Proxy.Clusters | Titanium Web Proxy + + + + + + + + + + + + + + + +
                +
                + + + + +
                +
                + +
                +
                Search Results for
                +
                +

                +
                +
                  +
                  +
                  + + + +
                  + + + + + + diff --git a/docs/api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html b/docs/api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html index 5ea40ec08..683bfe7db 100644 --- a/docs/api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html +++ b/docs/api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html @@ -228,7 +228,7 @@

                  Properties Edit this page - View Source + View Source

                  IdleReadTimeout

                  @@ -260,7 +260,7 @@
                  Property Value
                  Edit this page - View Source + View Source

                  IdleWriteTimeout

                  @@ -292,7 +292,7 @@
                  Property Value
                  Edit this page - View Source + View Source

                  IsPromise

                  @@ -323,7 +323,7 @@
                  Property Value
                  Edit this page - View Source + View Source

                  MaxBufferedBodyBytes

                  @@ -356,7 +356,7 @@
                  Property Value
                  Edit this page - View Source + View Source

                  MaxWebSocketFramePayloadBytes

                  @@ -389,7 +389,7 @@
                  Property Value
                  Edit this page - View Source + View Source

                  NetworkFailureRetryAttempts

                  @@ -422,7 +422,7 @@
                  Property Value
                  Edit this page - View Source + View Source

                  OriginHttpVersionPolicy

                  @@ -455,7 +455,7 @@
                  Property Value
                  Edit this page - View Source + View Source

                  ReRequest

                  @@ -486,7 +486,7 @@
                  Property Value
                  Edit this page - View Source + View Source

                  RequestTimeout

                  @@ -518,7 +518,7 @@
                  Property Value
                  Edit this page - View Source + View Source

                  ResponseHeaderTimeout

                  @@ -550,7 +550,7 @@
                  Property Value
                  Edit this page - View Source + View Source

                  UpstreamHttpProtocol

                  @@ -590,7 +590,7 @@
                  Property Value
                  Edit this page - View Source + View Source

                  WebSocketClientWriter

                  @@ -622,7 +622,7 @@
                  Property Value
                  Edit this page - View Source + View Source

                  WebSocketDecoder

                  @@ -653,7 +653,7 @@
                  Property Value
                  Edit this page - View Source + View Source

                  WebSocketDecoderReceive

                  @@ -683,7 +683,7 @@
                  Property Value
                  Edit this page - View Source + View Source

                  WebSocketDecoderSend

                  @@ -713,7 +713,7 @@
                  Property Value
                  Edit this page - View Source + View Source

                  WebSocketServerWriter

                  @@ -747,7 +747,7 @@

                  Methods Edit this page - View Source + View Source

                  Dispose(bool)

                  @@ -781,7 +781,7 @@
                  Overrides
                  Edit this page - View Source + View Source

                  DrainClientBodyAsync(CancellationToken)

                  @@ -828,7 +828,7 @@
                  Returns
                  Remarks
                  -

                  Useful when short-circuiting a request (e.g. Respond(Response, bool), RespondStreaming(Response, Func<Stream, CancellationToken, Task>, bool), or +

                  Useful when short-circuiting a request (e.g. Respond(Response, bool), RespondStreaming(StreamingProxyResult, bool), or blocking) while the client is uploading a body: draining leaves the client connection in a reusable state. Note the proxy already drains the client body automatically on the normal synthetic-response path, so this is only needed for advanced/manual control. @@ -840,7 +840,7 @@

                  Edit this page - View Source + View Source

                  DrainServerBodyAsync(CancellationToken)

                  @@ -1110,7 +1110,7 @@
                  Parameters
                  Edit this page - View Source + View Source

                  GetRequestBody(CancellationToken)

                  @@ -1160,7 +1160,7 @@
                  Returns
                  Edit this page - View Source + View Source

                  GetRequestBodyAsString(CancellationToken)

                  @@ -1210,7 +1210,7 @@
                  Returns
                  Edit this page - View Source + View Source

                  GetResponseBody(CancellationToken)

                  @@ -1260,7 +1260,7 @@
                  Returns
                  Edit this page - View Source + View Source

                  GetResponseBodyAsString(CancellationToken)

                  @@ -1404,7 +1404,7 @@
                  Parameters
                  Edit this page - View Source + View Source

                  Ok(string, IDictionary<string, HttpHeader>?, bool)

                  @@ -1451,7 +1451,7 @@
                  Parameters
                  Edit this page - View Source + View Source

                  Ok(string, IEnumerable<HttpHeader>?, bool)

                  @@ -1585,7 +1585,7 @@
                  Edit this page - View Source + View Source

                  RespondStreaming(Response, Func<Stream, CancellationToken, Task>, bool)

                  @@ -1636,12 +1636,53 @@
                  Respond(Response, bool) for the server body syphon-vs-close trade-off controlled by closeServerConnection.

                  + + | + Edit this page + + + View Source + + +

                  RespondStreaming(StreamingProxyResult, bool)

                  + +
                  +
                  Declaration
                  +
                  +
                  public void RespondStreaming(StreamingProxyResult result, bool closeServerConnection)
                  +
                  +
                  Parameters
                  + + + + + + + + + + + + + + + + + + + + +
                  TypeNameDescription
                  StreamingProxyResultresult

                  Streaming response metadata and body writer.

                  +
                  boolcloseServerConnection

                  Close the server connection used by request if any?

                  +
                  | Edit this page - View Source + View Source

                  SetRequestBody(byte[])

                  @@ -1675,7 +1716,7 @@
                  Parameters
                  Edit this page - View Source + View Source

                  SetRequestBodyString(string)

                  @@ -1709,7 +1750,7 @@
                  Parameters
                  Edit this page - View Source + View Source

                  SetResponseBody(byte[])

                  @@ -1743,7 +1784,7 @@
                  Parameters
                  Edit this page - View Source + View Source

                  SetResponseBodyString(string)

                  @@ -1777,7 +1818,7 @@
                  Parameters
                  Edit this page - View Source + View Source

                  TerminateServerConnection()

                  @@ -1795,7 +1836,7 @@

                  Events Edit this page - View Source + View Source

                  BeforeWebSocketFrame

                  Fired for each WebSocket frame after upgrade when at least one handler is subscribed. @@ -1831,7 +1872,7 @@

                  Event Type
                  Edit this page - View Source + View Source

                  MultipartRequestPartSent

                  Occurs when multipart request part sent.

                  diff --git a/docs/api/Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html b/docs/api/Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html index 6f5b4b7a7..44978b9d1 100644 --- a/docs/api/Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html +++ b/docs/api/Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html @@ -427,7 +427,7 @@
                  Property Value
                  Edit this page - View Source + View Source

                  Exception

                  @@ -520,7 +520,7 @@
                  Property Value
                  Edit this page - View Source + View Source

                  IsSocks

                  @@ -551,7 +551,7 @@
                  Property Value
                  Edit this page - View Source + View Source

                  IsTransparent

                  @@ -582,7 +582,7 @@
                  Property Value
                  Edit this page - View Source + View Source

                  LocalEndPoint

                  @@ -613,7 +613,7 @@
                  Property Value
                  Edit this page - View Source + View Source

                  Logger

                  @@ -646,7 +646,7 @@
                  Property Value
                  Edit this page - View Source + View Source

                  ProxyEndPoint

                  @@ -914,7 +914,7 @@

                  Methods Edit this page - View Source + View Source

                  Dispose()

                  @@ -930,7 +930,7 @@
                  Declaration
                  Edit this page - View Source + View Source

                  Dispose(bool)

                  @@ -962,7 +962,7 @@
                  Parameters
                  Edit this page - View Source + View Source

                  OnException(Exception)

                  @@ -994,7 +994,7 @@
                  Parameters
                  Edit this page - View Source + View Source

                  TerminateSession()

                  @@ -1012,7 +1012,7 @@

                  Events Edit this page - View Source + View Source

                  DataReceived

                  Fired when data is received within this session from client/server.

                  @@ -1042,7 +1042,7 @@
                  Event Type
                  Edit this page - View Source + View Source

                  DataSent

                  Fired when data is sent within this session to server/client.

                  diff --git a/docs/api/Titanium.Web.Proxy.Http.ProxyResults.html b/docs/api/Titanium.Web.Proxy.Http.ProxyResults.html new file mode 100644 index 000000000..1f6f15c1e --- /dev/null +++ b/docs/api/Titanium.Web.Proxy.Http.ProxyResults.html @@ -0,0 +1,734 @@ + + + + + + + + Class ProxyResults | Titanium Web Proxy + + + + + + + + + + + + + + + +
                  +
                  + + + + +
                  +
                  + +
                  +
                  Search Results for
                  +
                  +

                  +
                  +
                    +
                    +
                    + + + +
                    + + + + + + diff --git a/docs/api/Titanium.Web.Proxy.Http.StreamingProxyResult.html b/docs/api/Titanium.Web.Proxy.Http.StreamingProxyResult.html new file mode 100644 index 000000000..e2cf3a098 --- /dev/null +++ b/docs/api/Titanium.Web.Proxy.Http.StreamingProxyResult.html @@ -0,0 +1,275 @@ + + + + + + + + Struct StreamingProxyResult | Titanium Web Proxy + + + + + + + + + + + + + + + +
                    +
                    + + + + +
                    +
                    + +
                    +
                    Search Results for
                    +
                    +

                    +
                    +
                      +
                      +
                      + + + +
                      + + + + + + diff --git a/docs/api/Titanium.Web.Proxy.Http.html b/docs/api/Titanium.Web.Proxy.Http.html index fa354889a..b39df4e74 100644 --- a/docs/api/Titanium.Web.Proxy.Http.html +++ b/docs/api/Titanium.Web.Proxy.Http.html @@ -101,6 +101,11 @@

                      KnownHeader<

                      KnownHeaders

                      Well known http headers.

                      +
                      +

                      ProxyResults

                      +

                      Factory methods that build synthetic Response or StreamingProxyResult +objects for use with Respond(Response, bool) and +RespondStreaming(StreamingProxyResult, bool).

                      Request

                      Http(s) request object

                      @@ -120,6 +125,11 @@

                      GetEnumerator() for why this is worth a hand-written enumerator instead of the equivalent LINQ expression.

                      +

                      +

                      StreamingProxyResult

                      +

                      Pairs a synthetic response (status and headers) with a delegate that writes the body on the fly. +Pass to RespondStreaming(StreamingProxyResult, bool) to +stream without buffering the whole body in memory.

                      Enums diff --git a/docs/api/Titanium.Web.Proxy.Logging.ProxyLoggingOptions.html b/docs/api/Titanium.Web.Proxy.Logging.ProxyLoggingOptions.html index eab59ed1e..2000b9c26 100644 --- a/docs/api/Titanium.Web.Proxy.Logging.ProxyLoggingOptions.html +++ b/docs/api/Titanium.Web.Proxy.Logging.ProxyLoggingOptions.html @@ -128,12 +128,13 @@

                      Properties Edit this page - View Source + View Source

                      EnableConsole

                      -

                      Whether the built-in console sink is active. Defaults to true. Ignored when -LoggerFactory is set.

                      +

                      Whether the built-in async console sink is active. Defaults to true so +Error+ failures are visible without configuration. Ignored when LoggerFactory +is set. Writes never block session threads (bounded channel + background writer).

                      Declaration
                      @@ -160,7 +161,7 @@
                      Property Value
                      Edit this page - View Source + View Source

                      EnableConsoleColors

                      @@ -198,7 +199,7 @@
                      Property Value
                      Edit this page - View Source + View Source

                      EnableFile

                      @@ -230,14 +231,15 @@
                      Property Value
                      Edit this page - View Source + View Source

                      Enabled

                      -

                      Master switch for all proxy logging. When false (default is -true) the proxy uses a no-op logger; no log-related work of any kind is -performed anywhere in the library, so this is the zero-overhead configuration for users who -do not want logging at all.

                      +

                      Master switch for all proxy logging. Defaults to true so NuGet consumers +surface real failures out of the box (paired with MinimumLevel of Error and +the async console sink). Set to false for zero overhead: the proxy uses a +no-op logger and performs no log-related work (preferred for probes and perf-sensitive hosts). +Host apps should treat richer levels/file sinks as Debug-on / Release-opt-in.

                      Declaration
                      @@ -264,7 +266,7 @@
                      Property Value
                      Edit this page - View Source + View Source

                      FilePath

                      @@ -296,7 +298,7 @@
                      Property Value
                      Edit this page - View Source + View Source

                      LoggerFactory

                      @@ -329,7 +331,7 @@
                      Property Value
                      Edit this page - View Source + View Source

                      MaxFileSizeBytes

                      @@ -360,7 +362,7 @@
                      Property Value
                      Edit this page - View Source + View Source

                      MaxRolledFiles

                      @@ -391,15 +393,16 @@
                      Property Value
                      Edit this page - View Source + View Source

                      MinimumLevel

                      The minimum LogLevel that is actually written to any sink. Every caught exception in the proxy is still reported to the gateway regardless of this setting - this only controls how much of that stream is materialized/written. Defaults to -Error so out-of-the-box behavior stays quiet, while still surfacing -every genuinely unexpected failure.

                      +Error so out-of-the-box NuGet behavior stays quiet while still +surfacing genuinely unexpected failures. Raise the level (and/or enable file) only when +diagnosing.

                      Declaration
                      @@ -426,7 +429,7 @@
                      Property Value
                      Edit this page - View Source + View Source

                      QueueCapacity

                      diff --git a/docs/api/Titanium.Web.Proxy.Middleware.ProxyMiddlewarePipeline.html b/docs/api/Titanium.Web.Proxy.Middleware.ProxyMiddlewarePipeline.html new file mode 100644 index 000000000..f1c443e73 --- /dev/null +++ b/docs/api/Titanium.Web.Proxy.Middleware.ProxyMiddlewarePipeline.html @@ -0,0 +1,276 @@ + + + + + + + + Class ProxyMiddlewarePipeline | Titanium Web Proxy + + + + + + + + + + + + + + + +
                      +
                      + + + + +
                      +
                      + +
                      +
                      Search Results for
                      +
                      +

                      +
                      +
                        +
                        +
                        + + + +
                        + + + + + + diff --git a/docs/api/Titanium.Web.Proxy.Middleware.html b/docs/api/Titanium.Web.Proxy.Middleware.html new file mode 100644 index 000000000..9bb91b3af --- /dev/null +++ b/docs/api/Titanium.Web.Proxy.Middleware.html @@ -0,0 +1,129 @@ + + + + + + + + Namespace Titanium.Web.Proxy.Middleware | Titanium Web Proxy + + + + + + + + + + + + + + + +
                        +
                        + + + + +
                        +
                        + +
                        +
                        Search Results for
                        +
                        +

                        +
                        +
                          +
                          +
                          + + + +
                          + + + + + + diff --git a/docs/api/Titanium.Web.Proxy.Network.CertificateManager.html b/docs/api/Titanium.Web.Proxy.Network.CertificateManager.html index a2d9b1b23..667ca75e9 100644 --- a/docs/api/Titanium.Web.Proxy.Network.CertificateManager.html +++ b/docs/api/Titanium.Web.Proxy.Network.CertificateManager.html @@ -127,7 +127,7 @@

                          Properties Edit this page - View Source + View Source

                          CertificateCacheTimeOutMinutes

                          @@ -228,7 +228,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          CertificateStorage

                          @@ -301,7 +301,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          DisableWildCardCertificates

                          @@ -447,7 +447,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          OverwritePfxFile

                          @@ -677,7 +677,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          StorageFlag

                          @@ -705,12 +705,36 @@
                          Property Value

                          Methods

                          + + | + Edit this page + + + View Source + + +

                          ApplyFastColdStartLeafSettings()

                          +

                          Fast first-visit MITM for modern TLS clients (browsers, current HttpClient): +BouncyCastleFast, ECDSA P-256 leaves, and +SaveFakeCertificates enabled. The root CA stays RSA.

                          +

                          + Library Balanced still defaults to RSA-2048 leaves for + widest compatibility. Call this from Inspector, CLI, and desktop MITM hosts where clients + are known to accept ECDSA server certificates — RSA leaf generation is the dominant + cold-start cost when a page hits many not-yet-seen hosts (often ~1 s per host). +

                          +
                          +
                          +
                          Declaration
                          +
                          +
                          public void ApplyFastColdStartLeafSettings()
                          +
                          | Edit this page - View Source + View Source

                          ClearRootCertificate()

                          @@ -726,7 +750,7 @@
                          Declaration
                          Edit this page - View Source + View Source

                          CreateRootCertificate(bool)

                          @@ -776,7 +800,7 @@
                          Returns
                          Edit this page - View Source + View Source

                          CreateServerCertificate(string)

                          @@ -824,7 +848,7 @@
                          Returns
                          Edit this page - View Source + View Source

                          Dispose()

                          @@ -840,7 +864,7 @@
                          Declaration
                          Edit this page - View Source + View Source

                          EnsureRootCertificate()

                          @@ -857,7 +881,7 @@
                          Declaration
                          Edit this page - View Source + View Source

                          EnsureRootCertificate(bool, bool, bool)

                          @@ -905,7 +929,7 @@
                          Parameters
                          Edit this page - View Source + View Source

                          IsRootCertificateMachineTrusted()

                          @@ -936,7 +960,7 @@
                          Returns
                          Edit this page - View Source + View Source

                          IsRootCertificateUserTrusted()

                          @@ -967,7 +991,7 @@
                          Returns
                          Edit this page - View Source + View Source

                          LoadRootCertificate()

                          @@ -999,7 +1023,7 @@
                          Returns
                          Edit this page - View Source + View Source

                          LoadRootCertificate(string, string, bool, X509KeyStorageFlags)

                          @@ -1068,7 +1092,7 @@
                          Returns
                          Edit this page - View Source + View Source

                          RemoveTrustedRootCertificate(bool)

                          @@ -1104,7 +1128,7 @@
                          Parameters
                          Edit this page - View Source + View Source

                          RemoveTrustedRootCertificateAsAdmin(bool)

                          @@ -1153,7 +1177,7 @@
                          Returns
                          Edit this page - View Source + View Source

                          TrustRootCertificate(bool)

                          @@ -1191,7 +1215,7 @@
                          Parameters
                          Edit this page - View Source + View Source

                          TrustRootCertificateAsAdmin(bool)

                          diff --git a/docs/api/Titanium.Web.Proxy.ProxyServer.html b/docs/api/Titanium.Web.Proxy.ProxyServer.html index 532fd99af..b586bee70 100644 --- a/docs/api/Titanium.Web.Proxy.ProxyServer.html +++ b/docs/api/Titanium.Web.Proxy.ProxyServer.html @@ -147,7 +147,7 @@

                          Constructors Edit this page - View Source + View Source

                          ProxyServer(bool, bool, bool)

                          @@ -196,7 +196,7 @@
                          Parameters
                          Edit this page - View Source + View Source

                          ProxyServer(string?, string?, bool, bool, bool)

                          @@ -259,7 +259,7 @@

                          Properties Edit this page - View Source + View Source

                          AdmittedClientConnectionCount

                          @@ -293,7 +293,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          BlockPrivateNetworkDestinations

                          @@ -345,7 +345,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          BufferPool

                          @@ -379,7 +379,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          CertificateManager

                          @@ -410,7 +410,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          CheckCertificateRevocation

                          @@ -442,7 +442,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          ClientConnectionCount

                          @@ -474,7 +474,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          ClientHeaderTimeoutSeconds

                          @@ -514,7 +514,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          CompatibilityMode100Continue

                          @@ -552,7 +552,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          ConnectTimeOutSeconds

                          @@ -584,7 +584,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          ConnectionTimeOutSeconds

                          @@ -617,7 +617,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          CustomUpStreamProxyFailureFunc

                          @@ -649,7 +649,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          DnsServerEndPoint

                          @@ -689,7 +689,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          Enable100ContinueBehaviour

                          @@ -722,7 +722,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          EnableConnectionPool

                          @@ -764,7 +764,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          EnableHttp2

                          @@ -808,7 +808,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          EnableHttp3

                          @@ -862,7 +862,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          EnableHttpInterception

                          @@ -895,7 +895,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          EnableHttpsSvcbDnsDiscovery

                          @@ -937,7 +937,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          EnableIpv6UnreachableSoftSkip

                          @@ -972,7 +972,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          EnableQpackDynamicTable

                          @@ -1007,7 +1007,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          EnableRequestTimingCapture

                          @@ -1054,7 +1054,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          EnableRfc8441

                          @@ -1100,7 +1100,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          EnableTcpKeepAlive

                          @@ -1132,7 +1132,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          EnableTcpServerConnectionPrefetch

                          @@ -1170,7 +1170,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          EnableWinAuth

                          @@ -1203,7 +1203,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          EndpointAdmissionRejectionCount

                          @@ -1235,7 +1235,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          ForwardToUpstreamGateway

                          @@ -1267,7 +1267,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          GetCustomUpStreamProxyFunc

                          @@ -1299,7 +1299,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          GlobalAdmissionRejectionCount

                          @@ -1331,7 +1331,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          Http3ClientConnectionCount

                          @@ -1362,7 +1362,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          Http3ServerConnectionCount

                          @@ -1394,7 +1394,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          IdleReadTimeoutSeconds

                          @@ -1427,7 +1427,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          IdleWriteTimeoutSeconds

                          @@ -1460,7 +1460,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          ListenerBackLog

                          @@ -1491,7 +1491,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          Logger

                          @@ -1523,7 +1523,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          Logging

                          @@ -1564,7 +1564,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          MaxBufferedBodyBytes

                          @@ -1599,7 +1599,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          MaxCachedConnections

                          @@ -1653,7 +1653,7 @@
                          Exceptions
                          Edit this page - View Source + View Source

                          MaxConcurrentClientConnections

                          @@ -1693,7 +1693,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          MaxConcurrentHttp11HttpsOriginCreates

                          @@ -1744,7 +1744,7 @@
                          Exceptions
                          Edit this page - View Source + View Source

                          MaxDecodedHeaderListBytes

                          @@ -1779,7 +1779,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          MaxWebSocketFramePayloadBytes

                          @@ -1816,7 +1816,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          NetworkFailureRetryAttempts

                          @@ -1847,7 +1847,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          NoDelay

                          @@ -1879,7 +1879,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          OriginHttpVersionPolicy

                          @@ -1918,7 +1918,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          PolicyModes

                          @@ -1961,7 +1961,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          Profile

                          @@ -2007,7 +2007,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          ProxyAuthenticationRealm

                          @@ -2038,7 +2038,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          ProxyAuthenticationSchemes

                          @@ -2071,7 +2071,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          ProxyBasicAuthenticateFunc

                          @@ -2104,7 +2104,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          ProxyEndPoints

                          @@ -2135,7 +2135,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          ProxyRunning

                          @@ -2166,7 +2166,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          ProxySchemeAuthenticateFunc

                          @@ -2200,7 +2200,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          RequestTimeoutSeconds

                          @@ -2234,7 +2234,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          ResourceLimits

                          @@ -2275,7 +2275,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          ResponseHeaderTimeoutSeconds

                          @@ -2315,7 +2315,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          ReuseSocket

                          @@ -2343,12 +2343,44 @@
                          Property Value
                          + + | + Edit this page + + + View Source + + +

                          ReverseProxy

                          +

                          Optional reverse-proxy route/cluster configuration. When null (default), +Core keeps 6.x ForwardHost behavior with zero added cost on the hot path.

                          +
                          +
                          +
                          Declaration
                          +
                          +
                          public ReverseProxyOptions? ReverseProxy { get; set; }
                          +
                          +
                          Property Value
                          + + + + + + + + + + + + + +
                          TypeDescription
                          ReverseProxyOptions
                          | Edit this page - View Source + View Source

                          ServerConnectionCount

                          @@ -2380,7 +2412,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          ShouldInterceptHttp

                          @@ -2414,7 +2446,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          SupportedServerSslProtocols

                          @@ -2446,7 +2478,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          SupportedSslProtocols

                          @@ -2484,7 +2516,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          TcpTimeWaitSeconds

                          @@ -2520,7 +2552,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          ThreadPoolWorkerThread

                          @@ -2553,7 +2585,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          UpStreamEndPoint

                          @@ -2588,7 +2620,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          UpStreamEndPointIPv4

                          @@ -2620,7 +2652,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          UpStreamEndPointIPv6

                          @@ -2652,7 +2684,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          UpStreamHttpProxy

                          @@ -2683,7 +2715,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          UpStreamHttpsProxy

                          @@ -2714,7 +2746,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          UpstreamProxyConfigurationScript

                          @@ -2745,7 +2777,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          ViaHeaderPseudonym

                          @@ -2779,7 +2811,7 @@
                          Property Value
                          Edit this page - View Source + View Source

                          WinAuthCredentialsProvider

                          @@ -2815,7 +2847,7 @@

                          Methods Edit this page - View Source + View Source

                          AddEndPoint(ProxyEndPoint)

                          @@ -2849,7 +2881,7 @@
                          Parameters
                          Edit this page - View Source + View Source

                          ApplyLoggingConfiguration()

                          @@ -2870,7 +2902,7 @@
                          Declaration
                          Edit this page - View Source + View Source

                          DisableAllSystemProxies()

                          @@ -2886,7 +2918,7 @@
                          Declaration
                          Edit this page - View Source + View Source

                          DisableSystemHttpProxy()

                          @@ -2902,7 +2934,7 @@
                          Declaration
                          Edit this page - View Source + View Source

                          DisableSystemHttpsProxy()

                          @@ -2918,7 +2950,7 @@
                          Declaration
                          Edit this page - View Source + View Source

                          DisableSystemProxy(ProxyProtocolType)

                          @@ -2951,7 +2983,7 @@
                          Parameters
                          Edit this page - View Source + View Source

                          Dispose()

                          @@ -2967,7 +2999,7 @@
                          Declaration
                          Edit this page - View Source + View Source

                          Dispose(bool)

                          @@ -3000,7 +3032,7 @@
                          Parameters
                          Edit this page - View Source + View Source

                          RemoveEndPoint(ProxyEndPoint)

                          @@ -3035,7 +3067,7 @@
                          Parameters
                          Edit this page - View Source + View Source

                          RestoreOriginalProxySettings()

                          @@ -3051,7 +3083,7 @@
                          Declaration
                          Edit this page - View Source + View Source

                          SetAsSystemHttpProxy(ExplicitProxyEndPoint)

                          @@ -3085,7 +3117,7 @@
                          Parameters
                          Edit this page - View Source + View Source

                          SetAsSystemHttpProxy(ExplicitProxyEndPoint, SystemProxySettings)

                          @@ -3125,7 +3157,7 @@
                          Parameters
                          Edit this page - View Source + View Source

                          SetAsSystemHttpsProxy(ExplicitProxyEndPoint)

                          @@ -3159,7 +3191,7 @@
                          Parameters
                          Edit this page - View Source + View Source

                          SetAsSystemHttpsProxy(ExplicitProxyEndPoint, SystemProxySettings)

                          @@ -3199,7 +3231,7 @@
                          Parameters
                          Edit this page - View Source + View Source

                          SetAsSystemProxy(ExplicitProxyEndPoint, ProxyProtocolType)

                          @@ -3239,7 +3271,7 @@
                          Parameters
                          Edit this page - View Source + View Source

                          SetAsSystemProxy(ExplicitProxyEndPoint, ProxyProtocolType, SystemProxySettings?)

                          @@ -3276,6 +3308,58 @@
                          Parameters
                          SystemProxySettings settings

                          The Windows system proxy settings, or null to preserve the current bypass list.

                          + + + + + + | + Edit this page + + + View Source + + +

                          SetHttp3Enabled(bool)

                          +

                          Enables or disables EnableHttp3. Enabling still requires MsQuic +(IsSupported); disabling is always applied. +Safe to call while the proxy is running — new origin connections pick up the change. +Existing sessions keep the protocol they already negotiated.

                          +
                          +
                          +
                          Declaration
                          +
                          +
                          public bool SetHttp3Enabled(bool enabled)
                          +
                          +
                          Parameters
                          + + + + + + + + + + + + + + + +
                          TypeNameDescription
                          boolenabled
                          +
                          Returns
                          + + + + + + + + + + + @@ -3285,7 +3369,7 @@
                          Parameters
                          Edit this page - View Source + View Source

                          Start(bool)

                          @@ -3328,7 +3412,7 @@
                          Parameters
                          Edit this page - View Source + View Source

                          Stop()

                          @@ -3347,7 +3431,7 @@
                          Declaration
                          Edit this page - View Source + View Source

                          StopAsync(TimeSpan?)

                          @@ -3393,6 +3477,40 @@
                          Returns
                          TypeDescription
                          bool

                          true when HTTP/3 is enabled after the call.

                          + + | + Edit this page + + + View Source + + +

                          TryEnableHttp3IfSupported()

                          +

                          Turns on EnableHttp3 when MsQuic is available +(IsSupported). Hosts (CLI, Inspector, examples) +should call this instead of setting EnableHttp3 blindly. Returns +true when HTTP/3 was enabled.

                          +
                          +
                          +
                          Declaration
                          +
                          +
                          public bool TryEnableHttp3IfSupported()
                          +
                          +
                          Returns
                          + + + + + + + + + + + + + +
                          TypeDescription
                          bool

                          Events

                          @@ -3400,7 +3518,7 @@

                          Events Edit this page - View Source + View Source

                          AfterResponse

                          Intercept after response event from server.

                          @@ -3430,7 +3548,7 @@
                          Event Type
                          Edit this page - View Source + View Source

                          BeforeRequest

                          Intercept request event to server.

                          @@ -3460,7 +3578,7 @@
                          Event Type
                          Edit this page - View Source + View Source

                          BeforeResponse

                          Intercept response event from server.

                          @@ -3490,7 +3608,7 @@
                          Event Type
                          Edit this page - View Source + View Source

                          BeforeUpStreamConnectRequest

                          Intercept connect request sent to upstream proxy.

                          @@ -3520,7 +3638,7 @@
                          Event Type
                          Edit this page - View Source + View Source

                          ClientCertificateSelectionCallback

                          Event to override client certificate selection during mutual SSL authentication.

                          @@ -3550,7 +3668,7 @@
                          Event Type
                          Edit this page - View Source + View Source

                          ClientConnectionCountChanged

                          Event occurs when client connection count changed.

                          @@ -3580,7 +3698,7 @@
                          Event Type
                          Edit this page - View Source + View Source

                          Http3ClientConnectionCountChanged

                          Event occurs when inbound HTTP/3 client connection count changed.

                          @@ -3610,7 +3728,7 @@
                          Event Type
                          Edit this page - View Source + View Source

                          Http3ServerConnectionCountChanged

                          Event occurs when upstream HTTP/3 server connection count changed.

                          @@ -3640,7 +3758,7 @@
                          Event Type
                          Edit this page - View Source + View Source

                          OnClientConnectionCreate

                          Customize TcpClient used for client connection upon create.

                          @@ -3670,7 +3788,7 @@
                          Event Type
                          Edit this page - View Source + View Source

                          OnRequestBodyWrite

                          Intercept request body send event to server. @@ -3702,7 +3820,7 @@

                          Event Type
                          Edit this page - View Source + View Source

                          OnResponseBodyWrite

                          Intercept response body send event to client. @@ -3734,7 +3852,7 @@

                          Event Type
                          Edit this page - View Source + View Source

                          OnServerConnectionCreate

                          Customize TcpClient used for server connection upon create.

                          @@ -3764,7 +3882,7 @@
                          Event Type
                          Edit this page - View Source + View Source

                          ServerCertificateValidationCallback

                          Event to override the default verification logic of remote SSL certificate received during authentication.

                          @@ -3794,7 +3912,7 @@
                          Event Type
                          Edit this page - View Source + View Source

                          ServerConnectionCountChanged

                          Event occurs when server connection count changed.

                          @@ -3835,7 +3953,7 @@

                          Implements

                          Edit this page
                        • - View Source + View Source
                        • diff --git a/docs/api/Titanium.Web.Proxy.Routing.ReverseProxyFastPath.html b/docs/api/Titanium.Web.Proxy.Routing.ReverseProxyFastPath.html new file mode 100644 index 000000000..8ce347443 --- /dev/null +++ b/docs/api/Titanium.Web.Proxy.Routing.ReverseProxyFastPath.html @@ -0,0 +1,230 @@ + + + + + + + + Class ReverseProxyFastPath | Titanium Web Proxy + + + + + + + + + + + + + + + +
                          +
                          + + + + +
                          +
                          + +
                          +
                          Search Results for
                          +
                          +

                          +
                          +
                            +
                            +
                            + + + +
                            + + + + + + diff --git a/docs/api/Titanium.Web.Proxy.Routing.RouteMatcher.html b/docs/api/Titanium.Web.Proxy.Routing.RouteMatcher.html new file mode 100644 index 000000000..2e0271ea5 --- /dev/null +++ b/docs/api/Titanium.Web.Proxy.Routing.RouteMatcher.html @@ -0,0 +1,224 @@ + + + + + + + + Class RouteMatcher | Titanium Web Proxy + + + + + + + + + + + + + + + +
                            +
                            + + + + +
                            +
                            + +
                            +
                            Search Results for
                            +
                            +

                            +
                            +
                              +
                              +
                              + + + +
                              + + + + + + diff --git a/docs/api/Titanium.Web.Proxy.Routing.html b/docs/api/Titanium.Web.Proxy.Routing.html new file mode 100644 index 000000000..86e9b996d --- /dev/null +++ b/docs/api/Titanium.Web.Proxy.Routing.html @@ -0,0 +1,132 @@ + + + + + + + + Namespace Titanium.Web.Proxy.Routing | Titanium Web Proxy + + + + + + + + + + + + + + + +
                              +
                              + + + + +
                              +
                              + +
                              +
                              Search Results for
                              +
                              +

                              +
                              +
                                +
                                +
                                + + + +
                                + + + + + + diff --git a/docs/api/Titanium.Web.Proxy.Transforms.TransformEngine.html b/docs/api/Titanium.Web.Proxy.Transforms.TransformEngine.html new file mode 100644 index 000000000..3981f943c --- /dev/null +++ b/docs/api/Titanium.Web.Proxy.Transforms.TransformEngine.html @@ -0,0 +1,209 @@ + + + + + + + + Class TransformEngine | Titanium Web Proxy + + + + + + + + + + + + + + + +
                                +
                                + + + + +
                                +
                                + +
                                +
                                Search Results for
                                +
                                +

                                +
                                +
                                  +
                                  +
                                  + + + +
                                  + + + + + + diff --git a/docs/api/Titanium.Web.Proxy.Transforms.html b/docs/api/Titanium.Web.Proxy.Transforms.html new file mode 100644 index 000000000..8df7b38a1 --- /dev/null +++ b/docs/api/Titanium.Web.Proxy.Transforms.html @@ -0,0 +1,129 @@ + + + + + + + + Namespace Titanium.Web.Proxy.Transforms | Titanium Web Proxy + + + + + + + + + + + + + + + +
                                  +
                                  + + + + +
                                  +
                                  + +
                                  +
                                  Search Results for
                                  +
                                  +

                                  +
                                  +
                                    +
                                    +
                                    + + + +
                                    + + + + + + diff --git a/docs/api/toc.html b/docs/api/toc.html index 39ac2b04a..1d7057a50 100644 --- a/docs/api/toc.html +++ b/docs/api/toc.html @@ -52,6 +52,35 @@ +
                                  • + + Titanium.Web.Proxy.Caching + + +
                                  • +
                                  • + + Titanium.Web.Proxy.Clusters + + +
                                  • Titanium.Web.Proxy.Diagnostics @@ -189,6 +218,9 @@
                                  • KnownHeaders
                                  • +
                                  • + ProxyResults +
                                  • Request
                                  • @@ -198,6 +230,9 @@
                                  • Response
                                  • +
                                  • + StreamingProxyResult +
                                  • TunnelType
                                  • @@ -229,6 +264,16 @@ +
                                  • + + Titanium.Web.Proxy.Middleware + + +
                                  • Titanium.Web.Proxy.Models @@ -350,6 +395,19 @@
                                  • +
                                  • + + Titanium.Web.Proxy.Routing + + +
                                  • Titanium.Web.Proxy.StreamExtended @@ -405,6 +463,16 @@
                                  • +
                                  • + + Titanium.Web.Proxy.Transforms + + +
                                  • diff --git a/docs/api/toc.json b/docs/api/toc.json index 9c7aae767..c1a2a01c3 100644 --- a/docs/api/toc.json +++ b/docs/api/toc.json @@ -1,2 +1,2 @@ -{"items":[{"name":"Titanium.Web.Proxy","href":"Titanium.Web.Proxy.html","topicHref":"Titanium.Web.Proxy.html","topicUid":"Titanium.Web.Proxy","type":"Namespace","items":[{"name":"ProxyLimits","href":"Titanium.Web.Proxy.ProxyLimits.html","topicHref":"Titanium.Web.Proxy.ProxyLimits.html","topicUid":"Titanium.Web.Proxy.ProxyLimits","type":"Class"},{"name":"ProxyServer","href":"Titanium.Web.Proxy.ProxyServer.html","topicHref":"Titanium.Web.Proxy.ProxyServer.html","topicUid":"Titanium.Web.Proxy.ProxyServer","type":"Class"},{"name":"SystemProxyBypassRuleMode","href":"Titanium.Web.Proxy.SystemProxyBypassRuleMode.html","topicHref":"Titanium.Web.Proxy.SystemProxyBypassRuleMode.html","topicUid":"Titanium.Web.Proxy.SystemProxyBypassRuleMode","type":"Enum"},{"name":"SystemProxyLoopbackPlacement","href":"Titanium.Web.Proxy.SystemProxyLoopbackPlacement.html","topicHref":"Titanium.Web.Proxy.SystemProxyLoopbackPlacement.html","topicUid":"Titanium.Web.Proxy.SystemProxyLoopbackPlacement","type":"Enum"},{"name":"SystemProxySettings","href":"Titanium.Web.Proxy.SystemProxySettings.html","topicHref":"Titanium.Web.Proxy.SystemProxySettings.html","topicUid":"Titanium.Web.Proxy.SystemProxySettings","type":"Class"},{"name":"WebSocketDecoder","href":"Titanium.Web.Proxy.WebSocketDecoder.html","topicHref":"Titanium.Web.Proxy.WebSocketDecoder.html","topicUid":"Titanium.Web.Proxy.WebSocketDecoder","type":"Class"},{"name":"WebSocketFrame","href":"Titanium.Web.Proxy.WebSocketFrame.html","topicHref":"Titanium.Web.Proxy.WebSocketFrame.html","topicUid":"Titanium.Web.Proxy.WebSocketFrame","type":"Class"},{"name":"WebSocketFrameEncoder","href":"Titanium.Web.Proxy.WebSocketFrameEncoder.html","topicHref":"Titanium.Web.Proxy.WebSocketFrameEncoder.html","topicUid":"Titanium.Web.Proxy.WebSocketFrameEncoder","type":"Class"},{"name":"WebSocketFrameWriter","href":"Titanium.Web.Proxy.WebSocketFrameWriter.html","topicHref":"Titanium.Web.Proxy.WebSocketFrameWriter.html","topicUid":"Titanium.Web.Proxy.WebSocketFrameWriter","type":"Class"},{"name":"WebSocketProtocolException","href":"Titanium.Web.Proxy.WebSocketProtocolException.html","topicHref":"Titanium.Web.Proxy.WebSocketProtocolException.html","topicUid":"Titanium.Web.Proxy.WebSocketProtocolException","type":"Class"},{"name":"WebsocketOpCode","href":"Titanium.Web.Proxy.WebsocketOpCode.html","topicHref":"Titanium.Web.Proxy.WebsocketOpCode.html","topicUid":"Titanium.Web.Proxy.WebsocketOpCode","type":"Enum"}]},{"name":"Titanium.Web.Proxy.Diagnostics","href":"Titanium.Web.Proxy.Diagnostics.html","topicHref":"Titanium.Web.Proxy.Diagnostics.html","topicUid":"Titanium.Web.Proxy.Diagnostics","type":"Namespace","items":[{"name":"ClientTlsTiming","href":"Titanium.Web.Proxy.Diagnostics.ClientTlsTiming.html","topicHref":"Titanium.Web.Proxy.Diagnostics.ClientTlsTiming.html","topicUid":"Titanium.Web.Proxy.Diagnostics.ClientTlsTiming","type":"Class"},{"name":"HttpRequestTiming","href":"Titanium.Web.Proxy.Diagnostics.HttpRequestTiming.html","topicHref":"Titanium.Web.Proxy.Diagnostics.HttpRequestTiming.html","topicUid":"Titanium.Web.Proxy.Diagnostics.HttpRequestTiming","type":"Class"},{"name":"TunnelConnectTiming","href":"Titanium.Web.Proxy.Diagnostics.TunnelConnectTiming.html","topicHref":"Titanium.Web.Proxy.Diagnostics.TunnelConnectTiming.html","topicUid":"Titanium.Web.Proxy.Diagnostics.TunnelConnectTiming","type":"Class"},{"name":"UpstreamConnectionTiming","href":"Titanium.Web.Proxy.Diagnostics.UpstreamConnectionTiming.html","topicHref":"Titanium.Web.Proxy.Diagnostics.UpstreamConnectionTiming.html","topicUid":"Titanium.Web.Proxy.Diagnostics.UpstreamConnectionTiming","type":"Class"}]},{"name":"Titanium.Web.Proxy.EventArguments","href":"Titanium.Web.Proxy.EventArguments.html","topicHref":"Titanium.Web.Proxy.EventArguments.html","topicUid":"Titanium.Web.Proxy.EventArguments","type":"Namespace","items":[{"name":"AsyncEventHandler","href":"Titanium.Web.Proxy.EventArguments.AsyncEventHandler-1.html","topicHref":"Titanium.Web.Proxy.EventArguments.AsyncEventHandler-1.html","topicUid":"Titanium.Web.Proxy.EventArguments.AsyncEventHandler`1","type":"Delegate"},{"name":"BeforeBodyWriteEventArgs","href":"Titanium.Web.Proxy.EventArguments.BeforeBodyWriteEventArgs.html","topicHref":"Titanium.Web.Proxy.EventArguments.BeforeBodyWriteEventArgs.html","topicUid":"Titanium.Web.Proxy.EventArguments.BeforeBodyWriteEventArgs","type":"Class"},{"name":"BeforeHttpAuthenticateEventArgs","href":"Titanium.Web.Proxy.EventArguments.BeforeHttpAuthenticateEventArgs.html","topicHref":"Titanium.Web.Proxy.EventArguments.BeforeHttpAuthenticateEventArgs.html","topicUid":"Titanium.Web.Proxy.EventArguments.BeforeHttpAuthenticateEventArgs","type":"Class"},{"name":"BeforeQuicAuthenticateEventArgs","href":"Titanium.Web.Proxy.EventArguments.BeforeQuicAuthenticateEventArgs.html","topicHref":"Titanium.Web.Proxy.EventArguments.BeforeQuicAuthenticateEventArgs.html","topicUid":"Titanium.Web.Proxy.EventArguments.BeforeQuicAuthenticateEventArgs","type":"Class"},{"name":"BeforeSslAuthenticateEventArgs","href":"Titanium.Web.Proxy.EventArguments.BeforeSslAuthenticateEventArgs.html","topicHref":"Titanium.Web.Proxy.EventArguments.BeforeSslAuthenticateEventArgs.html","topicUid":"Titanium.Web.Proxy.EventArguments.BeforeSslAuthenticateEventArgs","type":"Class"},{"name":"CertificateSelectionEventArgs","href":"Titanium.Web.Proxy.EventArguments.CertificateSelectionEventArgs.html","topicHref":"Titanium.Web.Proxy.EventArguments.CertificateSelectionEventArgs.html","topicUid":"Titanium.Web.Proxy.EventArguments.CertificateSelectionEventArgs","type":"Class"},{"name":"CertificateValidationEventArgs","href":"Titanium.Web.Proxy.EventArguments.CertificateValidationEventArgs.html","topicHref":"Titanium.Web.Proxy.EventArguments.CertificateValidationEventArgs.html","topicUid":"Titanium.Web.Proxy.EventArguments.CertificateValidationEventArgs","type":"Class"},{"name":"MultipartRequestPartSentEventArgs","href":"Titanium.Web.Proxy.EventArguments.MultipartRequestPartSentEventArgs.html","topicHref":"Titanium.Web.Proxy.EventArguments.MultipartRequestPartSentEventArgs.html","topicUid":"Titanium.Web.Proxy.EventArguments.MultipartRequestPartSentEventArgs","type":"Class"},{"name":"ProxyEventArgsBase","href":"Titanium.Web.Proxy.EventArguments.ProxyEventArgsBase.html","topicHref":"Titanium.Web.Proxy.EventArguments.ProxyEventArgsBase.html","topicUid":"Titanium.Web.Proxy.EventArguments.ProxyEventArgsBase","type":"Class"},{"name":"SessionEventArgs","href":"Titanium.Web.Proxy.EventArguments.SessionEventArgs.html","topicHref":"Titanium.Web.Proxy.EventArguments.SessionEventArgs.html","topicUid":"Titanium.Web.Proxy.EventArguments.SessionEventArgs","type":"Class"},{"name":"SessionEventArgsBase","href":"Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html","topicHref":"Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html","topicUid":"Titanium.Web.Proxy.EventArguments.SessionEventArgsBase","type":"Class"},{"name":"SocksAuthenticateEventArgs","href":"Titanium.Web.Proxy.EventArguments.SocksAuthenticateEventArgs.html","topicHref":"Titanium.Web.Proxy.EventArguments.SocksAuthenticateEventArgs.html","topicUid":"Titanium.Web.Proxy.EventArguments.SocksAuthenticateEventArgs","type":"Class"},{"name":"TunnelConnectFailureEventArgs","href":"Titanium.Web.Proxy.EventArguments.TunnelConnectFailureEventArgs.html","topicHref":"Titanium.Web.Proxy.EventArguments.TunnelConnectFailureEventArgs.html","topicUid":"Titanium.Web.Proxy.EventArguments.TunnelConnectFailureEventArgs","type":"Class"},{"name":"TunnelConnectSessionEventArgs","href":"Titanium.Web.Proxy.EventArguments.TunnelConnectSessionEventArgs.html","topicHref":"Titanium.Web.Proxy.EventArguments.TunnelConnectSessionEventArgs.html","topicUid":"Titanium.Web.Proxy.EventArguments.TunnelConnectSessionEventArgs","type":"Class"},{"name":"WebSocketFrameDirection","href":"Titanium.Web.Proxy.EventArguments.WebSocketFrameDirection.html","topicHref":"Titanium.Web.Proxy.EventArguments.WebSocketFrameDirection.html","topicUid":"Titanium.Web.Proxy.EventArguments.WebSocketFrameDirection","type":"Enum"},{"name":"WebSocketFrameInterceptAction","href":"Titanium.Web.Proxy.EventArguments.WebSocketFrameInterceptAction.html","topicHref":"Titanium.Web.Proxy.EventArguments.WebSocketFrameInterceptAction.html","topicUid":"Titanium.Web.Proxy.EventArguments.WebSocketFrameInterceptAction","type":"Enum"},{"name":"WebSocketFrameInterceptEventArgs","href":"Titanium.Web.Proxy.EventArguments.WebSocketFrameInterceptEventArgs.html","topicHref":"Titanium.Web.Proxy.EventArguments.WebSocketFrameInterceptEventArgs.html","topicUid":"Titanium.Web.Proxy.EventArguments.WebSocketFrameInterceptEventArgs","type":"Class"}]},{"name":"Titanium.Web.Proxy.Exceptions","href":"Titanium.Web.Proxy.Exceptions.html","topicHref":"Titanium.Web.Proxy.Exceptions.html","topicUid":"Titanium.Web.Proxy.Exceptions","type":"Namespace","items":[{"name":"BodyNotFoundException","href":"Titanium.Web.Proxy.Exceptions.BodyNotFoundException.html","topicHref":"Titanium.Web.Proxy.Exceptions.BodyNotFoundException.html","topicUid":"Titanium.Web.Proxy.Exceptions.BodyNotFoundException","type":"Class"},{"name":"OutboundDestinationBlockedException","href":"Titanium.Web.Proxy.Exceptions.OutboundDestinationBlockedException.html","topicHref":"Titanium.Web.Proxy.Exceptions.OutboundDestinationBlockedException.html","topicUid":"Titanium.Web.Proxy.Exceptions.OutboundDestinationBlockedException","type":"Class"},{"name":"ProxyAuthorizationException","href":"Titanium.Web.Proxy.Exceptions.ProxyAuthorizationException.html","topicHref":"Titanium.Web.Proxy.Exceptions.ProxyAuthorizationException.html","topicUid":"Titanium.Web.Proxy.Exceptions.ProxyAuthorizationException","type":"Class"},{"name":"ProxyConnectException","href":"Titanium.Web.Proxy.Exceptions.ProxyConnectException.html","topicHref":"Titanium.Web.Proxy.Exceptions.ProxyConnectException.html","topicUid":"Titanium.Web.Proxy.Exceptions.ProxyConnectException","type":"Class"},{"name":"ProxyException","href":"Titanium.Web.Proxy.Exceptions.ProxyException.html","topicHref":"Titanium.Web.Proxy.Exceptions.ProxyException.html","topicUid":"Titanium.Web.Proxy.Exceptions.ProxyException","type":"Class"},{"name":"ProxyHttpException","href":"Titanium.Web.Proxy.Exceptions.ProxyHttpException.html","topicHref":"Titanium.Web.Proxy.Exceptions.ProxyHttpException.html","topicUid":"Titanium.Web.Proxy.Exceptions.ProxyHttpException","type":"Class"},{"name":"ProxyTimeoutException","href":"Titanium.Web.Proxy.Exceptions.ProxyTimeoutException.html","topicHref":"Titanium.Web.Proxy.Exceptions.ProxyTimeoutException.html","topicUid":"Titanium.Web.Proxy.Exceptions.ProxyTimeoutException","type":"Class"},{"name":"ProxyTimeoutKind","href":"Titanium.Web.Proxy.Exceptions.ProxyTimeoutKind.html","topicHref":"Titanium.Web.Proxy.Exceptions.ProxyTimeoutKind.html","topicUid":"Titanium.Web.Proxy.Exceptions.ProxyTimeoutKind","type":"Enum"},{"name":"UpstreamProxyConnectException","href":"Titanium.Web.Proxy.Exceptions.UpstreamProxyConnectException.html","topicHref":"Titanium.Web.Proxy.Exceptions.UpstreamProxyConnectException.html","topicUid":"Titanium.Web.Proxy.Exceptions.UpstreamProxyConnectException","type":"Class"}]},{"name":"Titanium.Web.Proxy.Http","href":"Titanium.Web.Proxy.Http.html","topicHref":"Titanium.Web.Proxy.Http.html","topicUid":"Titanium.Web.Proxy.Http","type":"Namespace","items":[{"name":"ConnectRequest","href":"Titanium.Web.Proxy.Http.ConnectRequest.html","topicHref":"Titanium.Web.Proxy.Http.ConnectRequest.html","topicUid":"Titanium.Web.Proxy.Http.ConnectRequest","type":"Class"},{"name":"ConnectResponse","href":"Titanium.Web.Proxy.Http.ConnectResponse.html","topicHref":"Titanium.Web.Proxy.Http.ConnectResponse.html","topicUid":"Titanium.Web.Proxy.Http.ConnectResponse","type":"Class"},{"name":"HeaderCollection","href":"Titanium.Web.Proxy.Http.HeaderCollection.html","topicHref":"Titanium.Web.Proxy.Http.HeaderCollection.html","topicUid":"Titanium.Web.Proxy.Http.HeaderCollection","type":"Class"},{"name":"HeaderCollection.Enumerator","href":"Titanium.Web.Proxy.Http.HeaderCollection.Enumerator.html","topicHref":"Titanium.Web.Proxy.Http.HeaderCollection.Enumerator.html","topicUid":"Titanium.Web.Proxy.Http.HeaderCollection.Enumerator","type":"Struct"},{"name":"HttpWebClient","href":"Titanium.Web.Proxy.Http.HttpWebClient.html","topicHref":"Titanium.Web.Proxy.Http.HttpWebClient.html","topicUid":"Titanium.Web.Proxy.Http.HttpWebClient","type":"Class"},{"name":"KnownHeader","href":"Titanium.Web.Proxy.Http.KnownHeader.html","topicHref":"Titanium.Web.Proxy.Http.KnownHeader.html","topicUid":"Titanium.Web.Proxy.Http.KnownHeader","type":"Class"},{"name":"KnownHeaders","href":"Titanium.Web.Proxy.Http.KnownHeaders.html","topicHref":"Titanium.Web.Proxy.Http.KnownHeaders.html","topicUid":"Titanium.Web.Proxy.Http.KnownHeaders","type":"Class"},{"name":"Request","href":"Titanium.Web.Proxy.Http.Request.html","topicHref":"Titanium.Web.Proxy.Http.Request.html","topicUid":"Titanium.Web.Proxy.Http.Request","type":"Class"},{"name":"RequestResponseBase","href":"Titanium.Web.Proxy.Http.RequestResponseBase.html","topicHref":"Titanium.Web.Proxy.Http.RequestResponseBase.html","topicUid":"Titanium.Web.Proxy.Http.RequestResponseBase","type":"Class"},{"name":"Response","href":"Titanium.Web.Proxy.Http.Response.html","topicHref":"Titanium.Web.Proxy.Http.Response.html","topicUid":"Titanium.Web.Proxy.Http.Response","type":"Class"},{"name":"TunnelType","href":"Titanium.Web.Proxy.Http.TunnelType.html","topicHref":"Titanium.Web.Proxy.Http.TunnelType.html","topicUid":"Titanium.Web.Proxy.Http.TunnelType","type":"Enum"}]},{"name":"Titanium.Web.Proxy.Http.Responses","href":"Titanium.Web.Proxy.Http.Responses.html","topicHref":"Titanium.Web.Proxy.Http.Responses.html","topicUid":"Titanium.Web.Proxy.Http.Responses","type":"Namespace","items":[{"name":"GenericResponse","href":"Titanium.Web.Proxy.Http.Responses.GenericResponse.html","topicHref":"Titanium.Web.Proxy.Http.Responses.GenericResponse.html","topicUid":"Titanium.Web.Proxy.Http.Responses.GenericResponse","type":"Class"},{"name":"OkResponse","href":"Titanium.Web.Proxy.Http.Responses.OkResponse.html","topicHref":"Titanium.Web.Proxy.Http.Responses.OkResponse.html","topicUid":"Titanium.Web.Proxy.Http.Responses.OkResponse","type":"Class"},{"name":"RedirectResponse","href":"Titanium.Web.Proxy.Http.Responses.RedirectResponse.html","topicHref":"Titanium.Web.Proxy.Http.Responses.RedirectResponse.html","topicUid":"Titanium.Web.Proxy.Http.Responses.RedirectResponse","type":"Class"}]},{"name":"Titanium.Web.Proxy.Logging","href":"Titanium.Web.Proxy.Logging.html","topicHref":"Titanium.Web.Proxy.Logging.html","topicUid":"Titanium.Web.Proxy.Logging","type":"Namespace","items":[{"name":"ProxyLoggingOptions","href":"Titanium.Web.Proxy.Logging.ProxyLoggingOptions.html","topicHref":"Titanium.Web.Proxy.Logging.ProxyLoggingOptions.html","topicUid":"Titanium.Web.Proxy.Logging.ProxyLoggingOptions","type":"Class"}]},{"name":"Titanium.Web.Proxy.Models","href":"Titanium.Web.Proxy.Models.html","topicHref":"Titanium.Web.Proxy.Models.html","topicUid":"Titanium.Web.Proxy.Models","type":"Namespace","items":[{"name":"ExplicitProxyEndPoint","href":"Titanium.Web.Proxy.Models.ExplicitProxyEndPoint.html","topicHref":"Titanium.Web.Proxy.Models.ExplicitProxyEndPoint.html","topicUid":"Titanium.Web.Proxy.Models.ExplicitProxyEndPoint","type":"Class"},{"name":"ExternalProxy","href":"Titanium.Web.Proxy.Models.ExternalProxy.html","topicHref":"Titanium.Web.Proxy.Models.ExternalProxy.html","topicUid":"Titanium.Web.Proxy.Models.ExternalProxy","type":"Class"},{"name":"ExternalProxyType","href":"Titanium.Web.Proxy.Models.ExternalProxyType.html","topicHref":"Titanium.Web.Proxy.Models.ExternalProxyType.html","topicUid":"Titanium.Web.Proxy.Models.ExternalProxyType","type":"Enum"},{"name":"HttpHeader","href":"Titanium.Web.Proxy.Models.HttpHeader.html","topicHref":"Titanium.Web.Proxy.Models.HttpHeader.html","topicUid":"Titanium.Web.Proxy.Models.HttpHeader","type":"Class"},{"name":"HttpInterceptionContext","href":"Titanium.Web.Proxy.Models.HttpInterceptionContext.html","topicHref":"Titanium.Web.Proxy.Models.HttpInterceptionContext.html","topicUid":"Titanium.Web.Proxy.Models.HttpInterceptionContext","type":"Struct"},{"name":"IExternalProxy","href":"Titanium.Web.Proxy.Models.IExternalProxy.html","topicHref":"Titanium.Web.Proxy.Models.IExternalProxy.html","topicUid":"Titanium.Web.Proxy.Models.IExternalProxy","type":"Interface"},{"name":"OriginHttpVersionPolicy","href":"Titanium.Web.Proxy.Models.OriginHttpVersionPolicy.html","topicHref":"Titanium.Web.Proxy.Models.OriginHttpVersionPolicy.html","topicUid":"Titanium.Web.Proxy.Models.OriginHttpVersionPolicy","type":"Enum"},{"name":"ProxyAuthenticationContext","href":"Titanium.Web.Proxy.Models.ProxyAuthenticationContext.html","topicHref":"Titanium.Web.Proxy.Models.ProxyAuthenticationContext.html","topicUid":"Titanium.Web.Proxy.Models.ProxyAuthenticationContext","type":"Class"},{"name":"ProxyAuthenticationResult","href":"Titanium.Web.Proxy.Models.ProxyAuthenticationResult.html","topicHref":"Titanium.Web.Proxy.Models.ProxyAuthenticationResult.html","topicUid":"Titanium.Web.Proxy.Models.ProxyAuthenticationResult","type":"Enum"},{"name":"ProxyEndPoint","href":"Titanium.Web.Proxy.Models.ProxyEndPoint.html","topicHref":"Titanium.Web.Proxy.Models.ProxyEndPoint.html","topicUid":"Titanium.Web.Proxy.Models.ProxyEndPoint","type":"Class"},{"name":"ProxyProtocolType","href":"Titanium.Web.Proxy.Models.ProxyProtocolType.html","topicHref":"Titanium.Web.Proxy.Models.ProxyProtocolType.html","topicUid":"Titanium.Web.Proxy.Models.ProxyProtocolType","type":"Enum"},{"name":"SocksProxyEndPoint","href":"Titanium.Web.Proxy.Models.SocksProxyEndPoint.html","topicHref":"Titanium.Web.Proxy.Models.SocksProxyEndPoint.html","topicUid":"Titanium.Web.Proxy.Models.SocksProxyEndPoint","type":"Class"},{"name":"TransparentBaseProxyEndPoint","href":"Titanium.Web.Proxy.Models.TransparentBaseProxyEndPoint.html","topicHref":"Titanium.Web.Proxy.Models.TransparentBaseProxyEndPoint.html","topicUid":"Titanium.Web.Proxy.Models.TransparentBaseProxyEndPoint","type":"Class"},{"name":"TransparentProxyEndPoint","href":"Titanium.Web.Proxy.Models.TransparentProxyEndPoint.html","topicHref":"Titanium.Web.Proxy.Models.TransparentProxyEndPoint.html","topicUid":"Titanium.Web.Proxy.Models.TransparentProxyEndPoint","type":"Class"},{"name":"TransparentQuicProxyEndPoint","href":"Titanium.Web.Proxy.Models.TransparentQuicProxyEndPoint.html","topicHref":"Titanium.Web.Proxy.Models.TransparentQuicProxyEndPoint.html","topicUid":"Titanium.Web.Proxy.Models.TransparentQuicProxyEndPoint","type":"Class"},{"name":"UpstreamHttpProtocol","href":"Titanium.Web.Proxy.Models.UpstreamHttpProtocol.html","topicHref":"Titanium.Web.Proxy.Models.UpstreamHttpProtocol.html","topicUid":"Titanium.Web.Proxy.Models.UpstreamHttpProtocol","type":"Enum"},{"name":"WinAuthCredentials","href":"Titanium.Web.Proxy.Models.WinAuthCredentials.html","topicHref":"Titanium.Web.Proxy.Models.WinAuthCredentials.html","topicUid":"Titanium.Web.Proxy.Models.WinAuthCredentials","type":"Class"}]},{"name":"Titanium.Web.Proxy.Network","href":"Titanium.Web.Proxy.Network.html","topicHref":"Titanium.Web.Proxy.Network.html","topicUid":"Titanium.Web.Proxy.Network","type":"Namespace","items":[{"name":"CertificateEngine","href":"Titanium.Web.Proxy.Network.CertificateEngine.html","topicHref":"Titanium.Web.Proxy.Network.CertificateEngine.html","topicUid":"Titanium.Web.Proxy.Network.CertificateEngine","type":"Enum"},{"name":"CertificateKeyAlgorithm","href":"Titanium.Web.Proxy.Network.CertificateKeyAlgorithm.html","topicHref":"Titanium.Web.Proxy.Network.CertificateKeyAlgorithm.html","topicUid":"Titanium.Web.Proxy.Network.CertificateKeyAlgorithm","type":"Enum"},{"name":"CertificateManager","href":"Titanium.Web.Proxy.Network.CertificateManager.html","topicHref":"Titanium.Web.Proxy.Network.CertificateManager.html","topicUid":"Titanium.Web.Proxy.Network.CertificateManager","type":"Class"},{"name":"DefaultCertificateDiskCache","href":"Titanium.Web.Proxy.Network.DefaultCertificateDiskCache.html","topicHref":"Titanium.Web.Proxy.Network.DefaultCertificateDiskCache.html","topicUid":"Titanium.Web.Proxy.Network.DefaultCertificateDiskCache","type":"Class"},{"name":"ICertificateCache","href":"Titanium.Web.Proxy.Network.ICertificateCache.html","topicHref":"Titanium.Web.Proxy.Network.ICertificateCache.html","topicUid":"Titanium.Web.Proxy.Network.ICertificateCache","type":"Interface"}]},{"name":"Titanium.Web.Proxy.Network.Quic","href":"Titanium.Web.Proxy.Network.Quic.html","topicHref":"Titanium.Web.Proxy.Network.Quic.html","topicUid":"Titanium.Web.Proxy.Network.Quic","type":"Namespace","items":[{"name":"IOriginalDestinationResolver","href":"Titanium.Web.Proxy.Network.Quic.IOriginalDestinationResolver.html","topicHref":"Titanium.Web.Proxy.Network.Quic.IOriginalDestinationResolver.html","topicUid":"Titanium.Web.Proxy.Network.Quic.IOriginalDestinationResolver","type":"Interface"}]},{"name":"Titanium.Web.Proxy.Options","href":"Titanium.Web.Proxy.Options.html","topicHref":"Titanium.Web.Proxy.Options.html","topicUid":"Titanium.Web.Proxy.Options","type":"Namespace","items":[{"name":"PolicyFamily","href":"Titanium.Web.Proxy.Options.PolicyFamily.html","topicHref":"Titanium.Web.Proxy.Options.PolicyFamily.html","topicUid":"Titanium.Web.Proxy.Options.PolicyFamily","type":"Enum"},{"name":"PolicyMode","href":"Titanium.Web.Proxy.Options.PolicyMode.html","topicHref":"Titanium.Web.Proxy.Options.PolicyMode.html","topicUid":"Titanium.Web.Proxy.Options.PolicyMode","type":"Enum"},{"name":"ProxyPolicyModes","href":"Titanium.Web.Proxy.Options.ProxyPolicyModes.html","topicHref":"Titanium.Web.Proxy.Options.ProxyPolicyModes.html","topicUid":"Titanium.Web.Proxy.Options.ProxyPolicyModes","type":"Class"},{"name":"ProxyProfile","href":"Titanium.Web.Proxy.Options.ProxyProfile.html","topicHref":"Titanium.Web.Proxy.Options.ProxyProfile.html","topicUid":"Titanium.Web.Proxy.Options.ProxyProfile","type":"Enum"},{"name":"ProxyProfileSettings","href":"Titanium.Web.Proxy.Options.ProxyProfileSettings.html","topicHref":"Titanium.Web.Proxy.Options.ProxyProfileSettings.html","topicUid":"Titanium.Web.Proxy.Options.ProxyProfileSettings","type":"Class"},{"name":"ProxyResourceLimits","href":"Titanium.Web.Proxy.Options.ProxyResourceLimits.html","topicHref":"Titanium.Web.Proxy.Options.ProxyResourceLimits.html","topicUid":"Titanium.Web.Proxy.Options.ProxyResourceLimits","type":"Class"},{"name":"ProxyTimeoutOptions","href":"Titanium.Web.Proxy.Options.ProxyTimeoutOptions.html","topicHref":"Titanium.Web.Proxy.Options.ProxyTimeoutOptions.html","topicUid":"Titanium.Web.Proxy.Options.ProxyTimeoutOptions","type":"Class"},{"name":"ResolvedSessionPolicy","href":"Titanium.Web.Proxy.Options.ResolvedSessionPolicy.html","topicHref":"Titanium.Web.Proxy.Options.ResolvedSessionPolicy.html","topicUid":"Titanium.Web.Proxy.Options.ResolvedSessionPolicy","type":"Class"}]},{"name":"Titanium.Web.Proxy.StreamExtended","href":"Titanium.Web.Proxy.StreamExtended.html","topicHref":"Titanium.Web.Proxy.StreamExtended.html","topicUid":"Titanium.Web.Proxy.StreamExtended","type":"Namespace","items":[{"name":"ClientHelloInfo","href":"Titanium.Web.Proxy.StreamExtended.ClientHelloInfo.html","topicHref":"Titanium.Web.Proxy.StreamExtended.ClientHelloInfo.html","topicUid":"Titanium.Web.Proxy.StreamExtended.ClientHelloInfo","type":"Class"},{"name":"ServerHelloInfo","href":"Titanium.Web.Proxy.StreamExtended.ServerHelloInfo.html","topicHref":"Titanium.Web.Proxy.StreamExtended.ServerHelloInfo.html","topicUid":"Titanium.Web.Proxy.StreamExtended.ServerHelloInfo","type":"Class"}]},{"name":"Titanium.Web.Proxy.StreamExtended.BufferPool","href":"Titanium.Web.Proxy.StreamExtended.BufferPool.html","topicHref":"Titanium.Web.Proxy.StreamExtended.BufferPool.html","topicUid":"Titanium.Web.Proxy.StreamExtended.BufferPool","type":"Namespace","items":[{"name":"IBufferPool","href":"Titanium.Web.Proxy.StreamExtended.BufferPool.IBufferPool.html","topicHref":"Titanium.Web.Proxy.StreamExtended.BufferPool.IBufferPool.html","topicUid":"Titanium.Web.Proxy.StreamExtended.BufferPool.IBufferPool","type":"Interface"}]},{"name":"Titanium.Web.Proxy.StreamExtended.Models","href":"Titanium.Web.Proxy.StreamExtended.Models.html","topicHref":"Titanium.Web.Proxy.StreamExtended.Models.html","topicUid":"Titanium.Web.Proxy.StreamExtended.Models","type":"Namespace","items":[{"name":"SslExtension","href":"Titanium.Web.Proxy.StreamExtended.Models.SslExtension.html","topicHref":"Titanium.Web.Proxy.StreamExtended.Models.SslExtension.html","topicUid":"Titanium.Web.Proxy.StreamExtended.Models.SslExtension","type":"Class"}]},{"name":"Titanium.Web.Proxy.StreamExtended.Network","href":"Titanium.Web.Proxy.StreamExtended.Network.html","topicHref":"Titanium.Web.Proxy.StreamExtended.Network.html","topicUid":"Titanium.Web.Proxy.StreamExtended.Network","type":"Namespace","items":[{"name":"DataEventArgs","href":"Titanium.Web.Proxy.StreamExtended.Network.DataEventArgs.html","topicHref":"Titanium.Web.Proxy.StreamExtended.Network.DataEventArgs.html","topicUid":"Titanium.Web.Proxy.StreamExtended.Network.DataEventArgs","type":"Class"},{"name":"IHttpStreamReader","href":"Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamReader.html","topicHref":"Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamReader.html","topicUid":"Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamReader","type":"Interface"},{"name":"IHttpStreamWriter","href":"Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamWriter.html","topicHref":"Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamWriter.html","topicUid":"Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamWriter","type":"Interface"},{"name":"ILineStream","href":"Titanium.Web.Proxy.StreamExtended.Network.ILineStream.html","topicHref":"Titanium.Web.Proxy.StreamExtended.Network.ILineStream.html","topicUid":"Titanium.Web.Proxy.StreamExtended.Network.ILineStream","type":"Interface"},{"name":"IPeekStream","href":"Titanium.Web.Proxy.StreamExtended.Network.IPeekStream.html","topicHref":"Titanium.Web.Proxy.StreamExtended.Network.IPeekStream.html","topicUid":"Titanium.Web.Proxy.StreamExtended.Network.IPeekStream","type":"Interface"}]}],"memberLayout":"SamePage"} +{"items":[{"name":"Titanium.Web.Proxy","href":"Titanium.Web.Proxy.html","topicHref":"Titanium.Web.Proxy.html","topicUid":"Titanium.Web.Proxy","type":"Namespace","items":[{"name":"ProxyLimits","href":"Titanium.Web.Proxy.ProxyLimits.html","topicHref":"Titanium.Web.Proxy.ProxyLimits.html","topicUid":"Titanium.Web.Proxy.ProxyLimits","type":"Class"},{"name":"ProxyServer","href":"Titanium.Web.Proxy.ProxyServer.html","topicHref":"Titanium.Web.Proxy.ProxyServer.html","topicUid":"Titanium.Web.Proxy.ProxyServer","type":"Class"},{"name":"SystemProxyBypassRuleMode","href":"Titanium.Web.Proxy.SystemProxyBypassRuleMode.html","topicHref":"Titanium.Web.Proxy.SystemProxyBypassRuleMode.html","topicUid":"Titanium.Web.Proxy.SystemProxyBypassRuleMode","type":"Enum"},{"name":"SystemProxyLoopbackPlacement","href":"Titanium.Web.Proxy.SystemProxyLoopbackPlacement.html","topicHref":"Titanium.Web.Proxy.SystemProxyLoopbackPlacement.html","topicUid":"Titanium.Web.Proxy.SystemProxyLoopbackPlacement","type":"Enum"},{"name":"SystemProxySettings","href":"Titanium.Web.Proxy.SystemProxySettings.html","topicHref":"Titanium.Web.Proxy.SystemProxySettings.html","topicUid":"Titanium.Web.Proxy.SystemProxySettings","type":"Class"},{"name":"WebSocketDecoder","href":"Titanium.Web.Proxy.WebSocketDecoder.html","topicHref":"Titanium.Web.Proxy.WebSocketDecoder.html","topicUid":"Titanium.Web.Proxy.WebSocketDecoder","type":"Class"},{"name":"WebSocketFrame","href":"Titanium.Web.Proxy.WebSocketFrame.html","topicHref":"Titanium.Web.Proxy.WebSocketFrame.html","topicUid":"Titanium.Web.Proxy.WebSocketFrame","type":"Class"},{"name":"WebSocketFrameEncoder","href":"Titanium.Web.Proxy.WebSocketFrameEncoder.html","topicHref":"Titanium.Web.Proxy.WebSocketFrameEncoder.html","topicUid":"Titanium.Web.Proxy.WebSocketFrameEncoder","type":"Class"},{"name":"WebSocketFrameWriter","href":"Titanium.Web.Proxy.WebSocketFrameWriter.html","topicHref":"Titanium.Web.Proxy.WebSocketFrameWriter.html","topicUid":"Titanium.Web.Proxy.WebSocketFrameWriter","type":"Class"},{"name":"WebSocketProtocolException","href":"Titanium.Web.Proxy.WebSocketProtocolException.html","topicHref":"Titanium.Web.Proxy.WebSocketProtocolException.html","topicUid":"Titanium.Web.Proxy.WebSocketProtocolException","type":"Class"},{"name":"WebsocketOpCode","href":"Titanium.Web.Proxy.WebsocketOpCode.html","topicHref":"Titanium.Web.Proxy.WebsocketOpCode.html","topicUid":"Titanium.Web.Proxy.WebsocketOpCode","type":"Enum"}]},{"name":"Titanium.Web.Proxy.Caching","href":"Titanium.Web.Proxy.Caching.html","topicHref":"Titanium.Web.Proxy.Caching.html","topicUid":"Titanium.Web.Proxy.Caching","type":"Namespace","items":[{"name":"HttpResponseCacheMiddleware","href":"Titanium.Web.Proxy.Caching.HttpResponseCacheMiddleware.html","topicHref":"Titanium.Web.Proxy.Caching.HttpResponseCacheMiddleware.html","topicUid":"Titanium.Web.Proxy.Caching.HttpResponseCacheMiddleware","type":"Class"},{"name":"MemoryHttpResponseCache","href":"Titanium.Web.Proxy.Caching.MemoryHttpResponseCache.html","topicHref":"Titanium.Web.Proxy.Caching.MemoryHttpResponseCache.html","topicUid":"Titanium.Web.Proxy.Caching.MemoryHttpResponseCache","type":"Class"}]},{"name":"Titanium.Web.Proxy.Clusters","href":"Titanium.Web.Proxy.Clusters.html","topicHref":"Titanium.Web.Proxy.Clusters.html","topicUid":"Titanium.Web.Proxy.Clusters","type":"Namespace","items":[{"name":"ClusterManager","href":"Titanium.Web.Proxy.Clusters.ClusterManager.html","topicHref":"Titanium.Web.Proxy.Clusters.ClusterManager.html","topicUid":"Titanium.Web.Proxy.Clusters.ClusterManager","type":"Class"},{"name":"DestinationHealthTracker","href":"Titanium.Web.Proxy.Clusters.DestinationHealthTracker.html","topicHref":"Titanium.Web.Proxy.Clusters.DestinationHealthTracker.html","topicUid":"Titanium.Web.Proxy.Clusters.DestinationHealthTracker","type":"Class"},{"name":"LoadBalancer","href":"Titanium.Web.Proxy.Clusters.LoadBalancer.html","topicHref":"Titanium.Web.Proxy.Clusters.LoadBalancer.html","topicUid":"Titanium.Web.Proxy.Clusters.LoadBalancer","type":"Class"}]},{"name":"Titanium.Web.Proxy.Diagnostics","href":"Titanium.Web.Proxy.Diagnostics.html","topicHref":"Titanium.Web.Proxy.Diagnostics.html","topicUid":"Titanium.Web.Proxy.Diagnostics","type":"Namespace","items":[{"name":"ClientTlsTiming","href":"Titanium.Web.Proxy.Diagnostics.ClientTlsTiming.html","topicHref":"Titanium.Web.Proxy.Diagnostics.ClientTlsTiming.html","topicUid":"Titanium.Web.Proxy.Diagnostics.ClientTlsTiming","type":"Class"},{"name":"HttpRequestTiming","href":"Titanium.Web.Proxy.Diagnostics.HttpRequestTiming.html","topicHref":"Titanium.Web.Proxy.Diagnostics.HttpRequestTiming.html","topicUid":"Titanium.Web.Proxy.Diagnostics.HttpRequestTiming","type":"Class"},{"name":"TunnelConnectTiming","href":"Titanium.Web.Proxy.Diagnostics.TunnelConnectTiming.html","topicHref":"Titanium.Web.Proxy.Diagnostics.TunnelConnectTiming.html","topicUid":"Titanium.Web.Proxy.Diagnostics.TunnelConnectTiming","type":"Class"},{"name":"UpstreamConnectionTiming","href":"Titanium.Web.Proxy.Diagnostics.UpstreamConnectionTiming.html","topicHref":"Titanium.Web.Proxy.Diagnostics.UpstreamConnectionTiming.html","topicUid":"Titanium.Web.Proxy.Diagnostics.UpstreamConnectionTiming","type":"Class"}]},{"name":"Titanium.Web.Proxy.EventArguments","href":"Titanium.Web.Proxy.EventArguments.html","topicHref":"Titanium.Web.Proxy.EventArguments.html","topicUid":"Titanium.Web.Proxy.EventArguments","type":"Namespace","items":[{"name":"AsyncEventHandler","href":"Titanium.Web.Proxy.EventArguments.AsyncEventHandler-1.html","topicHref":"Titanium.Web.Proxy.EventArguments.AsyncEventHandler-1.html","topicUid":"Titanium.Web.Proxy.EventArguments.AsyncEventHandler`1","type":"Delegate"},{"name":"BeforeBodyWriteEventArgs","href":"Titanium.Web.Proxy.EventArguments.BeforeBodyWriteEventArgs.html","topicHref":"Titanium.Web.Proxy.EventArguments.BeforeBodyWriteEventArgs.html","topicUid":"Titanium.Web.Proxy.EventArguments.BeforeBodyWriteEventArgs","type":"Class"},{"name":"BeforeHttpAuthenticateEventArgs","href":"Titanium.Web.Proxy.EventArguments.BeforeHttpAuthenticateEventArgs.html","topicHref":"Titanium.Web.Proxy.EventArguments.BeforeHttpAuthenticateEventArgs.html","topicUid":"Titanium.Web.Proxy.EventArguments.BeforeHttpAuthenticateEventArgs","type":"Class"},{"name":"BeforeQuicAuthenticateEventArgs","href":"Titanium.Web.Proxy.EventArguments.BeforeQuicAuthenticateEventArgs.html","topicHref":"Titanium.Web.Proxy.EventArguments.BeforeQuicAuthenticateEventArgs.html","topicUid":"Titanium.Web.Proxy.EventArguments.BeforeQuicAuthenticateEventArgs","type":"Class"},{"name":"BeforeSslAuthenticateEventArgs","href":"Titanium.Web.Proxy.EventArguments.BeforeSslAuthenticateEventArgs.html","topicHref":"Titanium.Web.Proxy.EventArguments.BeforeSslAuthenticateEventArgs.html","topicUid":"Titanium.Web.Proxy.EventArguments.BeforeSslAuthenticateEventArgs","type":"Class"},{"name":"CertificateSelectionEventArgs","href":"Titanium.Web.Proxy.EventArguments.CertificateSelectionEventArgs.html","topicHref":"Titanium.Web.Proxy.EventArguments.CertificateSelectionEventArgs.html","topicUid":"Titanium.Web.Proxy.EventArguments.CertificateSelectionEventArgs","type":"Class"},{"name":"CertificateValidationEventArgs","href":"Titanium.Web.Proxy.EventArguments.CertificateValidationEventArgs.html","topicHref":"Titanium.Web.Proxy.EventArguments.CertificateValidationEventArgs.html","topicUid":"Titanium.Web.Proxy.EventArguments.CertificateValidationEventArgs","type":"Class"},{"name":"MultipartRequestPartSentEventArgs","href":"Titanium.Web.Proxy.EventArguments.MultipartRequestPartSentEventArgs.html","topicHref":"Titanium.Web.Proxy.EventArguments.MultipartRequestPartSentEventArgs.html","topicUid":"Titanium.Web.Proxy.EventArguments.MultipartRequestPartSentEventArgs","type":"Class"},{"name":"ProxyEventArgsBase","href":"Titanium.Web.Proxy.EventArguments.ProxyEventArgsBase.html","topicHref":"Titanium.Web.Proxy.EventArguments.ProxyEventArgsBase.html","topicUid":"Titanium.Web.Proxy.EventArguments.ProxyEventArgsBase","type":"Class"},{"name":"SessionEventArgs","href":"Titanium.Web.Proxy.EventArguments.SessionEventArgs.html","topicHref":"Titanium.Web.Proxy.EventArguments.SessionEventArgs.html","topicUid":"Titanium.Web.Proxy.EventArguments.SessionEventArgs","type":"Class"},{"name":"SessionEventArgsBase","href":"Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html","topicHref":"Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html","topicUid":"Titanium.Web.Proxy.EventArguments.SessionEventArgsBase","type":"Class"},{"name":"SocksAuthenticateEventArgs","href":"Titanium.Web.Proxy.EventArguments.SocksAuthenticateEventArgs.html","topicHref":"Titanium.Web.Proxy.EventArguments.SocksAuthenticateEventArgs.html","topicUid":"Titanium.Web.Proxy.EventArguments.SocksAuthenticateEventArgs","type":"Class"},{"name":"TunnelConnectFailureEventArgs","href":"Titanium.Web.Proxy.EventArguments.TunnelConnectFailureEventArgs.html","topicHref":"Titanium.Web.Proxy.EventArguments.TunnelConnectFailureEventArgs.html","topicUid":"Titanium.Web.Proxy.EventArguments.TunnelConnectFailureEventArgs","type":"Class"},{"name":"TunnelConnectSessionEventArgs","href":"Titanium.Web.Proxy.EventArguments.TunnelConnectSessionEventArgs.html","topicHref":"Titanium.Web.Proxy.EventArguments.TunnelConnectSessionEventArgs.html","topicUid":"Titanium.Web.Proxy.EventArguments.TunnelConnectSessionEventArgs","type":"Class"},{"name":"WebSocketFrameDirection","href":"Titanium.Web.Proxy.EventArguments.WebSocketFrameDirection.html","topicHref":"Titanium.Web.Proxy.EventArguments.WebSocketFrameDirection.html","topicUid":"Titanium.Web.Proxy.EventArguments.WebSocketFrameDirection","type":"Enum"},{"name":"WebSocketFrameInterceptAction","href":"Titanium.Web.Proxy.EventArguments.WebSocketFrameInterceptAction.html","topicHref":"Titanium.Web.Proxy.EventArguments.WebSocketFrameInterceptAction.html","topicUid":"Titanium.Web.Proxy.EventArguments.WebSocketFrameInterceptAction","type":"Enum"},{"name":"WebSocketFrameInterceptEventArgs","href":"Titanium.Web.Proxy.EventArguments.WebSocketFrameInterceptEventArgs.html","topicHref":"Titanium.Web.Proxy.EventArguments.WebSocketFrameInterceptEventArgs.html","topicUid":"Titanium.Web.Proxy.EventArguments.WebSocketFrameInterceptEventArgs","type":"Class"}]},{"name":"Titanium.Web.Proxy.Exceptions","href":"Titanium.Web.Proxy.Exceptions.html","topicHref":"Titanium.Web.Proxy.Exceptions.html","topicUid":"Titanium.Web.Proxy.Exceptions","type":"Namespace","items":[{"name":"BodyNotFoundException","href":"Titanium.Web.Proxy.Exceptions.BodyNotFoundException.html","topicHref":"Titanium.Web.Proxy.Exceptions.BodyNotFoundException.html","topicUid":"Titanium.Web.Proxy.Exceptions.BodyNotFoundException","type":"Class"},{"name":"OutboundDestinationBlockedException","href":"Titanium.Web.Proxy.Exceptions.OutboundDestinationBlockedException.html","topicHref":"Titanium.Web.Proxy.Exceptions.OutboundDestinationBlockedException.html","topicUid":"Titanium.Web.Proxy.Exceptions.OutboundDestinationBlockedException","type":"Class"},{"name":"ProxyAuthorizationException","href":"Titanium.Web.Proxy.Exceptions.ProxyAuthorizationException.html","topicHref":"Titanium.Web.Proxy.Exceptions.ProxyAuthorizationException.html","topicUid":"Titanium.Web.Proxy.Exceptions.ProxyAuthorizationException","type":"Class"},{"name":"ProxyConnectException","href":"Titanium.Web.Proxy.Exceptions.ProxyConnectException.html","topicHref":"Titanium.Web.Proxy.Exceptions.ProxyConnectException.html","topicUid":"Titanium.Web.Proxy.Exceptions.ProxyConnectException","type":"Class"},{"name":"ProxyException","href":"Titanium.Web.Proxy.Exceptions.ProxyException.html","topicHref":"Titanium.Web.Proxy.Exceptions.ProxyException.html","topicUid":"Titanium.Web.Proxy.Exceptions.ProxyException","type":"Class"},{"name":"ProxyHttpException","href":"Titanium.Web.Proxy.Exceptions.ProxyHttpException.html","topicHref":"Titanium.Web.Proxy.Exceptions.ProxyHttpException.html","topicUid":"Titanium.Web.Proxy.Exceptions.ProxyHttpException","type":"Class"},{"name":"ProxyTimeoutException","href":"Titanium.Web.Proxy.Exceptions.ProxyTimeoutException.html","topicHref":"Titanium.Web.Proxy.Exceptions.ProxyTimeoutException.html","topicUid":"Titanium.Web.Proxy.Exceptions.ProxyTimeoutException","type":"Class"},{"name":"ProxyTimeoutKind","href":"Titanium.Web.Proxy.Exceptions.ProxyTimeoutKind.html","topicHref":"Titanium.Web.Proxy.Exceptions.ProxyTimeoutKind.html","topicUid":"Titanium.Web.Proxy.Exceptions.ProxyTimeoutKind","type":"Enum"},{"name":"UpstreamProxyConnectException","href":"Titanium.Web.Proxy.Exceptions.UpstreamProxyConnectException.html","topicHref":"Titanium.Web.Proxy.Exceptions.UpstreamProxyConnectException.html","topicUid":"Titanium.Web.Proxy.Exceptions.UpstreamProxyConnectException","type":"Class"}]},{"name":"Titanium.Web.Proxy.Http","href":"Titanium.Web.Proxy.Http.html","topicHref":"Titanium.Web.Proxy.Http.html","topicUid":"Titanium.Web.Proxy.Http","type":"Namespace","items":[{"name":"ConnectRequest","href":"Titanium.Web.Proxy.Http.ConnectRequest.html","topicHref":"Titanium.Web.Proxy.Http.ConnectRequest.html","topicUid":"Titanium.Web.Proxy.Http.ConnectRequest","type":"Class"},{"name":"ConnectResponse","href":"Titanium.Web.Proxy.Http.ConnectResponse.html","topicHref":"Titanium.Web.Proxy.Http.ConnectResponse.html","topicUid":"Titanium.Web.Proxy.Http.ConnectResponse","type":"Class"},{"name":"HeaderCollection","href":"Titanium.Web.Proxy.Http.HeaderCollection.html","topicHref":"Titanium.Web.Proxy.Http.HeaderCollection.html","topicUid":"Titanium.Web.Proxy.Http.HeaderCollection","type":"Class"},{"name":"HeaderCollection.Enumerator","href":"Titanium.Web.Proxy.Http.HeaderCollection.Enumerator.html","topicHref":"Titanium.Web.Proxy.Http.HeaderCollection.Enumerator.html","topicUid":"Titanium.Web.Proxy.Http.HeaderCollection.Enumerator","type":"Struct"},{"name":"HttpWebClient","href":"Titanium.Web.Proxy.Http.HttpWebClient.html","topicHref":"Titanium.Web.Proxy.Http.HttpWebClient.html","topicUid":"Titanium.Web.Proxy.Http.HttpWebClient","type":"Class"},{"name":"KnownHeader","href":"Titanium.Web.Proxy.Http.KnownHeader.html","topicHref":"Titanium.Web.Proxy.Http.KnownHeader.html","topicUid":"Titanium.Web.Proxy.Http.KnownHeader","type":"Class"},{"name":"KnownHeaders","href":"Titanium.Web.Proxy.Http.KnownHeaders.html","topicHref":"Titanium.Web.Proxy.Http.KnownHeaders.html","topicUid":"Titanium.Web.Proxy.Http.KnownHeaders","type":"Class"},{"name":"ProxyResults","href":"Titanium.Web.Proxy.Http.ProxyResults.html","topicHref":"Titanium.Web.Proxy.Http.ProxyResults.html","topicUid":"Titanium.Web.Proxy.Http.ProxyResults","type":"Class"},{"name":"Request","href":"Titanium.Web.Proxy.Http.Request.html","topicHref":"Titanium.Web.Proxy.Http.Request.html","topicUid":"Titanium.Web.Proxy.Http.Request","type":"Class"},{"name":"RequestResponseBase","href":"Titanium.Web.Proxy.Http.RequestResponseBase.html","topicHref":"Titanium.Web.Proxy.Http.RequestResponseBase.html","topicUid":"Titanium.Web.Proxy.Http.RequestResponseBase","type":"Class"},{"name":"Response","href":"Titanium.Web.Proxy.Http.Response.html","topicHref":"Titanium.Web.Proxy.Http.Response.html","topicUid":"Titanium.Web.Proxy.Http.Response","type":"Class"},{"name":"StreamingProxyResult","href":"Titanium.Web.Proxy.Http.StreamingProxyResult.html","topicHref":"Titanium.Web.Proxy.Http.StreamingProxyResult.html","topicUid":"Titanium.Web.Proxy.Http.StreamingProxyResult","type":"Struct"},{"name":"TunnelType","href":"Titanium.Web.Proxy.Http.TunnelType.html","topicHref":"Titanium.Web.Proxy.Http.TunnelType.html","topicUid":"Titanium.Web.Proxy.Http.TunnelType","type":"Enum"}]},{"name":"Titanium.Web.Proxy.Http.Responses","href":"Titanium.Web.Proxy.Http.Responses.html","topicHref":"Titanium.Web.Proxy.Http.Responses.html","topicUid":"Titanium.Web.Proxy.Http.Responses","type":"Namespace","items":[{"name":"GenericResponse","href":"Titanium.Web.Proxy.Http.Responses.GenericResponse.html","topicHref":"Titanium.Web.Proxy.Http.Responses.GenericResponse.html","topicUid":"Titanium.Web.Proxy.Http.Responses.GenericResponse","type":"Class"},{"name":"OkResponse","href":"Titanium.Web.Proxy.Http.Responses.OkResponse.html","topicHref":"Titanium.Web.Proxy.Http.Responses.OkResponse.html","topicUid":"Titanium.Web.Proxy.Http.Responses.OkResponse","type":"Class"},{"name":"RedirectResponse","href":"Titanium.Web.Proxy.Http.Responses.RedirectResponse.html","topicHref":"Titanium.Web.Proxy.Http.Responses.RedirectResponse.html","topicUid":"Titanium.Web.Proxy.Http.Responses.RedirectResponse","type":"Class"}]},{"name":"Titanium.Web.Proxy.Logging","href":"Titanium.Web.Proxy.Logging.html","topicHref":"Titanium.Web.Proxy.Logging.html","topicUid":"Titanium.Web.Proxy.Logging","type":"Namespace","items":[{"name":"ProxyLoggingOptions","href":"Titanium.Web.Proxy.Logging.ProxyLoggingOptions.html","topicHref":"Titanium.Web.Proxy.Logging.ProxyLoggingOptions.html","topicUid":"Titanium.Web.Proxy.Logging.ProxyLoggingOptions","type":"Class"}]},{"name":"Titanium.Web.Proxy.Middleware","href":"Titanium.Web.Proxy.Middleware.html","topicHref":"Titanium.Web.Proxy.Middleware.html","topicUid":"Titanium.Web.Proxy.Middleware","type":"Namespace","items":[{"name":"ProxyMiddlewarePipeline","href":"Titanium.Web.Proxy.Middleware.ProxyMiddlewarePipeline.html","topicHref":"Titanium.Web.Proxy.Middleware.ProxyMiddlewarePipeline.html","topicUid":"Titanium.Web.Proxy.Middleware.ProxyMiddlewarePipeline","type":"Class"}]},{"name":"Titanium.Web.Proxy.Models","href":"Titanium.Web.Proxy.Models.html","topicHref":"Titanium.Web.Proxy.Models.html","topicUid":"Titanium.Web.Proxy.Models","type":"Namespace","items":[{"name":"ExplicitProxyEndPoint","href":"Titanium.Web.Proxy.Models.ExplicitProxyEndPoint.html","topicHref":"Titanium.Web.Proxy.Models.ExplicitProxyEndPoint.html","topicUid":"Titanium.Web.Proxy.Models.ExplicitProxyEndPoint","type":"Class"},{"name":"ExternalProxy","href":"Titanium.Web.Proxy.Models.ExternalProxy.html","topicHref":"Titanium.Web.Proxy.Models.ExternalProxy.html","topicUid":"Titanium.Web.Proxy.Models.ExternalProxy","type":"Class"},{"name":"ExternalProxyType","href":"Titanium.Web.Proxy.Models.ExternalProxyType.html","topicHref":"Titanium.Web.Proxy.Models.ExternalProxyType.html","topicUid":"Titanium.Web.Proxy.Models.ExternalProxyType","type":"Enum"},{"name":"HttpHeader","href":"Titanium.Web.Proxy.Models.HttpHeader.html","topicHref":"Titanium.Web.Proxy.Models.HttpHeader.html","topicUid":"Titanium.Web.Proxy.Models.HttpHeader","type":"Class"},{"name":"HttpInterceptionContext","href":"Titanium.Web.Proxy.Models.HttpInterceptionContext.html","topicHref":"Titanium.Web.Proxy.Models.HttpInterceptionContext.html","topicUid":"Titanium.Web.Proxy.Models.HttpInterceptionContext","type":"Struct"},{"name":"IExternalProxy","href":"Titanium.Web.Proxy.Models.IExternalProxy.html","topicHref":"Titanium.Web.Proxy.Models.IExternalProxy.html","topicUid":"Titanium.Web.Proxy.Models.IExternalProxy","type":"Interface"},{"name":"OriginHttpVersionPolicy","href":"Titanium.Web.Proxy.Models.OriginHttpVersionPolicy.html","topicHref":"Titanium.Web.Proxy.Models.OriginHttpVersionPolicy.html","topicUid":"Titanium.Web.Proxy.Models.OriginHttpVersionPolicy","type":"Enum"},{"name":"ProxyAuthenticationContext","href":"Titanium.Web.Proxy.Models.ProxyAuthenticationContext.html","topicHref":"Titanium.Web.Proxy.Models.ProxyAuthenticationContext.html","topicUid":"Titanium.Web.Proxy.Models.ProxyAuthenticationContext","type":"Class"},{"name":"ProxyAuthenticationResult","href":"Titanium.Web.Proxy.Models.ProxyAuthenticationResult.html","topicHref":"Titanium.Web.Proxy.Models.ProxyAuthenticationResult.html","topicUid":"Titanium.Web.Proxy.Models.ProxyAuthenticationResult","type":"Enum"},{"name":"ProxyEndPoint","href":"Titanium.Web.Proxy.Models.ProxyEndPoint.html","topicHref":"Titanium.Web.Proxy.Models.ProxyEndPoint.html","topicUid":"Titanium.Web.Proxy.Models.ProxyEndPoint","type":"Class"},{"name":"ProxyProtocolType","href":"Titanium.Web.Proxy.Models.ProxyProtocolType.html","topicHref":"Titanium.Web.Proxy.Models.ProxyProtocolType.html","topicUid":"Titanium.Web.Proxy.Models.ProxyProtocolType","type":"Enum"},{"name":"SocksProxyEndPoint","href":"Titanium.Web.Proxy.Models.SocksProxyEndPoint.html","topicHref":"Titanium.Web.Proxy.Models.SocksProxyEndPoint.html","topicUid":"Titanium.Web.Proxy.Models.SocksProxyEndPoint","type":"Class"},{"name":"TransparentBaseProxyEndPoint","href":"Titanium.Web.Proxy.Models.TransparentBaseProxyEndPoint.html","topicHref":"Titanium.Web.Proxy.Models.TransparentBaseProxyEndPoint.html","topicUid":"Titanium.Web.Proxy.Models.TransparentBaseProxyEndPoint","type":"Class"},{"name":"TransparentProxyEndPoint","href":"Titanium.Web.Proxy.Models.TransparentProxyEndPoint.html","topicHref":"Titanium.Web.Proxy.Models.TransparentProxyEndPoint.html","topicUid":"Titanium.Web.Proxy.Models.TransparentProxyEndPoint","type":"Class"},{"name":"TransparentQuicProxyEndPoint","href":"Titanium.Web.Proxy.Models.TransparentQuicProxyEndPoint.html","topicHref":"Titanium.Web.Proxy.Models.TransparentQuicProxyEndPoint.html","topicUid":"Titanium.Web.Proxy.Models.TransparentQuicProxyEndPoint","type":"Class"},{"name":"UpstreamHttpProtocol","href":"Titanium.Web.Proxy.Models.UpstreamHttpProtocol.html","topicHref":"Titanium.Web.Proxy.Models.UpstreamHttpProtocol.html","topicUid":"Titanium.Web.Proxy.Models.UpstreamHttpProtocol","type":"Enum"},{"name":"WinAuthCredentials","href":"Titanium.Web.Proxy.Models.WinAuthCredentials.html","topicHref":"Titanium.Web.Proxy.Models.WinAuthCredentials.html","topicUid":"Titanium.Web.Proxy.Models.WinAuthCredentials","type":"Class"}]},{"name":"Titanium.Web.Proxy.Network","href":"Titanium.Web.Proxy.Network.html","topicHref":"Titanium.Web.Proxy.Network.html","topicUid":"Titanium.Web.Proxy.Network","type":"Namespace","items":[{"name":"CertificateEngine","href":"Titanium.Web.Proxy.Network.CertificateEngine.html","topicHref":"Titanium.Web.Proxy.Network.CertificateEngine.html","topicUid":"Titanium.Web.Proxy.Network.CertificateEngine","type":"Enum"},{"name":"CertificateKeyAlgorithm","href":"Titanium.Web.Proxy.Network.CertificateKeyAlgorithm.html","topicHref":"Titanium.Web.Proxy.Network.CertificateKeyAlgorithm.html","topicUid":"Titanium.Web.Proxy.Network.CertificateKeyAlgorithm","type":"Enum"},{"name":"CertificateManager","href":"Titanium.Web.Proxy.Network.CertificateManager.html","topicHref":"Titanium.Web.Proxy.Network.CertificateManager.html","topicUid":"Titanium.Web.Proxy.Network.CertificateManager","type":"Class"},{"name":"DefaultCertificateDiskCache","href":"Titanium.Web.Proxy.Network.DefaultCertificateDiskCache.html","topicHref":"Titanium.Web.Proxy.Network.DefaultCertificateDiskCache.html","topicUid":"Titanium.Web.Proxy.Network.DefaultCertificateDiskCache","type":"Class"},{"name":"ICertificateCache","href":"Titanium.Web.Proxy.Network.ICertificateCache.html","topicHref":"Titanium.Web.Proxy.Network.ICertificateCache.html","topicUid":"Titanium.Web.Proxy.Network.ICertificateCache","type":"Interface"}]},{"name":"Titanium.Web.Proxy.Network.Quic","href":"Titanium.Web.Proxy.Network.Quic.html","topicHref":"Titanium.Web.Proxy.Network.Quic.html","topicUid":"Titanium.Web.Proxy.Network.Quic","type":"Namespace","items":[{"name":"IOriginalDestinationResolver","href":"Titanium.Web.Proxy.Network.Quic.IOriginalDestinationResolver.html","topicHref":"Titanium.Web.Proxy.Network.Quic.IOriginalDestinationResolver.html","topicUid":"Titanium.Web.Proxy.Network.Quic.IOriginalDestinationResolver","type":"Interface"}]},{"name":"Titanium.Web.Proxy.Options","href":"Titanium.Web.Proxy.Options.html","topicHref":"Titanium.Web.Proxy.Options.html","topicUid":"Titanium.Web.Proxy.Options","type":"Namespace","items":[{"name":"PolicyFamily","href":"Titanium.Web.Proxy.Options.PolicyFamily.html","topicHref":"Titanium.Web.Proxy.Options.PolicyFamily.html","topicUid":"Titanium.Web.Proxy.Options.PolicyFamily","type":"Enum"},{"name":"PolicyMode","href":"Titanium.Web.Proxy.Options.PolicyMode.html","topicHref":"Titanium.Web.Proxy.Options.PolicyMode.html","topicUid":"Titanium.Web.Proxy.Options.PolicyMode","type":"Enum"},{"name":"ProxyPolicyModes","href":"Titanium.Web.Proxy.Options.ProxyPolicyModes.html","topicHref":"Titanium.Web.Proxy.Options.ProxyPolicyModes.html","topicUid":"Titanium.Web.Proxy.Options.ProxyPolicyModes","type":"Class"},{"name":"ProxyProfile","href":"Titanium.Web.Proxy.Options.ProxyProfile.html","topicHref":"Titanium.Web.Proxy.Options.ProxyProfile.html","topicUid":"Titanium.Web.Proxy.Options.ProxyProfile","type":"Enum"},{"name":"ProxyProfileSettings","href":"Titanium.Web.Proxy.Options.ProxyProfileSettings.html","topicHref":"Titanium.Web.Proxy.Options.ProxyProfileSettings.html","topicUid":"Titanium.Web.Proxy.Options.ProxyProfileSettings","type":"Class"},{"name":"ProxyResourceLimits","href":"Titanium.Web.Proxy.Options.ProxyResourceLimits.html","topicHref":"Titanium.Web.Proxy.Options.ProxyResourceLimits.html","topicUid":"Titanium.Web.Proxy.Options.ProxyResourceLimits","type":"Class"},{"name":"ProxyTimeoutOptions","href":"Titanium.Web.Proxy.Options.ProxyTimeoutOptions.html","topicHref":"Titanium.Web.Proxy.Options.ProxyTimeoutOptions.html","topicUid":"Titanium.Web.Proxy.Options.ProxyTimeoutOptions","type":"Class"},{"name":"ResolvedSessionPolicy","href":"Titanium.Web.Proxy.Options.ResolvedSessionPolicy.html","topicHref":"Titanium.Web.Proxy.Options.ResolvedSessionPolicy.html","topicUid":"Titanium.Web.Proxy.Options.ResolvedSessionPolicy","type":"Class"}]},{"name":"Titanium.Web.Proxy.Routing","href":"Titanium.Web.Proxy.Routing.html","topicHref":"Titanium.Web.Proxy.Routing.html","topicUid":"Titanium.Web.Proxy.Routing","type":"Namespace","items":[{"name":"ReverseProxyFastPath","href":"Titanium.Web.Proxy.Routing.ReverseProxyFastPath.html","topicHref":"Titanium.Web.Proxy.Routing.ReverseProxyFastPath.html","topicUid":"Titanium.Web.Proxy.Routing.ReverseProxyFastPath","type":"Class"},{"name":"RouteMatcher","href":"Titanium.Web.Proxy.Routing.RouteMatcher.html","topicHref":"Titanium.Web.Proxy.Routing.RouteMatcher.html","topicUid":"Titanium.Web.Proxy.Routing.RouteMatcher","type":"Class"}]},{"name":"Titanium.Web.Proxy.StreamExtended","href":"Titanium.Web.Proxy.StreamExtended.html","topicHref":"Titanium.Web.Proxy.StreamExtended.html","topicUid":"Titanium.Web.Proxy.StreamExtended","type":"Namespace","items":[{"name":"ClientHelloInfo","href":"Titanium.Web.Proxy.StreamExtended.ClientHelloInfo.html","topicHref":"Titanium.Web.Proxy.StreamExtended.ClientHelloInfo.html","topicUid":"Titanium.Web.Proxy.StreamExtended.ClientHelloInfo","type":"Class"},{"name":"ServerHelloInfo","href":"Titanium.Web.Proxy.StreamExtended.ServerHelloInfo.html","topicHref":"Titanium.Web.Proxy.StreamExtended.ServerHelloInfo.html","topicUid":"Titanium.Web.Proxy.StreamExtended.ServerHelloInfo","type":"Class"}]},{"name":"Titanium.Web.Proxy.StreamExtended.BufferPool","href":"Titanium.Web.Proxy.StreamExtended.BufferPool.html","topicHref":"Titanium.Web.Proxy.StreamExtended.BufferPool.html","topicUid":"Titanium.Web.Proxy.StreamExtended.BufferPool","type":"Namespace","items":[{"name":"IBufferPool","href":"Titanium.Web.Proxy.StreamExtended.BufferPool.IBufferPool.html","topicHref":"Titanium.Web.Proxy.StreamExtended.BufferPool.IBufferPool.html","topicUid":"Titanium.Web.Proxy.StreamExtended.BufferPool.IBufferPool","type":"Interface"}]},{"name":"Titanium.Web.Proxy.StreamExtended.Models","href":"Titanium.Web.Proxy.StreamExtended.Models.html","topicHref":"Titanium.Web.Proxy.StreamExtended.Models.html","topicUid":"Titanium.Web.Proxy.StreamExtended.Models","type":"Namespace","items":[{"name":"SslExtension","href":"Titanium.Web.Proxy.StreamExtended.Models.SslExtension.html","topicHref":"Titanium.Web.Proxy.StreamExtended.Models.SslExtension.html","topicUid":"Titanium.Web.Proxy.StreamExtended.Models.SslExtension","type":"Class"}]},{"name":"Titanium.Web.Proxy.StreamExtended.Network","href":"Titanium.Web.Proxy.StreamExtended.Network.html","topicHref":"Titanium.Web.Proxy.StreamExtended.Network.html","topicUid":"Titanium.Web.Proxy.StreamExtended.Network","type":"Namespace","items":[{"name":"DataEventArgs","href":"Titanium.Web.Proxy.StreamExtended.Network.DataEventArgs.html","topicHref":"Titanium.Web.Proxy.StreamExtended.Network.DataEventArgs.html","topicUid":"Titanium.Web.Proxy.StreamExtended.Network.DataEventArgs","type":"Class"},{"name":"IHttpStreamReader","href":"Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamReader.html","topicHref":"Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamReader.html","topicUid":"Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamReader","type":"Interface"},{"name":"IHttpStreamWriter","href":"Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamWriter.html","topicHref":"Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamWriter.html","topicUid":"Titanium.Web.Proxy.StreamExtended.Network.IHttpStreamWriter","type":"Interface"},{"name":"ILineStream","href":"Titanium.Web.Proxy.StreamExtended.Network.ILineStream.html","topicHref":"Titanium.Web.Proxy.StreamExtended.Network.ILineStream.html","topicUid":"Titanium.Web.Proxy.StreamExtended.Network.ILineStream","type":"Interface"},{"name":"IPeekStream","href":"Titanium.Web.Proxy.StreamExtended.Network.IPeekStream.html","topicHref":"Titanium.Web.Proxy.StreamExtended.Network.IPeekStream.html","topicUid":"Titanium.Web.Proxy.StreamExtended.Network.IPeekStream","type":"Interface"}]},{"name":"Titanium.Web.Proxy.Transforms","href":"Titanium.Web.Proxy.Transforms.html","topicHref":"Titanium.Web.Proxy.Transforms.html","topicUid":"Titanium.Web.Proxy.Transforms","type":"Namespace","items":[{"name":"TransformEngine","href":"Titanium.Web.Proxy.Transforms.TransformEngine.html","topicHref":"Titanium.Web.Proxy.Transforms.TransformEngine.html","topicUid":"Titanium.Web.Proxy.Transforms.TransformEngine","type":"Class"}]}],"memberLayout":"SamePage"} diff --git a/docs/index.json b/docs/index.json index d9aafd540..06939ea7e 100644 --- a/docs/index.json +++ b/docs/index.json @@ -1,4 +1,44 @@ { + "BRANCH-PROTECTION.html": { + "href": "BRANCH-PROTECTION.html", + "title": "Branch protection (beta / stable) | Titanium Web Proxy", + "summary": "Branch protection (beta / stable) Configure in GitHub Settings → Rules → Rulesets (or classic branch protection). Ruleset: release-lines (beta, stable) Rule Value Restrict creations optional Restrict updates / deletions yes Block force pushes yes Require a pull request before merging yes Require approvals recommended (≥1 maintainer) Require conversation resolution recommended Require status checks to pass yes Required checks .NET / build, .NET / ui-portable (all matrix legs), RPS saturation / rps Allow bypass admins only for emergencies develop Keep lighter rules for velocity (direct push OK if that is current practice). Do not require full compare-product on every feature PR. Applying via gh (optional) # Example — adjust org/repo and exact check names from Actions UI after first green run gh api repos/{owner}/{repo}/rulesets --input .github/branch-ruleset-beta-stable.json Exact check names must match the Actions job names as shown on a PR (including matrix suffixes for ui-portable)." + }, + "api/Titanium.Web.Proxy.Caching.HttpResponseCacheMiddleware.html": { + "href": "api/Titanium.Web.Proxy.Caching.HttpResponseCacheMiddleware.html", + "title": "Class HttpResponseCacheMiddleware | Titanium Web Proxy", + "summary": "Class HttpResponseCacheMiddleware GET/HEAD response cache middleware. Only allocated when placed in the middleware list; otherwise the hot path pays nothing. Inheritance object HttpResponseCacheMiddleware Implements IProxyMiddleware Inherited Members object.Equals(object) object.Equals(object, object) object.GetHashCode() object.GetType() object.ReferenceEquals(object, object) object.ToString() Namespace: Titanium.Web.Proxy.Caching Assembly: Titanium.Web.Proxy.dll Syntax public sealed class HttpResponseCacheMiddleware : IProxyMiddleware Constructors | Edit this page View Source HttpResponseCacheMiddleware(IHttpResponseCache, TimeSpan?) Declaration public HttpResponseCacheMiddleware(IHttpResponseCache cache, TimeSpan? defaultTtl = null) Parameters Type Name Description IHttpResponseCache cache TimeSpan? defaultTtl Methods | Edit this page View Source InvokeAsync(ProxyMiddlewareContext, ProxyMiddlewareDelegate, CancellationToken) Declaration public ValueTask InvokeAsync(ProxyMiddlewareContext context, ProxyMiddlewareDelegate next, CancellationToken cancellationToken) Parameters Type Name Description ProxyMiddlewareContext context ProxyMiddlewareDelegate next CancellationToken cancellationToken Returns Type Description ValueTask | Edit this page View Source TryCacheCurrentResponse(SessionEventArgs) Call from AfterResponse when caching upstream 200 bodies. Declaration public void TryCacheCurrentResponse(SessionEventArgs session) Parameters Type Name Description SessionEventArgs session Implements Titanium.Web.Proxy.Abstractions.Middleware.IProxyMiddleware" + }, + "api/Titanium.Web.Proxy.Caching.MemoryHttpResponseCache.html": { + "href": "api/Titanium.Web.Proxy.Caching.MemoryHttpResponseCache.html", + "title": "Class MemoryHttpResponseCache | Titanium Web Proxy", + "summary": "Class MemoryHttpResponseCache In-process GET/HEAD response cache. Zero cost when unused (not registered in middleware). Inheritance object MemoryHttpResponseCache Implements IHttpResponseCache Inherited Members object.Equals(object) object.Equals(object, object) object.GetHashCode() object.GetType() object.ReferenceEquals(object, object) object.ToString() Namespace: Titanium.Web.Proxy.Caching Assembly: Titanium.Web.Proxy.dll Syntax public sealed class MemoryHttpResponseCache : IHttpResponseCache Properties | Edit this page View Source Count Declaration public int Count { get; } Property Value Type Description int Methods | Edit this page View Source Purge(string?) Declaration public int Purge(string? pathPrefix = null) Parameters Type Name Description string pathPrefix Returns Type Description int | Edit this page View Source Set(string, CachedHttpResponse, TimeSpan) Declaration public void Set(string cacheKey, CachedHttpResponse response, TimeSpan ttl) Parameters Type Name Description string cacheKey CachedHttpResponse response TimeSpan ttl | Edit this page View Source TryGet(string, out CachedHttpResponse?) Declaration public bool TryGet(string cacheKey, out CachedHttpResponse? response) Parameters Type Name Description string cacheKey CachedHttpResponse response Returns Type Description bool Implements Titanium.Web.Proxy.Abstractions.Plugins.IHttpResponseCache" + }, + "api/Titanium.Web.Proxy.Caching.html": { + "href": "api/Titanium.Web.Proxy.Caching.html", + "title": "Namespace Titanium.Web.Proxy.Caching | Titanium Web Proxy", + "summary": "Namespace Titanium.Web.Proxy.Caching Classes HttpResponseCacheMiddleware GET/HEAD response cache middleware. Only allocated when placed in the middleware list; otherwise the hot path pays nothing. MemoryHttpResponseCache In-process GET/HEAD response cache. Zero cost when unused (not registered in middleware)." + }, + "api/Titanium.Web.Proxy.Clusters.ClusterManager.html": { + "href": "api/Titanium.Web.Proxy.Clusters.ClusterManager.html", + "title": "Class ClusterManager | Titanium Web Proxy", + "summary": "Class ClusterManager Thread-safe cluster manager. Snapshot is swapped with Interlocked.Exchange; in-flight sessions keep the previous snapshot reference. Inheritance object ClusterManager Implements IClusterManager Inherited Members object.Equals(object) object.Equals(object, object) object.GetHashCode() object.GetType() object.ReferenceEquals(object, object) object.ToString() Namespace: Titanium.Web.Proxy.Clusters Assembly: Titanium.Web.Proxy.dll Syntax public sealed class ClusterManager : IClusterManager Properties | Edit this page View Source Snapshot Declaration public ImmutableClusterSnapshot Snapshot { get; } Property Value Type Description ImmutableClusterSnapshot Methods | Edit this page View Source ApplyAsync(IReadOnlyList, CancellationToken) Declaration public ValueTask ApplyAsync(IReadOnlyList clusters, CancellationToken cancellationToken = default) Parameters Type Name Description IReadOnlyList clusters CancellationToken cancellationToken Returns Type Description ValueTask | Edit this page View Source GetDestinationState(string) Declaration public DestinationState GetDestinationState(string destinationId) Parameters Type Name Description string destinationId Returns Type Description DestinationState | Edit this page View Source SetDestinationState(string, DestinationState) Declaration public void SetDestinationState(string destinationId, DestinationState state) Parameters Type Name Description string destinationId DestinationState state Implements Titanium.Web.Proxy.Abstractions.Routing.IClusterManager" + }, + "api/Titanium.Web.Proxy.Clusters.DestinationHealthTracker.html": { + "href": "api/Titanium.Web.Proxy.Clusters.DestinationHealthTracker.html", + "title": "Class DestinationHealthTracker | Titanium Web Proxy", + "summary": "Class DestinationHealthTracker Passive health bookkeeping and active-request counters for destination pools. Inheritance object DestinationHealthTracker Inherited Members object.Equals(object) object.Equals(object, object) object.GetHashCode() object.GetType() object.ReferenceEquals(object, object) object.ToString() Namespace: Titanium.Web.Proxy.Clusters Assembly: Titanium.Web.Proxy.dll Syntax public sealed class DestinationHealthTracker Methods | Edit this page View Source GetActiveRequests(string) Declaration public long GetActiveRequests(string destinationId) Parameters Type Name Description string destinationId Returns Type Description long | Edit this page View Source ReportFailure(string, IClusterManager?, int) Declaration public void ReportFailure(string destinationId, IClusterManager? manager, int unhealthyThreshold = 3) Parameters Type Name Description string destinationId IClusterManager manager int unhealthyThreshold | Edit this page View Source ReportSuccess(string) Declaration public void ReportSuccess(string destinationId) Parameters Type Name Description string destinationId | Edit this page View Source TrackRequest(string) Declaration public IDisposable TrackRequest(string destinationId) Parameters Type Name Description string destinationId Returns Type Description IDisposable" + }, + "api/Titanium.Web.Proxy.Clusters.LoadBalancer.html": { + "href": "api/Titanium.Web.Proxy.Clusters.LoadBalancer.html", + "title": "Class LoadBalancer | Titanium Web Proxy", + "summary": "Class LoadBalancer Selects destinations, skipping Draining/Maintenance/Unhealthy. Honors weight, least-requests, least-time, and affinity. Inheritance object LoadBalancer Implements ILoadBalancer ILatencyRecorder Inherited Members object.Equals(object) object.Equals(object, object) object.GetHashCode() object.GetType() object.ReferenceEquals(object, object) object.ToString() Namespace: Titanium.Web.Proxy.Clusters Assembly: Titanium.Web.Proxy.dll Syntax public sealed class LoadBalancer : ILoadBalancer, ILatencyRecorder Constructors | Edit this page View Source LoadBalancer(DestinationHealthTracker?) Declaration public LoadBalancer(DestinationHealthTracker? health = null) Parameters Type Name Description DestinationHealthTracker health Properties | Edit this page View Source Health Declaration public DestinationHealthTracker Health { get; } Property Value Type Description DestinationHealthTracker Methods | Edit this page View Source GetDestinationLatency(string) Last observed latency for a destination; null if unknown. Declaration public TimeSpan? GetDestinationLatency(string destinationId) Parameters Type Name Description string destinationId Returns Type Description TimeSpan? | Edit this page View Source Record(string, TimeSpan) Declaration public void Record(string name, TimeSpan duration) Parameters Type Name Description string name TimeSpan duration | Edit this page View Source RecordDestination(string, TimeSpan) Record per-destination RTT for least-time LB. Default no-op. Declaration public void RecordDestination(string destinationId, TimeSpan duration) Parameters Type Name Description string destinationId TimeSpan duration | Edit this page View Source Select(ClusterConfig, ImmutableClusterSnapshot) Declaration public DestinationConfig? Select(ClusterConfig cluster, ImmutableClusterSnapshot snapshot) Parameters Type Name Description ClusterConfig cluster ImmutableClusterSnapshot snapshot Returns Type Description DestinationConfig | Edit this page View Source Select(ClusterConfig, ImmutableClusterSnapshot, LoadBalanceContext) Select with affinity / algorithm context. Default forwards to Titanium.Web.Proxy.Abstractions.Routing.ILoadBalancer.Select(Titanium.Web.Proxy.Abstractions.Clusters.ClusterConfig, Titanium.Web.Proxy.Abstractions.Clusters.ImmutableClusterSnapshot). Declaration public DestinationConfig? Select(ClusterConfig cluster, ImmutableClusterSnapshot snapshot, LoadBalanceContext context) Parameters Type Name Description ClusterConfig cluster ImmutableClusterSnapshot snapshot LoadBalanceContext context Returns Type Description DestinationConfig Implements Titanium.Web.Proxy.Abstractions.Routing.ILoadBalancer Titanium.Web.Proxy.Abstractions.Plugins.ILatencyRecorder" + }, + "api/Titanium.Web.Proxy.Clusters.html": { + "href": "api/Titanium.Web.Proxy.Clusters.html", + "title": "Namespace Titanium.Web.Proxy.Clusters | Titanium Web Proxy", + "summary": "Namespace Titanium.Web.Proxy.Clusters Classes ClusterManager Thread-safe cluster manager. Snapshot is swapped with Interlocked.Exchange; in-flight sessions keep the previous snapshot reference. DestinationHealthTracker Passive health bookkeeping and active-request counters for destination pools. LoadBalancer Selects destinations, skipping Draining/Maintenance/Unhealthy. Honors weight, least-requests, least-time, and affinity." + }, "api/Titanium.Web.Proxy.Diagnostics.ClientTlsTiming.html": { "href": "api/Titanium.Web.Proxy.Diagnostics.ClientTlsTiming.html", "title": "Class ClientTlsTiming | Titanium Web Proxy", @@ -72,7 +112,7 @@ "api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html": { "href": "api/Titanium.Web.Proxy.EventArguments.SessionEventArgs.html", "title": "Class SessionEventArgs | Titanium Web Proxy", - "summary": "Class SessionEventArgs Holds info related to a single proxy session (single request/response exchange). Under HTTP/2 and HTTP/3, many sessions share one client connection (one stream each); ending a session ends that request/response exchange, not necessarily the connection. Inheritance object EventArgs ProxyEventArgsBase SessionEventArgsBase SessionEventArgs Implements IDisposable Inherited Members SessionEventArgsBase.BufferPool SessionEventArgsBase.ClientConnectionId SessionEventArgsBase.ServerConnectionId SessionEventArgsBase.Timing SessionEventArgsBase.UpstreamConnectionTiming SessionEventArgsBase.UserData SessionEventArgsBase.ConnectTimeout SessionEventArgsBase.EnableWinAuth SessionEventArgsBase.IsHttps SessionEventArgsBase.ClientLocalEndPoint SessionEventArgsBase.ClientRemoteEndPoint SessionEventArgsBase.ClientEndPoint SessionEventArgsBase.ServerRemoteEndPoint SessionEventArgsBase.ServerIpAddress SessionEventArgsBase.HttpClient SessionEventArgsBase.WebSession SessionEventArgsBase.CustomUpStreamProxy SessionEventArgsBase.CustomUpStreamProxyUsed SessionEventArgsBase.ProxyEndPoint SessionEventArgsBase.LocalEndPoint SessionEventArgsBase.IsTransparent SessionEventArgsBase.IsSocks SessionEventArgsBase.Exception SessionEventArgsBase.Logger SessionEventArgsBase.Dispose() SessionEventArgsBase.OnException(Exception) SessionEventArgsBase.DataSent SessionEventArgsBase.DataReceived SessionEventArgsBase.TerminateSession() ProxyEventArgsBase.ClientUserData EventArgs.Empty object.Equals(object) object.Equals(object, object) object.GetHashCode() object.GetType() object.MemberwiseClone() object.ReferenceEquals(object, object) object.ToString() Namespace: Titanium.Web.Proxy.EventArguments Assembly: Titanium.Web.Proxy.dll Syntax public class SessionEventArgs : SessionEventArgsBase, IDisposable Properties | Edit this page View Source IdleReadTimeout Per-session override for IdleReadTimeoutSeconds. null uses the server default; Zero or negative disables. Declaration public TimeSpan? IdleReadTimeout { get; set; } Property Value Type Description TimeSpan? | Edit this page View Source IdleWriteTimeout Per-session override for IdleWriteTimeoutSeconds. null uses the server default; Zero or negative disables. Declaration public TimeSpan? IdleWriteTimeout { get; set; } Property Value Type Description TimeSpan? | Edit this page View Source IsPromise Is this session a HTTP/2 promise? Declaration public bool IsPromise { get; } Property Value Type Description bool | Edit this page View Source MaxBufferedBodyBytes Per-session override for MaxBufferedBodyBytes. null uses the server default. Set in BeforeRequest to increase the limit for large uploads/downloads without relaxing the global limit for all requests. Declaration public int? MaxBufferedBodyBytes { get; set; } Property Value Type Description int? | Edit this page View Source MaxWebSocketFramePayloadBytes Per-session override for MaxWebSocketFramePayloadBytes. null uses the server default. Set in BeforeRequest before the WebSocket upgrade completes. Declaration public int? MaxWebSocketFramePayloadBytes { get; set; } Property Value Type Description int? | Edit this page View Source NetworkFailureRetryAttempts Per-session override for NetworkFailureRetryAttempts. null uses the server default. Set to 0 in BeforeRequest for non-idempotent methods (POST, PATCH) to prevent unsafe retries. Declaration public int? NetworkFailureRetryAttempts { get; set; } Property Value Type Description int? | Edit this page View Source OriginHttpVersionPolicy Per-session override for OriginHttpVersionPolicy. null uses the server default (PreserveClientVersion unless the server property was changed). Set in BeforeRequest. Declaration public OriginHttpVersionPolicy? OriginHttpVersionPolicy { get; set; } Property Value Type Description OriginHttpVersionPolicy? | Edit this page View Source ReRequest Should we send the request again ? Declaration public bool ReRequest { get; set; } Property Value Type Description bool | Edit this page View Source RequestTimeout Per-session override for RequestTimeoutSeconds. null uses the server default; Zero or negative disables. Declaration public TimeSpan? RequestTimeout { get; set; } Property Value Type Description TimeSpan? | Edit this page View Source ResponseHeaderTimeout Per-session override for ResponseHeaderTimeoutSeconds. null uses the server default; Zero or negative disables. Declaration public TimeSpan? ResponseHeaderTimeout { get; set; } Property Value Type Description TimeSpan? | Edit this page View Source UpstreamHttpProtocol Per-request outbound protocol version policy. Overrides the connection-level UpstreamHttpProtocol value set during BeforeSslAuthenticate / BeforeQuicAuthenticate for this single request stream only. null uses the connection-level policy (or Auto if none was set). Evaluated in BeforeRequest; changes after that have no effect. On an H3 inbound connection (one client QUIC connection serving many concurrent streams), each stream resolves its outbound protocol independently after BeforeRequest fires, making per-stream protocol overrides possible even though the inbound leg is already QUIC. Declaration public UpstreamHttpProtocol? UpstreamHttpProtocol { get; set; } Property Value Type Description UpstreamHttpProtocol? | Edit this page View Source WebSocketClientWriter Inject frames toward the local client (server→client direction, unmasked). Available only while an intercepted WebSocket relay is active. Declaration public WebSocketFrameWriter? WebSocketClientWriter { get; } Property Value Type Description WebSocketFrameWriter | Edit this page View Source WebSocketDecoder Declaration [Obsolete(\"Use [WebSocketDecoderReceive] instead\")] public WebSocketDecoder WebSocketDecoder { get; } Property Value Type Description WebSocketDecoder | Edit this page View Source WebSocketDecoderReceive Declaration public WebSocketDecoder WebSocketDecoderReceive { get; } Property Value Type Description WebSocketDecoder | Edit this page View Source WebSocketDecoderSend Declaration public WebSocketDecoder WebSocketDecoderSend { get; } Property Value Type Description WebSocketDecoder | Edit this page View Source WebSocketServerWriter Inject frames toward the remote server (client→server direction, masked). Available only while an intercepted WebSocket relay is active. Declaration public WebSocketFrameWriter? WebSocketServerWriter { get; } Property Value Type Description WebSocketFrameWriter Methods | Edit this page View Source Dispose(bool) Declaration protected override void Dispose(bool disposing) Parameters Type Name Description bool disposing Overrides SessionEventArgsBase.Dispose(bool) | Edit this page View Source DrainClientBodyAsync(CancellationToken) Drains (reads and discards) any unread client request body from the underlying stream or connection so the client's keep-alive / multiplexed connection can be reused. This reads the bytes off the wire without buffering them in memory. It is a no-op if the body was already received or the request has no body. Declaration public Task DrainClientBodyAsync(CancellationToken cancellationToken = default) Parameters Type Name Description CancellationToken cancellationToken Returns Type Description Task Remarks Useful when short-circuiting a request (e.g. Respond(Response, bool), RespondStreaming(Response, Func, bool), or blocking) while the client is uploading a body: draining leaves the client connection in a reusable state. Note the proxy already drains the client body automatically on the normal synthetic-response path, so this is only needed for advanced/manual control. Warning: for an endless chunked request (one that never sends its terminating zero chunk) this will block until the passed cancellationToken is cancelled or the connection closes. | Edit this page View Source DrainServerBodyAsync(CancellationToken) Drains (reads and discards) any unread server response body from the underlying client/server stream or connection so it can be reused. This reads the bytes off the wire without buffering them in memory. It is a no-op if the body was already received or the response has no body. Declaration public Task DrainServerBodyAsync(CancellationToken cancellationToken = default) Parameters Type Name Description CancellationToken cancellationToken Returns Type Description Task Remarks Warning: for an endless chunked response (one that never sends its terminating zero chunk) this will block until the passed cancellationToken is cancelled or the connection closes. In that case prefer closing the connection (e.g. TerminateServerConnection()) instead. | Edit this page View Source GenericResponse(byte[], HttpStatusCode, IDictionary, bool) Before request is made to server respond with the specified byte[], the specified status to client. And then ignore the request. Declaration public void GenericResponse(byte[] result, HttpStatusCode status, IDictionary headers, bool closeServerConnection = false) Parameters Type Name Description byte[] result The bytes to sent. HttpStatusCode status The HTTP status code. IDictionary headers The HTTP headers. bool closeServerConnection Close the server connection used by request if any? | Edit this page View Source GenericResponse(byte[], HttpStatusCode, IEnumerable?, bool) Before request is made to server respond with the specified byte[], the specified status to client. And then ignore the request. Declaration public void GenericResponse(byte[] result, HttpStatusCode status, IEnumerable? headers, bool closeServerConnection = false) Parameters Type Name Description byte[] result The bytes to sent. HttpStatusCode status The HTTP status code. IEnumerable headers The HTTP headers. bool closeServerConnection Close the server connection used by request if any? | Edit this page View Source GenericResponse(string, HttpStatusCode, IDictionary?, bool) Before request is made to server respond with the specified HTML string and the specified status to client. And then ignore the request. Declaration public void GenericResponse(string html, HttpStatusCode status, IDictionary? headers, bool closeServerConnection = false) Parameters Type Name Description string html The html content. HttpStatusCode status The HTTP status code. IDictionary headers The HTTP headers. bool closeServerConnection Close the server connection used by request if any? | Edit this page View Source GenericResponse(string, HttpStatusCode, IEnumerable?, bool) Before request is made to server respond with the specified HTML string and the specified status to client. And then ignore the request. Declaration public void GenericResponse(string html, HttpStatusCode status, IEnumerable? headers = null, bool closeServerConnection = false) Parameters Type Name Description string html The html content. HttpStatusCode status The HTTP status code. IEnumerable headers The HTTP headers. bool closeServerConnection Close the server connection used by request if any? | Edit this page View Source GetRequestBody(CancellationToken) Gets the request body as bytes. Declaration public Task GetRequestBody(CancellationToken cancellationToken = default) Parameters Type Name Description CancellationToken cancellationToken Optional cancellation token for this async task. Returns Type Description Task The body as bytes. | Edit this page View Source GetRequestBodyAsString(CancellationToken) Gets the request body as string. Declaration public Task GetRequestBodyAsString(CancellationToken cancellationToken = default) Parameters Type Name Description CancellationToken cancellationToken Optional cancellation token for this async task. Returns Type Description Task The body as string. | Edit this page View Source GetResponseBody(CancellationToken) Gets the response body as bytes. Declaration public Task GetResponseBody(CancellationToken cancellationToken = default) Parameters Type Name Description CancellationToken cancellationToken Optional cancellation token for this async task. Returns Type Description Task The resulting bytes. | Edit this page View Source GetResponseBodyAsString(CancellationToken) Gets the response body as string. Declaration public Task GetResponseBodyAsString(CancellationToken cancellationToken = default) Parameters Type Name Description CancellationToken cancellationToken Optional cancellation token for this async task. Returns Type Description Task The string body. | Edit this page View Source Ok(byte[], IDictionary?, bool) Before request is made to server respond with the specified byte[] to client and ignore the request. Declaration public void Ok(byte[] result, IDictionary? headers, bool closeServerConnection = false) Parameters Type Name Description byte[] result The html content bytes. IDictionary headers The HTTP headers. bool closeServerConnection Close the server connection used by request if any? | Edit this page View Source Ok(byte[], IEnumerable?, bool) Before request is made to server respond with the specified byte[] to client and ignore the request. Declaration public void Ok(byte[] result, IEnumerable? headers = null, bool closeServerConnection = false) Parameters Type Name Description byte[] result The html content bytes. IEnumerable headers The HTTP headers. bool closeServerConnection Close the server connection used by request if any? | Edit this page View Source Ok(string, IDictionary?, bool) Before request is made to server respond with the specified HTML string to client and ignore the request. Declaration public void Ok(string html, IDictionary? headers, bool closeServerConnection = false) Parameters Type Name Description string html HTML content to sent. IDictionary headers HTTP response headers. bool closeServerConnection Close the server connection used by request if any? | Edit this page View Source Ok(string, IEnumerable?, bool) Before request is made to server respond with the specified HTML string to client and ignore the request. Declaration public void Ok(string html, IEnumerable? headers = null, bool closeServerConnection = false) Parameters Type Name Description string html HTML content to sent. IEnumerable headers HTTP response headers. bool closeServerConnection Close the server connection used by request if any? | Edit this page View Source Redirect(string, bool) Redirect to provided URL. Declaration public void Redirect(string url, bool closeServerConnection = false) Parameters Type Name Description string url The URL to redirect. bool closeServerConnection Close the server connection used by request if any? | Edit this page View Source Respond(Response, bool) Respond with given response object to client. Declaration public void Respond(Response response, bool closeServerConnection = false) Parameters Type Name Description Response response The response object. bool closeServerConnection Close the server connection used by request if any? Remarks If the server response was already received, the original server body (if any) is drained (syphoned) so the server connection stays reusable. To avoid reading a large or endless server body, pass closeServerConnection = true (or call TerminateServerConnection()), which closes the connection instead of draining. Note that an HTTP/1.1 connection cannot be both reused and have its body skipped. | Edit this page View Source RespondStreaming(Response, Func, bool) Respond to the client with a streamed body produced on the fly, without buffering the whole body in memory. Use this to serve large or endless bodies (e.g. a multi-gigabyte file or a synthetic server-sent-events stream) from scratch. Declaration public void RespondStreaming(Response response, Func writeBody, bool closeServerConnection = false) Parameters Type Name Description Response response The response object (status and headers). Func writeBody Delegate that writes the body to the provided stream. bool closeServerConnection Close the server connection used by request if any? Remarks Framing is chosen from the response headers: if a Content-Length is set on response the body is written raw (the delegate must write exactly that many bytes); otherwise HTTP/1.1 uses chunked transfer-encoding and HTTP/2/HTTP/3 emit DATA / stream frames. The delegate receives a write-only stream; only a single buffer is in flight at a time, so memory stays bounded regardless of the total size. See Respond(Response, bool) for the server body syphon-vs-close trade-off controlled by closeServerConnection. | Edit this page View Source SetRequestBody(byte[]) Sets the request body. Declaration public void SetRequestBody(byte[] body) Parameters Type Name Description byte[] body The request body bytes. | Edit this page View Source SetRequestBodyString(string) Sets the body with the specified string. Declaration public void SetRequestBodyString(string body) Parameters Type Name Description string body The request body string to set. | Edit this page View Source SetResponseBody(byte[]) Set the response body bytes. Declaration public void SetResponseBody(byte[] body) Parameters Type Name Description byte[] body The body bytes to set. | Edit this page View Source SetResponseBodyString(string) Replace the response body with the specified string. Declaration public void SetResponseBodyString(string body) Parameters Type Name Description string body The body string to set. | Edit this page View Source TerminateServerConnection() Terminate the connection to server at the end of this HTTP request/response session. Declaration public void TerminateServerConnection() Events | Edit this page View Source BeforeWebSocketFrame Fired for each WebSocket frame after upgrade when at least one handler is subscribed. Handlers may Forward, Drop, or Replace the frame, optionally with a Delay. Observational DataSent / DataReceived still fire for bytes actually written to the peer. Declaration public event AsyncEventHandler? BeforeWebSocketFrame Event Type Type Description AsyncEventHandler | Edit this page View Source MultipartRequestPartSent Occurs when multipart request part sent. Declaration public event EventHandler? MultipartRequestPartSent Event Type Type Description EventHandler Implements IDisposable" + "summary": "Class SessionEventArgs Holds info related to a single proxy session (single request/response exchange). Under HTTP/2 and HTTP/3, many sessions share one client connection (one stream each); ending a session ends that request/response exchange, not necessarily the connection. Inheritance object EventArgs ProxyEventArgsBase SessionEventArgsBase SessionEventArgs Implements IDisposable Inherited Members SessionEventArgsBase.BufferPool SessionEventArgsBase.ClientConnectionId SessionEventArgsBase.ServerConnectionId SessionEventArgsBase.Timing SessionEventArgsBase.UpstreamConnectionTiming SessionEventArgsBase.UserData SessionEventArgsBase.ConnectTimeout SessionEventArgsBase.EnableWinAuth SessionEventArgsBase.IsHttps SessionEventArgsBase.ClientLocalEndPoint SessionEventArgsBase.ClientRemoteEndPoint SessionEventArgsBase.ClientEndPoint SessionEventArgsBase.ServerRemoteEndPoint SessionEventArgsBase.ServerIpAddress SessionEventArgsBase.HttpClient SessionEventArgsBase.WebSession SessionEventArgsBase.CustomUpStreamProxy SessionEventArgsBase.CustomUpStreamProxyUsed SessionEventArgsBase.ProxyEndPoint SessionEventArgsBase.LocalEndPoint SessionEventArgsBase.IsTransparent SessionEventArgsBase.IsSocks SessionEventArgsBase.Exception SessionEventArgsBase.Logger SessionEventArgsBase.Dispose() SessionEventArgsBase.OnException(Exception) SessionEventArgsBase.DataSent SessionEventArgsBase.DataReceived SessionEventArgsBase.TerminateSession() ProxyEventArgsBase.ClientUserData EventArgs.Empty object.Equals(object) object.Equals(object, object) object.GetHashCode() object.GetType() object.MemberwiseClone() object.ReferenceEquals(object, object) object.ToString() Namespace: Titanium.Web.Proxy.EventArguments Assembly: Titanium.Web.Proxy.dll Syntax public class SessionEventArgs : SessionEventArgsBase, IDisposable Properties | Edit this page View Source IdleReadTimeout Per-session override for IdleReadTimeoutSeconds. null uses the server default; Zero or negative disables. Declaration public TimeSpan? IdleReadTimeout { get; set; } Property Value Type Description TimeSpan? | Edit this page View Source IdleWriteTimeout Per-session override for IdleWriteTimeoutSeconds. null uses the server default; Zero or negative disables. Declaration public TimeSpan? IdleWriteTimeout { get; set; } Property Value Type Description TimeSpan? | Edit this page View Source IsPromise Is this session a HTTP/2 promise? Declaration public bool IsPromise { get; } Property Value Type Description bool | Edit this page View Source MaxBufferedBodyBytes Per-session override for MaxBufferedBodyBytes. null uses the server default. Set in BeforeRequest to increase the limit for large uploads/downloads without relaxing the global limit for all requests. Declaration public int? MaxBufferedBodyBytes { get; set; } Property Value Type Description int? | Edit this page View Source MaxWebSocketFramePayloadBytes Per-session override for MaxWebSocketFramePayloadBytes. null uses the server default. Set in BeforeRequest before the WebSocket upgrade completes. Declaration public int? MaxWebSocketFramePayloadBytes { get; set; } Property Value Type Description int? | Edit this page View Source NetworkFailureRetryAttempts Per-session override for NetworkFailureRetryAttempts. null uses the server default. Set to 0 in BeforeRequest for non-idempotent methods (POST, PATCH) to prevent unsafe retries. Declaration public int? NetworkFailureRetryAttempts { get; set; } Property Value Type Description int? | Edit this page View Source OriginHttpVersionPolicy Per-session override for OriginHttpVersionPolicy. null uses the server default (PreserveClientVersion unless the server property was changed). Set in BeforeRequest. Declaration public OriginHttpVersionPolicy? OriginHttpVersionPolicy { get; set; } Property Value Type Description OriginHttpVersionPolicy? | Edit this page View Source ReRequest Should we send the request again ? Declaration public bool ReRequest { get; set; } Property Value Type Description bool | Edit this page View Source RequestTimeout Per-session override for RequestTimeoutSeconds. null uses the server default; Zero or negative disables. Declaration public TimeSpan? RequestTimeout { get; set; } Property Value Type Description TimeSpan? | Edit this page View Source ResponseHeaderTimeout Per-session override for ResponseHeaderTimeoutSeconds. null uses the server default; Zero or negative disables. Declaration public TimeSpan? ResponseHeaderTimeout { get; set; } Property Value Type Description TimeSpan? | Edit this page View Source UpstreamHttpProtocol Per-request outbound protocol version policy. Overrides the connection-level UpstreamHttpProtocol value set during BeforeSslAuthenticate / BeforeQuicAuthenticate for this single request stream only. null uses the connection-level policy (or Auto if none was set). Evaluated in BeforeRequest; changes after that have no effect. On an H3 inbound connection (one client QUIC connection serving many concurrent streams), each stream resolves its outbound protocol independently after BeforeRequest fires, making per-stream protocol overrides possible even though the inbound leg is already QUIC. Declaration public UpstreamHttpProtocol? UpstreamHttpProtocol { get; set; } Property Value Type Description UpstreamHttpProtocol? | Edit this page View Source WebSocketClientWriter Inject frames toward the local client (server→client direction, unmasked). Available only while an intercepted WebSocket relay is active. Declaration public WebSocketFrameWriter? WebSocketClientWriter { get; } Property Value Type Description WebSocketFrameWriter | Edit this page View Source WebSocketDecoder Declaration [Obsolete(\"Use [WebSocketDecoderReceive] instead\")] public WebSocketDecoder WebSocketDecoder { get; } Property Value Type Description WebSocketDecoder | Edit this page View Source WebSocketDecoderReceive Declaration public WebSocketDecoder WebSocketDecoderReceive { get; } Property Value Type Description WebSocketDecoder | Edit this page View Source WebSocketDecoderSend Declaration public WebSocketDecoder WebSocketDecoderSend { get; } Property Value Type Description WebSocketDecoder | Edit this page View Source WebSocketServerWriter Inject frames toward the remote server (client→server direction, masked). Available only while an intercepted WebSocket relay is active. Declaration public WebSocketFrameWriter? WebSocketServerWriter { get; } Property Value Type Description WebSocketFrameWriter Methods | Edit this page View Source Dispose(bool) Declaration protected override void Dispose(bool disposing) Parameters Type Name Description bool disposing Overrides SessionEventArgsBase.Dispose(bool) | Edit this page View Source DrainClientBodyAsync(CancellationToken) Drains (reads and discards) any unread client request body from the underlying stream or connection so the client's keep-alive / multiplexed connection can be reused. This reads the bytes off the wire without buffering them in memory. It is a no-op if the body was already received or the request has no body. Declaration public Task DrainClientBodyAsync(CancellationToken cancellationToken = default) Parameters Type Name Description CancellationToken cancellationToken Returns Type Description Task Remarks Useful when short-circuiting a request (e.g. Respond(Response, bool), RespondStreaming(StreamingProxyResult, bool), or blocking) while the client is uploading a body: draining leaves the client connection in a reusable state. Note the proxy already drains the client body automatically on the normal synthetic-response path, so this is only needed for advanced/manual control. Warning: for an endless chunked request (one that never sends its terminating zero chunk) this will block until the passed cancellationToken is cancelled or the connection closes. | Edit this page View Source DrainServerBodyAsync(CancellationToken) Drains (reads and discards) any unread server response body from the underlying client/server stream or connection so it can be reused. This reads the bytes off the wire without buffering them in memory. It is a no-op if the body was already received or the response has no body. Declaration public Task DrainServerBodyAsync(CancellationToken cancellationToken = default) Parameters Type Name Description CancellationToken cancellationToken Returns Type Description Task Remarks Warning: for an endless chunked response (one that never sends its terminating zero chunk) this will block until the passed cancellationToken is cancelled or the connection closes. In that case prefer closing the connection (e.g. TerminateServerConnection()) instead. | Edit this page View Source GenericResponse(byte[], HttpStatusCode, IDictionary, bool) Before request is made to server respond with the specified byte[], the specified status to client. And then ignore the request. Declaration public void GenericResponse(byte[] result, HttpStatusCode status, IDictionary headers, bool closeServerConnection = false) Parameters Type Name Description byte[] result The bytes to sent. HttpStatusCode status The HTTP status code. IDictionary headers The HTTP headers. bool closeServerConnection Close the server connection used by request if any? | Edit this page View Source GenericResponse(byte[], HttpStatusCode, IEnumerable?, bool) Before request is made to server respond with the specified byte[], the specified status to client. And then ignore the request. Declaration public void GenericResponse(byte[] result, HttpStatusCode status, IEnumerable? headers, bool closeServerConnection = false) Parameters Type Name Description byte[] result The bytes to sent. HttpStatusCode status The HTTP status code. IEnumerable headers The HTTP headers. bool closeServerConnection Close the server connection used by request if any? | Edit this page View Source GenericResponse(string, HttpStatusCode, IDictionary?, bool) Before request is made to server respond with the specified HTML string and the specified status to client. And then ignore the request. Declaration public void GenericResponse(string html, HttpStatusCode status, IDictionary? headers, bool closeServerConnection = false) Parameters Type Name Description string html The html content. HttpStatusCode status The HTTP status code. IDictionary headers The HTTP headers. bool closeServerConnection Close the server connection used by request if any? | Edit this page View Source GenericResponse(string, HttpStatusCode, IEnumerable?, bool) Before request is made to server respond with the specified HTML string and the specified status to client. And then ignore the request. Declaration public void GenericResponse(string html, HttpStatusCode status, IEnumerable? headers = null, bool closeServerConnection = false) Parameters Type Name Description string html The html content. HttpStatusCode status The HTTP status code. IEnumerable headers The HTTP headers. bool closeServerConnection Close the server connection used by request if any? | Edit this page View Source GetRequestBody(CancellationToken) Gets the request body as bytes. Declaration public Task GetRequestBody(CancellationToken cancellationToken = default) Parameters Type Name Description CancellationToken cancellationToken Optional cancellation token for this async task. Returns Type Description Task The body as bytes. | Edit this page View Source GetRequestBodyAsString(CancellationToken) Gets the request body as string. Declaration public Task GetRequestBodyAsString(CancellationToken cancellationToken = default) Parameters Type Name Description CancellationToken cancellationToken Optional cancellation token for this async task. Returns Type Description Task The body as string. | Edit this page View Source GetResponseBody(CancellationToken) Gets the response body as bytes. Declaration public Task GetResponseBody(CancellationToken cancellationToken = default) Parameters Type Name Description CancellationToken cancellationToken Optional cancellation token for this async task. Returns Type Description Task The resulting bytes. | Edit this page View Source GetResponseBodyAsString(CancellationToken) Gets the response body as string. Declaration public Task GetResponseBodyAsString(CancellationToken cancellationToken = default) Parameters Type Name Description CancellationToken cancellationToken Optional cancellation token for this async task. Returns Type Description Task The string body. | Edit this page View Source Ok(byte[], IDictionary?, bool) Before request is made to server respond with the specified byte[] to client and ignore the request. Declaration public void Ok(byte[] result, IDictionary? headers, bool closeServerConnection = false) Parameters Type Name Description byte[] result The html content bytes. IDictionary headers The HTTP headers. bool closeServerConnection Close the server connection used by request if any? | Edit this page View Source Ok(byte[], IEnumerable?, bool) Before request is made to server respond with the specified byte[] to client and ignore the request. Declaration public void Ok(byte[] result, IEnumerable? headers = null, bool closeServerConnection = false) Parameters Type Name Description byte[] result The html content bytes. IEnumerable headers The HTTP headers. bool closeServerConnection Close the server connection used by request if any? | Edit this page View Source Ok(string, IDictionary?, bool) Before request is made to server respond with the specified HTML string to client and ignore the request. Declaration public void Ok(string html, IDictionary? headers, bool closeServerConnection = false) Parameters Type Name Description string html HTML content to sent. IDictionary headers HTTP response headers. bool closeServerConnection Close the server connection used by request if any? | Edit this page View Source Ok(string, IEnumerable?, bool) Before request is made to server respond with the specified HTML string to client and ignore the request. Declaration public void Ok(string html, IEnumerable? headers = null, bool closeServerConnection = false) Parameters Type Name Description string html HTML content to sent. IEnumerable headers HTTP response headers. bool closeServerConnection Close the server connection used by request if any? | Edit this page View Source Redirect(string, bool) Redirect to provided URL. Declaration public void Redirect(string url, bool closeServerConnection = false) Parameters Type Name Description string url The URL to redirect. bool closeServerConnection Close the server connection used by request if any? | Edit this page View Source Respond(Response, bool) Respond with given response object to client. Declaration public void Respond(Response response, bool closeServerConnection = false) Parameters Type Name Description Response response The response object. bool closeServerConnection Close the server connection used by request if any? Remarks If the server response was already received, the original server body (if any) is drained (syphoned) so the server connection stays reusable. To avoid reading a large or endless server body, pass closeServerConnection = true (or call TerminateServerConnection()), which closes the connection instead of draining. Note that an HTTP/1.1 connection cannot be both reused and have its body skipped. | Edit this page View Source RespondStreaming(Response, Func, bool) Respond to the client with a streamed body produced on the fly, without buffering the whole body in memory. Use this to serve large or endless bodies (e.g. a multi-gigabyte file or a synthetic server-sent-events stream) from scratch. Declaration public void RespondStreaming(Response response, Func writeBody, bool closeServerConnection = false) Parameters Type Name Description Response response The response object (status and headers). Func writeBody Delegate that writes the body to the provided stream. bool closeServerConnection Close the server connection used by request if any? Remarks Framing is chosen from the response headers: if a Content-Length is set on response the body is written raw (the delegate must write exactly that many bytes); otherwise HTTP/1.1 uses chunked transfer-encoding and HTTP/2/HTTP/3 emit DATA / stream frames. The delegate receives a write-only stream; only a single buffer is in flight at a time, so memory stays bounded regardless of the total size. See Respond(Response, bool) for the server body syphon-vs-close trade-off controlled by closeServerConnection. | Edit this page View Source RespondStreaming(StreamingProxyResult, bool) Respond to the client with a streamed body produced by Stream(HttpStatusCode, string, Func, long?) or File(string, string, HttpStatusCode). Declaration public void RespondStreaming(StreamingProxyResult result, bool closeServerConnection) Parameters Type Name Description StreamingProxyResult result Streaming response metadata and body writer. bool closeServerConnection Close the server connection used by request if any? | Edit this page View Source SetRequestBody(byte[]) Sets the request body. Declaration public void SetRequestBody(byte[] body) Parameters Type Name Description byte[] body The request body bytes. | Edit this page View Source SetRequestBodyString(string) Sets the body with the specified string. Declaration public void SetRequestBodyString(string body) Parameters Type Name Description string body The request body string to set. | Edit this page View Source SetResponseBody(byte[]) Set the response body bytes. Declaration public void SetResponseBody(byte[] body) Parameters Type Name Description byte[] body The body bytes to set. | Edit this page View Source SetResponseBodyString(string) Replace the response body with the specified string. Declaration public void SetResponseBodyString(string body) Parameters Type Name Description string body The body string to set. | Edit this page View Source TerminateServerConnection() Terminate the connection to server at the end of this HTTP request/response session. Declaration public void TerminateServerConnection() Events | Edit this page View Source BeforeWebSocketFrame Fired for each WebSocket frame after upgrade when at least one handler is subscribed. Handlers may Forward, Drop, or Replace the frame, optionally with a Delay. Observational DataSent / DataReceived still fire for bytes actually written to the peer. Declaration public event AsyncEventHandler? BeforeWebSocketFrame Event Type Type Description AsyncEventHandler | Edit this page View Source MultipartRequestPartSent Occurs when multipart request part sent. Declaration public event EventHandler? MultipartRequestPartSent Event Type Type Description EventHandler Implements IDisposable" }, "api/Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html": { "href": "api/Titanium.Web.Proxy.EventArguments.SessionEventArgsBase.html", @@ -199,6 +239,11 @@ "title": "Class KnownHeaders | Titanium Web Proxy", "summary": "Class KnownHeaders Well known http headers. Inheritance object KnownHeaders Inherited Members object.Equals(object) object.Equals(object, object) object.GetHashCode() object.GetType() object.MemberwiseClone() object.ReferenceEquals(object, object) object.ToString() Namespace: Titanium.Web.Proxy.Http Assembly: Titanium.Web.Proxy.dll Syntax public static class KnownHeaders Fields | Edit this page View Source Accept Declaration public static readonly KnownHeader Accept Field Value Type Description KnownHeader | Edit this page View Source AcceptEncoding Declaration public static readonly KnownHeader AcceptEncoding Field Value Type Description KnownHeader | Edit this page View Source AltSvc Declaration public static readonly KnownHeader AltSvc Field Value Type Description KnownHeader | Edit this page View Source Authorization Declaration public static readonly KnownHeader Authorization Field Value Type Description KnownHeader | Edit this page View Source Connection Declaration public static readonly KnownHeader Connection Field Value Type Description KnownHeader | Edit this page View Source ConnectionClose Declaration public static readonly KnownHeader ConnectionClose Field Value Type Description KnownHeader | Edit this page View Source ConnectionKeepAlive Declaration public static readonly KnownHeader ConnectionKeepAlive Field Value Type Description KnownHeader | Edit this page View Source ContentEncoding Declaration public static readonly KnownHeader ContentEncoding Field Value Type Description KnownHeader | Edit this page View Source ContentEncodingBrotli Declaration public static readonly KnownHeader ContentEncodingBrotli Field Value Type Description KnownHeader | Edit this page View Source ContentEncodingDeflate Declaration public static readonly KnownHeader ContentEncodingDeflate Field Value Type Description KnownHeader | Edit this page View Source ContentEncodingGzip Declaration public static readonly KnownHeader ContentEncodingGzip Field Value Type Description KnownHeader | Edit this page View Source ContentEncodingIdentity Declaration public static readonly KnownHeader ContentEncodingIdentity Field Value Type Description KnownHeader | Edit this page View Source ContentLength Declaration public static readonly KnownHeader ContentLength Field Value Type Description KnownHeader | Edit this page View Source ContentLengthHttp2 Declaration public static readonly KnownHeader ContentLengthHttp2 Field Value Type Description KnownHeader | Edit this page View Source ContentType Declaration public static readonly KnownHeader ContentType Field Value Type Description KnownHeader | Edit this page View Source ContentTypeBoundary Declaration public static readonly KnownHeader ContentTypeBoundary Field Value Type Description KnownHeader | Edit this page View Source ContentTypeCharset Declaration public static readonly KnownHeader ContentTypeCharset Field Value Type Description KnownHeader | Edit this page View Source Expect Declaration public static readonly KnownHeader Expect Field Value Type Description KnownHeader | Edit this page View Source Expect100Continue Declaration public static readonly KnownHeader Expect100Continue Field Value Type Description KnownHeader | Edit this page View Source Host Declaration public static readonly KnownHeader Host Field Value Type Description KnownHeader | Edit this page View Source Location Declaration public static readonly KnownHeader Location Field Value Type Description KnownHeader | Edit this page View Source ProxyAuthenticate Declaration public static readonly KnownHeader ProxyAuthenticate Field Value Type Description KnownHeader | Edit this page View Source ProxyAuthorization Declaration public static readonly KnownHeader ProxyAuthorization Field Value Type Description KnownHeader | Edit this page View Source ProxyAuthorizationBasic Declaration public static readonly KnownHeader ProxyAuthorizationBasic Field Value Type Description KnownHeader | Edit this page View Source ProxyConnection Declaration public static readonly KnownHeader ProxyConnection Field Value Type Description KnownHeader | Edit this page View Source ProxyConnectionClose Declaration public static readonly KnownHeader ProxyConnectionClose Field Value Type Description KnownHeader | Edit this page View Source Trailer Declares which header field names will appear in the trailer of a chunked message (RFC 9110 §6.5). Titanium does not manage this header automatically; set/read it explicitly alongside TrailingHeaders if you want it announced/observed. Declaration public static readonly KnownHeader Trailer Field Value Type Description KnownHeader | Edit this page View Source TransferEncoding Declaration public static readonly KnownHeader TransferEncoding Field Value Type Description KnownHeader | Edit this page View Source TransferEncodingChunked Declaration public static readonly KnownHeader TransferEncodingChunked Field Value Type Description KnownHeader | Edit this page View Source Upgrade Declaration public static readonly KnownHeader Upgrade Field Value Type Description KnownHeader | Edit this page View Source UpgradeWebsocket Declaration public static readonly KnownHeader UpgradeWebsocket Field Value Type Description KnownHeader" }, + "api/Titanium.Web.Proxy.Http.ProxyResults.html": { + "href": "api/Titanium.Web.Proxy.Http.ProxyResults.html", + "title": "Class ProxyResults | Titanium Web Proxy", + "summary": "Class ProxyResults Factory methods that build synthetic Response or StreamingProxyResult objects for use with Respond(Response, bool) and RespondStreaming(StreamingProxyResult, bool). Inheritance object ProxyResults Inherited Members object.Equals(object) object.Equals(object, object) object.GetHashCode() object.GetType() object.MemberwiseClone() object.ReferenceEquals(object, object) object.ToString() Namespace: Titanium.Web.Proxy.Http Assembly: Titanium.Web.Proxy.dll Syntax public static class ProxyResults Methods | Edit this page View Source Bytes(byte[], string, HttpStatusCode) Builds a buffered response from raw bytes. Declaration public static Response Bytes(byte[] data, string contentType, HttpStatusCode status = HttpStatusCode.OK) Parameters Type Name Description byte[] data Body bytes. string contentType Full Content-Type value (for example image/png). HttpStatusCode status HTTP status code. Returns Type Description Response A response ready to pass to Respond(Response, bool). | Edit this page View Source File(string, string, HttpStatusCode) Builds a streamed response that serves a file from disk without buffering it in memory. Declaration public static StreamingProxyResult File(string path, string contentType, HttpStatusCode status = HttpStatusCode.OK) Parameters Type Name Description string path Path to the file. string contentType Full Content-Type value. HttpStatusCode status HTTP status code. Returns Type Description StreamingProxyResult A streaming result for RespondStreaming(StreamingProxyResult, bool). Remarks Does not handle HTTP Range requests. Clients expecting 206 Partial Content (browser