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 cd88323090b78b972059b7ab34af05456930e1a5
parent fa2305496e9fbe7710854b1ec10b3a40d0a107fa
Author: Henrik RydgÄrd <hrydgard@gmail.com>
Date:   Fri, 21 Jul 2023 15:12:16 +0200

Add support for specifying the user-agent per request.

Diffstat:
Mnaett.c | 23++++++++++++++++++-----
Mnaett.h | 6++++--
Msrc/naett_android.c | 2+-
Msrc/naett_core.c | 18+++++++++++++++---
Msrc/naett_internal.h | 6++++--
Msrc/naett_linux.c | 6+++++-
Msrc/naett_osx.c | 4++--
Msrc/naett_win.c | 16+++++++++++-----
8 files changed, 60 insertions(+), 21 deletions(-)

diff --git a/naett.c b/naett.c @@ -5,7 +5,7 @@ #ifndef NAETT_INTERNAL_H #define NAETT_INTERNAL_H -#ifdef _MSC_VER +#ifdef _MSC_VER #define strcasecmp _stricmp #define min(a,b) (((a)<(b))?(a):(b)) #define strdup _strdup @@ -55,6 +55,7 @@ typedef struct Buffer { typedef struct { const char* method; + const char* userAgent; int timeoutMS; naettReadFunc bodyReader; void* bodyReaderData; @@ -183,7 +184,7 @@ static int defaultBodyReader(void* dest, int bufferSize, void* userData) { if (dest == NULL) { return buffer->size; } - + int bytesToRead = buffer->size - buffer->position; if (bytesToRead > bufferSize) { bytesToRead = bufferSize; @@ -250,6 +251,18 @@ naettOption* naettMethod(const char* method) { return (naettOption*)option; } +naettOption* naettUserAgent(const char* method) { + naettAlloc(InternalOption, option); + option->numParams = 1; + InternalParam* param = &option->params[0]; + + param->string = method; + param->offset = offsetof(RequestOptions, userAgent); + param->setter = stringSetter; + + return (naettOption*)option; +} + naettOption* naettHeader(const char* name, const char* value) { naettAlloc(InternalOption, option); option->numParams = 1; @@ -363,7 +376,7 @@ naettReq* naettRequest_va(const char* url, int numArgs, ...) { if (naettPlatformInitRequest(req)) { return (naettReq*)req; } - + naettFree((naettReq*) req); return NULL; } @@ -386,7 +399,7 @@ naettReq* naettRequestWithOptions(const char* url, int numOptions, const naettOp if (naettPlatformInitRequest(req)) { return (naettReq*)req; } - + naettFree((naettReq*) req); return NULL; } @@ -697,7 +710,7 @@ static id createDelegate() { if (!TaskDelegateClass) { TaskDelegateClass = objc_allocateClassPair((Class)objc_getClass("NSObject"), "naettTaskDelegate", 0); class_addProtocol(TaskDelegateClass, objc_getProtocol("NSURLSessionDataDelegate")); - + addMethod(TaskDelegateClass, "URLSession:dataTask:didReceiveData:", didReceiveData, "v@:@@@"); addMethod(TaskDelegateClass, "URLSession:task:didCompleteWithError:", didComplete, "v@:@@@"); addIvar(TaskDelegateClass, "response", sizeof(void*), "^v"); diff --git a/naett.h b/naett.h @@ -44,6 +44,8 @@ naettOption* naettBodyReader(naettReadFunc reader, void* userData); naettOption* naettBodyWriter(naettWriteFunc writer, void* userData); // Sets connection timeout in milliseconds. naettOption* naettTimeout(int milliSeconds); +// Sets the user agent. +naettOption* naettUserAgent(const char *userAgent); /** * @brief Creates a new request to the specified url. @@ -53,7 +55,7 @@ naettOption* naettTimeout(int milliSeconds); /** * @brief Creates a new request to the specified url. - * Uses an array of options rather that varargs. + * Uses an array of options rather than varargs. */ naettReq* naettRequestWithOptions(const char* url, int numOptions, const naettOption** options); @@ -61,7 +63,7 @@ naettReq* naettRequestWithOptions(const char* url, int numOptions, const naettOp * @brief Makes a request and returns a response object. * The actual request is processed asynchronously, use `naettComplete` * to check if the response is completed. - * + * * A request object can be reused multiple times to make requests, but * there can be only one active request using the same request object. */ diff --git a/src/naett_android.c b/src/naett_android.c @@ -109,7 +109,7 @@ static void* processRequest(void* data) { { jstring name = (*env)->NewStringUTF(env, "User-Agent"); - jstring value = (*env)->NewStringUTF(env, NAETT_UA); + jstring value = (*env)->NewStringUTF(env, req->options.userAgent ? req->options.userAgent : NAETT_UA); voidCall(env, connection, "addRequestProperty", "(Ljava/lang/String;Ljava/lang/String;)V", name, value); (*env)->DeleteLocalRef(env, name); (*env)->DeleteLocalRef(env, value); diff --git a/src/naett_core.c b/src/naett_core.c @@ -69,7 +69,7 @@ static int defaultBodyReader(void* dest, int bufferSize, void* userData) { if (dest == NULL) { return buffer->size; } - + int bytesToRead = buffer->size - buffer->position; if (bytesToRead > bufferSize) { bytesToRead = bufferSize; @@ -149,6 +149,18 @@ naettOption* naettHeader(const char* name, const char* value) { return (naettOption*)option; } +naettOption* naettUserAgent(const char* method) { + naettAlloc(InternalOption, option); + option->numParams = 1; + InternalParam* param = &option->params[0]; + + param->string = method; + param->offset = offsetof(RequestOptions, userAgent); + param->setter = stringSetter; + + return (naettOption*)option; +} + naettOption* naettTimeout(int timeoutMS) { naettAlloc(InternalOption, option); option->numParams = 1; @@ -249,7 +261,7 @@ naettReq* naettRequest_va(const char* url, int numArgs, ...) { if (naettPlatformInitRequest(req)) { return (naettReq*)req; } - + naettFree((naettReq*) req); return NULL; } @@ -272,7 +284,7 @@ naettReq* naettRequestWithOptions(const char* url, int numOptions, const naettOp if (naettPlatformInitRequest(req)) { return (naettReq*)req; } - + naettFree((naettReq*) req); return NULL; } diff --git a/src/naett_internal.h b/src/naett_internal.h @@ -1,14 +1,15 @@ #ifndef NAETT_INTERNAL_H #define NAETT_INTERNAL_H -#ifdef _MSC_VER +#ifdef _MSC_VER #define strcasecmp _stricmp - #define min(a,b) (((a)<(b))?(a):(b)) + #undef strdup #define strdup _strdup #endif #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN +#define NOMINMAX #include <windows.h> #include <winhttp.h> #define __WINDOWS__ 1 @@ -51,6 +52,7 @@ typedef struct Buffer { typedef struct { const char* method; + const char* userAgent; int timeoutMS; naettReadFunc bodyReader; void* bodyReaderData; diff --git a/src/naett_linux.c b/src/naett_linux.c @@ -193,7 +193,11 @@ void naettPlatformMakeRequest(InternalResponse* res) { setupMethod(c, req->options.method); struct curl_slist* headerList = NULL; - headerList = curl_slist_append(headerList, "User-Agent: Naett/1.0"); + char uaBuf[512]; + if (req->options.userAgent) { + snprintf(uaBuf, sizeof(uaBuf), "User-Agent: %s", req->options.userAgent ? req->options.userAgent : NAETT_UA); + } + headerList = curl_slist_append(headerList, uaBuf); KVLink* header = req->options.headers; size_t bufferSize = 0; diff --git a/src/naett_osx.c b/src/naett_osx.c @@ -42,7 +42,7 @@ int naettPlatformInitRequest(InternalRequest* req) { { id name = NSString("User-Agent"); - id value = NSString(NAETT_UA); + id value = NSString(req->options.userAgent ? req->options.userAgent : NAETT_UA); objc_msgSend_t(void, id, id)(request, sel("setValue:forHTTPHeaderField:"), value, name); } @@ -129,7 +129,7 @@ static id createDelegate() { if (!TaskDelegateClass) { TaskDelegateClass = objc_allocateClassPair((Class)objc_getClass("NSObject"), "naettTaskDelegate", 0); class_addProtocol(TaskDelegateClass, objc_getProtocol("NSURLSessionDataDelegate")); - + addMethod(TaskDelegateClass, "URLSession:dataTask:didReceiveData:", didReceiveData, "v@:@@@"); addMethod(TaskDelegateClass, "URLSession:task:didCompleteWithError:", didComplete, "v@:@@@"); addIvar(TaskDelegateClass, "response", sizeof(void*), "^v"); diff --git a/src/naett_win.c b/src/naett_win.c @@ -7,6 +7,7 @@ #include <string.h> #include <winhttp.h> #include <assert.h> +#include <tchar.h> void naettPlatformInit(naettInitData initData) { } @@ -64,7 +65,7 @@ static LPCWSTR packHeaders(InternalRequest* req) { } static void unpackHeaders(InternalResponse* res, LPWSTR packed) { - int len = 0; + size_t len = 0; while ((len = wcslen(packed)) != 0) { char* header = winToUTF8(packed); char* split = strchr(header, ':'); @@ -137,7 +138,7 @@ static void callback(HINTERNET request, } size_t bytesToRead = min(res->bytesLeft, sizeof(res->buffer)); - if (!WinHttpReadData(request, res->buffer, bytesToRead, NULL)) { + if (!WinHttpReadData(request, res->buffer, (DWORD)bytesToRead, NULL)) { res->code = naettReadError; res->complete = 1; } @@ -147,7 +148,7 @@ static void callback(HINTERNET request, size_t bytesRead = statusInfoLength; InternalRequest* req = res->request; - if (req->options.bodyWriter(res->buffer, bytesRead, req->options.bodyWriterData) != bytesRead) { + if (req->options.bodyWriter(res->buffer, (int)bytesRead, req->options.bodyWriterData) != bytesRead) { res->code = naettReadError; res->complete = 1; } @@ -155,7 +156,7 @@ static void callback(HINTERNET request, res->bytesLeft -= bytesRead; if (res->bytesLeft > 0) { size_t bytesToRead = min(res->bytesLeft, sizeof(res->buffer)); - if (!WinHttpReadData(request, res->buffer, bytesToRead, NULL)) { + if (!WinHttpReadData(request, res->buffer, (DWORD)bytesToRead, NULL)) { res->code = naettReadError; res->complete = 1; } @@ -226,8 +227,13 @@ int naettPlatformInitRequest(InternalRequest* req) { req->resource = wcsndup(components.lpszUrlPath, components.dwUrlPathLength + components.dwExtraInfoLength); free(url); + LPWSTR uaBuf = 0; + if (req->options.userAgent) { + uaBuf = winFromUTF8(req->options.userAgent); + } req->session = WinHttpOpen( - L"Naett/1.0", WINHTTP_ACCESS_TYPE_NO_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, WINHTTP_FLAG_ASYNC); + uaBuf ? uaBuf : _T(NAETT_UA), WINHTTP_ACCESS_TYPE_NO_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, WINHTTP_FLAG_ASYNC); + free(uaBuf); if (!req->session) { return 0;