1// Copyright 2017 Google Inc. All Rights Reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15import Foundation 16import Dispatch 17import KituraNet 18 19// fetch makes a synchronous request using KituraNet's ClientRequest class 20// https://github.com/IBM-Swift/Kitura-net/blob/master/Sources/KituraNet/ClientRequest.swift 21public func fetch(_ urlRequest: URLRequest) -> (Data?, HTTPURLResponse?, Error?) { 22 var data: Data? 23 var urlResponse: HTTPURLResponse? 24 let error: Error? = nil // make this mutable when we start using it 25 let sem = DispatchSemaphore(value: 0) 26 guard let method = urlRequest.httpMethod else { 27 return (data, urlResponse, error) 28 } 29 guard let url = urlRequest.url else { 30 return (data, urlResponse, error) 31 } 32 guard let scheme = url.scheme else { 33 return (data, urlResponse, error) 34 } 35 guard let host = url.host else { 36 return (data, urlResponse, error) 37 } 38 guard let port = url.port else { 39 return (data, urlResponse, error) 40 } 41 let options : [ClientRequest.Options] = [ 42 .method(method), 43 .schema(scheme), 44 .hostname(host), 45 .port(Int16(port)), 46 .path(url.path), 47 // headers, etc 48 ] 49 let request = HTTP.request(options) { (response) in 50 guard let response = response else { 51 sem.signal() 52 return 53 } 54 var responseData = Data() 55 do { 56 let code = response.httpStatusCode 57 try response.readAllData(into: &responseData) 58 data = responseData 59 urlResponse = HTTPURLResponse(url:url, 60 statusCode:code.rawValue, 61 httpVersion:"HTTP/1.1", 62 headerFields:[:]) 63 sem.signal() 64 return 65 } catch { 66 sem.signal() 67 return 68 } 69 } 70 if let requestData = urlRequest.httpBody { 71 request.write(from:requestData) 72 } 73 request.end() // send the request 74 // now wait on the semaphore for a response 75 let result = sem.wait(timeout: DispatchTime.distantFuture) 76 switch result { 77 case .success: 78 return (data, urlResponse, error) 79 default: // includes .timeout 80 return (data, urlResponse, error) 81 } 82} 83 84// fetch makes an asynchronous request using KituraNet's ClientRequest class 85// https://github.com/IBM-Swift/Kitura-net/blob/master/Sources/KituraNet/ClientRequest.swift 86public func fetch(_ urlRequest: URLRequest, callback:@escaping (Data?, HTTPURLResponse?, Error?) -> ()) { 87 var data: Data? 88 var urlResponse: HTTPURLResponse? 89 let error: Error? = nil // make this mutable when we start using it 90 guard let method = urlRequest.httpMethod else { 91 callback (data, urlResponse, error) 92 return 93 } 94 guard let url = urlRequest.url else { 95 callback (data, urlResponse, error) 96 return 97 } 98 guard let scheme = url.scheme else { 99 callback (data, urlResponse, error) 100 return 101 } 102 guard let host = url.host else { 103 callback (data, urlResponse, error) 104 return 105 } 106 guard let port = url.port else { 107 callback (data, urlResponse, error) 108 return 109 } 110 let options : [ClientRequest.Options] = [ 111 .method(method), 112 .schema(scheme), 113 .hostname(host), 114 .port(Int16(port)), 115 .path(url.path), 116 // headers, etc 117 ] 118 let request = HTTP.request(options) { (response) in 119 guard let response = response else { 120 callback (data, urlResponse, nil) 121 return 122 } 123 var responseData = Data() 124 do { 125 let code = response.httpStatusCode 126 try response.readAllData(into: &responseData) 127 data = responseData 128 urlResponse = HTTPURLResponse(url:url, 129 statusCode:code.rawValue, 130 httpVersion:"HTTP/1.1", 131 headerFields:[:]) 132 callback (data, urlResponse, nil) 133 return 134 } catch { 135 callback (data, urlResponse, nil) 136 return 137 } 138 } 139 if let requestData = urlRequest.httpBody { 140 request.write(from:requestData) 141 } 142 request.end() // send the request 143} 144