naett.c

Tiny cross-platform HTTP / HTTPS client library in C.
git clone git://git.finwo.net/lib/naett.c
Log | Files | Refs | README | LICENSE

commit 1e8ce8525227056d979829289a8495fadc13cf37
parent 4de7889194b21c245e05209264c556412d4a49d4
Author: Erik Agsjö <erik.agsjo@gmail.com>
Date:   Sun, 12 Dec 2021 16:19:14 +0100

Win bug fixes + better error handling

Diffstat:
Msrc/naett_win.c | 75++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
1 file changed, 58 insertions(+), 17 deletions(-)

diff --git a/src/naett_win.c b/src/naett_win.c @@ -6,11 +6,12 @@ #include <stdio.h> #include <string.h> #include <winhttp.h> +#include <assert.h> void naettPlatformInit(naettInitData initData) { } -char* winToUTF8(LPWSTR source) { +static char* winToUTF8(LPWSTR source) { int length = WideCharToMultiByte(CP_UTF8, 0, source, -1, NULL, 0, NULL, NULL); char* chars = (char*)malloc(length); int result = WideCharToMultiByte(CP_UTF8, 0, source, -1, chars, length, NULL, NULL); @@ -21,7 +22,7 @@ char* winToUTF8(LPWSTR source) { return chars; } -LPWSTR winFromUTF8(const char* source) { +static LPWSTR winFromUTF8(const char* source) { int length = MultiByteToWideChar(CP_UTF8, 0, source, -1, NULL, 0); LPWSTR chars = (LPWSTR)malloc(length * sizeof(WCHAR)); int result = MultiByteToWideChar(CP_UTF8, 0, source, -1, chars, length); @@ -39,13 +40,19 @@ LPWSTR winFromUTF8(const char* source) { snprintf(*(result), len + 1, fmt, __VA_ARGS__); \ } -LPCWSTR packHeaders(InternalRequest* req) { +static LPWSTR wcsndup(LPCWSTR str, size_t len) { + LPWSTR result = calloc(1, sizeof(WCHAR) * (len + 1)); + wcsncpy(result, str, len); + return result; +} + +static LPCWSTR packHeaders(InternalRequest* req) { char* packed = strdup(""); KVLink* node = req->options.headers; while (node != NULL) { char* update; - ASPRINTF(&update, "%s%s=%s%s", packed, node->key, node->value, node->next ? "\r\n" : ""); + ASPRINTF(&update, "%s%s:%s%s", packed, node->key, node->value, node->next ? "\r\n" : ""); free(packed); packed = update; node = node->next; @@ -134,7 +141,7 @@ static void callback(HINTERNET request, res->code = naettReadError; res->complete = 1; } - }break; + } break; case WINHTTP_CALLBACK_STATUS_READ_COMPLETE: { size_t bytesRead = statusInfoLength; @@ -215,8 +222,8 @@ int naettPlatformInitRequest(InternalRequest* req) { return 0; } - req->host = wcsncat(wcsdup(L""), components.lpszHostName, components.dwHostNameLength); - req->resource = wcsncat(wcsdup(L""), components.lpszUrlPath, components.dwUrlPathLength); + req->host = wcsndup(components.lpszHostName, components.dwHostNameLength); + req->resource = wcsndup(components.lpszUrlPath, components.dwUrlPathLength); free(url); req->session = WinHttpOpen( @@ -230,7 +237,7 @@ int naettPlatformInitRequest(InternalRequest* req) { req->connection = WinHttpConnect(req->session, req->host, components.nPort, 0); if (!req->connection) { - WinHttpCloseHandle(req->session); + naettPlatformFreeRequest(req); return 0; } @@ -244,31 +251,65 @@ int naettPlatformInitRequest(InternalRequest* req) { components.nScheme == INTERNET_SCHEME_HTTPS ? WINHTTP_FLAG_SECURE : 0); free(verb); if (!req->request) { - WinHttpCloseHandle(req->session); - WinHttpCloseHandle(req->connection); + naettPlatformFreeRequest(req); return 0; } LPCWSTR headers = packHeaders(req); - WinHttpAddRequestHeaders(req->request, headers, 0, WINHTTP_ADDREQ_FLAG_ADD); + if (headers[0] != 0) { + if (!WinHttpAddRequestHeaders( + req->request, headers, -1, WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE)) { + naettPlatformFreeRequest(req); + free((LPWSTR)headers); + return 0; + } + } free((LPWSTR)headers); return 1; } void naettPlatformMakeRequest(InternalResponse* res) { - if (!WinHttpSendRequest(res->request->request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, NULL, 0, 0, (DWORD_PTR)res)) { + InternalRequest* req = res->request; + + LPCWSTR extraHeaders = WINHTTP_NO_ADDITIONAL_HEADERS; + WCHAR contentLengthHeader[64]; + + int contentLength = req->options.bodyReader(NULL, 0, req->options.bodyReaderData); + if (contentLength > 0) { + wsprintfW(contentLengthHeader, L"Content-Length: %d", contentLength); + extraHeaders = contentLengthHeader; + } + + if (!WinHttpSendRequest(req->request, extraHeaders, -1, NULL, 0, 0, (DWORD_PTR)res)) { res->code = naettConnectionError; res->complete = 1; } } void naettPlatformFreeRequest(InternalRequest* req) { - WinHttpCloseHandle(req->session); - WinHttpCloseHandle(req->connection); - WinHttpCloseHandle(req->request); - free(req->host); - free(req->resource); + assert(req != NULL); + + if (req->request != NULL) { + WinHttpCloseHandle(req->request); + req->request = NULL; + } + if (req->connection != NULL) { + WinHttpCloseHandle(req->connection); + req->connection = NULL; + } + if (req->session != NULL) { + WinHttpCloseHandle(req->session); + req->session = NULL; + } + if (req->host != NULL) { + free(req->host); + req->host = NULL; + } + if (req->resource != NULL) { + free(req->resource); + req->resource = NULL; + } } void naettPlatformCloseResponse(InternalResponse* res) {