Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

Add Lower Level (Complete) HTTP Request/Response API

Đang mở
#56 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

Đánh giá

Độ khó
5/5
Thời gian dự kiến
Hơn một tuần
Mức phù hợp với người mới
35/100
Loại issue
Tính năng
Độ rõ ràng
Khá rõ ràng
Mức độ hoạt động
Đình trệ
Công nghệ
python
Lĩnh vực
api, backend-api-design

Hướng nghiên cứu

Bắt đầu bằng việc xem xét các interface WIT và các stub được nêu tên trong stubs/wit_world/imports/http_req.py, http_resp.py, http_downstream.py và http_body.py. Sau đó, kiểm tra các SDK wrapper hiện có và hỗ trợ kiểm thử @on_viceroy của Viceroy. Công việc được xem là hoàn tất khi các API Request, Response, Headers, Body và metadata downstream được mô tả ở đây đã được triển khai, kèm coverage cho các thao tác HTTP được liệt kê và hành vi streaming.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

Overview

Add low-level HTTP Request and Response wrappers for advanced use cases requiring direct control over HTTP primitives, streaming, and Fastly-specific features.

Context - What exists:

  • WSGI adapter - Run Flask/Bottle apps unmodified
  • requests facade - Client API for making backend calls (requests.get(), etc.)
  • Low-level Request/Response API - This issue

What this enables:

  • Streaming/proxying without buffering entire request/response bodies
  • Access to Fastly-specific metadata (TLS fingerprints, client IP, compliance region)
  • Request transformation (modify incoming request, send to backend)
  • Cache control and surrogate key management
  • Foundation for other SDK features (cache, security, image optimizer APIs)

When to use what:

Use Case Use This Not This
Run Flask app WSGI adapter This
Make API calls from app requests.get() This
Proxy/stream requests This (Request/Response) requests facade
Need TLS/IP metadata This (Request.downstream) WSGI
Cache override/surrogate keys This requests facade

WIT Interface

interface http-req {
  use types.{error};
  use http-types.{http-version};
  use http-resp.{response};
  use http-body.{body};
  use backend.{backend};

  resource request {
    new: static func() -> result<request, error>;
    set-cache-override: func(cache-override: cache-override) -> result<_, error>;
    get-header-names: func(max-len: u64, cursor: u32) -> result<tuple<string, option<u32>>, error>;
    get-header-value: func(name: string, max-len: u64) -> result<option<list<u8>>, error>;
    get-header-values: func(name: string, max-len: u64, cursor: u32) -> result<tuple<list<u8>, option<u32>>, error>;
    set-header-values: func(name: string, values: list<u8>) -> result<_, error>;
    get-method: func(max-len: u64) -> result<string, error>;
    set-method: func(method: string) -> result<_, error>;
    get-uri: func(max-len: u64) -> result<string, error>;
    set-uri: func(uri: string) -> result<_, error>;
    get-version: func() -> result<http-version, error>;
    set-version: func(version: http-version) -> result<_, error>;
    send: func(backend: borrow<backend>, body: body) -> result<response, error>;
  }
}

interface http-resp {
  use types.{error};
  use http-types.{http-version};
  use http-body.{body};

  resource response {
    new: static func() -> result<response, error>;
    get-status: func() -> result<u16, error>;
    set-status: func(status: u16) -> result<_, error>;
    get-version: func() -> result<http-version, error>;
    set-version: func(version: http-version) -> result<_, error>;
    get-header-names: func(max-len: u64, cursor: u32) -> result<tuple<string, option<u32>>, error>;
    get-header-value: func(name: string, max-len: u64) -> result<option<list<u8>>, error>;
    get-header-values: func(name: string, max-len: u64, cursor: u32) -> result<tuple<list<u8>, option<u32>>, error>;
    set-header-values: func(name: string, values: list<u8>) -> result<_, error>;
    send-downstream: func(body: body, streaming: bool) -> result<_, error>;
  }
}

interface http-downstream {
  use types.{ip-address, error};
  use http-req.{request};

