| // |
| // UsergridRequest.swift |
| // UsergridSDK |
| // |
| // Created by Robert Walsh on 1/12/16. |
| // |
| /* |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. The ASF licenses this file to You |
| * under the Apache License, Version 2.0 (the "License"); you may not |
| * use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. For additional information regarding |
| * copyright in this work, please see the NOTICE file in the top level |
| * directory of this distribution. |
| * |
| */ |
| |
| import Foundation |
| |
| /** |
| The UsergridRequest class incapsulates the properties that all requests made by the SDK have in common. |
| |
| This class is also functions to create `NSURLRequest` objects based on the properties of the class. |
| */ |
| public class UsergridRequest : NSObject { |
| |
| // MARK: - Instance Properties - |
| |
| /// The HTTP method. |
| public let method: UsergridHttpMethod |
| |
| /// The base URL. |
| public let baseUrl: String |
| |
| /// The paths to append to the base URL. |
| public let paths: [String]? |
| |
| /// The query to append to the URL. |
| public let query: UsergridQuery? |
| |
| /// The auth that will be used. |
| public let auth: UsergridAuth? |
| |
| /// The headers to add to the request. |
| public let headers: [String:String]? |
| |
| /// The JSON body that will be set on the request. Can be either a valid JSON object or NSData. |
| public let jsonBody: AnyObject? |
| |
| /// The query params that will be set on the request. |
| public let queryParams: [String:String]? |
| |
| // MARK: - Initialization - |
| |
| /** |
| The designated initializer for `UsergridRequest` objects. |
| |
| - parameter method: The HTTP method. |
| - parameter baseUrl: The base URL. |
| - parameter paths: The optional paths to append to the base URL. |
| - parameter query: The optional query to append to the URL. |
| - parameter auth: The optional `UsergridAuth` that will be used in the Authorization header. |
| - parameter headers: The optional headers. |
| - parameter jsonBody: The optional JSON body. Can be either a valid JSON object or NSData. |
| - parameter queryParams: The optional query params to be appended to the request url. |
| |
| - returns: A new instance of `UsergridRequest`. |
| */ |
| public init(method:UsergridHttpMethod, |
| baseUrl:String, |
| paths:[String]? = nil, |
| query:UsergridQuery? = nil, |
| auth:UsergridAuth? = nil, |
| headers:[String:String]? = nil, |
| jsonBody:AnyObject? = nil, |
| queryParams:[String:String]? = nil) { |
| self.method = method |
| self.baseUrl = baseUrl |
| self.paths = paths |
| self.auth = auth |
| self.headers = headers |
| self.query = query |
| self.queryParams = queryParams |
| if let body = jsonBody where (body is NSData || NSJSONSerialization.isValidJSONObject(body)) { |
| self.jsonBody = body |
| } else { |
| self.jsonBody = nil |
| } |
| } |
| |
| // MARK: - Instance Methods - |
| |
| /** |
| Constructs a `NSURLRequest` object with this objects instance properties. |
| |
| - returns: An initialized and configured `NSURLRequest` object. |
| */ |
| public func buildNSURLRequest() -> NSURLRequest { |
| let request = NSMutableURLRequest(URL: self.buildURL()) |
| request.HTTPMethod = self.method.stringValue |
| self.applyHeaders(request) |
| self.applyBody(request) |
| self.applyAuth(request) |
| return request |
| } |
| |
| private func buildURL() -> NSURL { |
| var constructedURLString = self.baseUrl |
| if let appendingPaths = self.paths { |
| for pathToAppend in appendingPaths { |
| if let encodedPath = pathToAppend.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLPathAllowedCharacterSet()) { |
| constructedURLString = "\(constructedURLString)\(UsergridRequest.FORWARD_SLASH)\(encodedPath)" |
| } |
| } |
| } |
| if let queryToAppend = self.query { |
| let appendFromQuery = queryToAppend.build() |
| if !appendFromQuery.isEmpty { |
| constructedURLString = "\(constructedURLString)\(UsergridRequest.FORWARD_SLASH)\(appendFromQuery)" |
| } |
| } |
| if let queryParams = self.queryParams { |
| if let components = NSURLComponents(string: constructedURLString) { |
| components.queryItems = components.queryItems ?? [] |
| for (key, value) in queryParams { |
| let q: NSURLQueryItem = NSURLQueryItem(name: key, value: value) |
| components.queryItems!.append(q) |
| } |
| constructedURLString = components.string! |
| } |
| } |
| return NSURL(string:constructedURLString)! |
| } |
| |
| private func applyHeaders(request:NSMutableURLRequest) { |
| if let httpHeaders = self.headers { |
| for (key,value) in httpHeaders { |
| request.setValue(value, forHTTPHeaderField: key) |
| } |
| } |
| } |
| |
| private func applyBody(request:NSMutableURLRequest) { |
| if let jsonBody = self.jsonBody, httpBody = UsergridRequest.jsonBodyToData(jsonBody) { |
| request.HTTPBody = httpBody |
| request.setValue(String(format: "%lu", httpBody.length), forHTTPHeaderField: UsergridRequest.CONTENT_LENGTH) |
| } |
| } |
| |
| private func applyAuth(request:NSMutableURLRequest) { |
| if let usergridAuth = self.auth { |
| if usergridAuth.isValid, let accessToken = usergridAuth.accessToken { |
| request.setValue("\(UsergridRequest.BEARER) \(accessToken)", forHTTPHeaderField: UsergridRequest.AUTHORIZATION) |
| } |
| } |
| } |
| |
| private static func jsonBodyToData(jsonBody:AnyObject) -> NSData? { |
| if let jsonBodyAsNSData = jsonBody as? NSData { |
| return jsonBodyAsNSData |
| } else { |
| var jsonBodyAsNSData: NSData? = nil |
| do { jsonBodyAsNSData = try NSJSONSerialization.dataWithJSONObject(jsonBody, options: NSJSONWritingOptions(rawValue: 0)) } |
| catch { print(error) } |
| return jsonBodyAsNSData |
| } |
| } |
| |
| private static let AUTHORIZATION = "Authorization" |
| private static let ACCESS_TOKEN = "access_token" |
| private static let APPLICATION_JSON = "application/json; charset=utf-8" |
| private static let BEARER = "Bearer" |
| private static let CONTENT_LENGTH = "Content-Length" |
| private static let CONTENT_TYPE = "Content-Type" |
| private static let FORWARD_SLASH = "/" |
| |
| static let JSON_CONTENT_TYPE_HEADER = [UsergridRequest.CONTENT_TYPE:UsergridRequest.APPLICATION_JSON] |
| } |
| |
| /** |
| The `UsergridRequest` sub class which is used for uploading assets. |
| */ |
| public class UsergridAssetUploadRequest: UsergridRequest { |
| |
| // MARK: - Instance Properties - |
| |
| /// The asset to use for uploading. |
| public let asset: UsergridAsset |
| |
| /// A constructed multipart http body for requests to upload. |
| public var multiPartHTTPBody: NSData { |
| let httpBodyString = UsergridAssetUploadRequest.MULTIPART_START + |
| "\(UsergridAssetUploadRequest.CONTENT_DISPOSITION):\(UsergridAssetUploadRequest.FORM_DATA); name=file; filename=\(self.asset.filename)\r\n" + |
| "\(UsergridRequest.CONTENT_TYPE): \(self.asset.contentType)\r\n\r\n" as NSString |
| |
| let httpBody = NSMutableData() |
| httpBody.appendData(httpBodyString.dataUsingEncoding(NSUTF8StringEncoding)!) |
| httpBody.appendData(self.asset.data) |
| httpBody.appendData(UsergridAssetUploadRequest.MULTIPART_END.dataUsingEncoding(NSUTF8StringEncoding)!) |
| |
| return httpBody |
| } |
| |
| // MARK: - Initialization - |
| |
| /** |
| The designated initializer for `UsergridAssetUploadRequest` objects. |
| |
| - parameter baseUrl: The base URL. |
| - parameter paths: The optional paths to append to the base URL. |
| - parameter auth: The optional `UsergridAuth` that will be used in the Authorization header. |
| - parameter asset: The asset to upload. |
| |
| - returns: A new instance of `UsergridRequest`. |
| */ |
| public init(baseUrl:String, |
| paths:[String]? = nil, |
| auth:UsergridAuth? = nil, |
| asset:UsergridAsset) { |
| self.asset = asset |
| super.init(method: .Put, baseUrl: baseUrl, paths: paths, auth: auth) |
| } |
| |
| private override func applyHeaders(request: NSMutableURLRequest) { |
| super.applyHeaders(request) |
| request.setValue(UsergridAssetUploadRequest.ASSET_UPLOAD_CONTENT_HEADER, forHTTPHeaderField: UsergridRequest.CONTENT_TYPE) |
| request.setValue(String(format: "%lu", self.multiPartHTTPBody.length), forHTTPHeaderField: UsergridRequest.CONTENT_LENGTH) |
| } |
| |
| private static let ASSET_UPLOAD_BOUNDARY = "usergrid-asset-upload-boundary" |
| private static let ASSET_UPLOAD_CONTENT_HEADER = "multipart/form-data; boundary=\(UsergridAssetUploadRequest.ASSET_UPLOAD_BOUNDARY)" |
| private static let CONTENT_DISPOSITION = "Content-Disposition" |
| private static let MULTIPART_START = "--\(UsergridAssetUploadRequest.ASSET_UPLOAD_BOUNDARY)\r\n" |
| private static let MULTIPART_END = "\r\n--\(UsergridAssetUploadRequest.ASSET_UPLOAD_BOUNDARY)--\r\n" as NSString |
| private static let FORM_DATA = "form-data" |
| } |