| 
									
										
										
										
											2019-04-11 14:40:54 +08:00
										 |  |  | // Copyright (c) 2016-2018 Kiwano - Nomango
 | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | // 
 | 
					
						
							|  |  |  | // Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
					
						
							|  |  |  | // of this software and associated documentation files (the "Software"), to deal
 | 
					
						
							|  |  |  | // in the Software without restriction, including without limitation the rights
 | 
					
						
							|  |  |  | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
					
						
							|  |  |  | // copies of the Software, and to permit persons to whom the Software is
 | 
					
						
							|  |  |  | // furnished to do so, subject to the following conditions:
 | 
					
						
							|  |  |  | // 
 | 
					
						
							|  |  |  | // The above copyright notice and this permission notice shall be included in
 | 
					
						
							|  |  |  | // all copies or substantial portions of the Software.
 | 
					
						
							|  |  |  | // 
 | 
					
						
							|  |  |  | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
					
						
							|  |  |  | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
					
						
							|  |  |  | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
					
						
							|  |  |  | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
					
						
							|  |  |  | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
					
						
							|  |  |  | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
					
						
							|  |  |  | // THE SOFTWARE.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <thread>
 | 
					
						
							| 
									
										
										
										
											2019-03-31 23:09:49 +08:00
										 |  |  | #include <codecvt>
 | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-11 21:55:29 +08:00
										 |  |  | #include <kiwano-network/HttpRequest.h>
 | 
					
						
							|  |  |  | #include <kiwano-network/HttpResponse.hpp>
 | 
					
						
							|  |  |  | #include <kiwano-network/HttpClient.h>
 | 
					
						
							| 
									
										
										
										
											2019-09-30 10:59:04 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include <kiwano/base/Logger.h>
 | 
					
						
							|  |  |  | #include <kiwano/platform/Application.h>
 | 
					
						
							| 
									
										
										
										
											2019-10-11 21:12:29 +08:00
										 |  |  | #include <3rd-party/curl/curl.h>  // CURL
 | 
					
						
							| 
									
										
										
										
											2019-04-05 16:06:32 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | namespace | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-04-11 14:40:54 +08:00
										 |  |  | 	using namespace kiwano; | 
					
						
							|  |  |  | 	using namespace kiwano::network; | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-29 22:23:13 +08:00
										 |  |  | 	std::uint32_t write_data(void* buffer, std::uint32_t size, std::uint32_t nmemb, void* userp) | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2019-08-02 16:07:01 +08:00
										 |  |  | 		kiwano::string* recv_buffer = (kiwano::string*)userp; | 
					
						
							| 
									
										
										
										
											2019-09-29 22:23:13 +08:00
										 |  |  | 		std::uint32_t total = size * nmemb; | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// add data to the end of recv_buffer
 | 
					
						
							|  |  |  | 		// write data maybe called more than once in a single request
 | 
					
						
							|  |  |  | 		recv_buffer->append((char*)buffer, total); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-20 00:21:44 +08:00
										 |  |  | 		return total; | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-02 16:07:01 +08:00
										 |  |  | 	kiwano::string convert_to_utf8(kiwano::wstring const& str) | 
					
						
							| 
									
										
										
										
											2019-03-31 23:09:49 +08:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2019-09-29 22:23:13 +08:00
										 |  |  | 		std::wstring_convert<std::codecvt_utf8<wchar_t>> utf8_conv; | 
					
						
							| 
									
										
										
										
											2019-08-02 16:07:01 +08:00
										 |  |  | 		kiwano::string result; | 
					
						
							| 
									
										
										
										
											2019-03-31 23:09:49 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		try | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			result = utf8_conv.to_bytes(str.c_str()); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		catch (std::range_error&) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			// bad conversion
 | 
					
						
							| 
									
										
										
										
											2019-08-02 16:07:01 +08:00
										 |  |  | 			result = wide_to_string(str); | 
					
						
							| 
									
										
										
										
											2019-03-31 23:09:49 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		return result; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-02 16:07:01 +08:00
										 |  |  | 	kiwano::wstring convert_from_utf8(kiwano::string const& str) | 
					
						
							| 
									
										
										
										
											2019-03-31 23:09:49 +08:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2019-09-29 22:23:13 +08:00
										 |  |  | 		kiwano::string_convert<std::codecvt_utf8<wchar_t>> utf8_conv; | 
					
						
							| 
									
										
										
										
											2019-08-02 16:07:01 +08:00
										 |  |  | 		kiwano::wstring result; | 
					
						
							| 
									
										
										
										
											2019-03-31 23:09:49 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		try | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			result = utf8_conv.from_bytes(str); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		catch (std::range_error&) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			// bad conversion
 | 
					
						
							| 
									
										
										
										
											2019-08-02 16:07:01 +08:00
										 |  |  | 			result = string_to_wide(str); | 
					
						
							| 
									
										
										
										
											2019-03-31 23:09:49 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		return result; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | 	class Curl | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	public: | 
					
						
							|  |  |  | 		Curl() | 
					
						
							|  |  |  | 			: curl_(curl_easy_init()) | 
					
						
							|  |  |  | 			, curl_headers_(nullptr) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		~Curl() | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			if (curl_) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				curl_easy_cleanup(curl_); | 
					
						
							|  |  |  | 				curl_ = nullptr; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (curl_headers_) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				curl_slist_free_all(curl_headers_); | 
					
						
							|  |  |  | 				curl_headers_ = nullptr; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-13 21:16:38 +08:00
										 |  |  | 		bool Init(HttpClient* client, Vector<kiwano::string> const& headers, kiwano::string const& url, kiwano::string* response_data, kiwano::string* response_header, char* error_buffer) | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			if (!SetOption(CURLOPT_ERRORBUFFER, error_buffer)) | 
					
						
							|  |  |  | 				return false; | 
					
						
							|  |  |  | 			if (!SetOption(CURLOPT_TIMEOUT, client->GetTimeoutForRead())) | 
					
						
							|  |  |  | 				return false; | 
					
						
							|  |  |  | 			if (!SetOption(CURLOPT_CONNECTTIMEOUT, client->GetTimeoutForConnect())) | 
					
						
							|  |  |  | 				return false; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-02 16:07:01 +08:00
										 |  |  | 			const auto ssl_ca_file = wide_to_string(client->GetSSLVerification()); | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | 			if (ssl_ca_file.empty()) { | 
					
						
							|  |  |  | 				if (!SetOption(CURLOPT_SSL_VERIFYPEER, 0L)) | 
					
						
							|  |  |  | 					return false; | 
					
						
							|  |  |  | 				if (!SetOption(CURLOPT_SSL_VERIFYHOST, 0L)) | 
					
						
							|  |  |  | 					return false; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else { | 
					
						
							|  |  |  | 				if (!SetOption(CURLOPT_SSL_VERIFYPEER, 1L)) | 
					
						
							|  |  |  | 					return false; | 
					
						
							|  |  |  | 				if (!SetOption(CURLOPT_SSL_VERIFYHOST, 2L)) | 
					
						
							|  |  |  | 					return false; | 
					
						
							|  |  |  | 				if (!SetOption(CURLOPT_CAINFO, ssl_ca_file.c_str())) | 
					
						
							|  |  |  | 					return false; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (!SetOption(CURLOPT_NOSIGNAL, 1L)) | 
					
						
							|  |  |  | 				return false; | 
					
						
							|  |  |  | 			if (!SetOption(CURLOPT_ACCEPT_ENCODING, "")) | 
					
						
							|  |  |  | 				return false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// set request headers
 | 
					
						
							|  |  |  | 			if (!headers.empty()) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				for (const auto& header : headers) | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					curl_headers_ = curl_slist_append(curl_headers_, header.c_str()); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				if (!SetOption(CURLOPT_HTTPHEADER, curl_headers_)) | 
					
						
							|  |  |  | 					return false; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			return SetOption(CURLOPT_URL, url.c_str()) | 
					
						
							|  |  |  | 				&& SetOption(CURLOPT_WRITEFUNCTION, write_data) | 
					
						
							|  |  |  | 				&& SetOption(CURLOPT_WRITEDATA, response_data) | 
					
						
							|  |  |  | 				&& SetOption(CURLOPT_HEADERFUNCTION, write_data) | 
					
						
							|  |  |  | 				&& SetOption(CURLOPT_HEADERDATA, response_header); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		bool Perform(long* response_code) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			if (CURLE_OK != curl_easy_perform(curl_)) | 
					
						
							|  |  |  | 				return false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			CURLcode code = curl_easy_getinfo(curl_, CURLINFO_RESPONSE_CODE, response_code); | 
					
						
							| 
									
										
										
										
											2019-03-31 13:09:31 +08:00
										 |  |  | 			return code == CURLE_OK && (*response_code >= 200 && *response_code < 300); | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		template <typename ..._Args> | 
					
						
							|  |  |  | 		bool SetOption(CURLoption option, _Args&&... args) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			return CURLE_OK == curl_easy_setopt(curl_, option, std::forward<_Args>(args)...); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	public: | 
					
						
							| 
									
										
										
										
											2019-03-31 13:09:31 +08:00
										 |  |  | 		static inline bool GetRequest( | 
					
						
							|  |  |  | 			HttpClient* client, | 
					
						
							| 
									
										
										
										
											2019-08-13 21:16:38 +08:00
										 |  |  | 			Vector<kiwano::string> const& headers, | 
					
						
							| 
									
										
										
										
											2019-08-02 16:07:01 +08:00
										 |  |  | 			kiwano::string const& url, | 
					
						
							| 
									
										
										
										
											2019-03-31 13:09:31 +08:00
										 |  |  | 			long* response_code, | 
					
						
							| 
									
										
										
										
											2019-08-02 16:07:01 +08:00
										 |  |  | 			kiwano::string* response_data, | 
					
						
							|  |  |  | 			kiwano::string* response_header, | 
					
						
							| 
									
										
										
										
											2019-03-31 13:09:31 +08:00
										 |  |  | 			char* error_buffer) | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			Curl curl; | 
					
						
							| 
									
										
										
										
											2019-03-31 13:09:31 +08:00
										 |  |  | 			return curl.Init(client, headers, url, response_data, response_header, error_buffer) | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | 				&& curl.SetOption(CURLOPT_FOLLOWLOCATION, true) | 
					
						
							|  |  |  | 				&& curl.Perform(response_code); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-31 13:09:31 +08:00
										 |  |  | 		static inline bool PostRequest( | 
					
						
							|  |  |  | 			HttpClient* client, | 
					
						
							| 
									
										
										
										
											2019-08-13 21:16:38 +08:00
										 |  |  | 			Vector<kiwano::string> const& headers, | 
					
						
							| 
									
										
										
										
											2019-08-02 16:07:01 +08:00
										 |  |  | 			kiwano::string const& url, | 
					
						
							|  |  |  | 			kiwano::string const& request_data, | 
					
						
							| 
									
										
										
										
											2019-03-31 13:09:31 +08:00
										 |  |  | 			long* response_code, | 
					
						
							| 
									
										
										
										
											2019-08-02 16:07:01 +08:00
										 |  |  | 			kiwano::string* response_data, | 
					
						
							|  |  |  | 			kiwano::string* response_header, | 
					
						
							| 
									
										
										
										
											2019-03-31 13:09:31 +08:00
										 |  |  | 			char* error_buffer) | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			Curl curl; | 
					
						
							| 
									
										
										
										
											2019-03-31 13:09:31 +08:00
										 |  |  | 			return curl.Init(client, headers, url, response_data, response_header, error_buffer) | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | 				&& curl.SetOption(CURLOPT_POST, 1) | 
					
						
							|  |  |  | 				&& curl.SetOption(CURLOPT_POSTFIELDS, request_data.c_str()) | 
					
						
							|  |  |  | 				&& curl.SetOption(CURLOPT_POSTFIELDSIZE, request_data.size()) | 
					
						
							|  |  |  | 				&& curl.Perform(response_code); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-31 13:09:31 +08:00
										 |  |  | 		static inline bool PutRequest( | 
					
						
							|  |  |  | 			HttpClient* client, | 
					
						
							| 
									
										
										
										
											2019-08-13 21:16:38 +08:00
										 |  |  | 			Vector<kiwano::string> const& headers, | 
					
						
							| 
									
										
										
										
											2019-08-02 16:07:01 +08:00
										 |  |  | 			kiwano::string const& url, | 
					
						
							|  |  |  | 			kiwano::string const& request_data, | 
					
						
							| 
									
										
										
										
											2019-03-31 13:09:31 +08:00
										 |  |  | 			long* response_code, | 
					
						
							| 
									
										
										
										
											2019-08-02 16:07:01 +08:00
										 |  |  | 			kiwano::string* response_data, | 
					
						
							|  |  |  | 			kiwano::string* response_header, | 
					
						
							| 
									
										
										
										
											2019-03-31 13:09:31 +08:00
										 |  |  | 			char* error_buffer) | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			Curl curl; | 
					
						
							| 
									
										
										
										
											2019-03-31 13:09:31 +08:00
										 |  |  | 			return curl.Init(client, headers, url, response_data, response_header, error_buffer) | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | 				&& curl.SetOption(CURLOPT_CUSTOMREQUEST, "PUT") | 
					
						
							|  |  |  | 				&& curl.SetOption(CURLOPT_POSTFIELDS, request_data.c_str()) | 
					
						
							|  |  |  | 				&& curl.SetOption(CURLOPT_POSTFIELDSIZE, request_data.size()) | 
					
						
							|  |  |  | 				&& curl.Perform(response_code); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-31 13:09:31 +08:00
										 |  |  | 		static inline bool DeleteRequest( | 
					
						
							|  |  |  | 			HttpClient* client, | 
					
						
							| 
									
										
										
										
											2019-08-13 21:16:38 +08:00
										 |  |  | 			Vector<kiwano::string> const& headers, | 
					
						
							| 
									
										
										
										
											2019-08-02 16:07:01 +08:00
										 |  |  | 			kiwano::string const& url, | 
					
						
							| 
									
										
										
										
											2019-03-31 13:09:31 +08:00
										 |  |  | 			long* response_code, | 
					
						
							| 
									
										
										
										
											2019-08-02 16:07:01 +08:00
										 |  |  | 			kiwano::string* response_data, | 
					
						
							|  |  |  | 			kiwano::string* response_header, | 
					
						
							| 
									
										
										
										
											2019-03-31 13:09:31 +08:00
										 |  |  | 			char* error_buffer) | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			Curl curl; | 
					
						
							| 
									
										
										
										
											2019-03-31 13:09:31 +08:00
										 |  |  | 			return curl.Init(client, headers, url, response_data, response_header, error_buffer) | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | 				&& curl.SetOption(CURLOPT_CUSTOMREQUEST, "DELETE") | 
					
						
							|  |  |  | 				&& curl.SetOption(CURLOPT_FOLLOWLOCATION, true) | 
					
						
							|  |  |  | 				&& curl.Perform(response_code); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	private: | 
					
						
							|  |  |  | 		CURL* curl_; | 
					
						
							|  |  |  | 		curl_slist* curl_headers_; | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-11 14:40:54 +08:00
										 |  |  | namespace kiwano | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | { | 
					
						
							|  |  |  | 	namespace network | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		HttpClient::HttpClient() | 
					
						
							| 
									
										
										
										
											2019-04-24 13:33:19 +08:00
										 |  |  | 			: timeout_for_connect_(30000 /* 30 seconds */) | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | 			, timeout_for_read_(60000 /* 60 seconds */) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-12 14:51:54 +08:00
										 |  |  | 		void HttpClient::SetupComponent() | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			::curl_global_init(CURL_GLOBAL_ALL); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-18 22:49:44 +08:00
										 |  |  | 			std::thread thread(Closure(this, &HttpClient::NetworkThread)); | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | 			thread.detach(); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		void HttpClient::DestroyComponent() | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			::curl_global_cleanup(); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-03 15:27:18 +08:00
										 |  |  | 		void HttpClient::Send(HttpRequestPtr request) | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			if (!request) | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			request_mutex_.lock(); | 
					
						
							|  |  |  | 			request_queue_.push(request); | 
					
						
							|  |  |  | 			request_mutex_.unlock(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			sleep_condition_.notify_one(); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		void HttpClient::NetworkThread() | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			while (true) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				HttpRequestPtr request; | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					std::lock_guard<std::mutex> lock(request_mutex_); | 
					
						
							|  |  |  | 					while (request_queue_.empty()) | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						sleep_condition_.wait(request_mutex_); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					request = request_queue_.front(); | 
					
						
							|  |  |  | 					request_queue_.pop(); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				HttpResponsePtr response = new (std::nothrow) HttpResponse(request); | 
					
						
							|  |  |  | 				Perform(request, response); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				response_mutex_.lock(); | 
					
						
							|  |  |  | 				response_queue_.push(response); | 
					
						
							|  |  |  | 				response_mutex_.unlock(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-18 22:49:44 +08:00
										 |  |  | 				Application::PreformInMainThread(Closure(this, &HttpClient::DispatchResponseCallback)); | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-03 15:27:18 +08:00
										 |  |  | 		void HttpClient::Perform(HttpRequestPtr request, HttpResponsePtr response) | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			bool ok = false; | 
					
						
							|  |  |  | 			long response_code = 0; | 
					
						
							| 
									
										
										
										
											2019-03-31 13:09:31 +08:00
										 |  |  | 			char error_message[256] = { 0 }; | 
					
						
							| 
									
										
										
										
											2019-08-02 16:07:01 +08:00
										 |  |  | 			kiwano::string response_header; | 
					
						
							|  |  |  | 			kiwano::string response_data; | 
					
						
							| 
									
										
										
										
											2019-03-31 13:09:31 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-02 16:07:01 +08:00
										 |  |  | 			kiwano::string url = convert_to_utf8(request->GetUrl()); | 
					
						
							|  |  |  | 			kiwano::string data = convert_to_utf8(request->GetData()); | 
					
						
							| 
									
										
										
										
											2019-03-31 23:09:49 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-13 21:16:38 +08:00
										 |  |  | 			Vector<kiwano::string> headers; | 
					
						
							| 
									
										
										
										
											2019-03-31 13:09:31 +08:00
										 |  |  | 			headers.reserve(request->GetHeaders().size()); | 
					
						
							| 
									
										
										
										
											2019-03-31 23:09:49 +08:00
										 |  |  | 			for (const auto& pair : request->GetHeaders()) | 
					
						
							| 
									
										
										
										
											2019-03-31 13:09:31 +08:00
										 |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2019-08-02 16:07:01 +08:00
										 |  |  | 				headers.push_back(wide_to_string(pair.first) + ":" + wide_to_string(pair.second)); | 
					
						
							| 
									
										
										
										
											2019-03-31 13:09:31 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			switch (request->GetType()) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 			case HttpRequest::Type::Get: | 
					
						
							| 
									
										
										
										
											2019-03-31 13:09:31 +08:00
										 |  |  | 				ok = Curl::GetRequest(this, headers, url, &response_code, &response_data, &response_header, error_message); | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | 				break; | 
					
						
							|  |  |  | 			case HttpRequest::Type::Post: | 
					
						
							| 
									
										
										
										
											2019-03-31 13:09:31 +08:00
										 |  |  | 				ok = Curl::PostRequest(this, headers, url, data, &response_code, &response_data, &response_header, error_message); | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | 				break; | 
					
						
							|  |  |  | 			case HttpRequest::Type::Put: | 
					
						
							| 
									
										
										
										
											2019-03-31 13:09:31 +08:00
										 |  |  | 				ok = Curl::PutRequest(this, headers, url, data, &response_code, &response_data, &response_header, error_message); | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | 				break; | 
					
						
							|  |  |  | 			case HttpRequest::Type::Delete: | 
					
						
							| 
									
										
										
										
											2019-03-31 13:09:31 +08:00
										 |  |  | 				ok = Curl::DeleteRequest(this, headers, url, &response_code, &response_data, &response_header, error_message); | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | 				break; | 
					
						
							|  |  |  | 			default: | 
					
						
							| 
									
										
										
										
											2019-04-11 14:40:54 +08:00
										 |  |  | 				KGE_ERROR_LOG(L"HttpClient: unknown request type, only GET, POST, PUT or DELETE is supported"); | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			response->SetResponseCode(response_code); | 
					
						
							| 
									
										
										
										
											2019-08-02 16:07:01 +08:00
										 |  |  | 			response->SetHeader(string_to_wide(response_header)); | 
					
						
							| 
									
										
										
										
											2019-03-31 23:09:49 +08:00
										 |  |  | 			response->SetData(convert_from_utf8(response_data)); | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | 			if (!ok) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				response->SetSucceed(false); | 
					
						
							| 
									
										
										
										
											2019-08-02 16:07:01 +08:00
										 |  |  | 				response->SetError(string_to_wide(error_message)); | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			else | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				response->SetSucceed(true); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		void HttpClient::DispatchResponseCallback() | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			HttpResponsePtr response; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			response_mutex_.lock(); | 
					
						
							|  |  |  | 			if (!response_queue_.empty()) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				response = response_queue_.front(); | 
					
						
							|  |  |  | 				response_queue_.pop(); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			response_mutex_.unlock(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (response) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				HttpRequestPtr request = response->GetRequest(); | 
					
						
							|  |  |  | 				const auto& callback = request->GetResponseCallback(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if (callback) | 
					
						
							|  |  |  | 				{ | 
					
						
							| 
									
										
										
										
											2019-09-30 10:59:04 +08:00
										 |  |  | 					callback(request.get(), response.get()); | 
					
						
							| 
									
										
										
										
											2019-03-31 01:37:06 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |