Skip to content

Client-level params silently dropped when a request passes its own params #82

Description

@thomasht86

Summary

When a request passes its own params, the client-level params are silently discarded instead of merged. Since Client(params={"api_key": ...}) is the standard way to configure an API client, any request that adds a query parameter silently drops the credential.

A related defect: per-request cookies are emitted as a second Cookie: header rather than merged into one.

Cause

src/lib.rs:416 (and the identical line in _stream, src/lib.rs:589):

let params = params.or_else(|| self.params.clone());

or_else replaces; it never merges. For cookies, src/lib.rs:460 appends a fresh COOKIE header via request_builder.header(COOKIE, ...) on top of the client's existing one.

Reproduction

Against a local server echoing the raw request line and headers:

c = httpr.Client(params={"api_key": "SECRET"}, cookies={"session": "abc"})
c.get(url)                                              # baseline
c.get(url, params={"q": "1"}, cookies={"tracking": "t1"})
httpr httpx
client only GET /x?api_key=SECRET GET /x?api_key=SECRET
+ per-request GET /x?q=1 GET /x?api_key=SECRET&q=1
cookies cookie: session=abc and cookie: tracking=t1 (two headers) ❌ Cookie: session=abc; tracking=t1 (one)

RFC 6265 §5.4 states a user agent MUST NOT attach more than one Cookie header field; servers commonly read only the first, so tracking is silently ignored.

Expected

Per-request params and cookies merge with the client-level values, with the per-request value winning on key collision — matching httpx and requests.

Proposed fix

In both request() and _stream() in src/lib.rs:

  • Build the effective params by cloning self.params and then extending with the per-request map (per-request key wins), instead of or_else.
  • Merge per-request cookies into the existing COOKIE header value rather than adding a second header.

Note the two functions duplicate this whole block; factoring the shared setup into one helper would prevent the two copies drifting.

Suggested tests

  • Client-level + per-request params both appear in the query string.
  • Per-request value overrides the client-level value for the same key.
  • Exactly one Cookie header is sent, containing both cookies.

Size

~1 hour.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingrustPull requests that update rust code

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions