1 /*
2 * Copyright (c) 2021-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 #include "constant.h"
17 #include "curl/curl.h"
18 #include "netstack_common_utils.h"
19 #include "netstack_log.h"
20
21 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM)
22 #include <netinet/tcp.h>
23 #endif
24 #include "http_request_options.h"
25 #include "secure_char.h"
26
27 namespace OHOS::NetStack::Http {
28 static constexpr const uint32_t MIN_PRIORITY = 1;
29 static constexpr const uint32_t MAX_PRIORITY = 1000;
30
31 static constexpr const int64_t MIN_RESUM_NUMBER = 1;
32 static constexpr const int64_t MAX_RESUM_NUMBER = 4294967296;
33
HttpRequestOptions()34 HttpRequestOptions::HttpRequestOptions()
35 : method_(HttpConstant::HTTP_METHOD_GET),
36 readTimeout_(HttpConstant::DEFAULT_READ_TIMEOUT),
37 maxLimit_(HttpConstant::DEFAULT_MAX_LIMIT),
38 connectTimeout_(HttpConstant::DEFAULT_CONNECT_TIMEOUT),
39 usingProtocol_(HttpProtocol::HTTP_NONE),
40 dataType_(HttpDataType::NO_DATA_TYPE),
41 priority_(MIN_PRIORITY),
42 usingHttpProxyType_(UsingHttpProxyType::USE_DEFAULT),
43 httpProxyPort_(0),
44 resumeFromNumber_(0),
45 resumeToNumber_(0)
46 {
47 }
48
SetUrl(const std::string & url)49 void HttpRequestOptions::SetUrl(const std::string &url)
50 {
51 url_ = url;
52 }
53
SetMethod(const std::string & method)54 void HttpRequestOptions::SetMethod(const std::string &method)
55 {
56 method_ = method;
57 }
58
SetBody(const void * data,size_t length)59 void HttpRequestOptions::SetBody(const void *data, size_t length)
60 {
61 body_.append(static_cast<const char *>(data), length);
62 }
63
SetHeader(const std::string & key,const std::string & val)64 void HttpRequestOptions::SetHeader(const std::string &key, const std::string &val)
65 {
66 header_[key] = val;
67 }
68
SetReadTimeout(uint32_t readTimeout)69 void HttpRequestOptions::SetReadTimeout(uint32_t readTimeout)
70 {
71 readTimeout_ = readTimeout;
72 tcpOption_.SetTcpUserTimeout(readTimeout);
73 }
74
SetMaxLimit(uint32_t maxLimit)75 void HttpRequestOptions::SetMaxLimit(uint32_t maxLimit)
76 {
77 if (maxLimit > HttpConstant::MAX_LIMIT) {
78 NETSTACK_LOGD("maxLimit setting exceeds the maximum limit, use max limit");
79 maxLimit_ = HttpConstant::MAX_LIMIT;
80 return;
81 }
82 maxLimit_ = maxLimit;
83 }
84
SetConnectTimeout(uint32_t connectTimeout)85 void HttpRequestOptions::SetConnectTimeout(uint32_t connectTimeout)
86 {
87 connectTimeout_ = connectTimeout;
88 }
89
GetUrl() const90 const std::string &HttpRequestOptions::GetUrl() const
91 {
92 return url_;
93 }
94
GetMethod() const95 const std::string &HttpRequestOptions::GetMethod() const
96 {
97 return method_;
98 }
99
GetBody() const100 const std::string &HttpRequestOptions::GetBody() const
101 {
102 return body_;
103 }
104
GetHeader() const105 const std::map<std::string, std::string> &HttpRequestOptions::GetHeader() const
106 {
107 return header_;
108 }
109
GetReadTimeout() const110 uint32_t HttpRequestOptions::GetReadTimeout() const
111 {
112 return readTimeout_;
113 }
114
GetMaxLimit() const115 uint32_t HttpRequestOptions::GetMaxLimit() const
116 {
117 return maxLimit_;
118 }
119
GetConnectTimeout() const120 uint32_t HttpRequestOptions::GetConnectTimeout() const
121 {
122 return connectTimeout_;
123 }
124
SetUsingProtocol(HttpProtocol httpProtocol)125 void HttpRequestOptions::SetUsingProtocol(HttpProtocol httpProtocol)
126 {
127 usingProtocol_ = httpProtocol;
128 }
129
GetHttpVersion() const130 uint32_t HttpRequestOptions::GetHttpVersion() const
131 {
132 if (usingProtocol_ == HttpProtocol::HTTP3) {
133 NETSTACK_LOGD("CURL_HTTP_VERSION_3");
134 return CURL_HTTP_VERSION_3;
135 }
136 if (usingProtocol_ == HttpProtocol::HTTP2) {
137 NETSTACK_LOGD("CURL_HTTP_VERSION_2_0");
138 return CURL_HTTP_VERSION_2_0;
139 }
140 if (usingProtocol_ == HttpProtocol::HTTP1_1) {
141 NETSTACK_LOGD("CURL_HTTP_VERSION_1_1");
142 return CURL_HTTP_VERSION_1_1;
143 }
144 return CURL_HTTP_VERSION_NONE;
145 }
146
SetRequestTime(const std::string & time)147 void HttpRequestOptions::SetRequestTime(const std::string &time)
148 {
149 requestTime_ = time;
150 }
151
GetRequestTime() const152 const std::string &HttpRequestOptions::GetRequestTime() const
153 {
154 return requestTime_;
155 }
156
SetHttpDataType(HttpDataType dataType)157 void HttpRequestOptions::SetHttpDataType(HttpDataType dataType)
158 {
159 if (dataType != HttpDataType::STRING && dataType != HttpDataType::ARRAY_BUFFER &&
160 dataType != HttpDataType::OBJECT) {
161 return;
162 }
163 dataType_ = dataType;
164 }
165
GetHttpDataType() const166 HttpDataType HttpRequestOptions::GetHttpDataType() const
167 {
168 return dataType_;
169 }
170
SetPriority(uint32_t priority)171 void HttpRequestOptions::SetPriority(uint32_t priority)
172 {
173 if (priority < MIN_PRIORITY || priority > MAX_PRIORITY) {
174 return;
175 }
176 priority_ = priority;
177 }
178
GetPriority() const179 uint32_t HttpRequestOptions::GetPriority() const
180 {
181 return priority_;
182 }
183
SetCanSkipCertVerifyFlag(bool canCertVerify)184 void HttpRequestOptions::SetCanSkipCertVerifyFlag(bool canCertVerify)
185 {
186 canSkipCertVerify_ = canCertVerify;
187 }
188
GetCanSkipCertVerifyFlag() const189 bool HttpRequestOptions::GetCanSkipCertVerifyFlag() const
190 {
191 return canSkipCertVerify_;
192 }
SetUsingHttpProxyType(UsingHttpProxyType type)193 void HttpRequestOptions::SetUsingHttpProxyType(UsingHttpProxyType type)
194 {
195 usingHttpProxyType_ = type;
196 }
197
GetUsingHttpProxyType() const198 UsingHttpProxyType HttpRequestOptions::GetUsingHttpProxyType() const
199 {
200 return usingHttpProxyType_;
201 }
202
SetSpecifiedHttpProxy(const std::string & host,int32_t port,const std::string & exclusionList)203 void HttpRequestOptions::SetSpecifiedHttpProxy(const std::string &host, int32_t port, const std::string &exclusionList)
204 {
205 httpProxyHost_ = host;
206 httpProxyPort_ = port;
207 httpProxyExclusions_ = exclusionList;
208 }
209
GetSpecifiedHttpProxy(std::string & host,int32_t & port,std::string & exclusionList)210 void HttpRequestOptions::GetSpecifiedHttpProxy(std::string &host, int32_t &port, std::string &exclusionList)
211 {
212 host = httpProxyHost_;
213 port = httpProxyPort_;
214 exclusionList = httpProxyExclusions_;
215 }
216
SetClientCert(std::string & cert,std::string & certType,std::string & key,Secure::SecureChar & keyPasswd)217 void HttpRequestOptions::SetClientCert(
218 std::string &cert, std::string &certType, std::string &key, Secure::SecureChar &keyPasswd)
219 {
220 cert_ = cert;
221 certType_ = certType;
222 key_ = key;
223 keyPasswd_ = keyPasswd;
224 }
225
AddMultiFormData(const MultiFormData & multiFormData)226 void HttpRequestOptions::AddMultiFormData(const MultiFormData &multiFormData)
227 {
228 multiFormDataList_.push_back(multiFormData);
229 }
230
GetClientCert(std::string & cert,std::string & certType,std::string & key,Secure::SecureChar & keyPasswd)231 void HttpRequestOptions::GetClientCert(
232 std::string &cert, std::string &certType, std::string &key, Secure::SecureChar &keyPasswd)
233 {
234 cert = cert_;
235 certType = certType_;
236 key = key_;
237 keyPasswd = keyPasswd_;
238 }
239
SetCaPath(const std::string & path)240 void HttpRequestOptions::SetCaPath(const std::string &path)
241 {
242 if (path.empty()) {
243 return;
244 }
245
246 caPath_ = path;
247 }
248
GetCaPath() const249 const std::string &HttpRequestOptions::GetCaPath() const
250 {
251 return caPath_;
252 }
253
SetCaData(const std::string & caData)254 void HttpRequestOptions::SetCaData(const std::string &caData)
255 {
256 if (caData.empty()) {
257 return;
258 }
259
260 caData_ = caData;
261 }
262
GetCaData() const263 const std::string &HttpRequestOptions::GetCaData() const
264 {
265 return caData_;
266 }
267
SetTlsOption(const TlsOption & tlsOption)268 void HttpRequestOptions::SetTlsOption(const TlsOption &tlsOption)
269 {
270 tlsOption_.tlsVersionMax = tlsOption.tlsVersionMax;
271 tlsOption_.tlsVersionMin = tlsOption.tlsVersionMin;
272 tlsOption_.cipherSuite = tlsOption.cipherSuite;
273 }
274
GetTlsOption() const275 const TlsOption HttpRequestOptions::GetTlsOption() const
276 {
277 return tlsOption_;
278 }
279
GetTCPOption() const280 const HttpRequestOptions::TcpConfiguration HttpRequestOptions::GetTCPOption() const
281 {
282 return tcpOption_;
283 }
284
SetServerAuthentication(const ServerAuthentication & serverAuthentication)285 void HttpRequestOptions::SetServerAuthentication(const ServerAuthentication &serverAuthentication)
286 {
287 serverAuthentication_.authenticationType = serverAuthentication.authenticationType;
288 serverAuthentication_.credential.password = serverAuthentication.credential.password;
289 serverAuthentication_.credential.username = serverAuthentication.credential.username;
290 }
291
GetServerAuthentication() const292 const ServerAuthentication HttpRequestOptions::GetServerAuthentication() const
293 {
294 return serverAuthentication_;
295 }
296
SetDohUrl(const std::string & dohUrl)297 void HttpRequestOptions::SetDohUrl(const std::string &dohUrl)
298 {
299 if (dohUrl.empty()) {
300 return;
301 }
302 dohUrl_ = dohUrl;
303 }
304
GetDohUrl() const305 const std::string &HttpRequestOptions::GetDohUrl() const
306 {
307 return dohUrl_;
308 }
309
SetRangeNumber(int64_t resumeFromNumber,int64_t resumeToNumber)310 void HttpRequestOptions::SetRangeNumber(int64_t resumeFromNumber, int64_t resumeToNumber)
311 {
312 if (resumeFromNumber >= MIN_RESUM_NUMBER && resumeFromNumber <= MAX_RESUM_NUMBER) {
313 resumeFromNumber_ = resumeFromNumber;
314 }
315 if (resumeToNumber >= MIN_RESUM_NUMBER && resumeToNumber <= MAX_RESUM_NUMBER) {
316 resumeToNumber_ = resumeToNumber;
317 }
318 }
319
GetRangeString() const320 std::string HttpRequestOptions::GetRangeString() const
321 {
322 bool isSetFrom = resumeFromNumber_ >= MIN_RESUM_NUMBER;
323 bool isSetTo = resumeToNumber_ >= MIN_RESUM_NUMBER;
324 if (!isSetTo && !isSetFrom) {
325 return "";
326 } else if (!isSetTo && isSetFrom) {
327 return std::to_string(resumeFromNumber_) + '-';
328 } else if (isSetTo && !isSetFrom) {
329 return '-' + std::to_string(resumeToNumber_);
330 } else if (resumeToNumber_ <= resumeFromNumber_) {
331 return "";
332 } else {
333 return std::to_string(resumeFromNumber_) + '-' + std::to_string(resumeToNumber_);
334 }
335 }
336
GetDnsServers() const337 const std::vector<std::string> &HttpRequestOptions::GetDnsServers() const
338 {
339 return dnsServers_;
340 }
341
SetDnsServers(const std::vector<std::string> & dnsServers)342 void HttpRequestOptions::SetDnsServers(const std::vector<std::string> &dnsServers)
343 {
344 dnsServers_ = dnsServers;
345 }
346
GetMultiPartDataList()347 std::vector<MultiFormData> HttpRequestOptions::GetMultiPartDataList()
348 {
349 return multiFormDataList_;
350 }
351
SetCertificatePinning(std::string certPIN)352 void HttpRequestOptions::SetCertificatePinning(std::string certPIN)
353 {
354 certificatePinning_ = std::move(certPIN);
355 }
356
GetCertificatePinning() const357 std::string HttpRequestOptions::GetCertificatePinning() const
358 {
359 return certificatePinning_;
360 }
361
SetAddressFamily(std::string addressFamily)362 void HttpRequestOptions::SetAddressFamily(std::string addressFamily)
363 {
364 addressFamily_ = std::move(addressFamily);
365 }
366
GetAddressFamily() const367 std::string HttpRequestOptions::GetAddressFamily() const
368 {
369 return addressFamily_;
370 }
371
SetOptionToSocket(int sock)372 bool HttpRequestOptions::TcpConfiguration::SetOptionToSocket(int sock)
373 {
374 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(IOS_PLATFORM)
375 int proto = -1;
376 auto len = static_cast<socklen_t>(sizeof(proto));
377 /*
378 https://man7.org/linux/man-pages/man2/getsockopt.2.html
379 RETURN VALUE top
380 On success, zero is returned for the standard options. On error,
381 -1 is returned, and errno is set to indicate the error.
382
383 Netfilter allows the programmer to define custom socket options
384 with associated handlers; for such options, the return value on
385 success is the value returned by the handler.
386 */
387 auto res = getsockopt(sock, SOL_SOCKET, SO_PROTOCOL, &proto, &len);
388 if (res != 0 || proto != IPPROTO_TCP) {
389 return false;
390 }
391 if (setsockopt(sock, SOL_TCP, TCP_USER_TIMEOUT, &userTimeout_, sizeof(userTimeout_)) != 0) {
392 NETSTACK_LOGE("set TCP_USER_TIMEOUT failed, errno = %{public}d userTimeout = %{public}d sock = %{public}d",
393 errno, userTimeout_, sock);
394 return false;
395 }
396
397 int keepAlive_ = 1;
398 /*
399 https://man7.org/linux/man-pages/man7/socket.7.html
400 SO_KEEPALIVE
401 Enable sending of keep-alive messages on connection-
402 oriented sockets. Expects an integer boolean flag.
403
404 https://man7.org/linux/man-pages/man3/setsockopt.3p.html
405 RETURN VALUE top
406 Upon successful completion, setsockopt() shall return 0.
407 Otherwise, -1 shall be returned and errno set to indicate the
408 error.
409 */
410 if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &keepAlive_, sizeof(keepAlive_)) != 0) {
411 NETSTACK_LOGE("set SO_KEEPALIVE failed, errno = %{public}d sock = %{public}d", errno, sock);
412 return false;
413 }
414 if (setsockopt(sock, SOL_TCP, TCP_KEEPIDLE, &keepIdle_, sizeof(keepIdle_)) != 0) {
415 NETSTACK_LOGE("set TCP_KEEPIDLE failed, errno = %{public}d keepIdle = %{public}d sock = %{public}d",
416 errno, keepIdle_, sock);
417 return false;
418 }
419 if (setsockopt(sock, SOL_TCP, TCP_KEEPCNT, &keepCnt_, sizeof(keepCnt_)) != 0) {
420 NETSTACK_LOGE("set TCP_KEEPCNT failed, errno = %{public}d keepCnt = %{public}d sock = %{public}d",
421 errno, keepCnt_, sock);
422 return false;
423 }
424 if (setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, &keepInterval_, sizeof(keepInterval_)) != 0) {
425 NETSTACK_LOGE("set TCP_KEEPINTVL failed, errno = %{public}d keepInterval = %{public}d sock = %{public}d",
426 errno, keepInterval_, sock);
427 return false;
428 }
429 #endif
430 return true;
431 }
432
SetTcpUserTimeout(const uint32_t & timeout)433 void HttpRequestOptions::TcpConfiguration::SetTcpUserTimeout(const uint32_t &timeout)
434 {
435 userTimeout_ = timeout;
436 }
437 } // namespace OHOS::NetStack::Http