Skip to content

Instantly share code, notes, and snippets.

@vitalymak
Forked from sciolist/CorsProxy.swift
Created December 4, 2017 12:04
Show Gist options
  • Save vitalymak/06744e66e74eda106a98b1162dabf476 to your computer and use it in GitHub Desktop.
Save vitalymak/06744e66e74eda106a98b1162dabf476 to your computer and use it in GitHub Desktop.
GCDWebServer Cors proxy
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
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