Skip to content

Instantly share code, notes, and snippets.

@sciolist
Created July 8, 2015 08:07
Show Gist options
  • Save sciolist/2e741ff651ffe58b28f4 to your computer and use it in GitHub Desktop.
Save sciolist/2e741ff651ffe58b28f4 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!)
}
}
@sciolist
Copy link
Author

sciolist commented Apr 3, 2019

@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