0001 // Validation.swift 0002 // 0003 // Copyright (c) 2014–2016 Alamofire Software Foundation (http://alamofire.org/) 0004 // 0005 // Permission is hereby granted, free of charge, to any person obtaining a copy 0006 // of this software and associated documentation files (the "Software"), to deal 0007 // in the Software without restriction, including without limitation the rights 0008 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 0009 // copies of the Software, and to permit persons to whom the Software is 0010 // furnished to do so, subject to the following conditions: 0011 // 0012 // The above copyright notice and this permission notice shall be included in 0013 // all copies or substantial portions of the Software. 0014 // 0015 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 0016 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 0017 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 0018 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 0019 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 0020 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 0021 // THE SOFTWARE. 0022 0023 import Foundation 0024 0025 extension Request { 0026 0027 /** 0028 Used to represent whether validation was successful or encountered an error resulting in a failure. 0029 0030 - Success: The validation was successful. 0031 - Failure: The validation failed encountering the provided error. 0032 */ 0033 public enum ValidationResult{ 0034 case Success
Validation.swift:42 public typealias Validation = (NSURLRequest?, NSHTTPURLResponse) -> ValidationResult0035 case Failure
Validation.swift:80 return .SuccessValidation.swift:133 guard let validData = self.delegate.data where validData.length > 0 else { return .Success }Validation.swift:141 return .SuccessValidation.swift:147 return .Success(NSError) 0036 } 0037 0038 /** 0039 A closure used to validate a request that takes a URL request and URL response, and returns whether the 0040 request was valid. 0041 */ 0042 public typealias Validation
Validation.swift:57 case let .Failure(error) = validation(self.request, response)Validation.swift:83 return .Failure(Error.errorWithCode(.StatusCodeValidationFailed, failureReason: failureReason))Validation.swift:163 return .Failure(Error.errorWithCode(.ContentTypeValidationFailed, failureReason: failureReason))= (NSURLRequest?, NSHTTPURLResponse) -> ValidationResult 0043 0044 /** 0045 Validates the request, using the specified closure. 0046 0047 If validation fails, subsequent calls to response handlers will have an associated error. 0048 0049 - parameter validation: A closure to validate the request. 0050 0051 - returns: The request. 0052 */ 0053 public func validate
Validation.swift:53 public func validate(validation: Validation) -> Self {(validation: Validation) -> Self { 0054 delegate.queue.addOperationWithBlock { 0055 if let 0056 response = self.response where self.delegate.error == nil, 0057 case let .Failure(error) = validation(self.request, response) 0058 { 0059 self.delegate.error = error 0060 } 0061 } 0062 0063 return self 0064 } 0065 0066 // MARK: - Status Code 0067 0068 /** 0069 Validates that the response has a status code in the specified range. 0070 0071 If validation fails, subsequent calls to response handlers will have an associated error. 0072 0073 - parameter range: The range of acceptable status codes. 0074 0075 - returns: The request. 0076 */ 0077 public func validate
Validation.swift:78 return validate { _, response inValidation.swift:132 return validate { _, response in<S: SequenceType where S.Generator.Element == Int>(statusCode acceptableStatusCode: S) -> Self { 0078 return validate { _, response in 0079 if acceptableStatusCode.contains(response.statusCode) { 0080 return .Success 0081 } else { 0082 let failureReason = "Response status code was unacceptable: \(response.statusCode)" 0083 return .Failure(Error.errorWithCode(.StatusCodeValidationFailed, failureReason: failureReason)) 0084 } 0085 } 0086 } 0087 0088 // MARK: - Content-Type 0089 0090 private struct MIMEType
Validation.swift:187 return validate(statusCode: acceptableStatusCodes).validate(contentType: acceptableContentTypes){ 0091 let type
Validation.swift:112 func matches(MIME: MIMEType) -> Bool {Validation.swift:137 responseMIMEType = MIMEType(responseContentType)Validation.swift:140 if let acceptableMIMEType = MIMEType(contentType) where acceptableMIMEType.matches(responseMIMEType) {Validation.swift:146 if let MIMEType = MIMEType(contentType) where MIMEType.type == "*" && MIMEType.subtype == "*" {: String 0092 let subtype
Validation.swift:105 self.type = typeValidation.swift:113 switch (type, subtype) {Validation.swift:114 case (MIME.type, MIME.subtype), (MIME.type, "*"), ("*", MIME.subtype), ("*", "*"):Validation.swift:114 case (MIME.type, MIME.subtype), (MIME.type, "*"), ("*", MIME.subtype), ("*", "*"):Validation.swift:146 if let MIMEType = MIMEType(contentType) where MIMEType.type == "*" && MIMEType.subtype == "*" {: String 0093 0094 init
Validation.swift:106 self.subtype = subtypeValidation.swift:113 switch (type, subtype) {Validation.swift:114 case (MIME.type, MIME.subtype), (MIME.type, "*"), ("*", MIME.subtype), ("*", "*"):Validation.swift:114 case (MIME.type, MIME.subtype), (MIME.type, "*"), ("*", MIME.subtype), ("*", "*"):Validation.swift:146 if let MIMEType = MIMEType(contentType) where MIMEType.type == "*" && MIMEType.subtype == "*" {?(_ string: String) { 0095 let components: [String] = { 0096 let stripped = string.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()) 0097 let split = stripped.substringToIndex(stripped.rangeOfString(";")?.startIndex ?? stripped.endIndex) 0098 return split.componentsSeparatedByString("/") 0099 }() 0100 0101 if let 0102 type = components.first, 0103 subtype = components.last 0104 { 0105 self.type = type 0106 self.subtype = subtype 0107 } else { 0108 return nil 0109 } 0110 } 0111 0112 func matches
Validation.swift:137 responseMIMEType = MIMEType(responseContentType)Validation.swift:140 if let acceptableMIMEType = MIMEType(contentType) where acceptableMIMEType.matches(responseMIMEType) {Validation.swift:146 if let MIMEType = MIMEType(contentType) where MIMEType.type == "*" && MIMEType.subtype == "*" {(MIME: MIMEType) -> Bool { 0113 switch (type, subtype) { 0114 case (MIME.type, MIME.subtype), (MIME.type, "*"), ("*", MIME.subtype), ("*", "*"): 0115 return true 0116 default: 0117 return false 0118 } 0119 } 0120 } 0121 0122 /** 0123 Validates that the response has a content type in the specified array. 0124 0125 If validation fails, subsequent calls to response handlers will have an associated error. 0126 0127 - parameter contentType: The acceptable content types, which may specify wildcard types and/or subtypes. 0128 0129 - returns: The request. 0130 */ 0131 public func validate
Validation.swift:140 if let acceptableMIMEType = MIMEType(contentType) where acceptableMIMEType.matches(responseMIMEType) {<S : SequenceType where S.Generator.Element == String>(contentType acceptableContentTypes: S) -> Self { 0132 return validate { _, response in 0133 guard let validData = self.delegate.data where validData.length > 0 else { return .Success } 0134 0135 if let 0136 responseContentType = response.MIMEType, 0137 responseMIMEType = MIMEType(responseContentType) 0138 { 0139 for contentType in acceptableContentTypes { 0140 if let acceptableMIMEType = MIMEType(contentType) where acceptableMIMEType.matches(responseMIMEType) { 0141 return .Success 0142 } 0143 } 0144 } else { 0145 for contentType in acceptableContentTypes { 0146 if let MIMEType = MIMEType(contentType) where MIMEType.type == "*" && MIMEType.subtype == "*" { 0147 return .Success 0148 } 0149 } 0150 } 0151 0152 let failureReason: String 0153 0154 if let responseContentType = response.MIMEType { 0155 failureReason = ( 0156 "Response content type \"\(responseContentType)\" does not match any acceptable " + 0157 "content types: \(acceptableContentTypes)" 0158 ) 0159 } else { 0160 failureReason = "Response content type was missing and acceptable content type does not match \"*/*\"" 0161 } 0162 0163 return .Failure(Error.errorWithCode(.ContentTypeValidationFailed, failureReason: failureReason)) 0164 } 0165 } 0166 0167 // MARK: - Automatic 0168 0169 /** 0170 Validates that the response has a status code in the default acceptable range of 200...299, and that the content 0171 type matches any specified in the Accept HTTP header field. 0172 0173 If validation fails, subsequent calls to response handlers will have an associated error. 0174 0175 - returns: The request. 0176 */ 0177 public func validate() -> Self { 0178 let acceptableStatusCodes: Range<Int> = 200..<300 0179 let acceptableContentTypes: [String] = { 0180 if let accept = request?.valueForHTTPHeaderField("Accept") { 0181 return accept.componentsSeparatedByString(",") 0182 } 0183 0184 return ["*/*"] 0185 }() 0186 0187 return validate(statusCode: acceptableStatusCodes).validate(contentType: acceptableContentTypes) 0188 } 0189 } 0190
Validation.swift:187 return validate(statusCode: acceptableStatusCodes).validate(contentType: acceptableContentTypes)