-
Notifications
You must be signed in to change notification settings - Fork 125
make API non-throwing #66
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -60,33 +60,34 @@ extension HTTPClient { | |
} | ||
|
||
public struct Request { | ||
public var version: HTTPVersion | ||
public var method: HTTPMethod | ||
public var url: URL | ||
public var scheme: String | ||
public var host: String | ||
public let version: HTTPVersion | ||
public let method: HTTPMethod | ||
public let url: URL | ||
public var headers: HTTPHeaders | ||
public var body: Body? | ||
|
||
internal let scheme: String | ||
internal let host: String | ||
|
||
public init(url: String, version: HTTPVersion = HTTPVersion(major: 1, minor: 1), method: HTTPMethod = .GET, headers: HTTPHeaders = HTTPHeaders(), body: Body? = nil) throws { | ||
public init?(url: String, version: HTTPVersion = HTTPVersion(major: 1, minor: 1), method: HTTPMethod = .GET, headers: HTTPHeaders = HTTPHeaders(), body: Body? = nil) { | ||
guard let url = URL(string: url) else { | ||
throw HTTPClientError.invalidURL | ||
return nil | ||
} | ||
|
||
try self.init(url: url, version: version, method: method, headers: headers, body: body) | ||
self.init(url: url, version: version, method: method, headers: headers, body: body) | ||
} | ||
|
||
public init(url: URL, version: HTTPVersion = HTTPVersion(major: 1, minor: 1), method: HTTPMethod = .GET, headers: HTTPHeaders = HTTPHeaders(), body: Body? = nil) throws { | ||
guard let scheme = url.scheme else { | ||
throw HTTPClientError.emptyScheme | ||
public init?(url: URL, version: HTTPVersion = HTTPVersion(major: 1, minor: 1), method: HTTPMethod = .GET, headers: HTTPHeaders = HTTPHeaders(), body: Body? = nil) { | ||
guard let scheme = url.scheme?.lowercased() else { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I do agree that this is much nicer as a user, but we're sacrificing the type of error for a "this worked or not" without the context on what the problem was. I think I'd prefer to keep the granular errors vs. checking for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I didn't follow all of the discussions here recently... but would it be an option to add address the above concern by adding There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great call, that helps with surfacing the specific issue if someone really wants it. 🧠 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I find I'd be strongly -1 on this without at least the option for a constructor that gives me better diagnostics, but frankly I'm not sure if the convenience of the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Lukasa this PR originated as a simpler and safer way compared to #56. totally agree on the information loss point as brought up by @Yasumoto and @ktoso ^^, and think we can keep the API throwing - i was just mirroring #56 in that sense. that said, the existing throwing code has a validation/mutability race that needs to be addressed and this PR demonstrates that part There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is the throwing version: #67 |
||
return nil | ||
} | ||
|
||
guard Request.isSchemeSupported(scheme: scheme) else { | ||
throw HTTPClientError.unsupportedScheme(scheme) | ||
return nil | ||
} | ||
|
||
guard let host = url.host else { | ||
throw HTTPClientError.emptyHost | ||
return nil | ||
} | ||
|
||
self.version = version | ||
|
@@ -99,14 +100,14 @@ extension HTTPClient { | |
} | ||
|
||
public var useTLS: Bool { | ||
return self.url.scheme == "https" | ||
return self.scheme == "https" | ||
} | ||
|
||
public var port: Int { | ||
return self.url.port ?? (self.useTLS ? 443 : 80) | ||
} | ||
|
||
static func isSchemeSupported(scheme: String?) -> Bool { | ||
static func isSchemeSupported(scheme: String) -> Bool { | ||
return scheme == "http" || scheme == "https" | ||
} | ||
} | ||
|
@@ -514,7 +515,7 @@ internal struct RedirectHandler<T> { | |
return nil | ||
} | ||
|
||
guard HTTPClient.Request.isSchemeSupported(scheme: url.scheme) else { | ||
guard HTTPClient.Request.isSchemeSupported(scheme: request.scheme) else { | ||
return nil | ||
} | ||
|
||
|
@@ -526,44 +527,36 @@ internal struct RedirectHandler<T> { | |
} | ||
|
||
func redirect(status: HTTPResponseStatus, to redirectURL: URL, promise: EventLoopPromise<T>) { | ||
let originalURL = self.request.url | ||
|
||
var request = self.request | ||
request.url = redirectURL | ||
|
||
if let redirectHost = redirectURL.host { | ||
request.host = redirectHost | ||
} else { | ||
preconditionFailure("redirectURL doesn't contain a host") | ||
} | ||
|
||
if let redirectScheme = redirectURL.scheme { | ||
request.scheme = redirectScheme | ||
} else { | ||
preconditionFailure("redirectURL doesn't contain a scheme") | ||
} | ||
let originalRequest = self.request | ||
|
||
var convertToGet = false | ||
if status == .seeOther, request.method != .HEAD { | ||
convertToGet = true | ||
} else if status == .movedPermanently || status == .found, request.method == .POST { | ||
convertToGet = true | ||
} | ||
|
||
|
||
var method = originalRequest.method | ||
var headers = originalRequest.headers | ||
var body = originalRequest.body | ||
|
||
if convertToGet { | ||
request.method = .GET | ||
request.body = nil | ||
request.headers.remove(name: "Content-Length") | ||
request.headers.remove(name: "Content-Type") | ||
method = .GET | ||
body = nil | ||
headers.remove(name: "Content-Length") | ||
headers.remove(name: "Content-Type") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's this whitespace about? |
||
} | ||
|
||
if !originalURL.hasTheSameOrigin(as: redirectURL) { | ||
request.headers.remove(name: "Origin") | ||
request.headers.remove(name: "Cookie") | ||
request.headers.remove(name: "Authorization") | ||
request.headers.remove(name: "Proxy-Authorization") | ||
if !originalRequest.url.hasTheSameOrigin(as: redirectURL) { | ||
headers.remove(name: "Origin") | ||
headers.remove(name: "Cookie") | ||
headers.remove(name: "Authorization") | ||
headers.remove(name: "Proxy-Authorization") | ||
} | ||
|
||
guard let request = HTTPClient.Request(url: redirectURL, version: originalRequest.version, method: method, headers: headers, body: body) else { | ||
return promise.fail(HTTPClientError.invalidURL) | ||
} | ||
|
||
return self.execute(request).futureResult.cascade(to: promise) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if user will modify the url parameter? And new url doesn't contain a host?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@artemredkin url is a let in this PR