1/*
2 * Copyright (c) 2023-2024 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#include <cstring>
17#include <map>
18#include <securec.h>
19#include <string>
20#include <vector>
21
22#define private public
23#include "http_client.h"
24#include "http_client_request.h"
25#undef private
26#include "http_request_options.h"
27#include "netstack_log.h"
28#include "secure_char.h"
29
30namespace OHOS {
31namespace NetStack {
32namespace Http {
33namespace {
34using namespace OHOS::NetStack::HttpClient;
35const uint8_t *g_baseFuzzData = nullptr;
36size_t g_baseFuzzSize = 0;
37size_t g_baseFuzzPos = 0;
38constexpr size_t STR_LEN = 255;
39constexpr int32_t TEST_PORT = 8888;
40} // namespace
41template <class T> T GetData()
42{
43    T object{};
44    size_t objectSize = sizeof(object);
45    if (g_baseFuzzData == nullptr || g_baseFuzzSize <= g_baseFuzzPos || objectSize > g_baseFuzzSize - g_baseFuzzPos) {
46        return object;
47    }
48    if (memcpy_s(&object, objectSize, g_baseFuzzData + g_baseFuzzPos, objectSize)) {
49        return {};
50    }
51    g_baseFuzzPos += objectSize;
52    return object;
53}
54
55void SetGlobalFuzzData(const uint8_t *data, size_t size)
56{
57    g_baseFuzzData = data;
58    g_baseFuzzSize = size;
59    g_baseFuzzPos = 0;
60}
61
62std::string GetStringFromData(int strlen)
63{
64    if (strlen < 1) {
65        return "";
66    }
67
68    char cstr[strlen];
69    cstr[strlen - 1] = '\0';
70    for (int i = 0; i < strlen - 1; i++) {
71        cstr[i] = GetData<char>();
72    }
73    std::string str(cstr);
74    return str;
75}
76
77void SetCaPathFuzzTest(const uint8_t *data, size_t size)
78{
79    if ((data == nullptr) || (size < 1)) {
80        return;
81    }
82    SetGlobalFuzzData(data, size);
83    std::string str = GetStringFromData(STR_LEN);
84
85    HttpRequestOptions requestOptions;
86    requestOptions.SetCaPath(str);
87}
88
89void SetUrlFuzzTest(const uint8_t *data, size_t size)
90{
91    if ((data == nullptr) || (size < 1)) {
92        return;
93    }
94    SetGlobalFuzzData(data, size);
95    HttpRequestOptions requestOptions;
96    std::string str = GetStringFromData(STR_LEN);
97    requestOptions.SetUrl(str);
98}
99
100void SetMethodFuzzTest(const uint8_t *data, size_t size)
101{
102    if ((data == nullptr) || (size < 1)) {
103        return;
104    }
105    SetGlobalFuzzData(data, size);
106    HttpRequestOptions requestOptions;
107    std::string str = GetStringFromData(STR_LEN);
108    requestOptions.SetMethod(str);
109}
110
111void SetHeaderFuzzTest(const uint8_t *data, size_t size)
112{
113    if ((data == nullptr) || (size < 1)) {
114        return;
115    }
116    SetGlobalFuzzData(data, size);
117    HttpRequestOptions requestOptions;
118    std::string str = GetStringFromData(STR_LEN);
119    requestOptions.SetHeader(str, str);
120}
121
122void SetReadTimeoutFuzzTest(const uint8_t *data, size_t size)
123{
124    if ((data == nullptr) || (size < 1)) {
125        return;
126    }
127    SetGlobalFuzzData(data, size);
128    HttpRequestOptions requestOptions;
129    requestOptions.SetReadTimeout(size);
130}
131
132void SetConnectTimeoutFuzzTest(const uint8_t *data, size_t size)
133{
134    if ((data == nullptr) || (size < 1)) {
135        return;
136    }
137    SetGlobalFuzzData(data, size);
138    HttpRequestOptions requestOptions;
139    requestOptions.SetConnectTimeout(size);
140}
141
142void SetUsingProtocolFuzzTest(const uint8_t *data, size_t size)
143{
144    if ((data == nullptr) || (size < 1)) {
145        return;
146    }
147    SetGlobalFuzzData(data, size);
148    HttpRequestOptions requestOptions;
149}
150
151void SetHttpDataTypeFuzzTest(const uint8_t *data, size_t size)
152{
153    if ((data == nullptr) || (size < 1)) {
154        return;
155    }
156    SetGlobalFuzzData(data, size);
157    HttpRequestOptions requestOptions;
158    std::string str = GetStringFromData(STR_LEN);
159    requestOptions.SetRequestTime(str);
160}
161
162void SetUsingHttpProxyTypeFuzzTest(const uint8_t *data, size_t size)
163{
164    if ((data == nullptr) || (size < 1)) {
165        return;
166    }
167    SetGlobalFuzzData(data, size);
168    HttpRequestOptions requestOptions;
169    requestOptions.SetUsingHttpProxyType(UsingHttpProxyType::USE_SPECIFIED);
170}
171
172void SetSpecifiedHttpProxyFuzzTest(const uint8_t *data, size_t size)
173{
174    if ((data == nullptr) || (size < 1)) {
175        return;
176    }
177    SetGlobalFuzzData(data, size);
178    HttpRequestOptions requestOptions;
179    std::string str = GetStringFromData(STR_LEN);
180    requestOptions.SetSpecifiedHttpProxy(str, size, str);
181}
182
183void SetDnsServersFuzzTest(const uint8_t *data, size_t size)
184{
185    if ((data == nullptr) || (size < 1)) {
186        return;
187    }
188    SetGlobalFuzzData(data, size);
189    HttpRequestOptions requestOptions;
190    std::vector<std::string> dnsServers = { GetStringFromData(STR_LEN), GetStringFromData(STR_LEN),
191        GetStringFromData(STR_LEN) };
192    requestOptions.SetDnsServers(dnsServers);
193}
194
195void SetDohUrlFuzzTest(const uint8_t *data, size_t size)
196{
197    if ((data == nullptr) || (size < 1)) {
198        return;
199    }
200    SetGlobalFuzzData(data, size);
201
202    HttpRequestOptions requestOptions;
203    std::string str = GetStringFromData(STR_LEN);
204    requestOptions.SetDohUrl(str);
205}
206
207void SetRangeNumberFuzzTest(const uint8_t *data, size_t size)
208{
209    if ((data == nullptr) || (size < 1)) {
210        return;
211    }
212    SetGlobalFuzzData(data, size);
213    HttpRequestOptions requestOptions;
214    requestOptions.SetRangeNumber(size, size);
215}
216
217void SetClientCertFuzzTest(const uint8_t *data, size_t size)
218{
219    if ((data == nullptr) || (size < 1)) {
220        return;
221    }
222    SetGlobalFuzzData(data, size);
223
224    HttpRequestOptions requestOptions;
225    std::string str = GetStringFromData(STR_LEN);
226    Secure::SecureChar pwd(str);
227    requestOptions.SetClientCert(str, str, str, pwd);
228}
229
230void AddMultiFormDataFuzzTest(const uint8_t *data, size_t size)
231{
232    if ((data == nullptr) || (size < 1)) {
233        return;
234    }
235    SetGlobalFuzzData(data, size);
236    HttpRequestOptions requestOptions;
237    MultiFormData multiFormData;
238    std::string str = GetStringFromData(STR_LEN);
239    multiFormData.name = str;
240    multiFormData.data = str;
241    multiFormData.contentType = str;
242    multiFormData.remoteFileName = str;
243    multiFormData.filePath = str;
244    requestOptions.AddMultiFormData(multiFormData);
245}
246
247HttpClientRequest CreateHttpClientRequest()
248{
249    HttpClientRequest httpReq;
250    std::string url = "https://www.baidu.com";
251    httpReq.SetURL(url);
252    return httpReq;
253}
254
255HttpClientRequest CreateHttpClientRequest(const uint8_t *data, size_t size)
256{
257    g_baseFuzzData = data;
258    g_baseFuzzSize = size;
259    g_baseFuzzPos = 0;
260    HttpClientRequest httpReq;
261    std::string str = GetStringFromData(STR_LEN);
262    httpReq.SetURL(str);
263    return httpReq;
264}
265
266void HttpSessionCreateTaskFuzzTest(const uint8_t *data, size_t size)
267{
268    if ((data == nullptr) || (size < 1)) {
269        return;
270    }
271    HttpClientRequest httpReq = CreateHttpClientRequest();
272    auto testTask = HttpSession::GetInstance().CreateTask(httpReq);
273    testTask->Start();
274
275    httpReq = CreateHttpClientRequest(data, size);
276    testTask = HttpSession::GetInstance().CreateTask(httpReq);
277    testTask->Start();
278}
279
280void HttpClientTaskGetHttpVersionFuzzTest(const uint8_t *data, size_t size)
281{
282    if ((data == nullptr) || (size < 1)) {
283        return;
284    }
285
286    HttpClientRequest httpReq = CreateHttpClientRequest();
287    auto task = HttpSession::GetInstance().CreateTask(httpReq);
288    HttpClient::HttpProtocol ptcl = HttpClient::HttpProtocol::HTTP1_1;
289    HttpClientRequest request;
290    request.SetHttpProtocol(ptcl);
291    uint32_t timeout = GetData<uint32_t>();
292    request.SetTimeout(timeout);
293    std::string testData = GetStringFromData(STR_LEN);
294    std::string result = request.GetBody();
295    request.body_ = "";
296    request.SetCaPath(testData);
297    uint32_t priority = GetData<uint32_t>();
298    request.SetPriority(priority);
299    result = request.GetURL();
300    result = request.GetMethod();
301    uint32_t ret = request.GetTimeout();
302    ret = request.GetConnectTimeout();
303    ptcl = request.GetHttpProtocol();
304    HttpClient::HttpProxyType proType = request.GetHttpProxyType();
305    NETSTACK_LOGD("ptcl = %{private}d, proType = %{private}d", ptcl, proType);
306    result = request.GetCaPath();
307    ret = request.GetPriority();
308    HttpProxy proxy = request.GetHttpProxy();
309    request.SetRequestTime(testData);
310    result = request.GetRequestTime();
311    task->GetHttpVersion(ptcl);
312}
313
314void HttpClientTaskSetHttpProtocolFuzzTest(const uint8_t *data, size_t size)
315{
316    if ((data == nullptr) || (size < 1)) {
317        return;
318    }
319
320    HttpClientRequest httpReq = CreateHttpClientRequest(data, size);
321    auto task = HttpSession::GetInstance().CreateTask(httpReq);
322    HttpClientRequest request;
323    HttpClient::HttpProtocol ptcl = HttpClient::HttpProtocol::HTTP1_1;
324    request.SetHttpProtocol(ptcl);
325    HttpProxy proxy = request.GetHttpProxy();
326    std::string testData = GetStringFromData(STR_LEN);
327    request.SetCaPath(testData);
328    request.SetRequestTime(testData);
329    std::string result = request.GetRequestTime();
330    result = request.GetBody();
331    request.body_ = "";
332    task->GetHttpVersion(ptcl);
333    result = request.GetURL();
334    result = request.GetMethod();
335    result = request.GetCaPath();
336    uint32_t timeout = GetData<uint32_t>();
337    request.SetTimeout(timeout);
338    uint32_t prio = GetData<uint32_t>();
339    request.SetPriority(prio);
340    uint32_t ret = request.GetTimeout();
341    ret = request.GetConnectTimeout();
342    ret = request.GetPriority();
343    ptcl = request.GetHttpProtocol();
344    HttpClient::HttpProxyType proType = request.GetHttpProxyType();
345    NETSTACK_LOGD("ptcl = %{private}d, proType = %{private}d", ptcl, proType);
346}
347
348void HttpClientTaskSetOtherCurlOptionFuzzTest(const uint8_t *data, size_t size)
349{
350    if ((data == nullptr) || (size < 1)) {
351        return;
352    }
353
354    HttpClientRequest request;
355    std::string url = "http://www.httpbin.org/get";
356    request.SetURL(url);
357    request.SetHttpProxyType(NOT_USE);
358    HttpProxy testProxy;
359    testProxy.host = "192.168.147.60";
360    testProxy.exclusions = "www.httpbin.org";
361    testProxy.port = TEST_PORT;
362    testProxy.tunnel = false;
363    request.SetHttpProxy(testProxy);
364    auto task = HttpSession::GetInstance().CreateTask(request);
365    task->SetOtherCurlOption(task->curlHandle_);
366
367    request = CreateHttpClientRequest(data, size);
368    task = HttpSession::GetInstance().CreateTask(request);
369    task->SetOtherCurlOption(task->curlHandle_);
370}
371
372void HttpClientTaskSetCurlOptionsFuzzTest(const uint8_t *data, size_t size)
373{
374    if ((data == nullptr) || (size < 1)) {
375        return;
376    }
377
378    HttpClientRequest httpReq;
379    std::string url = "http://www.httpbin.org/get";
380    httpReq.SetURL(url);
381    auto task = HttpSession::GetInstance().CreateTask(httpReq);
382    task->request_.SetMethod(HttpConstant::HTTP_METHOD_HEAD);
383    task->SetCurlOptions();
384
385    httpReq = CreateHttpClientRequest(data, size);
386    task = HttpSession::GetInstance().CreateTask(httpReq);
387    task->request_.SetMethod(HttpConstant::HTTP_METHOD_HEAD);
388    task->SetCurlOptions();
389}
390
391void HttpClientTaskGetTypeFuzzTest(const uint8_t *data, size_t size)
392{
393    if ((data == nullptr) || (size < 1)) {
394        return;
395    }
396
397    HttpClientRequest httpReq = CreateHttpClientRequest();
398    auto task = HttpSession::GetInstance().CreateTask(httpReq);
399    TaskType type = task->GetType();
400    std::string result = task->GetFilePath();
401    int taskId = task->GetTaskId();
402    TaskStatus status = static_cast<TaskStatus>(size % 2);
403    task->SetStatus(status);
404    status = task->GetStatus();
405    NETSTACK_LOGD("type = %{private}d, result = %{private}s, taskId = %{private}d, status = %{private}d", type,
406        result.c_str(), taskId, status);
407    task->OnSuccess([task](const HttpClientRequest &request, const HttpClientResponse &response) {});
408    task->OnCancel([](const HttpClientRequest &request, const HttpClientResponse &response) {});
409    task->OnFail(
410        [](const HttpClientRequest &request, const HttpClientResponse &response, const HttpClientError &error) {});
411    task->OnDataReceive([](const HttpClientRequest &request, const uint8_t *data, size_t length) {});
412    task->OnProgress(
413        [](const HttpClientRequest &request, u_long dltotal, u_long dlnow, u_long ultotal, u_long ulnow) {});
414    task->OnDataReceive([](const HttpClientRequest &request, const uint8_t *data, size_t length) {});
415    httpReq = CreateHttpClientRequest(data, size);
416    task = HttpSession::GetInstance().CreateTask(httpReq);
417    type = task->GetType();
418    result = task->GetFilePath();
419    taskId = task->GetTaskId();
420    status = task->GetStatus();
421    task->SetStatus(status);
422}
423} // namespace Http
424} // namespace NetStack
425} // namespace OHOS
426
427/* Fuzzer entry point */
428extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
429{
430    /* Run your code on data */
431    OHOS::NetStack::Http::SetCaPathFuzzTest(data, size);
432    OHOS::NetStack::Http::SetUrlFuzzTest(data, size);
433    OHOS::NetStack::Http::SetMethodFuzzTest(data, size);
434    OHOS::NetStack::Http::SetHeaderFuzzTest(data, size);
435    OHOS::NetStack::Http::SetReadTimeoutFuzzTest(data, size);
436    OHOS::NetStack::Http::SetConnectTimeoutFuzzTest(data, size);
437    OHOS::NetStack::Http::SetUsingProtocolFuzzTest(data, size);
438    OHOS::NetStack::Http::SetHttpDataTypeFuzzTest(data, size);
439    OHOS::NetStack::Http::SetUsingHttpProxyTypeFuzzTest(data, size);
440    OHOS::NetStack::Http::SetSpecifiedHttpProxyFuzzTest(data, size);
441    OHOS::NetStack::Http::SetDnsServersFuzzTest(data, size);
442    OHOS::NetStack::Http::SetDohUrlFuzzTest(data, size);
443    OHOS::NetStack::Http::SetRangeNumberFuzzTest(data, size);
444    OHOS::NetStack::Http::SetClientCertFuzzTest(data, size);
445    OHOS::NetStack::Http::AddMultiFormDataFuzzTest(data, size);
446    OHOS::NetStack::Http::HttpSessionCreateTaskFuzzTest(data, size);
447    OHOS::NetStack::Http::HttpClientTaskGetHttpVersionFuzzTest(data, size);
448    OHOS::NetStack::Http::HttpClientTaskSetHttpProtocolFuzzTest(data, size);
449    OHOS::NetStack::Http::HttpClientTaskSetOtherCurlOptionFuzzTest(data, size);
450    OHOS::NetStack::Http::HttpClientTaskSetCurlOptionsFuzzTest(data, size);
451    OHOS::NetStack::Http::HttpClientTaskGetTypeFuzzTest(data, size);
452    return 0;
453}