1 /* 2 * Copyright 2008-2018 Max Kellermann <max.kellermann@gmail.com> 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * - Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * - Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the 14 * distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 19 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 20 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 27 * OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #ifndef CURL_REQUEST_HXX 31 #define CURL_REQUEST_HXX 32 33 #include "Easy.hxx" 34 35 #include <map> 36 #include <string> 37 38 struct StringView; 39 class CurlGlobal; 40 class CurlResponseHandler; 41 42 class CurlRequest final { 43 CurlGlobal &global; 44 45 CurlResponseHandler &handler; 46 47 /** the curl handle */ 48 CurlEasy easy; 49 50 enum class State { 51 HEADERS, 52 BODY, 53 CLOSED, 54 } state = State::HEADERS; 55 56 std::multimap<std::string, std::string> headers; 57 58 /** error message provided by libcurl */ 59 char error_buffer[CURL_ERROR_SIZE]; 60 61 bool registered = false; 62 63 public: 64 /** 65 * To start sending the request, call Start(). 66 */ 67 CurlRequest(CurlGlobal &_global, 68 CurlResponseHandler &_handler); 69 CurlRequest(CurlGlobal & _global,const char * url,CurlResponseHandler & _handler)70 CurlRequest(CurlGlobal &_global, const char *url, 71 CurlResponseHandler &_handler) 72 :CurlRequest(_global, _handler) { 73 SetUrl(url); 74 } 75 76 ~CurlRequest() noexcept; 77 78 CurlRequest(const CurlRequest &) = delete; 79 CurlRequest &operator=(const CurlRequest &) = delete; 80 81 /** 82 * Register this request via CurlGlobal::Add(), which starts 83 * the request. 84 * 85 * This method must be called in the event loop thread. 86 */ 87 void Start(); 88 89 /** 90 * A thread-safe version of Start(). 91 */ 92 void StartIndirect(); 93 94 /** 95 * Unregister this request via CurlGlobal::Remove(). 96 * 97 * This method must be called in the event loop thread. 98 */ 99 void Stop() noexcept; 100 101 /** 102 * A thread-safe version of Stop(). 103 */ 104 void StopIndirect(); 105 Get()106 CURL *Get() noexcept { 107 return easy.Get(); 108 } 109 110 template<typename T> SetOption(CURLoption option,T value)111 void SetOption(CURLoption option, T value) { 112 easy.SetOption(option, value); 113 } 114 SetUrl(const char * url)115 void SetUrl(const char *url) { 116 easy.SetURL(url); 117 } 118 SetRequestHeaders(struct curl_slist * request_headers)119 void SetRequestHeaders(struct curl_slist *request_headers) { 120 easy.SetRequestHeaders(request_headers); 121 } 122 SetVerifyHost(bool value)123 void SetVerifyHost(bool value) { 124 easy.SetVerifyHost(value); 125 } 126 SetVerifyPeer(bool value)127 void SetVerifyPeer(bool value) { 128 easy.SetVerifyPeer(value); 129 } 130 SetNoBody(bool value=true)131 void SetNoBody(bool value=true) { 132 easy.SetNoBody(value); 133 } 134 SetPost(bool value=true)135 void SetPost(bool value=true) { 136 easy.SetPost(value); 137 } 138 SetRequestBody(const void * data,size_t size)139 void SetRequestBody(const void *data, size_t size) { 140 easy.SetRequestBody(data, size); 141 } 142 143 void Resume() noexcept; 144 145 /** 146 * A HTTP request is finished. Called by #CurlGlobal. 147 */ 148 void Done(CURLcode result) noexcept; 149 150 private: 151 /** 152 * Frees the current "libcurl easy" handle, and everything 153 * associated with it. 154 */ 155 void FreeEasy() noexcept; 156 157 void FinishHeaders(); 158 void FinishBody(); 159 160 size_t DataReceived(const void *ptr, size_t size) noexcept; 161 162 void HeaderFunction(StringView s) noexcept; 163 164 /** called by curl when new data is available */ 165 static size_t _HeaderFunction(char *ptr, size_t size, size_t nmemb, 166 void *stream) noexcept; 167 168 /** called by curl when new data is available */ 169 static size_t WriteFunction(char *ptr, size_t size, size_t nmemb, 170 void *stream) noexcept; 171 }; 172 173 #endif 174