File size: 2,126 Bytes
77cc323
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
from fastapi import FastAPI, Request, HTTPException
from fastapi.responses import StreamingResponse
from fastapi.middleware.cors import CORSMiddleware
from urllib.parse import urlparse
import httpx

ALLOWED_HOSTS = {
    "huggingface.co",
    "cas-bridge.xethub.hf.co",
    # Add more if you need: "cdn-lfs.huggingface.co", etc.
}

app = FastAPI(title="cozip CORS proxy")

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_methods=["GET", "HEAD", "OPTIONS"],
    allow_headers=["Range", "Content-Type"],
    expose_headers=["Content-Range", "Accept-Ranges", "Content-Length", "Content-Type"],
    max_age=86400,
)


@app.get("/")
async def root():
    return {
        "service": "cozip CORS proxy",
        "usage": "/proxy?url=<cozip_url>",
        "allowed_hosts": sorted(ALLOWED_HOSTS),
    }


@app.api_route("/proxy", methods=["GET", "HEAD"])
async def proxy(url: str, request: Request):
    parsed = urlparse(url)
    if parsed.hostname not in ALLOWED_HOSTS:
        raise HTTPException(
            status_code=403,
            detail=f"Host not allowed: {parsed.hostname}",
        )

    fwd_headers = {}
    if "range" in request.headers:
        fwd_headers["Range"] = request.headers["range"]

    client = httpx.AsyncClient(follow_redirects=True, timeout=60.0)
    try:
        req = client.build_request(request.method, url, headers=fwd_headers)
        upstream = await client.send(req, stream=True)
    except Exception as e:
        await client.aclose()
        raise HTTPException(status_code=502, detail=f"Upstream error: {e}")

    response_headers = {}
    for h in ("content-range", "accept-ranges", "content-length", "content-type"):
        if h in upstream.headers:
            response_headers[h] = upstream.headers[h]

    async def stream():
        try:
            async for chunk in upstream.aiter_bytes(chunk_size=65536):
                yield chunk
        finally:
            await upstream.aclose()
            await client.aclose()

    return StreamingResponse(
        stream(),
        status_code=upstream.status_code,
        headers=response_headers,
    )