diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/http/http.c (renamed from src/http.c) | 962 | ||||
-rw-r--r-- | src/http/http.h (renamed from src/http.h) | 0 | ||||
-rw-r--r-- | src/libpiano/response.c | 2 | ||||
-rw-r--r-- | src/main.h | 4 | ||||
-rw-r--r-- | src/player/player2.c (renamed from src/player2.c) | 0 | ||||
-rw-r--r-- | src/player/player2.h (renamed from src/player2.h) | 0 | ||||
-rw-r--r-- | src/ui.h | 2 |
7 files changed, 485 insertions, 485 deletions
diff --git a/src/http.c b/src/http/http.c index 2c86b44..dd64ad1 100644 --- a/src/http.c +++ b/src/http/http.c @@ -1,481 +1,481 @@ -/*
-Copyright (c) 2015
- Michał Cichoń <thedmd@interia.pl>
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-*/
-
-#include "config.h"
-#include "http.h"
-#include <Windows.h>
-#include <winhttp.h>
-#pragma comment(lib, "winhttp.lib")
-
-struct _http_t {
- HINTERNET session;
- HINTERNET connection;
- wchar_t* endpoint;
- wchar_t* securePort;
- wchar_t* autoProxy;
- wchar_t* proxy;
- wchar_t* proxyUsername;
- wchar_t* proxyPassword;
- char* error;
-};
-
-static char* HttpToString(const wchar_t* wideString, int size);
-static wchar_t* HttpToWideString(const char* string, int size);
-static bool HttpCreateConnection (http_t http);
-static void HttpCloseConnection (http_t http);
-static void HttpSetLastError (http_t http, const char* message);
-static void HttpSetLastErrorFromWinHttp (http_t http);
-static char* HttpFormatWinApiError (DWORD errorCode, HINSTANCE module);
-static char* HttpFormatWinHttpError (DWORD errorCode);
-static void HttpClearProxy (http_t http);
-
-# define WINHTTP_SAFE(condition) do { if (condition) break; HttpSetLastErrorFromWinHttp (http); return false; } while (false)
-# define WINHTTP_SAFE_DONE(condition) do { if (condition) break; HttpSetLastErrorFromWinHttp (http); goto done; } while (false)
-
-static char* HttpToString(const wchar_t* wideString, int size) {
- int utfSize = WideCharToMultiByte(CP_UTF8, 0, wideString, size, NULL, 0, NULL, NULL);
- char* utfMessage = malloc(utfSize + 1);
- if (utfMessage) {
- utfMessage[utfSize] = 0;
- WideCharToMultiByte(CP_UTF8, 0, wideString, size, utfMessage, utfSize, NULL, NULL);
- }
- return utfMessage;
-}
-
-static wchar_t* HttpToWideString(const char* string, int size) {
- int wideSize = MultiByteToWideChar(CP_UTF8, 0, string, size, NULL, 0);
- int wideBytes = (wideSize + 1) * sizeof(wchar_t);
- wchar_t* wideMessage = malloc(wideBytes);
- if (wideMessage) {
- wideMessage[wideSize] = 0;
- MultiByteToWideChar(CP_UTF8, 0, string, size, wideMessage, wideSize);
- }
- return wideMessage;
-}
-
-
-static bool HttpCreateConnection (http_t http) {
- INTERNET_PORT defaultPort = INTERNET_DEFAULT_PORT;
-
- HttpCloseConnection (http);
-
- http->session = WinHttpOpen(
- L"WinHTTP/1.0",
- WINHTTP_ACCESS_TYPE_NO_PROXY,
- WINHTTP_NO_PROXY_NAME,
- WINHTTP_NO_PROXY_BYPASS,
- 0);
- WINHTTP_SAFE(http->session != NULL);
-
- WinHttpSetTimeouts(http->session,
- 60 * 1000, // DNS time-out
- 60 * 1000, // connect time-out
- 30 * 1000, // send time-out
- 30 * 1000); // receive time-out
-
- http->connection = WinHttpConnect(
- http->session,
- http->endpoint,
- defaultPort,
- 0);
- WINHTTP_SAFE(http->connection != NULL);
-
- return true;
-}
-
-static void HttpCloseConnection (http_t http) {
- if (http->connection) {
- WinHttpCloseHandle(http->connection);
- http->connection = NULL;
- }
-
- if (http->session) {
- WinHttpCloseHandle(http->session);
- http->session = NULL;
- }
-}
-
-static void HttpSetLastError (http_t http, const char* message) {
- free(http->error);
- http->error = NULL;
-
- if (message)
- http->error = strdup(message);
-}
-
-static void HttpSetLastErrorFromWinHttp (http_t http) {
- free(http->error);
- http->error = NULL;
-
- DWORD error = GetLastError();
- if (error)
- http->error = HttpFormatWinHttpError(error);
-}
-
-static char* HttpFormatWinApiError (DWORD errorCode, HINSTANCE module) {
- const int source_flag = module ? FORMAT_MESSAGE_FROM_HMODULE : FORMAT_MESSAGE_FROM_SYSTEM;
-
- HLOCAL buffer = NULL;
- int bufferLength = FormatMessageW(
- FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | source_flag,
- (void*)module,
- errorCode,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPWSTR)&buffer,
- 0,
- NULL);
-
- if (bufferLength > 0) {
- char* message;
-
- wchar_t* wideMessage = (wchar_t*)buffer;
-
- /* Drop new line from the end. */
- wchar_t* wideMessageBack = wideMessage + bufferLength - 1;
- while (wideMessageBack > wideMessage && (*wideMessageBack == '\r' || *wideMessageBack == '\n'))
- --wideMessageBack;
-
- message = HttpToString (wideMessage, wideMessageBack - wideMessage + 1);
-
- LocalFree(buffer);
-
- return message;
- }
- else
- return NULL;
-}
-
-static char* HttpFormatWinHttpError (DWORD errorCode) {
- if (errorCode >= WINHTTP_ERROR_BASE && errorCode <= WINHTTP_ERROR_LAST) {
- HMODULE module = GetModuleHandleW(L"WinHTTP.dll");
- if (module) {
- char* message = HttpFormatWinApiError(errorCode, module);
- if (message)
- return message;
- }
- }
-
- return HttpFormatWinApiError(errorCode, NULL);
-}
-
-bool HttpInit(http_t* http, const char* endpoint, const char* securePort) {
- http_t out = malloc(sizeof(struct _http_t));
- if (!out)
- return false;
- memset(out, 0, sizeof(struct _http_t));
-
- out->endpoint = HttpToWideString(endpoint, -1);
- out->securePort = HttpToWideString(securePort, -1);
-
- if (!HttpCreateConnection (out)) {
- HttpDestroy (out);
- return false;
- }
-
- *http = out;
- return true;
-}
-
-void HttpDestroy(http_t http) {
- if (http) {
- free(http->endpoint);
- free(http->securePort);
- http->endpoint = NULL;
- http->securePort = NULL;
- HttpCloseConnection (http);
- HttpClearProxy (http);
- }
- free(http);
-}
-
-static void HttpClearProxy (http_t http) {
- if (http->autoProxy) {
- free(http->autoProxy);
- http->autoProxy = NULL;
- }
-
- if (http->proxy) {
- free(http->proxy);
- http->proxy = NULL;
- }
-
- if (http->proxyUsername) {
- free(http->proxyUsername);
- http->proxyUsername = NULL;
- }
-
- if (http->proxyPassword) {
- free(http->proxyPassword);
- http->proxyPassword = NULL;
- }
-}
-
-bool HttpSetAutoProxy (http_t http, const char* url) {
- HttpClearProxy (http);
- if (HttpSetProxy (http, url)) {
- http->autoProxy = http->proxy;
- http->proxy = NULL;
- return true;
- }
- else
- return false;
-}
-
-bool HttpSetProxy (http_t http, const char* url) {
- URL_COMPONENTS urlComponents;
- wchar_t* wideUrl = NULL;
- wchar_t* wideUrl2 = NULL;
- wchar_t* wideUsername = NULL;
- wchar_t* widePassword = NULL;
-
- ZeroMemory(&urlComponents, sizeof(urlComponents));
- urlComponents.dwStructSize = sizeof(urlComponents);
- urlComponents.dwUserNameLength = -1;
- urlComponents.dwPasswordLength = -1;
-
- wideUrl = HttpToWideString(url, -1);
- if (WinHttpCrackUrl(wideUrl, wcslen(wideUrl), 0, &urlComponents)) {
- if (urlComponents.lpszUserName && urlComponents.dwUserNameLength > 0) {
- wideUsername = wcsdup(urlComponents.lpszUserName);
- wideUsername[urlComponents.dwUserNameLength] = 0;
- }
- if (urlComponents.lpszPassword && urlComponents.dwPasswordLength > 0) {
- widePassword = wcsdup(urlComponents.lpszPassword);
- widePassword[urlComponents.dwPasswordLength] = 0;
- }
- }
-
- ZeroMemory(&urlComponents, sizeof(urlComponents));
- urlComponents.dwStructSize = sizeof(urlComponents);
- urlComponents.dwHostNameLength = -1;
- urlComponents.dwUrlPathLength = -1;
-
- if (!WinHttpCrackUrl(wideUrl, wcslen(wideUrl), 0, &urlComponents)) {
- free(wideUsername);
- free(widePassword);
- return false;
- }
-
- if (urlComponents.lpszHostName && urlComponents.dwHostNameLength > 0) {
- wideUrl2 = wcsdup(urlComponents.lpszHostName);
- wideUrl2[urlComponents.lpszUrlPath - urlComponents.lpszHostName] = 0;
- }
-
- free(wideUrl);
-
- HttpClearProxy(http);
- http->proxy = wideUrl2;
- http->proxyUsername = wideUsername;
- http->proxyPassword = widePassword;
- return true;
-}
-
-bool HttpRequest(http_t http, PianoRequest_t * const request) {
- HINTERNET handle = NULL;
- wchar_t* wideQuery = NULL;
- bool requestSent = false;
- bool complete = false;
- int retryLimit = 3;
- size_t responseDataSize;
-
- wideQuery = HttpToWideString(request->urlPath, -1);
- WINHTTP_SAFE_DONE(wideQuery != NULL);
-
- handle = WinHttpOpenRequest(
- http->connection,
- L"POST",
- wideQuery,
- L"HTTP/1.1",
- WINHTTP_NO_REFERER,
- WINHTTP_DEFAULT_ACCEPT_TYPES,
- request->secure ? WINHTTP_FLAG_SECURE : 0);
- WINHTTP_SAFE_DONE(handle != NULL);
-
- if (http->proxy || http->autoProxy) {
- wchar_t* fullUrl;
- DWORD fullUrlSize = 0;
- WINHTTP_PROXY_INFO proxyInfo;
- bool success;
-
- if (http->autoProxy) {
- WINHTTP_AUTOPROXY_OPTIONS proxyOptions = { 0 };
-
- success = WinHttpQueryOption(request, WINHTTP_OPTION_URL, NULL, &fullUrlSize);
- WINHTTP_SAFE(!success && GetLastError() == ERROR_INSUFFICIENT_BUFFER);
- fullUrl = calloc(1, fullUrlSize + 1);
- success = WinHttpQueryOption(request, WINHTTP_OPTION_URL, fullUrl, &fullUrlSize);
- if (!success) {
- free(fullUrl);
- WINHTTP_SAFE(success);
- }
-
- proxyOptions.lpszAutoConfigUrl = http->autoProxy;
- proxyOptions.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL;
-
- if (!(success = WinHttpGetProxyForUrl(http->session, fullUrl, &proxyOptions, &proxyInfo))) {
- proxyOptions.fAutoLogonIfChallenged = true;
- success = WinHttpGetProxyForUrl(http->session, fullUrl, &proxyOptions, &proxyInfo);
- }
-
- if (!success) {
- free(fullUrl);
- WINHTTP_SAFE(success);
- }
- }
- else {
- proxyInfo.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
- proxyInfo.lpszProxy = http->proxy;
- proxyInfo.lpszProxyBypass = NULL;
- }
-
- WINHTTP_SAFE(WinHttpSetOption(handle,
- WINHTTP_OPTION_PROXY,
- &proxyInfo, sizeof(proxyInfo)));
-
- if (http->proxyUsername && http->proxyPassword) {
- WINHTTP_SAFE(WinHttpSetCredentials(handle,
- WINHTTP_AUTH_TARGET_PROXY,
- WINHTTP_AUTH_SCHEME_BASIC,
- http->proxyUsername,
- http->proxyPassword,
- NULL));
- }
- }
-
- while (retryLimit > 0) {
- DWORD errorCode, statusCode, statusCodeSize;
- bool succeeded = false;
- bool retry = false;
-
- if (!requestSent) {
- size_t postDataSize = strlen(request->postData);
- succeeded = WinHttpSendRequest(handle,
- WINHTTP_NO_ADDITIONAL_HEADERS,
- 0,
- request->postData,
- postDataSize,
- postDataSize,
- 0);
-
- if (succeeded)
- requestSent = true;
- }
-
- if (requestSent)
- succeeded = WinHttpReceiveResponse(handle, NULL);
-
- errorCode = GetLastError();
-
- statusCode = 0;
- statusCodeSize = sizeof(statusCode);
- if (!WinHttpQueryHeaders(handle,
- WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,
- WINHTTP_HEADER_NAME_BY_INDEX,
- &statusCode, &statusCodeSize, WINHTTP_NO_HEADER_INDEX)) {
- statusCode = 0;
- }
-
- if (succeeded && statusCode == 407) {
- requestSent = false;
- retry = true;
- }
- else {
- if (errorCode == ERROR_SUCCESS)
- break;
-
- switch (errorCode) {
- case ERROR_WINHTTP_RESEND_REQUEST:
- requestSent = false;
- /* pass trough */
-
- case ERROR_WINHTTP_NAME_NOT_RESOLVED:
- case ERROR_WINHTTP_CANNOT_CONNECT:
- case ERROR_WINHTTP_TIMEOUT:
- retry = true;
- break;
-
- default:
- HttpSetLastErrorFromWinHttp (http);
- goto done;
- }
- }
-
- if (retry)
- --retryLimit;
- }
-
- responseDataSize = 0;
- while (retryLimit > 0)
- {
- DWORD bytesLeft;
- char* writePtr;
-
- DWORD bytesAvailable = 0;
- if (!WinHttpQueryDataAvailable(handle, &bytesAvailable)) {
- WINHTTP_SAFE(GetLastError() == ERROR_WINHTTP_TIMEOUT);
- --retryLimit;
- continue;
- }
-
- if (0 == bytesAvailable)
- break;
-
- responseDataSize += bytesAvailable;
- request->responseData = realloc(request->responseData, responseDataSize + 1);
-
- writePtr = request->responseData + responseDataSize - bytesAvailable;
- writePtr[bytesAvailable] = 0;
-
- bytesLeft = bytesAvailable;
- while (bytesLeft > 0)
- {
- DWORD bytesRead = 0;
- if (!WinHttpReadData(handle, writePtr, bytesLeft, &bytesRead))
- {
- WINHTTP_SAFE(GetLastError() == ERROR_WINHTTP_TIMEOUT);
- if (--retryLimit == 0)
- break;
-
- continue;
- }
-
- bytesLeft -= bytesRead;
- writePtr += bytesRead;
- }
-
- if (bytesLeft > 0)
- HttpSetLastError (http, "Maximum retries count exceeded");
- }
-
- complete = true;
-
- HttpSetLastError (http, NULL);
-
-done:
- free(wideQuery);
- return complete;
-}
-
-const char* HttpGetError(http_t http) {
- return http->error;
-}
+/* +Copyright (c) 2015 + Michał Cichoń <thedmd@interia.pl> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "config.h" +#include "http.h" +#include <Windows.h> +#include <winhttp.h> +#pragma comment(lib, "winhttp.lib") + +struct _http_t { + HINTERNET session; + HINTERNET connection; + wchar_t* endpoint; + wchar_t* securePort; + wchar_t* autoProxy; + wchar_t* proxy; + wchar_t* proxyUsername; + wchar_t* proxyPassword; + char* error; +}; + +static char* HttpToString(const wchar_t* wideString, int size); +static wchar_t* HttpToWideString(const char* string, int size); +static bool HttpCreateConnection (http_t http); +static void HttpCloseConnection (http_t http); +static void HttpSetLastError (http_t http, const char* message); +static void HttpSetLastErrorFromWinHttp (http_t http); +static char* HttpFormatWinApiError (DWORD errorCode, HINSTANCE module); +static char* HttpFormatWinHttpError (DWORD errorCode); +static void HttpClearProxy (http_t http); + +# define WINHTTP_SAFE(condition) do { if (condition) break; HttpSetLastErrorFromWinHttp (http); return false; } while (false) +# define WINHTTP_SAFE_DONE(condition) do { if (condition) break; HttpSetLastErrorFromWinHttp (http); goto done; } while (false) + +static char* HttpToString(const wchar_t* wideString, int size) { + int utfSize = WideCharToMultiByte(CP_UTF8, 0, wideString, size, NULL, 0, NULL, NULL); + char* utfMessage = malloc(utfSize + 1); + if (utfMessage) { + utfMessage[utfSize] = 0; + WideCharToMultiByte(CP_UTF8, 0, wideString, size, utfMessage, utfSize, NULL, NULL); + } + return utfMessage; +} + +static wchar_t* HttpToWideString(const char* string, int size) { + int wideSize = MultiByteToWideChar(CP_UTF8, 0, string, size, NULL, 0); + int wideBytes = (wideSize + 1) * sizeof(wchar_t); + wchar_t* wideMessage = malloc(wideBytes); + if (wideMessage) { + wideMessage[wideSize] = 0; + MultiByteToWideChar(CP_UTF8, 0, string, size, wideMessage, wideSize); + } + return wideMessage; +} + + +static bool HttpCreateConnection (http_t http) { + INTERNET_PORT defaultPort = INTERNET_DEFAULT_PORT; + + HttpCloseConnection (http); + + http->session = WinHttpOpen( + L"WinHTTP/1.0", + WINHTTP_ACCESS_TYPE_NO_PROXY, + WINHTTP_NO_PROXY_NAME, + WINHTTP_NO_PROXY_BYPASS, + 0); + WINHTTP_SAFE(http->session != NULL); + + WinHttpSetTimeouts(http->session, + 60 * 1000, // DNS time-out + 60 * 1000, // connect time-out + 30 * 1000, // send time-out + 30 * 1000); // receive time-out + + http->connection = WinHttpConnect( + http->session, + http->endpoint, + defaultPort, + 0); + WINHTTP_SAFE(http->connection != NULL); + + return true; +} + +static void HttpCloseConnection (http_t http) { + if (http->connection) { + WinHttpCloseHandle(http->connection); + http->connection = NULL; + } + + if (http->session) { + WinHttpCloseHandle(http->session); + http->session = NULL; + } +} + +static void HttpSetLastError (http_t http, const char* message) { + free(http->error); + http->error = NULL; + + if (message) + http->error = strdup(message); +} + +static void HttpSetLastErrorFromWinHttp (http_t http) { + free(http->error); + http->error = NULL; + + DWORD error = GetLastError(); + if (error) + http->error = HttpFormatWinHttpError(error); +} + +static char* HttpFormatWinApiError (DWORD errorCode, HINSTANCE module) { + const int source_flag = module ? FORMAT_MESSAGE_FROM_HMODULE : FORMAT_MESSAGE_FROM_SYSTEM; + + HLOCAL buffer = NULL; + int bufferLength = FormatMessageW( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | source_flag, + (void*)module, + errorCode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPWSTR)&buffer, + 0, + NULL); + + if (bufferLength > 0) { + char* message; + + wchar_t* wideMessage = (wchar_t*)buffer; + + /* Drop new line from the end. */ + wchar_t* wideMessageBack = wideMessage + bufferLength - 1; + while (wideMessageBack > wideMessage && (*wideMessageBack == '\r' || *wideMessageBack == '\n')) + --wideMessageBack; + + message = HttpToString (wideMessage, wideMessageBack - wideMessage + 1); + + LocalFree(buffer); + + return message; + } + else + return NULL; +} + +static char* HttpFormatWinHttpError (DWORD errorCode) { + if (errorCode >= WINHTTP_ERROR_BASE && errorCode <= WINHTTP_ERROR_LAST) { + HMODULE module = GetModuleHandleW(L"WinHTTP.dll"); + if (module) { + char* message = HttpFormatWinApiError(errorCode, module); + if (message) + return message; + } + } + + return HttpFormatWinApiError(errorCode, NULL); +} + +bool HttpInit(http_t* http, const char* endpoint, const char* securePort) { + http_t out = malloc(sizeof(struct _http_t)); + if (!out) + return false; + memset(out, 0, sizeof(struct _http_t)); + + out->endpoint = HttpToWideString(endpoint, -1); + out->securePort = HttpToWideString(securePort, -1); + + if (!HttpCreateConnection (out)) { + HttpDestroy (out); + return false; + } + + *http = out; + return true; +} + +void HttpDestroy(http_t http) { + if (http) { + free(http->endpoint); + free(http->securePort); + http->endpoint = NULL; + http->securePort = NULL; + HttpCloseConnection (http); + HttpClearProxy (http); + } + free(http); +} + +static void HttpClearProxy (http_t http) { + if (http->autoProxy) { + free(http->autoProxy); + http->autoProxy = NULL; + } + + if (http->proxy) { + free(http->proxy); + http->proxy = NULL; + } + + if (http->proxyUsername) { + free(http->proxyUsername); + http->proxyUsername = NULL; + } + + if (http->proxyPassword) { + free(http->proxyPassword); + http->proxyPassword = NULL; + } +} + +bool HttpSetAutoProxy (http_t http, const char* url) { + HttpClearProxy (http); + if (HttpSetProxy (http, url)) { + http->autoProxy = http->proxy; + http->proxy = NULL; + return true; + } + else + return false; +} + +bool HttpSetProxy (http_t http, const char* url) { + URL_COMPONENTS urlComponents; + wchar_t* wideUrl = NULL; + wchar_t* wideUrl2 = NULL; + wchar_t* wideUsername = NULL; + wchar_t* widePassword = NULL; + + ZeroMemory(&urlComponents, sizeof(urlComponents)); + urlComponents.dwStructSize = sizeof(urlComponents); + urlComponents.dwUserNameLength = -1; + urlComponents.dwPasswordLength = -1; + + wideUrl = HttpToWideString(url, -1); + if (WinHttpCrackUrl(wideUrl, wcslen(wideUrl), 0, &urlComponents)) { + if (urlComponents.lpszUserName && urlComponents.dwUserNameLength > 0) { + wideUsername = wcsdup(urlComponents.lpszUserName); + wideUsername[urlComponents.dwUserNameLength] = 0; + } + if (urlComponents.lpszPassword && urlComponents.dwPasswordLength > 0) { + widePassword = wcsdup(urlComponents.lpszPassword); + widePassword[urlComponents.dwPasswordLength] = 0; + } + } + + ZeroMemory(&urlComponents, sizeof(urlComponents)); + urlComponents.dwStructSize = sizeof(urlComponents); + urlComponents.dwHostNameLength = -1; + urlComponents.dwUrlPathLength = -1; + + if (!WinHttpCrackUrl(wideUrl, wcslen(wideUrl), 0, &urlComponents)) { + free(wideUsername); + free(widePassword); + return false; + } + + if (urlComponents.lpszHostName && urlComponents.dwHostNameLength > 0) { + wideUrl2 = wcsdup(urlComponents.lpszHostName); + wideUrl2[urlComponents.lpszUrlPath - urlComponents.lpszHostName] = 0; + } + + free(wideUrl); + + HttpClearProxy(http); + http->proxy = wideUrl2; + http->proxyUsername = wideUsername; + http->proxyPassword = widePassword; + return true; +} + +bool HttpRequest(http_t http, PianoRequest_t * const request) { + HINTERNET handle = NULL; + wchar_t* wideQuery = NULL; + bool requestSent = false; + bool complete = false; + int retryLimit = 3; + size_t responseDataSize; + + wideQuery = HttpToWideString(request->urlPath, -1); + WINHTTP_SAFE_DONE(wideQuery != NULL); + + handle = WinHttpOpenRequest( + http->connection, + L"POST", + wideQuery, + L"HTTP/1.1", + WINHTTP_NO_REFERER, + WINHTTP_DEFAULT_ACCEPT_TYPES, + request->secure ? WINHTTP_FLAG_SECURE : 0); + WINHTTP_SAFE_DONE(handle != NULL); + + if (http->proxy || http->autoProxy) { + wchar_t* fullUrl; + DWORD fullUrlSize = 0; + WINHTTP_PROXY_INFO proxyInfo; + bool success; + + if (http->autoProxy) { + WINHTTP_AUTOPROXY_OPTIONS proxyOptions = { 0 }; + + success = WinHttpQueryOption(request, WINHTTP_OPTION_URL, NULL, &fullUrlSize); + WINHTTP_SAFE(!success && GetLastError() == ERROR_INSUFFICIENT_BUFFER); + fullUrl = calloc(1, fullUrlSize + 1); + success = WinHttpQueryOption(request, WINHTTP_OPTION_URL, fullUrl, &fullUrlSize); + if (!success) { + free(fullUrl); + WINHTTP_SAFE(success); + } + + proxyOptions.lpszAutoConfigUrl = http->autoProxy; + proxyOptions.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL; + + if (!(success = WinHttpGetProxyForUrl(http->session, fullUrl, &proxyOptions, &proxyInfo))) { + proxyOptions.fAutoLogonIfChallenged = true; + success = WinHttpGetProxyForUrl(http->session, fullUrl, &proxyOptions, &proxyInfo); + } + + if (!success) { + free(fullUrl); + WINHTTP_SAFE(success); + } + } + else { + proxyInfo.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY; + proxyInfo.lpszProxy = http->proxy; + proxyInfo.lpszProxyBypass = NULL; + } + + WINHTTP_SAFE(WinHttpSetOption(handle, + WINHTTP_OPTION_PROXY, + &proxyInfo, sizeof(proxyInfo))); + + if (http->proxyUsername && http->proxyPassword) { + WINHTTP_SAFE(WinHttpSetCredentials(handle, + WINHTTP_AUTH_TARGET_PROXY, + WINHTTP_AUTH_SCHEME_BASIC, + http->proxyUsername, + http->proxyPassword, + NULL)); + } + } + + while (retryLimit > 0) { + DWORD errorCode, statusCode, statusCodeSize; + bool succeeded = false; + bool retry = false; + + if (!requestSent) { + size_t postDataSize = strlen(request->postData); + succeeded = WinHttpSendRequest(handle, + WINHTTP_NO_ADDITIONAL_HEADERS, + 0, + request->postData, + postDataSize, + postDataSize, + 0); + + if (succeeded) + requestSent = true; + } + + if (requestSent) + succeeded = WinHttpReceiveResponse(handle, NULL); + + errorCode = GetLastError(); + + statusCode = 0; + statusCodeSize = sizeof(statusCode); + if (!WinHttpQueryHeaders(handle, + WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, + WINHTTP_HEADER_NAME_BY_INDEX, + &statusCode, &statusCodeSize, WINHTTP_NO_HEADER_INDEX)) { + statusCode = 0; + } + + if (succeeded && statusCode == 407) { + requestSent = false; + retry = true; + } + else { + if (errorCode == ERROR_SUCCESS) + break; + + switch (errorCode) { + case ERROR_WINHTTP_RESEND_REQUEST: + requestSent = false; + /* pass trough */ + + case ERROR_WINHTTP_NAME_NOT_RESOLVED: + case ERROR_WINHTTP_CANNOT_CONNECT: + case ERROR_WINHTTP_TIMEOUT: + retry = true; + break; + + default: + HttpSetLastErrorFromWinHttp (http); + goto done; + } + } + + if (retry) + --retryLimit; + } + + responseDataSize = 0; + while (retryLimit > 0) + { + DWORD bytesLeft; + char* writePtr; + + DWORD bytesAvailable = 0; + if (!WinHttpQueryDataAvailable(handle, &bytesAvailable)) { + WINHTTP_SAFE(GetLastError() == ERROR_WINHTTP_TIMEOUT); + --retryLimit; + continue; + } + + if (0 == bytesAvailable) + break; + + responseDataSize += bytesAvailable; + request->responseData = realloc(request->responseData, responseDataSize + 1); + + writePtr = request->responseData + responseDataSize - bytesAvailable; + writePtr[bytesAvailable] = 0; + + bytesLeft = bytesAvailable; + while (bytesLeft > 0) + { + DWORD bytesRead = 0; + if (!WinHttpReadData(handle, writePtr, bytesLeft, &bytesRead)) + { + WINHTTP_SAFE(GetLastError() == ERROR_WINHTTP_TIMEOUT); + if (--retryLimit == 0) + break; + + continue; + } + + bytesLeft -= bytesRead; + writePtr += bytesRead; + } + + if (bytesLeft > 0) + HttpSetLastError (http, "Maximum retries count exceeded"); + } + + complete = true; + + HttpSetLastError (http, NULL); + +done: + free(wideQuery); + return complete; +} + +const char* HttpGetError(http_t http) { + return http->error; +} diff --git a/src/http.h b/src/http/http.h index a321cd3..a321cd3 100644 --- a/src/http.h +++ b/src/http/http.h diff --git a/src/libpiano/response.c b/src/libpiano/response.c index 783e2f0..8b6ed52 100644 --- a/src/libpiano/response.c +++ b/src/libpiano/response.c @@ -21,7 +21,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include "../config.h" +#include "config.h" #include <json/json.h> #include <string.h> @@ -28,8 +28,8 @@ THE SOFTWARE. #include <piano.h> -#include "player2.h" -#include "http.h" +#include "player/player2.h" +#include "http/http.h" #include "settings.h" #include "ui_readline.h" diff --git a/src/player2.c b/src/player/player2.c index 01fe33c..01fe33c 100644 --- a/src/player2.c +++ b/src/player/player2.c diff --git a/src/player2.h b/src/player/player2.h index b426ee2..b426ee2 100644 --- a/src/player2.h +++ b/src/player/player2.h @@ -29,7 +29,7 @@ THE SOFTWARE. #include <piano.h> #include "settings.h" -#include "player2.h" +#include "player/player2.h" #include "main.h" #include "ui_readline.h" #include "ui_types.h" |