'URLRequest equality doesn't include httpBody

Overview

There are 2 URLRequests, one with httpBody and one with no httpBody.
However when compared, it shows both are equal.

Question

Is this expected behaviour or am I missing something ?

Code

let url = URL(string: "www.somevalidURL.com")!

var r1 = URLRequest(url: url)
r1.addValue("Content-Type", forHTTPHeaderField: "application/json; charset=utf-8")
r1.httpBody = makeBody(withParameters: ["email" : "[email protected]"])

var r2 = URLRequest(url: url)
r2.addValue("Content-Type", forHTTPHeaderField: "application/json; charset=utf-8")

if r1 == r2 {
    print("requests are equal")
}
else {
    print("requests are not equal")
}

if r1.httpBody == r2.httpBody {
    print("body is equal")
}
else {
    print("body is not equal")
}

func makeBody(withParameters bodyParameters: [String : Any]?) -> Data? {
    guard let bodyParameters = bodyParameters,
        !bodyParameters.isEmpty else {
            return nil
    }
    let body : Data?
    do {
        body = try JSONSerialization.data(withJSONObject: bodyParameters,
                                          options: .prettyPrinted)
    }
    catch {
        print("Error in creating Web Service Body = \(error)")
        body = nil
    }
    return body
}

Output

requests are equal
body is not equal

Xcode 10
Swift Version: 4.2



Solution 1:[1]

If you've come here wondering why your identical URLRequests aren't equal to each other like I did I found the reason to be that URLRequest's equatable implementation differentiates between httpBody being set to nil or being defaulting to nil.

If we do the following:

let request = URLRequest(url: URL(string: "test.com"))
var expectedRequest = URLRequest(url: URL(string: "test.com"))
expectedRequest.httpBody = nil

Then:

request == expectedRequest //false
print(request.httpBody) // nil
request.httpBody = nil
request == expectedRequest //true

Explicitly settings the httpBody to nil will fix this issue. In fact what the body is doesn't matter, only that it has been explicitly set.

request.httpBody = Data()
request == expectedRequest //true

Potential explanation

As Martin rightly points out Swift's source code does not include httpBody. However all of the properties (in the link) being equal (and both being castable as NSURLRequests) does not return true (see lldb output below). I can only presume the linked code is overridden to include another property and this is modified when didSet or willSet is called on httpBody lldb Terminal Log

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1