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