<commit_before>//
//  XcodeServer.swift
//  Buildasaur
//
//  Created by <NAME> on 14/12/2014.
//  Copyright (c) 2014 <NAME>. All rights reserved.
//

import Foundation
import BuildaUtils

// MARK: XcodeServer Class
public class XcodeServer : CIServer {
    
    public let config: XcodeServerConfig
    let endpoints: XcodeServerEndpoints
    
    public init(config: XcodeServerConfig, endpoints: XcodeServerEndpoints) {
        
        self.config = config
        self.endpoints = endpoints
        
        super.init()
        
        let sessionConfig = NSURLSessionConfiguration.defaultSessionConfiguration()
        let delegate: NSURLSessionDelegate = self
        let queue = NSOperationQueue.mainQueue()
        let session = NSURLSession(configuration: sessionConfig, delegate: delegate, delegateQueue: queue)
        self.http.session = session
    }
}

// MARK: NSURLSession delegate implementation
extension XcodeServer : NSURLSessionDelegate {
    
    var credential: NSURLCredential? {
        
        if
            let user = self.config.user,
            let password = self.config.password {
                return NSURLCredential(user: user, password: password, persistence: NSURLCredentialPersistence.None)
        }
        return nil
    }
    
    public func URLSession(session: NSURLSession, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) {
        
        var disposition: NSURLSessionAuthChallengeDisposition = .PerformDefaultHandling
        var credential: NSURLCredential?
        
        if challenge.previousFailureCount > 0 {
            disposition = .CancelAuthenticationChallenge
        } else {
            
            switch challenge.protectionSpace.authenticationMethod {
                
            case NSURLAuthenticationMethodServerTrust:
                credential = NSURLCredential(forTrust: challenge.protectionSpace.serverTrust!)
            default:
                credential = self.credential ?? session.configuration.URLCredentialStorage?.defaultCredentialForProtectionSpace(challenge.protectionSpace)
            }
            
            if credential != nil {
                disposition = .UseCredential
            }
        }
        
        completionHandler(disposition, credential)
    }
}

// MARK: Header constants
let Headers_APIVersion = "X-XCSAPIVersion"
let SupportedAPIVersion: Int = 3 //will change with time, this codebase supports this version

// MARK: XcodeServer API methods
public extension XcodeServer {
    
    private func verifyAPIVersion(response: NSHTTPURLResponse) -> NSError? {
        
        guard let headers = response.allHeaderFields as? [String: AnyObject] else {
            return Error.withInfo("No headers provided in response")
        }
        
        guard let apiVersionString = headers[Headers_APIVersion] as? String else {
            return Error.withInfo("Couldn't find API version Int in headers")
        }
        
        guard let apiVersion = Int(apiVersionString) else {
            return Error.withInfo("Couldn't find API version Int in headers")
        }
        
        if SupportedAPIVersion != apiVersion {
            var common = "Version mismatch: response from API version \(apiVersion), but we support version \(SupportedAPIVersion). "
            
            if apiVersion > SupportedAPIVersion {
                common += "You're using a newer Xcode Server than we support. Please visit https://github.com/czechboy0/XcodeServerSDK to check whether there's a new version of the SDK for it."
            } else {
                common += "You're using an old Xcode Server which we don't support any more. Please look for an older version of the SDK at https://github.com/czechboy0/XcodeServerSDK or consider upgrading your Xcode Server to the current version."
            }
            
            return Error.withInfo(common)
        }
        
        //all good
        return nil
    }
    
    /**
    Internal usage generic method for sending HTTP requests.
    
    - parameter method:     HTTP method.
    - parameter endpoint:   API endpoint.
    - parameter params:     URL paramaters.
    - parameter query:      URL query.
    - parameter body:       POST method request body.
    - parameter completion: Completion.
    */
    internal func sendRequestWithMethod(method: HTTP.Method, endpoint: XcodeServerEndpoints.Endpoint, params: [String: String]?, query: [String: String]?, body: NSDictionary?, completion: HTTP.Completion) {
        if let request = self.endpoints.createRequest(method, endpoint: endpoint, params: params, query: query, body: body) {
            
            self.http.sendRequest(request, completion: { (response, body, error) -> () in
                
                //TODO: fix hack, make completion always return optionals
                let resp: NSHTTPURLResponse? = response
                
                guard let r = resp else {
                    let e = error ?? Error.withInfo("Nil response")
                    completion(response: nil, body: body, error: e)
                    return
                }
                
                if let versionError = self.verifyAPIVersion(r) {
                    completion(response: response, body: body, error: versionError)
                    return
                }
                
                if case (200...299) = r.statusCode {
                    //pass on
                    completion(response: response, body: body, error: error)
                } else {
                    //see if we haven't received a XCS failure in headers
                    if let xcsStatusMessage = r.allHeaderFields["X-XCSResponse-Status-Message"] as? String {
                        let e = Error.withInfo(xcsStatusMessage)
                        completion(response: response, body: body, error: e)
                    } else {
                        completion(response: response, body: body, error: error)
                    }
                }
            })
            
        } else {
            completion(response: nil, body: nil, error: Error.withInfo("Couldn't create Request"))
        }
    }
    
}
<commit_msg>Support API v5<commit_after>//
//  XcodeServer.swift
//  Buildasaur
//
//  Created by <NAME> on 14/12/2014.
//  Copyright (c) 2014 <NAME>. All rights reserved.
//

