-
-
Save zqqf16/fc1b2f37eead98ec44b5bc682b07796b 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!) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Here's a Swift 4 (not Swift 4.2, sadly) direct translation of the main part (no improvements like migrating sync methods to async ones; and a couple of warnings about deprecated methods) that I've just briefly tested for GET a request to https://www.bbc.co.uk. It appears to work!