obs/Source/HTTPClient.cpp

282 lines
8.0 KiB
C++

/********************************************************************************
Copyright (C) 2012 Hugh Bailey <obs.jim@gmail.com>
Richard Stanway
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
********************************************************************************/
#include "Main.h"
#include <winhttp.h>
BOOL HTTPGetFile (CTSTR url, CTSTR outputPath, CTSTR extraHeaders, int *responseCode, TCHAR *sigOut, DWORD *sigOutLen)
{
HINTERNET hSession = NULL;
HINTERNET hConnect = NULL;
HINTERNET hRequest = NULL;
URL_COMPONENTS urlComponents;
BOOL secure = FALSE;
BOOL ret = FALSE;
String hostName, path;
const TCHAR *acceptTypes[] = {
TEXT("*/*"),
NULL
};
hostName.SetLength(256);
path.SetLength(1024);
zero(&urlComponents, sizeof(urlComponents));
urlComponents.dwStructSize = sizeof(urlComponents);
urlComponents.lpszHostName = hostName;
urlComponents.dwHostNameLength = hostName.Length();
urlComponents.lpszUrlPath = path;
urlComponents.dwUrlPathLength = path.Length();
WinHttpCrackUrl(url, 0, 0, &urlComponents);
if (urlComponents.nPort == 443)
secure = TRUE;
hSession = WinHttpOpen(OBS_VERSION_STRING, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
if (!hSession)
goto failure;
hConnect = WinHttpConnect(hSession, hostName, secure ? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT, 0);
if (!hConnect)
goto failure;
hRequest = WinHttpOpenRequest(hConnect, TEXT("GET"), path, NULL, WINHTTP_NO_REFERER, acceptTypes, secure ? WINHTTP_FLAG_SECURE|WINHTTP_FLAG_REFRESH : WINHTTP_FLAG_REFRESH);
if (!hRequest)
goto failure;
BOOL bResults = WinHttpSendRequest(hRequest, extraHeaders, extraHeaders ? -1 : 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0);
// End the request.
if (bResults)
bResults = WinHttpReceiveResponse(hRequest, NULL);
else
goto failure;
TCHAR statusCode[8];
DWORD statusCodeLen;
statusCodeLen = sizeof(statusCode);
if (!WinHttpQueryHeaders (hRequest, WINHTTP_QUERY_STATUS_CODE, WINHTTP_HEADER_NAME_BY_INDEX, &statusCode, &statusCodeLen, WINHTTP_NO_HEADER_INDEX))
goto failure;
*responseCode = wcstoul(statusCode, NULL, 10);
if (sigOut)
{
if (!WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_CUSTOM, TEXT("X-Signature"), sigOut, sigOutLen, WINHTTP_NO_HEADER_INDEX))
{
if (GetLastError() == ERROR_WINHTTP_HEADER_NOT_FOUND)
*sigOutLen = 0;
else if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
*sigOutLen = 0;
else
goto failure;
}
else
{
// We need character count, not byte count.
*sigOutLen /= 2;
}
}
if (bResults && *responseCode == 200)
{
BYTE buffer[16384];
DWORD dwSize, dwOutSize;
XFile updateFile;
if (!updateFile.Open(outputPath, XFILE_WRITE, CREATE_ALWAYS))
goto failure;
do
{
// Check for available data.
dwSize = 0;
if (!WinHttpQueryDataAvailable(hRequest, &dwSize))
goto failure;
if (!WinHttpReadData(hRequest, (LPVOID)buffer, dwSize, &dwOutSize))
{
goto failure;
}
else
{
if (!dwOutSize)
break;
if (!updateFile.Write(buffer, dwOutSize))
goto failure;
}
} while (dwSize > 0);
updateFile.Close();
}
ret = TRUE;
failure:
if (hSession)
WinHttpCloseHandle(hSession);
if (hConnect)
WinHttpCloseHandle(hConnect);
if (hRequest)
WinHttpCloseHandle(hRequest);
if (sigOutLen && !ret)
*sigOutLen = 0;
return ret;
}
String HTTPGetString (CTSTR url, CTSTR extraHeaders, int *responseCode)
{
HINTERNET hSession = NULL;
HINTERNET hConnect = NULL;
HINTERNET hRequest = NULL;
URL_COMPONENTS urlComponents;
BOOL secure = FALSE;
String result = "";
String hostName, path;
const TCHAR *acceptTypes[] = {
TEXT("*/*"),
NULL
};
hostName.SetLength(256);
path.SetLength(1024);
zero(&urlComponents, sizeof(urlComponents));
urlComponents.dwStructSize = sizeof(urlComponents);
urlComponents.lpszHostName = hostName;
urlComponents.dwHostNameLength = hostName.Length();
urlComponents.lpszUrlPath = path;
urlComponents.dwUrlPathLength = path.Length();
WinHttpCrackUrl(url, 0, 0, &urlComponents);
if (urlComponents.nPort == 443)
secure = TRUE;
hSession = WinHttpOpen(OBS_VERSION_STRING, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
if (!hSession)
goto failure;
hConnect = WinHttpConnect(hSession, hostName, secure ? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT, 0);
if (!hConnect)
goto failure;
hRequest = WinHttpOpenRequest(hConnect, TEXT("GET"), path, NULL, WINHTTP_NO_REFERER, acceptTypes, secure ? WINHTTP_FLAG_SECURE|WINHTTP_FLAG_REFRESH : WINHTTP_FLAG_REFRESH);
if (!hRequest)
goto failure;
BOOL bResults = WinHttpSendRequest(hRequest, extraHeaders, extraHeaders ? -1 : 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0);
// End the request.
if (bResults)
bResults = WinHttpReceiveResponse(hRequest, NULL);
else
goto failure;
TCHAR statusCode[8];
DWORD statusCodeLen;
statusCodeLen = sizeof(statusCode);
if (!WinHttpQueryHeaders (hRequest, WINHTTP_QUERY_STATUS_CODE, WINHTTP_HEADER_NAME_BY_INDEX, &statusCode, &statusCodeLen, WINHTTP_NO_HEADER_INDEX))
goto failure;
*responseCode = wcstoul(statusCode, NULL, 10);
if (bResults && *responseCode == 200)
{
CHAR buffer[16384];
DWORD dwSize, dwOutSize;
do
{
// Check for available data.
dwSize = 0;
if (!WinHttpQueryDataAvailable(hRequest, &dwSize))
goto failure;
if (!WinHttpReadData(hRequest, (LPVOID)buffer, dwSize, &dwOutSize))
{
goto failure;
}
else
{
if (!dwOutSize)
break;
// Ensure the string is terminated.
buffer[dwOutSize] = 0;
String b = String((LPCSTR)buffer);
result.AppendString(b);
}
} while (dwSize > 0);
}
failure:
if (hSession)
WinHttpCloseHandle(hSession);
if (hConnect)
WinHttpCloseHandle(hConnect);
if (hRequest)
WinHttpCloseHandle(hRequest);
return result;
}
String CreateHTTPURL(String host, String path, String extra, bool secure)
{
URL_COMPONENTS components = {
sizeof URL_COMPONENTS,
secure ? L"https" : L"http",
secure ? 5 : 4,
secure ? INTERNET_SCHEME_HTTPS : INTERNET_SCHEME_HTTP,
host.Array(), host.Length(),
secure ? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT,
nullptr, 0,
nullptr, 0,
path.Array(), path.Length(),
extra.Array(), extra.Length()
};
String url;
url.SetLength(MAX_PATH);
DWORD length = MAX_PATH;
if (!WinHttpCreateUrl(&components, ICU_ESCAPE, url.Array(), &length))
return String();
url.SetLength(length);
return url;
}