karpetrosyan / hishel

An elegant HTTP Cache implementation for HTTPX and HTTP Core.
https://hishel.com
BSD 3-Clause "New" or "Revised" License
175 stars 22 forks source link

"If-None-Match" append twice to headers #238

Open Guibod opened 4 months ago

Guibod commented 4 months ago

I really don’t know how this happens but hishel manages to build preconditional headers with twice "If-None-Match" items , Cloudflare doesn’t like that and raises an HTTP 400.

In hishel._async._transports.AsyncCacheTransport.handle_async_request, revalidation_request request already provides If-None-Match a construct_response_from_cache provides a with twice provided cache control key.

Screenshot 2024-06-17 at 10 48 42

Either the cache entry should not contains the cache control headers, or hishel._controller.Controller._make_request_conditional should deduplicate the cache headers.

karpetrosyan commented 4 months ago

Hi! I can't reproduce the bug using this script

import httpx
import hishel

responses = [
    httpx.Response(
        200,
        content=b"Hello, world!",
        headers={
            "Cache-Control": "max-age=1",
            "Date": "Mon, 01 Jan 2000 00:00:00 GMT",
            "ETag": "abc123",
        },
    ),
    httpx.Response(304),
]

class MockTransport(httpx.BaseTransport):
    def handle_request(self, request: httpx.Request) -> httpx.Response:
        print(request.headers.raw)
        return responses.pop(0)

transport = hishel.CacheTransport(transport=MockTransport())

resp = transport.handle_request(httpx.Request("GET", "https://www.example.com/"))
resp = transport.handle_request(httpx.Request("GET", "https://www.example.com/"))
print(resp.status_code == 200)
print(resp.extensions["from_cache"]) # True

Can you provide minimal reproducible example please?