Skip to content

Commit 03fcf08

Browse files
authored
Merge pull request #2742 from spevans/pr_sr_12135
SR-12135: Data(contentsOf:) does not account for failed HTTP response codes.
2 parents eac91ab + 820d280 commit 03fcf08

File tree

3 files changed

+70
-11
lines changed

3 files changed

+70
-11
lines changed

Sources/FoundationNetworking/URLSession/NetworkingSpecific.swift

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,15 @@ class _NSNonfileURLContentLoader: _NSNonfileURLContentLoading {
4040

4141
@usableFromInline
4242
func contentsOf(url: URL) throws -> (result: NSData, textEncodingNameIfAvailable: String?) {
43+
44+
func cocoaError(with error: Error? = nil) -> Error {
45+
var userInfo: [String: Any] = [:]
46+
if let error = error {
47+
userInfo[NSUnderlyingErrorKey] = error
48+
}
49+
return CocoaError.error(.fileReadUnknown, userInfo: userInfo, url: url)
50+
}
51+
4352
var urlResponse: URLResponse?
4453
let session = URLSession(configuration: URLSessionConfiguration.default)
4554
let cond = NSCondition()
@@ -63,10 +72,25 @@ class _NSNonfileURLContentLoader: _NSNonfileURLContentLoading {
6372
cond.wait()
6473
}
6574
cond.unlock()
66-
75+
76+
guard resError == nil else {
77+
throw cocoaError(with: resError)
78+
}
79+
6780
guard let data = resData else {
68-
throw resError!
81+
throw cocoaError()
82+
}
83+
84+
if let statusCode = (urlResponse as? HTTPURLResponse)?.statusCode {
85+
switch statusCode {
86+
// These are the only valid response codes that data will be returned for, all other codes will be treated as error.
87+
case 101, 200...399, 401, 407:
88+
return (NSData(bytes: UnsafeMutableRawPointer(mutating: (data as NSData).bytes), length: data.count), urlResponse?.textEncodingName)
89+
90+
default:
91+
break
92+
}
6993
}
70-
return (NSData(bytes: UnsafeMutableRawPointer(mutating: (data as NSData).bytes), length: data.count), urlResponse?.textEncodingName)
94+
throw cocoaError()
7195
}
7296
}

Tests/Foundation/HTTPServer.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -716,7 +716,11 @@ public class TestURLSessionServer {
716716
bodyData: helloWorld)
717717
}
718718

719-
return _HTTPResponse(response: .OK, body: capitals[String(uri.dropFirst())]!)
719+
guard let capital = capitals[String(uri.dropFirst())] else {
720+
return _HTTPResponse(response: .NOTFOUND, body: "Not Found")
721+
}
722+
return _HTTPResponse(response: .OK, body: capital)
723+
720724
}
721725
}
722726

Tests/Foundation/Tests/TestNSData.swift

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1517,13 +1517,44 @@ extension TestNSData {
15171517
#endif
15181518
}
15191519

1520-
func test_contentsOfURL() {
1521-
let urlString = "http://127.0.0.1:\(TestURLSession.serverPort)/country.txt"
1522-
let url = URL(string: urlString)!
1523-
let contents = NSData(contentsOf: url)
1524-
XCTAssertNotNil(contents)
1525-
if let contents = contents {
1526-
XCTAssertTrue(contents.length > 0)
1520+
func test_contentsOfURL() throws {
1521+
do {
1522+
let urlString = "http://127.0.0.1:\(TestURLSession.serverPort)/country.txt"
1523+
let url = try XCTUnwrap(URL(string: urlString))
1524+
let contents = NSData(contentsOf: url)
1525+
XCTAssertNotNil(contents)
1526+
if let contents = contents {
1527+
XCTAssertTrue(contents.length > 0)
1528+
}
1529+
}
1530+
1531+
do {
1532+
let urlString = "http://127.0.0.1:\(TestURLSession.serverPort)/NotFound"
1533+
let url = try XCTUnwrap(URL(string: urlString))
1534+
XCTAssertNil(NSData(contentsOf: url))
1535+
do {
1536+
_ = try NSData(contentsOf: url, options: [])
1537+
XCTFail("NSData(contentsOf:options: did not throw")
1538+
} catch let error as NSError {
1539+
if let nserror = error as? NSError {
1540+
XCTAssertEqual(NSCocoaErrorDomain, nserror.domain)
1541+
XCTAssertEqual(CocoaError.fileReadUnknown.rawValue, nserror.code)
1542+
} else {
1543+
XCTFail("Not an NSError")
1544+
}
1545+
}
1546+
1547+
do {
1548+
_ = try Data(contentsOf: url)
1549+
XCTFail("Data(contentsOf:options: did not throw")
1550+
} catch let error as NSError {
1551+
if let nserror = error as? NSError {
1552+
XCTAssertEqual(NSCocoaErrorDomain, nserror.domain)
1553+
XCTAssertEqual(CocoaError.fileReadUnknown.rawValue, nserror.code)
1554+
} else {
1555+
XCTFail("Not an NSError")
1556+
}
1557+
}
15271558
}
15281559
}
15291560

0 commit comments

Comments
 (0)