swift-http-types
swift-http-types copied to clipboard
Should order matter when comparing `HTTPFields` for equality?
Currently order matters when comparing if two HTTPFields
instances are equal.
I'm by no means an expert in HTTP standards but I found this surprising as the interface is very similar to that of a Dictionary.
My use case is I want to verify a HTTPRequest
is as expected in tests but currently the test fails due to the headers having different ordering.
Should order matter here?
static func testHeadersSameOrder() -> Bool {
var headers1: HTTPFields = [:]
headers1[.contentType] = "application/json"
headers1[.acceptLanguage] = "fr-CA"
var headers2: HTTPFields = [:]
headers2[.contentType] = "application/json"
headers2[.acceptLanguage] = "fr-CA"
// returns true
return headers1 == headers2
}
static func testHeadersDifferentOrder() -> Bool {
var headers1: HTTPFields = [:]
headers1[.acceptLanguage] = "fr-CA"
headers1[.contentType] = "application/json"
var headers2: HTTPFields = [:]
headers2[.contentType] = "application/json"
headers2[.acceptLanguage] = "fr-CA"
// returns false
return headers1 == headers2
}
That's a good point. There are situations where ordering is relevant:
WWW-Authenticate: challenge1
WWW-Authenticate: challenge2
These challenges are sent in its order of preference, so we do need to preserve the order.
I can think of a few ways to resolve it:
- During comparison, do a stable sort before comparing. The drawback is slowing down comparison.
- Use a deterministic ordering when inserting a new field through the subscript. The drawback is that it breaks the indexing optimization and could slow down subsequent lookups.
Note that RFC 7230 speaks to this: https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.2
The order in which header fields with differing field names are received is not significant.
And
A recipient MAY combine multiple header fields with the same field name into one "field-name: field-value" pair, without changing the semantics of the message, by appending each subsequent field value to the combined field value in order, separated by a comma. The order in which header fields with the same field name are received is therefore significant to the interpretation of the combined field value; a proxy MUST NOT change the order of these field values when forwarding a message.
My interpretation is that field order is insignificant between fields of different names, but significant between fields of the same name. It'd be great if the implementation of equality followed that, as otherwise I suspect at least some adopters will have to implement comparison that matches this RFC in their client packages, so we might as well provide it.