import Foundation
import BuildaUtils

// MARK: XcodeServer Class
public class XcodeServer : CIServer {
    
    public let config: XcodeServerConfig
    let endpoints: XcodeServerEndpoints
    
    public init(config: XcodeServerConfig, endpoints: XcodeServerEndpoints) {
        
        self.config = config
        self.endpoints = endpoints
        
        super.init()
        
        let sessionConfig = NSURLSessionConfiguration.defaultSessionConfiguration()
        let delegate: NSURLSessionDelegate = self
        let queue = NSOperationQueue.mainQueue()
        let session = NSURLSession(configuration: sessionConfig, delegate: delegate, delegateQueue: queue)
        self.http.session = session
    }
}

// MARK: NSURLSession delegate implementation
extension XcodeServer : NSURLSessionDelegate {
    
    var credential: NSURLCredential? {
        
        if
            let user = self.config.user,
            let password = self.config.password {
                return NSURLCredential(user: user, password: password, persistence: NSURLCredentialPersistence.None)
        }
        return nil
    }
    
    public func URLSession(session: NSURLSession, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) {
        
        var disposition: NSURLSessionAuthChallengeDisposition = .PerformDefaultHandling
        var credential: NSURLCredential?
        
        if challenge.previousFailureCount > 0 {
            disposition = .CancelAuthenticationChallenge
        } else {
            
            switch challenge.protectionSpace.authenticationMethod {
                
            case NSURLAuthenticationMethodServerTrust:
                credential = NSURLCredential(forTrust: challenge.protectionSpace.serverTrust!)
            default:
                credential = self.credential ?? session.configuration.URLCredentialStorage?.defaultCredentialForProtectionSpace(challenge.protectionSpace)
            }
            
            if credential != nil {
                disposition = .UseCredential
            }
        }
        
        completionHandler(disposition, credential)
    }
}

// MARK: Header constants
let Headers_APIVersion = "X-XCSAPIVersion"
let SupportedAPIVersion: Int = 5 //will change with time, this codebase supports this version

// MARK: XcodeServer API methods
public extension XcodeServer {
    
    private func verifyAPIVersion(response: NSHTTPURLResponse) -> NSError? {
        
        guard let headers = response.allHeaderFields as? [String: AnyObject] else {
            return Error.withInfo("No headers provided in response")
        }
        
        guard let apiVersionString = headers[Headers_APIVersion] as? String else {
            return Error.withInfo("Couldn't find API version Int in headers")
        }
        
        guard let apiVersion = Int(apiVersionString) else {
            return Error.withInfo("Couldn't find API version Int in headers")
        }
        
        if SupportedAPIVersion != apiVersion {
            var common = "Version mismatch: response from API version \(apiVersion), but we support version \(SupportedAPIVersion). "
            
            if apiVersion > SupportedAPIVersion {
                common += "You're using a newer Xcode Server than we support. Please visit https://github.com/czechboy0/XcodeServerSDK to check whether there's a new version of the SDK for it."
            } else {
                common += "You're using an old Xcode Server which we don't support any more. Please look for an older version of the SDK at https://github.com/czechboy0/XcodeServerSDK or consider upgrading your Xcode Server to the current version."
            }
            
            return Error.withInfo(common)
        }
        
        //all good
        return nil
    }
    
    /**
    Internal usage generic method for sending HTTP requests.
    
    - parameter method:     HTTP method.
    - parameter endpoint:   API endpoint.
    - parameter params:     URL paramaters.
    - parameter query:      URL query.
    - parameter body:       POST method request body.
    - parameter completion: Completion.
    */
    internal func sendRequestWithMethod(method: HTTP.Method, endpoint: XcodeServerEndpoints.Endpoint, params: [String: String]?, query: [String: String]?, body: NSDictionary?, completion: HTTP.Completion) {
        if let request = self.endpoints.createRequest(method, endpoint: endpoint, params: params, query: query, body: body) {
            
            self.http.sendRequest(request, completion: { (response, body, error) -> () in
                
                //TODO: fix hack, make completion always return optionals
                let resp: NSHTTPURLResponse? = response
                
                guard let r = resp else {
                    let e = error ?? Error.withInfo("Nil response")
                    completion(response: nil, body: body, error: e)
                    return
                }
                
                if let versionError = self.verifyAPIVersion(r) {
                    completion(response: response, body: body, error: versionError)
                    return
                }
                
                if case (200...299) = r.statusCode {
                    //pass on
                    completion(response: response, body: body, error: error)
                } else {
                    //see if we haven't received a XCS failure in headers
                    if let xcsStatusMessage = r.allHeaderFields["X-XCSResponse-Status-Message"] as? String {
                        let e = Error.withInfo(xcsStatusMessage)
                        completion(response: response, body: body, error: e)
                    } else {
                        completion(response: response, body: body, error: error)
                    }
                }
            })
            
        } else {
            completion(response: nil, body: nil, error: Error.withInfo("Couldn't create Request"))
        }
    }
    
}

{'fraction_non_alphanumeric': 0.07415676580814927, 'fraction_numerical': 0.003588230603620126, 'mean_word_length': 1.944822728339986, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 17, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2864115', 'n_tokens_mistral': 3136, 'n_tokens_neox': 3019, 'n_words': 904}