Skip to content

header_json emits incorrect JSON with multi-value headers  #10704

Closed
@inca

Description

@inca

I did this

There is a backend that returns several multi-value headers in overlapping order:

< HTTP/2 200 
< server: nginx
< date: Tue, 07 Mar 2023 15:14:41 GMT
< content-type: application/json
< content-length: 12265
< vary: Accept-Encoding
< access-control-allow-origin: *
< vary: Accept-Encoding
< referrer-policy: strict-origin-when-cross-origin
< access-control-allow-methods: GET, POST, PUT, DELETE, OPTIONS
< access-control-max-age: 1728000
< access-control-allow-headers: Authorization, Content-Type, AuthorizationOauth, X-EARLY-ACCESS
< access-control-expose-headers: 
< vary: Accept
< etag: W/"2678f9ab2ba550d164e7cc014aefd31e"
< cache-control: max-age=0, private, must-revalidate
< x-request-id: 375b343b3d2ecf9b442c0daf00fc4a9a
< strict-transport-security: max-age=31536000; includeSubDomains
< x-content-type-options: nosniff
< x-xss-protection: 1; mode=block
< referrer-policy: strict-origin-when-cross-origin
< feature-policy: accelerometer 'none'; camera 'none'; geolocation 'none'; gyroscope 'none'; magnetometer 'none'; microphone 'none'; payment 'none'; usb 'none'

You can see the vary and referrer-policy occurring multiple times. With -w %{header_json} option the JSON produced becomes incorrect:

{
	"server": ["nginx"],
	"date": ["Tue, 07 Mar 2023 11:31:47 GMT"],
	"content-type": ["application/json"],
	"content-length": ["12265"],
	"vary": ["Accept-Encoding", "Accept-Encoding", "Accept"],
	"etag": ["W/\"2678f9ab2ba550d164e7cc014aefd31e\""],
	"cache-control": ["max-age=0, private, must-revalidate"],
	"x-request-id": ["ad2176d584f1c5b1a56b564af1969efa"],
	"strict-transport-security": ["max-age=31536000; includeSubDomains"],
	"x-content-type-options": ["nosniff"],
	"x-xss-protection": ["1; mode=block"],
	"referrer-policy": ],
	"feature-policy": ["accelerometer 'none'; camera 'none'; geolocation 'none'; gyroscope 'none'; magnetometer 'none'; microphone 'none'; payment 'none'; usb 'none'"]
}

Notice the "referrer-policy": ],. Also notice that headers between the first occurrence of the first multi-value header (vary) are also missing.

Here's the cURL command to reproduce the issue (note: the token is taken from the official docs, so feel free to use it).

curl https://api.pagerduty.com/oncalls -H "Accept: application/vnd.pagerduty+json;version=2" -H "Content-Type: application/json" -H "Authorization: Token token=y_NbAkKc66ryYTWUXYEu" -w %{header_json}

I managed to track it down to headerJSON right here:

if(curl_easy_header(per->curl, name, i, CURLH_HEADER,
-1, &header))
— I suspect that prev pointer gets overwritten by that last call to curl_easy_header before breaking from the loop; therefore the next iteration of the while starts from etag (which is the next header after the last occurrence of vary) and therefore misses the first occurrence of another multi-value header referrer-policy (along with all other headers in between the first and the last occurrence of vary). By the time the outer loop reaches referrer-policy it actually sees the second occurrence (with index 1) and that causes the method to only emit a closing bracket because the branch before it is never entered.

I expected the following

JSON should be valid. All headers should be present.

curl/libcurl version

7.88.1

operating system

macOS 12.5.1

/cc @christellevs

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions