Created
July 8, 2015 08:07
-
-
Save sciolist/2e741ff651ffe58b28f4 to your computer and use it in GitHub Desktop.
GCDWebServer Cors proxy
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import GCDWebServer | |
let webserver = GCDWebServer() | |
let proxy = CorsProxy(webserver: webserver!, urlPrefix: "/CORS/") | |
webserver.startWithPort(8080, bonjourName: nil) | |
// $ curl -i -H "Origin: test-site" http://127.0.0.1/CORS/http://my/test/site | |
// HTTP/1.1 200 OK | |
// Access-Control-Allow-Origin: test-site | |
// Server: GCDWebServer | |
// Access-Control-Allow-Credentials: true | |
// Connection: Close | |
// Access-Control-Allow-Methods: PUT,POST,GET,PATCH,DELETE | |
// Cache-Control: no-cache |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import GCDWebServer | |
class CorsProxy { | |
init(webserver : GCDWebServer!, urlPrefix: String) { | |
var prefix = | |
(urlPrefix.hasPrefix("/") ? "" : "/") | |
+ urlPrefix | |
+ (urlPrefix.hasSuffix("/") ? "" : "/") | |
let pattern = "^" + NSRegularExpression.escapedPatternForString(prefix) + ".*" | |
webserver.addHandlerForMethod("POST", pathRegex: pattern, requestClass: GCDWebServerDataRequest.self, processBlock:{ req in | |
return self.sendProxyResult(prefix, req: req) | |
}) | |
webserver.addHandlerForMethod("PUT", pathRegex: pattern, requestClass: GCDWebServerDataRequest.self, processBlock:{ req in | |
return self.sendProxyResult(prefix, req: req) | |
}) | |
webserver.addHandlerForMethod("PATCH", pathRegex: pattern, requestClass: GCDWebServerDataRequest.self, processBlock:{ req in | |
return self.sendProxyResult(prefix, req: req) | |
}) | |
webserver.addHandlerForMethod("DELETE", pathRegex: pattern, requestClass: GCDWebServerDataRequest.self, processBlock:{ req in | |
return self.sendProxyResult(prefix, req: req) | |
}) | |
webserver.addHandlerForMethod("GET", pathRegex: pattern, requestClass: GCDWebServerRequest.self, processBlock:{ req in | |
return self.sendProxyResult(prefix, req: req) | |
}) | |
webserver.addHandlerForMethod("OPTIONS", pathRegex: pattern, requestClass: GCDWebServerRequest.self, processBlock:{ req in | |
return self.sendCorsHeaders(prefix, req: req) | |
}) | |
} | |
func sendProxyResult(prefix: String, req: GCDWebServerRequest) -> GCDWebServerResponse! { | |
let query = req.URL.query == nil ? "" : "?" + req.URL.query! | |
var url = NSURL(string: req.path.substringFromIndex(prefix.endIndex) + query) | |
if (url == nil) { return sendError("Invalid URL") } | |
var err: NSErrorPointer = nil | |
var urlResp: NSURLResponse? | |
let urlReq = NSMutableURLRequest(URL: url!, cachePolicy: NSURLRequestCachePolicy.ReloadIgnoringLocalCacheData, timeoutInterval: 320000) | |
urlReq.HTTPMethod = req.method | |
urlReq.allHTTPHeaderFields = req.headers | |
urlReq.allHTTPHeaderFields?["Host"] = url!.host | |
if (req.hasBody()) { | |
urlReq.HTTPBody = (req as! GCDWebServerDataRequest).data | |
} | |
let output = NSURLConnection.sendSynchronousRequest(urlReq | |
, returningResponse: &urlResp | |
, error: err) | |
if (urlResp == nil) { | |
return sendError(output == nil ? nil : NSString(data: output!, encoding: NSUTF8StringEncoding) as? String); | |
} | |
var httpResponse = urlResp as! NSHTTPURLResponse | |
let resp = GCDWebServerDataResponse(data: output == nil ? NSData() : output, contentType: "application/x-unknown") | |
resp.statusCode = httpResponse.statusCode | |
for key in httpResponse.allHeaderFields { | |
if (toString(key.0) == "Content-Encoding") { continue; } | |
resp.setValue(toString(key.1), forAdditionalHeader: toString(key.0)) | |
} | |
if (output != nil) { | |
resp.setValue(String(output!.length), forAdditionalHeader: "Content-Length") | |
} | |
return resp | |
} | |
func sendCorsHeaders(prefix: String, req: GCDWebServerRequest) -> GCDWebServerResponse! { | |
let resp = GCDWebServerResponse() | |
resp.setValue(toString(req.headers["Origin"]), forAdditionalHeader: "Access-Control-Allow-Origin") | |
resp.setValue("PUT,POST,GET,PATCH,DELETE", forAdditionalHeader: "Access-Control-Allow-Methods") | |
resp.setValue("true", forAdditionalHeader: "Access-Control-Allow-Credentials") | |
return resp | |
} | |
func sendError(error: String?) -> GCDWebServerResponse! { | |
var msg = error == nil ? "An error occured" : error! | |
let errorData = msg.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true) | |
let resp = GCDWebServerDataResponse(data: errorData, contentType: "text/plain") | |
resp.statusCode = 500 | |
return resp | |
} | |
func toString(v: AnyObject?) -> String! { | |
if (v == nil) { return ""; } | |
return String(stringInterpolationSegment: v!) | |
} | |
} |
@troyanskiy 320000 seconds is indeed far too long for any real use case, there's no good reason for it to be that high.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@troyanskiy I'm afraid I can't really comment on any of the implementation/design decisions (and I don't pretend to be an expert on proxying), as I merely translated the code to Swift 4.
I would however agree that 88 hours does seem rather excessive for a network timeout; by contrast, web browsers frequently use around 40 seconds for request timeouts.