  downstream-client-ip-addr: func(ds-request: borrow<request>) -> option<ip-address>;
  downstream-server-ip-addr: func(ds-request: borrow<request>) -> option<ip-address>;
  downstream-client-request-id: func(ds-request: borrow<request>, max-len: u64) -> result<string, error>;
  downstream-tls-cipher-openssl-name: func(ds-request: borrow<request>, max-len: u64) -> result<option<list<u8>>, error>;
  downstream-tls-protocol: func(ds-request: borrow<request>, max-len: u64) -> result<option<list<u8>>, error>;
  downstream-tls-ja3-md5: func(ds-request: borrow<request>) -> result<option<list<u8>>, error>;
  downstream-tls-ja4: func(ds-request: borrow<request>, max-len: u64) -> result<option<string>, error>;
}

WIT bindings: stubs/wit_world/imports/http_req.py, http_resp.py, http_downstream.py, http_body.py

API Design

Core types:

  • Request - Wraps http_req.Request with Pythonic API (properties for method, uri, version)
  • Response - Wraps http_resp.Response
  • Headers - Dict-like interface for header manipulation
  • Body - io.IOBase-compatible for streaming (use shutil.copyfileobj(), etc.)

Key features:

  • Downstream metadata via request.downstream accessor:
    • client_ip()IPv4Address | IPv6Address
    • tls_cipher(), tls_ja3_md5(), tls_ja4() → TLS fingerprints
    • compliance_region() → GDPR/data residency region
  • Cache control: request.set_cache_override(ttl=..., surrogate_key=...)
  • Backend requests: request.send(backend, body)Response
  • Streaming: Bodies are file-like objects, work with stdlib

Example - Proxying with transformation:

def handle(incoming_req, incoming_body):
    # Access metadata
    client_ip = incoming_req.downstream.client_ip()
    
    # Transform request
    incoming_req.headers['X-Forwarded-For'] = str(client_ip)
    incoming_req.set_cache_override(ttl=3600, surrogate_key='user-data')
    
    # Send to backend (streaming)
    response = incoming_req.send('origin', incoming_body)
    return response

Integration with Existing SDK

WSGI Adapter

Can wrap incoming WIT request in Request object and expose via environ['fastly.request']:

from flask import Flask, request

@app.route("/api/data")
def get_data():
    fastly_req = request.environ['fastly.request']
    client_ip = fastly_req.downstream.client_ip()
    return {"client_ip": str(client_ip)}
Requests Facade

The requests.get() / requests.post() API is for making outgoing requests (client use case). It should NOT be extended for proxying - that's what this low-level API is for.

Clear separation:

  • Client pattern (outgoing): Use requests.get(url) - builds request from scratch
  • Server/Proxy pattern (incoming): Use Request/Response API - transforms received request

The requests facade could use Request wrappers internally but public API stays the same.

Cross-SDK Comparison:

  • Rust: Request/Response types wrapping HTTP standard types. Methods for headers, body streams, methods, URLs. Rich builder patterns. Strongly typed.
  • Go: Standard *http.Request/*http.Response from stdlib with Fastly extensions via embedded fields/methods.
  • JS: Standard Request/Response from Fetch API with Fastly extensions.

Recommended approach: Python should provide standard library-compatible types (similar to requests or urllib) while adding Fastly-specific extensions.

Viceroy Testing

Viceroy supports HTTP request/response handling with full metadata access in tests. The @on_viceroy decorator can provide synthetic requests with headers, bodies, and metadata.

Tests can verify:

  • Request/response creation and manipulation
  • Header handling (case-insensitive, multi-value)
  • Body streaming and reading
  • Downstream metadata access (may have defaults for TLS info in Viceroy)

HTTP operations are well-supported in Viceroy testing.

Reference

Ngôn ngữ chính
Python
Star
5
Fork
1
Chỉ số merge pull request
Không có pull request nào được merge trong 30 ngày

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của fastly/compute-sdk-python

Tất cả issue của fastly/compute-sdk-python

Issue tương tự

Thêm issue về Python

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.