File Index Symbol Index

/*********************************************************************** Author: Zihan Chen (vczh) Licensed under https://github.com/vczh-libraries/License ***********************************************************************/
#include "HttpUtility.h"
#ifdef VCZH_MSVC
#include <Windows.h> #include <winhttp.h>
#pragma comment(lib,
"WinHttp.lib"
)
namespace
vl
{
using
namespace
collections
;
/*********************************************************************** HttpRequest ***********************************************************************/
bool
HttpRequest
::
SetHost
(
const
WString
&
inputQuery
) {
if
(
method
==
L""
) {
method
=
L"GET"
; }
server
=
L""
;
query
=
L""
;
port
=
0
;
secure
=
false
; {
if
(
server
==
L""
) {
if
(
inputQuery
.
Length
() >
7
) {
WString
protocol
=
inputQuery
.
Sub
(
0
,
8
);
if
(
_wcsicmp
(
protocol
.
Buffer
(),
L"https://"
) ==
0
) {
const
wchar_t
*
reading
=
inputQuery
.
Buffer
() +
8
;
const
wchar_t
*
index1
=
wcschr
(
reading
,
L':'
);
const
wchar_t
*
index2
=
wcschr
(
reading
,
L'/'
);
if
(
index2
) {
query
=
index2
;
server
=
WString
(
reading
, (
index1
?
index1
:
index2
) -
reading
);
secure
=
true
;
if
(
index1
) {
WString
portString
(
index1
+
1
,
index2
-
index1
-
1
);
port
=
_wtoi
(
portString
.
Buffer
()); }
return
true
; } } } }
if
(
server
==
L""
) {
if
(
inputQuery
.
Length
() >
6
) {
WString
protocol
=
inputQuery
.
Sub
(
0
,
7
);
if
(
_wcsicmp
(
protocol
.
Buffer
(),
L"http://"
) ==
0
) {
const
wchar_t
*
reading
=
inputQuery
.
Buffer
() +
7
;
const
wchar_t
*
index1
=
wcschr
(
reading
,
L':'
);
const
wchar_t
*
index2
=
wcschr
(
reading
,
L'/'
);
if
(
index2
) {
query
=
index2
;
server
=
WString
(
reading
, (
index1
?
index1
:
index2
) -
reading
);
if
(
index1
) {
WString
portString
(
index1
+
1
,
index2
-
index1
-
1
);
port
=
_wtoi
(
portString
.
Buffer
()); }
return
true
; } } } } }
return
false
; }
void
HttpRequest
::
SetBodyUtf8
(
const
WString
&
bodyString
) {
char
*
utf8
=
new
char
[
utf8Size
+
1
];
body
.
Resize
(
utf8Size
);
memcpy
(&
body
[
0
],
utf8
,
utf8Size
);
delete
[]
utf8
; }
/*********************************************************************** HttpResponse ***********************************************************************/
WString
HttpResponse
::
GetBodyUtf8
() {
WString
response
;
char
*
utf8
= &
body
[
0
];
vint
totalSize
=
body
.
Count
();
wchar_t
*
utf16
=
new
wchar_t
[
utf16Size
+
1
];
response
=
utf16
;
delete
[]
utf16
;
return
response
; }
/*********************************************************************** Utilities ***********************************************************************/
struct
BufferPair
{
char
*
buffer
;
vint
length
;
BufferPair
() :buffer(
0
) , length(
0
) { }
BufferPair
(
char
*
_buffer
,
vint
_length
) :buffer(
_buffer
) , length(
_length
) { }
bool
operator
=
=
(
const
BufferPair
&
pair
) {
return
false
; }
bool
operator
!
=
(
const
BufferPair
&
pair
) {
return
true
; } };
bool
HttpQuery
(
const
HttpRequest
&
request
,
HttpResponse
&
response
) {
// initialize
response
.
statusCode
= -
1
;
DWORD
error
=
0
;
List
<
LPCWSTR
>
acceptTypes
;
List
<
BufferPair
>
availableBuffers
;
// access http
error
=
GetLastError
();
if
(!
internet
)
goto
CLEANUP;
// connect
connectedInternet
=
WinHttpConnect
(
internet
,
request
.
server
.
Buffer
(), (
int
)
request
.
port
,
0
);
error
=
GetLastError
();
if
(!
connectedInternet
)
goto
CLEANUP;
// open request
for
(
vint
i
=
0
;
i
<
request
.
acceptTypes
.
Count
();
i
++) {
acceptTypes
.
Add
(
request
.
acceptTypes
.
Get
(
i
).
Buffer
()); }
acceptTypes
.
Add
(
0
);
error
=
GetLastError
();
if
(!
requestInternet
)
goto
CLEANUP;
// authentication, cookie and request
if
(
request
.
username
!
=
L""
&&
request
.
password
!=
L""
) { }
if
(
request
.
contentType
!
=
L""
) { }
if
(
request
.
cookie
!
=
L""
) { }
// extra headers
for
(
int
i
=
0
;
i
<
request
.
extraHeaders
.
Count
();
i
++) {
WString
key
=
request
.
extraHeaders
.
Keys
()
[
i
];
WString
value
=
request
.
extraHeaders
.
Values
().
Get
(
i
); }
if
(
request
.
body
.
Count
() >
0
) { }
else
{ }
error
=
GetLastError
();
// receive response
error
=
GetLastError
();
// read response status code
{
DWORD
headerLength
=
sizeof
(
DWORD
);
DWORD
statusCode
=
0
;
error
=
GetLastError
();
response
.
statusCode
=
statusCode
; }
// read respons cookie
{
DWORD
headerLength
=
sizeof
(
DWORD
);
error
=
GetLastError
(); {
wchar_t
*
rawHeader
=
new
wchar_t
[
headerLength
/
sizeof
(
wchar_t
)];
const
wchar_t
*
cookieStart
=
wcsstr
(
rawHeader
,
L"Cookie:"
);
if
(
cookieStart
) {
const
wchar_t
*
cookieEnd
=
wcsstr
(
cookieStart
,
L";"
);
if
(
cookieEnd
) {
response
.
cookie
=
WString
(
cookieStart
+
7
,
cookieEnd
-
cookieStart
-
7
); } }
delete
[]
rawHeader
; } }
// read response body
while
(
true
) {
DWORD
bytesAvailable
=
0
;
BOOL
queryDataAvailableResult
=
WinHttpQueryDataAvailable
(
requestInternet
, &
bytesAvailable
);
error
=
GetLastError
(); {
char
*
utf8
=
new
char
[
bytesAvailable
];
DWORD
bytesRead
=
0
;
BOOL
readDataResult
=
WinHttpReadData
(
requestInternet
,
utf8
,
bytesAvailable
, &
bytesRead
);
error
=
GetLastError
(); {
availableBuffers
.
Add
(
BufferPair
(
utf8
,
bytesRead
)); }
else
{
delete
[]
utf8
; } }
else
{
break
; } } {
// concatincate response body
vint
totalSize
=
0
; {
totalSize
+=
p
.
length
; }
response
.
body
.
Resize
(
totalSize
);
if
(
totalSize
>
0
) {
char
*
utf8
=
new
char
[
totalSize
]; {
char
*
temp
=
utf8
; {
memcpy
(
temp
,
p
.
buffer
,
p
.
length
);
temp
+=
p
.
length
; } }
memcpy
(&
response
.
body
[
0
],
utf8
,
totalSize
);
delete
[]
utf8
; } {
delete
[]
p
.
buffer
; } } CLEANUP:
if
(
requestInternet
)
WinHttpCloseHandle
(
requestInternet
);
if
(
connectedInternet
)
WinHttpCloseHandle
(
connectedInternet
);
if
(
internet
)
WinHttpCloseHandle
(
internet
);
return
response
.
statusCode
!= -
1
; }
WString
UrlEncodeQuery
(
const
WString
&
query
) {
char
*
utf8
=
new
char
[
utf8Size
+
1
];
wchar_t
*
encoded
=
new
wchar_t
[
utf8Size
*
3
+
1
];
wchar_t
*
writing
=
encoded
;
for
(
vint
i
=
0
;
i
<
utf8Size
;
i
++) {
unsigned
char
x
= (
unsigned
char
)
utf8
[
i
];
if
(
L'a'
<=
x
&&
x
<=
'z'
||
L'A'
<=
x
&&
x
<=
L'Z'
||
L'0'
<=
x
&&
x
<=
L'9'
) {
writing
[
0
] =
x
;
writing
+=
1
; }
else
{
writing
[
0
] =
L'%'
;
writing
[
1
] =
L"0123456789ABCDEF"
[
x
/
16
];
writing
[
2
] =
L"0123456789ABCDEF"
[
x
%
16
];
writing
+=
3
; } }
WString
result
=
encoded
;
delete
[]
encoded
;
delete
[]
utf8
;
return
result
; } }
#endif