Implement get_all function to return non-folding set-cookie headers
issue : https://github.com/cloudflare/workers-rs/issues/423
Define get_all in worker_sys::ext::headers::Headers and implement in worker::Headers
This PR implements the get_all function for Headers with the following approach:
- Define the get_all method in worker_sys::ext::headers::Headers
- Implement get_all in worker::Headers using the worker_sys implementation
Specification of the get_all function:
- Retrieves all values of the
Set-Cookieheader - Returns the result as Result<Vec<String>>
- Returns an error if the header name is not
Set-Cookie - When there are multiple set-cookie headers, do not combine them
Why limit only to set-cookie header?
The workerd code I used as reference for implementation made an error when a header other than set-cookie was specified, so I implemented it as is.
https://github.com/cloudflare/workerd/blob/a265d5c22bf2a6bc6394aa54db517ff86d6c788c/src/workerd/api/http.c%2B%2B#L229-L242
I see, I can ask internally about this.
If this is already implemented in the runtime, would it make sense to just add the getAll method to the wasm_bindgen Header extension type here https://github.com/cloudflare/workers-rs/blob/main/worker-sys/src/ext/headers.rs?
@kflansburg
Yes, I think that is the simplest way. I implemented it that way. (Like other functions, such as “entries”.)
If you have any suggestions for improving this implementation, I would greatly appreciate your feedback. Thank you.
Can we invoke the JavaScript getAll method via wasm-bindgen, rather than re-implementing it in Rust?
@kflansburg
This looks great! Were you able to test this?
I created the following application under the example directory and verified its operation with curl. (Not git committed)
/// create sample application. examples/cookie/src/lib.rs
use worker::*;
// Main entry point for the worker
#[event(fetch)]
pub async fn main(req: Request, env: Env, _ctx: worker::Context) -> Result<Response> {
// Set up a router and define a route for "/test_cookies"
Router::with_data(())
.get_async("/test_cookies", test_cookies)
.run(req, env)
.await
}
// Handler function for the "/test_cookies" route
async fn test_cookies(req: Request, _ctx: RouteContext<()>) -> Result<Response> {
// Retrieve all Set-Cookie headers from the input request
let input_cookies = req.headers().get_all("Set-Cookie")?;
// Create a new response
let mut res = Response::ok("Cookies processed")?;
// Add the input Set-Cookie headers to the new response
for cookie in &input_cookies {
// Append each Set-Cookie header to the response
res.headers_mut().append("Set-Cookie", cookie)?;
}
// Log the request and response headers for debugging
console_log!("Request Set-Cookie headers: {:?}", input_cookies);
console_log!("Response headers: {:?}", res.headers());
// Return the response
Ok(res)
}
# curl command in console
% curl 'http://localhost:8787/test_cookies' \
-H 'Set-Cookie: a=1; Expires=Wed, 21 Oct 2015 07:28:00 GMT' \
-H 'Set-Cookie: b=2; Expires=Wed, 21 Oct 2015 07:28:00 GMT' \
-v
* Host localhost:8787 was resolved.
> GET /test_cookies HTTP/1.1
> ・・・・・・・
> Set-Cookie: a=1; Expires=Wed, 21 Oct 2015 07:28:00 GMT
> Set-Cookie: b=2; Expires=Wed, 21 Oct 2015 07:28:00 GMT
>
< HTTP/1.1 200 OK
< Content-Length: 17
< Content-Type: text/plain; charset=utf-8
< Set-Cookie: a=1; Expires=Wed, 21 Oct 2015 07:28:00 GMT
< Set-Cookie: b=2; Expires=Wed, 21 Oct 2015 07:28:00 GMT
<
* Connection #0 to host localhost left intact
Cookies processed
# wrangler dev console
% cd workers-rs/examples/cookie
% npx wrangler dev
[wrangler:inf] Ready on http://localhost:8787
Request Set-Cookie headers: ["a=1; Expires=Wed, 21 Oct 2015 07:28:00 GMT", "b=2; Expires=Wed, 21 Oct 2015 07:28:00 GMT"]
Response headers: Headers {
content-type = text/plain; charset=utf-8
set-cookie = a=1; Expires=Wed, 21 Oct 2015 07:28:00 GMT
set-cookie = b=2; Expires=Wed, 21 Oct 2015 07:28:00 GMT
}
[wrangler:inf] GET /test_cookies 200 OK (12ms)