From 425516925d3201ac9397bd8bc7544f4175e978f4 Mon Sep 17 00:00:00 2001 From: Victor Sigler Date: Fri, 10 Jul 2020 15:35:44 -0400 Subject: [PATCH] Fix an issue causing a crash when the Content-Lenght was negative * Add an uni tests for the new exception * Fix an Swiftlint warning regarding the colon * Fix a spelling error --- XCode/Sources/HttpParser.swift | 8 +++++++- XCode/Sources/HttpResponse.swift | 2 +- XCode/Sources/WebSockets.swift | 2 +- XCode/Tests/SwifterTestsHttpParser.swift | 8 ++++++++ 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/XCode/Sources/HttpParser.swift b/XCode/Sources/HttpParser.swift index 34a1e86e..5c1abfa9 100644 --- a/XCode/Sources/HttpParser.swift +++ b/XCode/Sources/HttpParser.swift @@ -7,8 +7,9 @@ import Foundation -enum HttpParserError: Error { +enum HttpParserError: Error, Equatable { case invalidStatusLine(String) + case negativeContentLength } public class HttpParser { @@ -29,6 +30,11 @@ public class HttpParser { request.queryParams = urlComponents?.queryItems?.map { ($0.name, $0.value ?? "") } ?? [] request.headers = try readHeaders(socket) if let contentLength = request.headers["content-length"], let contentLengthValue = Int(contentLength) { + // Prevent a buffer overflow and runtime error trying to create an `UnsafeMutableBufferPointer` with + // a negative length + guard contentLengthValue >= 0 else { + throw HttpParserError.negativeContentLength + } request.body = try readBody(socket, size: contentLengthValue) } return request diff --git a/XCode/Sources/HttpResponse.swift b/XCode/Sources/HttpResponse.swift index a3f66099..eae75140 100644 --- a/XCode/Sources/HttpResponse.swift +++ b/XCode/Sources/HttpResponse.swift @@ -85,7 +85,7 @@ public enum HttpResponse { case movedTemporarily(String) case badRequest(HttpResponseBody?), unauthorized, forbidden, notFound case internalServerError - case raw(Int, String, [String:String]?, ((HttpResponseBodyWriter) throws -> Void)? ) + case raw(Int, String, [String: String]?, ((HttpResponseBodyWriter) throws -> Void)? ) public var statusCode: Int { switch self { diff --git a/XCode/Sources/WebSockets.swift b/XCode/Sources/WebSockets.swift index cf88f91e..a2d46e30 100644 --- a/XCode/Sources/WebSockets.swift +++ b/XCode/Sources/WebSockets.swift @@ -233,7 +233,7 @@ public class WebSocketSession: Hashable, Equatable { frm.rsv3 = fst & 0x10 guard frm.rsv1 == 0 && frm.rsv2 == 0 && frm.rsv3 == 0 else { - throw WsError.protocolError("Reserved frame bit has not been negocitated.") + throw WsError.protocolError("Reserved frame bit has not been negociated.") } let opc = fst & 0x0F guard let opcode = OpCode(rawValue: opc) else { diff --git a/XCode/Tests/SwifterTestsHttpParser.swift b/XCode/Tests/SwifterTestsHttpParser.swift index 4fef4135..973c7aeb 100644 --- a/XCode/Tests/SwifterTestsHttpParser.swift +++ b/XCode/Tests/SwifterTestsHttpParser.swift @@ -101,6 +101,14 @@ class SwifterTestsHttpParser: XCTestCase { XCTAssert(false, "Parser should not throw any errors if there is a valid 'Content-Length' header.") } + do { + _ = try parser.readHttpRequest(TestSocket("GET / HTTP/1.0\r\nContent-Length: -1\r\n\r\n")) + } catch let error { + let error = error as? HttpParserError + XCTAssertNotNil(error) + XCTAssertEqual(error!, HttpParserError.negativeContentLength) + } + do { _ = try parser.readHttpRequest(TestSocket("GET / HTTP/1.0\nContent-Length: 5\n\n12345")) } catch {