1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
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  */
15 
16 #ifndef COMMUNICATIONNETSTACK_HTTP_CLIENT_TASK_H
17 #define COMMUNICATIONNETSTACK_HTTP_CLIENT_TASK_H
18 
19 #include <atomic>
20 #include <functional>
21 #include <memory>
22 #include <mutex>
23 #include <stdio.h>
24 #include <string.h>
25 #include <string>
26 
27 #include "http_client_error.h"
28 #include "http_client_request.h"
29 #include "http_client_response.h"
30 #if HAS_NETMANAGER_BASE
31 #include "netstack_network_profiler.h"
32 #endif
33 
34 namespace OHOS {
35 namespace NetStack {
36 namespace HttpClient {
37 enum TaskStatus {
38     IDLE,
39     RUNNING,
40 };
41 
42 enum TaskType {
43     DEFAULT,
44     UPLOAD,
45 };
46 
47 class HttpClientTask : public std::enable_shared_from_this<HttpClientTask> {
48 public:
49     /**
50      * Constructs an HttpClientTask object with the specified request.
51      * @param request The HTTP request object.
52      */
53     HttpClientTask(const HttpClientRequest &request);
54 
55     /**
56      * Constructs an HttpClientTask object with the specified request, type, and file path.
57      * @param request The HTTP request object.
58      * @param type The task type.
59      * @param filePath The file path to save the response content.
60      */
61     HttpClientTask(const HttpClientRequest &request, TaskType type, const std::string &filePath);
62 
63     /**
64      * Destructor that releases any allocated resources.
65      */
66     ~HttpClientTask();
67 
68     /**
69      * Starts the HTTP request task.
70      * @return Returns true if the task starts successfully, false otherwise.
71      */
72     bool Start();
73 
74     /**
75      * Cancels the ongoing HTTP request task.
76      */
77     void Cancel();
78 
79     /**
80      * Gets the status of the HTTP request task.
81      * @return The current status of the task.
82      */
83     [[nodiscard]] TaskStatus GetStatus();
84 
85     /**
86      * Gets the type of the HTTP request task.
87      * @return The type of the task.
88      */
89     [[nodiscard]] TaskType GetType();
90 
91     /**
92      * Gets the ID of the HTTP request task.
93      * @return The ID of the task.
94      */
95     [[nodiscard]] unsigned int GetTaskId();
96 
97     /**
98      * Gets the file path to save the response content.
99      * @return The file path.
100      */
101     [[nodiscard]] const std::string &GetFilePath();
102 
103     /**
104      * Gets the HTTP request object associated with this task.
105      * @return A reference to the HTTP request object.
106      */
GetRequest()107     [[nodiscard]] HttpClientRequest &GetRequest()
108     {
109         return request_;
110     }
111 
112     /**
113      * Gets the HTTP response object associated with this task.
114      * @return A reference to the HTTP response object.
115      */
GetResponse()116     [[nodiscard]] HttpClientResponse &GetResponse()
117     {
118         return response_;
119     }
120 
121     /**
122      * Gets the HTTP error object associated with this task.
123      * @return A reference to the HTTP error object.
124      */
GetError()125     [[nodiscard]] HttpClientError &GetError()
126     {
127         return error_;
128     }
129 
130     /**
131      * Gets the handle for interacting with the CURL library.
132      * @return The CURL handle.
133      */
GetCurlHandle()134     [[nodiscard]] CURL *GetCurlHandle()
135     {
136         return curlHandle_;
137     }
138 
139     /**
140      * Sets a callback function to be called when the HTTP request succeeds.
141      * @param onSucceeded The callback function to be called when the request succeeds.
142      *                    It takes the HttpClientRequest object and the HttpClientResponse object as parameters.
143      */
144     void OnSuccess(
145         const std::function<void(const HttpClientRequest &request, const HttpClientResponse &response)> &onSucceeded);
146 
147     /**
148      * Sets a callback function to be called when the HTTP request is canceled.
149      * @param onCanceled The callback function to be called when the request is canceled.
150      *                   It takes the HttpClientRequest object and the HttpClientResponse object as parameters.
151      */
152     void OnCancel(
153         const std::function<void(const HttpClientRequest &request, const HttpClientResponse &response)> &onCanceled);
154 
155     /**
156      * Sets a callback function to be called when the HTTP request fails.
157      * @param onFailed The callback function to be called when the request fails.
158      *                 It takes the HttpClientRequest object, the HttpClientResponse object,
159      *                 and the HttpClientError object as parameters.
160      */
161     void OnFail(const std::function<void(const HttpClientRequest &request, const HttpClientResponse &response,
162                                          const HttpClientError &error)> &onFailed);
163 
164     /**
165      * Sets a callback function to be called when data is received in the HTTP response.
166      * @param onDataReceive The callback function to be called when data is received.
167      *                      It takes the HttpClientRequest object, a pointer to the received data,
168      *                      and the length of the received data as parameters.
169      */
170     void OnDataReceive(
171         const std::function<void(const HttpClientRequest &request, const uint8_t *data, size_t length)> &onDataReceive);
172 
173     /**
174      * Sets a callback function to be called to report the progress of the HTTP request.
175      * @param onProgress The callback function to be called to report the progress.
176      *                   It takes the HttpClientRequest object, the total number of bytes to download,
177      *                   the number of bytes downloaded, the total number of bytes to upload,
178      *                   and the number of bytes uploaded as parameters.
179      */
180     void OnProgress(const std::function<void(const HttpClientRequest &request, u_long dlTotal, u_long dlNow,
181                                              u_long ulTotal, u_long ulNow)> &onProgress);
182     /**
183      * Sets the response received from the server for this HTTP request.
184      * @param response The HttpClientResponse object representing the response from the server.
185      */
186     void SetResponse(const HttpClientResponse &response);
187 
188 private:
189     friend class HttpSession;
190 
191     /**
192      * Sets the status of the HTTP request task.
193      * @param status The status to be set.
194      */
195     void SetStatus(TaskStatus status);
196 
197     /**
198      * Sets the Curl options for the HTTP request.
199      * @return Returns true if the Curl options are set successfully, false otherwise.
200      */
201     bool SetCurlOptions();
202 
203     /**
204      * Sets other Curl options for the HTTP request.
205      * @param handle The Curl handle.
206      * @return Returns true if the Curl options are set successfully, false otherwise.
207      */
208     bool SetOtherCurlOption(CURL *handle);
209 
210     /**
211      * Sets the server ssl cert options for the HTTP request.
212      * @param handle The Curl handle.
213      * @return Returns true if the set options are set successfully, false otherwise.
214      */
215     bool SetServerSSLCertOption(CURL *curl);
216 
217     /**
218      * Sets the ssl cert options for the HTTP request.
219      * @param handle The Curl handle.
220      * @return Returns true if the set options are set successfully, false otherwise.
221      */
222     bool SetSSLCertOption(CURL *curl);
223 
224     /**
225      * Ssl verify function for the HTTP request.
226      * @param handle The Curl handle.
227      * @param sslCtl The SSL handle.
228      * @return Returns CURLM_OK if the set options are set successfully, error code otherwise.
229      */
230     CURLcode SslCtxFunction(CURL *curl, void *sslCtx);
231 
232     /**
233      * Sets the upload options for the HTTP request.
234      * @param handle The Curl handle.
235      * @return Returns true if the upload options are set successfully, false otherwise.
236      */
237     bool SetUploadOptions(CURL *handle);
238 
239     /**
240      * Converts the HttpProtocol enum value to the corresponding Http version.
241      * @param ptcl The HttpProtocol enum value.
242      * @return The Http version as an unsigned integer.
243      */
244     uint32_t GetHttpVersion(HttpProtocol ptcl) const;
245 
246     /**
247      * Retrieves the HttpProxyInfo including host, port, exclusions, and tunnel flag.
248      * @param host The output string to store the proxy host.
249      * @param port The output integer to store the proxy port.
250      * @param exclusions The output string to store the proxy exclusions.
251      * @param tunnel The output bool to indicate if the proxy uses tunneling.
252      */
253     void GetHttpProxyInfo(std::string &host, int32_t &port, std::string &exclusions,
254                           bool &tunnel);
255 
256     /**
257      * Callback function used to report the progress of the HTTP request.
258      * @param userData User-defined data passed to the callback function.
259      * @param dltotal The total number of bytes to download.
260      * @param dlnow The number of bytes downloaded so far.
261      * @param ultotal The total number of bytes to upload.
262      * @param ulnow The number of bytes uploaded so far.
263      * @return Returns 0 to continue the transfer, or a non-zero value to abort the transfer.
264      */
265     static int ProgressCallback(void *userData, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal,
266                                 curl_off_t ulnow);
267 
268     /**
269      * Callback function used to receive data in the HTTP response.
270      * @param data Pointer to the received data.
271      * @param size Size of each element in the data buffer.
272      * @param memBytes Number of elements in the data buffer.
273      * @param userData User-defined data passed to the callback function.
274      * @return The number of bytes processed by the callback function.
275      */
276     static size_t DataReceiveCallback(const void *data, size_t size, size_t memBytes, void *userData);
277 
278     /**
279      * Callback function used to receive header data in the HTTP response.
280      * @param data Pointer to the received header data.
281      * @param size Size of each element in the data buffer.
282      * @param memBytes Number of elements in the data buffer.
283      * @param userData User-defined data passed to the callback function.
284      * @return The number of bytes processed by the callback function.
285      */
286     static size_t HeaderReceiveCallback(const void *data, size_t size, size_t memBytes, void *userData);
287 
288     /**
289      * Processes the Curl response message and updates the task status.
290      * @param msg The Curl message.
291      */
292     void ProcessResponse(CURLMsg *msg);
293 
294     /**
295      * Processes the response code in the HTTP response.
296      * @return Returns true if the response code is processed successfully, false otherwise.
297      */
298     bool ProcessResponseCode();
299 
300     /**
301      * Get the timing from curl handle
302      * @return Returns timing, unit is seconds.
303      */
304     double GetTimingFromCurl(CURL *handle, CURLINFO info) const;
305 
306     /**
307      * Processes the cookie in the HTTP response.
308      * @param handle The Curl handle.
309      */
310     void ProcessCookie(CURL *handle);
311 
312     /**
313      * Get download or uploader size from curl handle
314      * @return Returns size, unit is bytes.
315      */
316     curl_off_t GetSizeFromCurl(CURL *handle) const;
317 
318     /**
319      * dump http informations from curl
320      */
321     void DumpHttpPerformance() const;
322 
323     std::function<void(const HttpClientRequest &request, const HttpClientResponse &response)> onSucceeded_;
324     std::function<void(const HttpClientRequest &request, const HttpClientResponse &response)> onCanceled_;
325     std::function<void(const HttpClientRequest &request, const HttpClientResponse &response,
326                        const HttpClientError &error)>
327         onFailed_;
328     std::function<void(const HttpClientRequest &request, const uint8_t *data, size_t length)> onDataReceive_;
329     std::function<void(const HttpClientRequest &request, u_long dlTotal, u_long dlNow, u_long ulTotal, u_long ulNow)>
330         onProgress_;
331 
332     HttpClientRequest request_;
333     HttpClientResponse response_;
334     HttpClientError error_;
335 
336     TaskType type_;
337     TaskStatus status_;
338     unsigned int taskId_;
339     struct curl_slist *curlHeaderList_;
340     bool canceled_;
341 
342     std::mutex mutex_;
343     CURL *curlHandle_;
344     static std::atomic<unsigned int> nextTaskId_;
345     std::string filePath_;
346     FILE *file_ = nullptr;
347 #if HAS_NETMANAGER_BASE
348     std::unique_ptr<NetworkProfilerUtils> networkProfilerUtils_;
349 #endif
350 };
351 
352 } // namespace HttpClient
353 } // namespace NetStack
354 } // namespace OHOS
355 
356 #endif // COMMUNICATIONNETSTACK_HTTP_CLIENT_TASK_H