2 * Copyright 2019, 2023 NXP.
4 * Redistribution and use in source and binary forms, with or without modification,
5 * are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright notice, this
11 * list of conditions and the following disclaimer in the documentation and/or
12 * other materials provided with the distribution.
14 * Neither the name of the NXP Semiconductor nor the names of its
15 * contributors may be used to endorse or promote products derived from this
16 * software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
34 // request += "Connection: Keep-Alive\n";
38 #pragma comment(lib, "Winhttp.lib")
40 #include <sys/types.h>
41 #include <sys/socket.h>
43 #define INVALID_SOCKET -1
55 uuu_askpasswd g_ask_passwd
;
56 int uuu_set_askpasswd(uuu_askpasswd ask
)
62 map
<string
, pair
<string
, string
>> g_passwd_map
;
65 #include <openssl/ssl.h>
66 #include <openssl/err.h>
68 static const char* base64_table
=
69 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
70 "abcdefghijklmnopqrstuvwxyz"
73 static string
base64_encode(string str
)
76 for (size_t i
= 0; i
< str
.length(); i
+= 3)
78 ret
.push_back(base64_table
[(str
[i
] >> 2) & 0x3f]);
79 if (i
+ 1 < str
.length())
82 index
= ((str
[i
] & 3) << 4)
83 + ((str
[i
+ 1] >> 4) & 0xf);
84 ret
.push_back(base64_table
[index
]);
88 ret
.push_back(base64_table
[(str
[i
] & 0x3) << 4]);
94 if (i
+ 2 < str
.length())
97 index
= (((str
[i
+ 1]) & 0xF) << 2)
98 + (((str
[i
+ 2]) >> 6) & 0x3);
99 ret
.push_back(base64_table
[index
]);
100 index
= str
[i
+ 2] & 0x3f;
101 ret
.push_back(base64_table
[index
]);
106 ret
.push_back(base64_table
[((str
[i
+ 1]) & 0xF) << 2]);
119 #if OPENSSL_VERSION_NUMBER < 0x10100000L
121 SSLeay_add_ssl_algorithms();
122 SSL_load_error_strings();
124 OPENSSL_init_ssl(0, nullptr);
125 SSLeay_add_ssl_algorithms();
133 static CUUUSSL g_uuussl
;
141 DWORD
ChooseAuthScheme(DWORD dwSupportedSchemes
)
143 if (dwSupportedSchemes
& WINHTTP_AUTH_SCHEME_NEGOTIATE
)
144 return WINHTTP_AUTH_SCHEME_NEGOTIATE
;
145 else if (dwSupportedSchemes
& WINHTTP_AUTH_SCHEME_NTLM
)
146 return WINHTTP_AUTH_SCHEME_NTLM
;
147 else if (dwSupportedSchemes
& WINHTTP_AUTH_SCHEME_PASSPORT
)
148 return WINHTTP_AUTH_SCHEME_PASSPORT
;
149 else if (dwSupportedSchemes
& WINHTTP_AUTH_SCHEME_DIGEST
)
150 return WINHTTP_AUTH_SCHEME_DIGEST
;
151 else if (dwSupportedSchemes
& WINHTTP_AUTH_SCHEME_BASIC
)
152 return WINHTTP_AUTH_SCHEME_BASIC
;
157 HttpStream::HttpStream()
165 int HttpStream::HttpGetHeader(std::string host
, std::string path
, int port
, bool ishttps
)
168 m_hSession
= WinHttpOpen(L
"WinHTTP UUU/1.0",
169 WINHTTP_ACCESS_TYPE_DEFAULT_PROXY
,
170 WINHTTP_NO_PROXY_NAME
,
171 WINHTTP_NO_PROXY_BYPASS
, 0);
175 set_last_err_string("fail WinHttpOpen");
179 wstring_convert
<codecvt_utf8_utf16
<wchar_t>> converter
;
180 wstring whost
= converter
.from_bytes(host
);
183 m_hConnect
= WinHttpConnect(m_hSession
, whost
.c_str(),
188 set_last_err_string("Fail Connection");
192 wstring wpath
= converter
.from_bytes(path
);
194 m_hRequest
= WinHttpOpenRequest(m_hConnect
, L
"GET", wpath
.c_str(),
195 nullptr, WINHTTP_NO_REFERER
,
196 WINHTTP_DEFAULT_ACCEPT_TYPES
,
197 ishttps
?WINHTTP_FLAG_SECURE
:0);
199 BOOL bResults
= FALSE
;
202 set_last_err_string("Fail WinHttpOpenRequest");
206 DWORD dwProxyAuthScheme
= 0;
209 pair
<string
, string
> up
= g_passwd_map
[host
];
214 DWORD dwSize
= sizeof(status
);
216 bResults
= WinHttpSendRequest(m_hRequest
,
217 WINHTTP_NO_ADDITIONAL_HEADERS
, 0,
218 WINHTTP_NO_REQUEST_DATA
, 0,
223 bResults
= WinHttpReceiveResponse(m_hRequest
, NULL
);
225 // Resend the request in case of
226 // ERROR_WINHTTP_RESEND_REQUEST error.
227 if (!bResults
&& GetLastError() == ERROR_WINHTTP_RESEND_REQUEST
)
230 // Check the status code.
232 bResults
= WinHttpQueryHeaders(m_hRequest
,
233 WINHTTP_QUERY_STATUS_CODE
|
234 WINHTTP_QUERY_FLAG_NUMBER
,
242 DWORD dwSupportedSchemes
;
244 DWORD dwSelectedScheme
;
249 case HTTP_STATUS_OK
: //200
250 g_passwd_map
[host
] = up
;
253 case HTTP_STATUS_DENIED
: //401
254 // The server requires authentication.
255 if(g_passwd_map
[host
].first
.empty())
257 char user
[MAX_USER_LEN
];
258 char passwd
[MAX_USER_LEN
];
259 if (g_ask_passwd((char*)host
.c_str(), user
, passwd
))
265 // Obtain the supported and preferred schemes.
266 bResults
= WinHttpQueryAuthSchemes(m_hRequest
,
271 // Set the credentials before resending the request.
274 dwSelectedScheme
= ChooseAuthScheme(dwSupportedSchemes
);
276 std::wstring_convert
<std::codecvt_utf8
<wchar_t>> convert
;
278 if (dwSelectedScheme
== 0)
280 set_last_err_string("unsupported http auth");
284 bResults
= WinHttpSetCredentials(m_hRequest
,
287 convert
.from_bytes(up
.first
).c_str(),
288 convert
.from_bytes(up
.second
).c_str(),
298 case HTTP_STATUS_PROXY_AUTH_REQ
:
299 set_last_err_string("unsupported proxy auth");
303 g_passwd_map
[host
] = up
;
304 // The status code does not indicate success.
306 str
.format("Error. Status code %d returned.\n", status
);
307 set_last_err_string(str
);
316 size_t HttpStream::HttpGetFileSize()
319 BOOL bResults
= FALSE
;
322 WinHttpQueryHeaders(m_hRequest
, WINHTTP_QUERY_CONTENT_LENGTH
,
323 WINHTTP_HEADER_NAME_BY_INDEX
, nullptr,
324 &dwSize
, WINHTTP_NO_HEADER_INDEX
);
326 // Allocate memory for the buffer.
327 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
329 out
.resize(dwSize
/ sizeof(WCHAR
));
331 // Now, use WinHttpQueryHeaders to retrieve the header.
332 bResults
= WinHttpQueryHeaders(m_hRequest
,
333 WINHTTP_QUERY_CONTENT_LENGTH
,
334 WINHTTP_HEADER_NAME_BY_INDEX
,
335 (LPVOID
)out
.c_str(), &dwSize
,
336 WINHTTP_NO_HEADER_INDEX
);
338 return _wtoll(out
.c_str());
341 int HttpStream::HttpDownload(char *buff
, size_t sz
)
344 DWORD dwDownloaded
= 0;
347 if (!WinHttpQueryDataAvailable(m_hRequest
, &dwSize
))
349 set_last_err_string("WinHttpQueryDataAvailable");
356 if (!WinHttpReadData(m_hRequest
, (LPVOID
)buff
,
357 dwSize
, &dwDownloaded
))
359 set_last_err_string("Fail at WinHttpReadData");
362 buff
+= dwDownloaded
;
368 HttpStream::~HttpStream()
371 WinHttpCloseHandle(m_hRequest
);
373 WinHttpCloseHandle(m_hConnect
);
375 WinHttpCloseHandle(m_hSession
);
380 HttpStream::HttpStream()
385 int HttpStream::SendPacket(char *buff
, size_t sz
)
389 return SSL_write((SSL
*)m_ssl
, buff
, sz
);
391 return send(m_socket
, buff
, sz
, 0);
395 int HttpStream::RecvPacket(char *buff
, size_t sz
)
399 return SSL_read((SSL
*)m_ssl
, buff
, sz
);
401 return recv(m_socket
, buff
, sz
, 0);
408 CAutoAddrInfo(addrinfo
*pAddrInfo
)
418 int HttpStream::HttpGetHeader(std::string host
, std::string path
, int port
, bool ishttps
)
423 snprintf(s_port
, 10, "%d", port
);
425 if (getaddrinfo(host
.c_str(), s_port
, 0, &pAddrInfo
))
427 set_last_err_string("get network address error");
431 CAutoAddrInfo
A(pAddrInfo
);
433 m_socket
= socket(pAddrInfo
->ai_family
, pAddrInfo
->ai_socktype
, pAddrInfo
->ai_protocol
);
439 setsockopt(m_socket
, SOL_SOCKET
, SO_RCVTIMEO
, (const char*)&tv
, sizeof(tv
));
441 if (m_socket
== INVALID_SOCKET
)
443 set_last_err_string("Can't get sock");
447 if (connect(m_socket
, pAddrInfo
->ai_addr
, pAddrInfo
->ai_addrlen
))
449 set_last_err_string("connect error");
457 const SSL_METHOD
* meth
=
458 #if (OPENSSL_VERSION_NUMBER < 0x10100000L)
459 TLSv1_2_client_method();
465 set_last_err_string("Failure at TLSv1_2_client_method\n");
468 SSL_CTX
*ctx
= SSL_CTX_new (meth
);
471 set_last_err_string("Error create ssl ctx\n");
474 m_ssl
= SSL_new (ctx
);
477 set_last_err_string("Error create SSL\n");
480 SSL_set_fd((SSL
*)m_ssl
, m_socket
);
481 if( SSL_connect((SSL
*)m_ssl
) <= 0)
483 set_last_err_string("error build ssl connection");
487 set_last_err_string("Can't support https");
493 pair
<string
, string
> up
= g_passwd_map
[host
];
496 string userpd
= up
.first
+ ":" + up
.second
;
497 string httppath
= path
;
500 httppath
= "https://" + host
+ path
;
502 string request
= "GET " + httppath
+ " HTTP/1.1\r\n";
503 request
+= "Host: " + host
+ "\r\n";
505 if (!up
.first
.empty())
506 request
+= "Authorization: Basic " + base64_encode(userpd
) + "\r\n";
508 request
+= "User-Agent:uuu\r\nAccept: */*\r\n";
511 ret
= SendPacket((char*)request
.c_str(), request
.size());
512 if ((size_t)(ret
) != request
.size())
514 set_last_err_string("http send error");
519 ret
= RecvPacket((char*)m_buff
.data(), m_buff
.size());
522 set_last_err_string("http recv Error");
527 for (i
= 0; i
< 1024 - 4; i
++)
529 if (m_buff
[i
] == 0xd &&
530 m_buff
[i
+ 1] == 0xa &&
531 m_buff
[i
+ 2] == 0xd &&
532 m_buff
[i
+ 3] == 0xa)
540 set_last_err_string("Can't find terminate");
544 m_data_start
= i
+ 4;
548 memcpy((void*)str
.c_str(), m_buff
.data(), i
+ 2);
550 int ret
= parser_response(str
);
551 if (ret
== ERR_ACCESS_DENIED
)
553 if(g_passwd_map
[host
].first
.empty())
555 char user
[MAX_USER_LEN
];
556 char passwd
[MAX_USER_LEN
];
557 if (g_ask_passwd((char*)host
.c_str(), user
, passwd
))
567 g_passwd_map
[host
] = up
;
570 g_passwd_map
[host
] = up
;
576 size_t HttpStream::HttpGetFileSize()
578 return atoll(m_response
["Content-Length"].c_str());
581 int HttpStream::parser_response(string rep
)
583 size_t pos
= rep
.find("\r\n");
584 if (pos
== string::npos
)
586 set_last_err_string("Can't find \r\n");
590 string str
= rep
.substr(0, pos
);
591 if (str
== "HTTP/1.1 401 Unauthorized")
592 return ERR_ACCESS_DENIED
;
594 if (str
!= "HTTP/1.1 200 OK")
596 set_last_err_string(str
);
602 while (pos
!= string::npos
)
605 size_t split
= rep
.find(':', pos
);
606 if (split
== string::npos
)
608 string key
= rep
.substr(pos
, split
- pos
);
609 pos
= rep
.find("\r\n", pos
);
610 string value
= rep
.substr(split
+ 1, pos
- split
- 1);
611 m_response
[key
] = value
;
617 int HttpStream::HttpDownload(char *buff
, size_t sz
)
620 if (m_data_start
< m_buff
.size())
621 left
= m_buff
.size() - m_data_start
;
623 size_t trim_transferred
= 0;
628 trim_transferred
= sz
;
629 if (trim_transferred
> left
)
630 trim_transferred
= left
;
632 memcpy(buff
, m_buff
.data() + m_data_start
, trim_transferred
);
633 m_data_start
+= trim_transferred
;
636 if (trim_transferred
< sz
)
639 sz
-= trim_transferred
;
640 buff
+= trim_transferred
;
641 while (sz
&& ((ret
= RecvPacket(buff
, sz
)) > 0))
649 set_last_err_string("recv error");
657 HttpStream::~HttpStream()
663 SSL_CTX_free(SSL_get_SSL_CTX((SSL
*)m_ssl
));
664 SSL_free((SSL
*)m_ssl
);