mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-09-11 15:13:37 +02:00
Enable HTTPS on Linux, through naett's libcurl backend
naett has had a complete libcurl backend all along; we just never built it, so Linux ran with HTTPS_NOT_AVAILABLE. That means no homebrew store over HTTPS, and RetroAchievements talking to plain http://retroachievements.org. libcurl is loaded with dlopen rather than linked, the same way we handle the Vulkan loader, so it stays a soft dependency: we need the curl headers at build time, but a build made here still starts on a machine without libcurl installed - it just reports HTTPS as unavailable, exactly like today. Distro packagers get the behavior they'd expect either way, and certificate validation comes free from the system CA store. New net::HTTPSAvailable() answers "did that work", and SDLMain folds it into SYSPROP_SUPPORTS_HTTPS, which everything downstream already degrades on. Four fixes to the backend itself, all noted in ext/naett/README-ppsspp.md: - panic() called exit(1) on a pipe or curl_multi_perform failure. Taking the emulator down because a download failed isn't acceptable - the backend now disables itself and requests complete with naettGenericError. - CURLINFO_RESPONSE_CODE writes a long into res->code, which is an int. Eight bytes into four, getting away with it only because the next field absorbs the zeroes. - curl_easy_setopt is varargs and wants a long for these options; int literals and int variables are UB on LP64. - naettPlatformCloseResponse called through a null function pointer when libcurl was missing. Found by testing that path, which segfaulted. CI needs libcurl4-openssl-dev (curl-dev on Alpine) or it would quietly keep building without HTTPS.
This commit is contained in:
@@ -321,7 +321,7 @@ jobs:
|
||||
if: runner.os == 'Linux' && matrix.extra != 'android' && matrix.extra != 'loongarch64'
|
||||
run: |
|
||||
sudo apt-get update -y -qq
|
||||
sudo apt-get install libsdl3-dev libgl1-mesa-dev libglu1-mesa-dev libsdl3-ttf-dev libfontconfig1-dev
|
||||
sudo apt-get install libsdl3-dev libgl1-mesa-dev libglu1-mesa-dev libsdl3-ttf-dev libfontconfig1-dev libcurl4-openssl-dev
|
||||
|
||||
- name: Install macOS SDL3 dependencies
|
||||
if: runner.os == 'macOS' && matrix.id == 'macos'
|
||||
@@ -475,7 +475,7 @@ jobs:
|
||||
if: runner.os == 'Linux'
|
||||
run: |
|
||||
sudo apt-get update -y -qq
|
||||
sudo apt-get install libsdl3-dev libgl1-mesa-dev libglu1-mesa-dev libsdl3-ttf-dev libfontconfig1-dev
|
||||
sudo apt-get install libsdl3-dev libgl1-mesa-dev libglu1-mesa-dev libsdl3-ttf-dev libfontconfig1-dev libcurl4-openssl-dev
|
||||
|
||||
- name: Install macOS dependencies
|
||||
if: runner.os == 'macOS'
|
||||
@@ -524,7 +524,7 @@ jobs:
|
||||
steps:
|
||||
- name: Install Linux dependencies (Alpine)
|
||||
run: |
|
||||
apk add build-base wget git bash cmake python3 glu-dev sdl3-dev sdl3_ttf-dev
|
||||
apk add build-base wget git bash cmake python3 glu-dev sdl3-dev sdl3_ttf-dev curl-dev
|
||||
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
|
||||
+14
-1
@@ -271,7 +271,20 @@ if(ANDROID)
|
||||
set(USING_GLES2 ON)
|
||||
endif()
|
||||
|
||||
if(NOT ANDROID AND NOT WIN32 AND (NOT APPLE OR IOS))
|
||||
# naett wraps a native HTTPS implementation per platform: WinHTTP on Windows, the Java
|
||||
# APIs on Android, NSURLSession on macOS, and libcurl elsewhere.
|
||||
if(WIN32 OR ANDROID OR (APPLE AND NOT IOS))
|
||||
# Nothing to do, these need no external library.
|
||||
elseif(UNIX AND NOT APPLE AND NOT LIBRETRO)
|
||||
# We only need the curl headers at build time - libcurl itself is loaded with dlopen
|
||||
# (see ext/naett-lib/src/naett_curl.h), so it stays optional at runtime and a build made
|
||||
# here still starts on a machine without it, just without HTTPS.
|
||||
find_package(CURL)
|
||||
if(NOT CURL_FOUND)
|
||||
message(STATUS "libcurl headers not found - building without HTTPS support")
|
||||
set(HTTPS_NOT_AVAILABLE ON)
|
||||
endif()
|
||||
else()
|
||||
set(HTTPS_NOT_AVAILABLE ON)
|
||||
endif()
|
||||
|
||||
|
||||
+19
-1
@@ -16,6 +16,12 @@
|
||||
|
||||
#ifndef HTTPS_NOT_AVAILABLE
|
||||
#include "ext/naett-lib/naett.h"
|
||||
// Note: PPSSPP_PLATFORM(LINUX) is also set on Android, which needs no loader.
|
||||
#if PPSSPP_PLATFORM(LINUX) && !PPSSPP_PLATFORM(ANDROID)
|
||||
// On Linux, naett goes through libcurl, which we load at runtime - so HTTPS support is
|
||||
// only known once we've tried.
|
||||
#include "ext/naett-lib/src/naett_curl.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if PPSSPP_PLATFORM(ANDROID)
|
||||
@@ -44,13 +50,25 @@ void Init() {
|
||||
_assert_(gJvm != nullptr);
|
||||
naettInit(gJvm);
|
||||
#else
|
||||
naettInit(NULL);
|
||||
if (HTTPSAvailable()) {
|
||||
naettInit(NULL);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
g_naettInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool HTTPSAvailable() {
|
||||
#ifdef HTTPS_NOT_AVAILABLE
|
||||
return false;
|
||||
#elif PPSSPP_PLATFORM(LINUX) && !PPSSPP_PLATFORM(ANDROID)
|
||||
return naettCurlLoad() != 0;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Shutdown() {
|
||||
#ifdef _WIN32
|
||||
if (g_wsaInitialized) {
|
||||
|
||||
@@ -12,6 +12,11 @@ namespace net {
|
||||
void Init();
|
||||
void Shutdown();
|
||||
|
||||
// Whether we have a working HTTPS backend. False if PPSSPP was built without one, and on
|
||||
// Linux also if libcurl couldn't be loaded at runtime. Safe to call before Init().
|
||||
// Platform ports should factor this into SYSPROP_SUPPORTS_HTTPS.
|
||||
bool HTTPSAvailable();
|
||||
|
||||
enum class DNSType {
|
||||
ANY = 0,
|
||||
IPV4 = 1,
|
||||
|
||||
+2
-1
@@ -1193,7 +1193,8 @@ bool System_GetPropertyBool(SystemProperty prop) {
|
||||
return true; // FileUtil.cpp: OpenFileInEditor
|
||||
#ifndef HTTPS_NOT_AVAILABLE
|
||||
case SYSPROP_SUPPORTS_HTTPS:
|
||||
return !g_Config.bDisableHTTPS;
|
||||
// On Linux this also depends on whether libcurl could be loaded.
|
||||
return !g_Config.bDisableHTTPS && net::HTTPSAvailable();
|
||||
#endif
|
||||
case SYSPROP_HAS_FOLDER_BROWSER:
|
||||
case SYSPROP_HAS_FILE_BROWSER:
|
||||
|
||||
@@ -14,10 +14,14 @@ elseif(ANDROID)
|
||||
elseif(APPLE)
|
||||
list(APPEND ALL_SOURCE_FILES ${SRC_DIR}/naett_osx.c)
|
||||
elseif(UNIX)
|
||||
list(APPEND ALL_SOURCE_FILES ${SRC_DIR}/naett_linux.c)
|
||||
list(APPEND ALL_SOURCE_FILES ${SRC_DIR}/naett_linux.c ${SRC_DIR}/naett_curl.c)
|
||||
endif()
|
||||
|
||||
add_library(naett STATIC ${ALL_SOURCE_FILES})
|
||||
if(WIN32)
|
||||
target_link_libraries(naett winhttp)
|
||||
elseif(UNIX AND NOT APPLE AND NOT ANDROID)
|
||||
# Headers only - libcurl itself is dlopen'd, see ../naett/src/naett_curl.h.
|
||||
target_include_directories(naett PRIVATE ${CURL_INCLUDE_DIRS})
|
||||
target_link_libraries(naett ${CMAKE_DL_LIBS})
|
||||
endif()
|
||||
|
||||
@@ -21,3 +21,15 @@ Keep this list up to date - it's what makes it possible to move to a newer upstr
|
||||
`exit`/`calloc`/`realloc`/`free`/`fprintf` but never included either header - in the amalgam it
|
||||
got them from `naett_core.c` further up the concatenation. Building it on its own is an error
|
||||
with a modern compiler.
|
||||
- `src/naett_curl.h` / `src/naett_curl.c`: new, ours. Loads libcurl with `dlopen` instead of
|
||||
linking against it, so libcurl stays a soft dependency at runtime. `naett_linux.c` includes
|
||||
that header in place of `<curl/curl.h>`.
|
||||
- `src/naett_linux.c`: replaced the `panic()` that called `exit(1)` on a pipe or
|
||||
`curl_multi_perform` failure. Taking the whole emulator down because a download failed isn't
|
||||
acceptable, so the backend now disables itself and requests complete with `naettGenericError`.
|
||||
- `src/naett_linux.c`: `CURLINFO_RESPONSE_CODE` writes a `long`, and `res->code` is an `int` -
|
||||
upstream passed `&res->code` straight to `curl_easy_getinfo`, writing 8 bytes into 4. Reads
|
||||
into a `long` local now.
|
||||
- `src/naett_linux.c`: `curl_easy_setopt` is varargs and takes a `long` for these options;
|
||||
upstream passed `int` literals and `int` variables, which is UB on LP64 (and what curl's own
|
||||
typecheck macros warn about). They're `1L`/`(long)` now.
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
// PPSSPP addition - not part of upstream naett. See naett_curl.h.
|
||||
|
||||
#if __linux__ && !__ANDROID__
|
||||
|
||||
#define NAETT_CURL_INTERNAL
|
||||
#include "naett_curl.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <stdio.h>
|
||||
|
||||
NaettCurl g_curl;
|
||||
|
||||
// libcurl's SONAME has been libcurl.so.4 since 2007. The gnutls and nss flavors are
|
||||
// separate sonames on Debian-likes and old Fedora respectively, and are ABI compatible.
|
||||
// libcurl.so last, since that one only exists if the -dev package is installed.
|
||||
static const char *g_curlLibNames[] = {
|
||||
"libcurl.so.4",
|
||||
"libcurl-gnutls.so.4",
|
||||
"libcurl-nss.so.4",
|
||||
"libcurl.so",
|
||||
};
|
||||
|
||||
static int LoadSymbols(void *lib) {
|
||||
// Every one of these has existed since libcurl 7.28 (2012), so a partial load means
|
||||
// something is badly wrong rather than "the host libcurl is a bit old" - bail out
|
||||
// entirely rather than crash later on a null pointer.
|
||||
#define LOAD(field, name) \
|
||||
g_curl.field = (__typeof__(g_curl.field))dlsym(lib, name); \
|
||||
if (!g_curl.field) { \
|
||||
fprintf(stderr, "naett: libcurl is missing %s\n", name); \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
LOAD(global_init, "curl_global_init")
|
||||
LOAD(easy_init, "curl_easy_init")
|
||||
LOAD(easy_setopt, "curl_easy_setopt")
|
||||
LOAD(easy_getinfo, "curl_easy_getinfo")
|
||||
LOAD(easy_cleanup, "curl_easy_cleanup")
|
||||
LOAD(multi_init, "curl_multi_init")
|
||||
LOAD(multi_add_handle, "curl_multi_add_handle")
|
||||
LOAD(multi_perform, "curl_multi_perform")
|
||||
LOAD(multi_info_read, "curl_multi_info_read")
|
||||
LOAD(multi_wait, "curl_multi_wait")
|
||||
LOAD(slist_append, "curl_slist_append")
|
||||
LOAD(slist_free_all, "curl_slist_free_all")
|
||||
|
||||
#undef LOAD
|
||||
return 1;
|
||||
}
|
||||
|
||||
int naettCurlLoad(void) {
|
||||
static int loaded = -1;
|
||||
if (loaded >= 0) {
|
||||
return loaded;
|
||||
}
|
||||
|
||||
loaded = 0;
|
||||
for (size_t i = 0; i < sizeof(g_curlLibNames) / sizeof(g_curlLibNames[0]); i++) {
|
||||
// RTLD_GLOBAL so that libcurl's own dependencies resolve normally.
|
||||
void *lib = dlopen(g_curlLibNames[i], RTLD_NOW | RTLD_GLOBAL);
|
||||
if (!lib) {
|
||||
continue;
|
||||
}
|
||||
if (LoadSymbols(lib)) {
|
||||
loaded = 1;
|
||||
} else {
|
||||
dlclose(lib);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!loaded) {
|
||||
fprintf(stderr, "naett: libcurl not found, HTTPS will be unavailable\n");
|
||||
}
|
||||
return loaded;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,76 @@
|
||||
// PPSSPP addition - not part of upstream naett.
|
||||
//
|
||||
// Loads libcurl at runtime instead of linking against it, so that libcurl stays a soft
|
||||
// dependency: a build made on a machine with the curl headers still starts on a machine
|
||||
// without libcurl installed, just with HTTPS reported as unavailable. Same idea as
|
||||
// Common/GPU/Vulkan/VulkanLoader.cpp.
|
||||
//
|
||||
// The curl headers are still needed at build time, for the types and the option enums.
|
||||
// Only naett_linux.c and naett_curl.c want the redirect macros, so those are behind
|
||||
// NAETT_CURL_INTERNAL; everyone else gets just the loader entry point and doesn't pull
|
||||
// <curl/curl.h> into their translation unit.
|
||||
|
||||
#ifndef NAETT_CURL_H
|
||||
#define NAETT_CURL_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Loads libcurl if it isn't loaded yet, and returns 1 if it's available.
|
||||
// The result is cached, so calling this repeatedly is cheap. Not thread safe - call it
|
||||
// once during startup before any other thread can reach it (PPSSPP does so in net::Init).
|
||||
int naettCurlLoad(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef NAETT_CURL_INTERNAL
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
// curl.h defines these as typechecking macros when built with GCC/Clang. We need the
|
||||
// plain names to redirect, and we lose the typechecking, which is fine - the calls below
|
||||
// are checked at build time in exactly the same way for anyone building against a normal
|
||||
// libcurl.
|
||||
#undef curl_easy_setopt
|
||||
#undef curl_easy_getinfo
|
||||
|
||||
typedef struct {
|
||||
CURLcode (*global_init)(long flags);
|
||||
|
||||
CURL *(*easy_init)(void);
|
||||
CURLcode (*easy_setopt)(CURL *handle, CURLoption option, ...);
|
||||
CURLcode (*easy_getinfo)(CURL *handle, CURLINFO info, ...);
|
||||
void (*easy_cleanup)(CURL *handle);
|
||||
|
||||
CURLM *(*multi_init)(void);
|
||||
CURLMcode (*multi_add_handle)(CURLM *multi, CURL *easy);
|
||||
CURLMcode (*multi_perform)(CURLM *multi, int *runningHandles);
|
||||
CURLMsg *(*multi_info_read)(CURLM *multi, int *msgsInQueue);
|
||||
CURLMcode (*multi_wait)(CURLM *multi, struct curl_waitfd extraFDs[], unsigned int extraNFDs, int timeoutMS,
|
||||
int *numFDs);
|
||||
|
||||
struct curl_slist *(*slist_append)(struct curl_slist *list, const char *data);
|
||||
void (*slist_free_all)(struct curl_slist *list);
|
||||
} NaettCurl;
|
||||
|
||||
extern NaettCurl g_curl;
|
||||
|
||||
#define curl_global_init g_curl.global_init
|
||||
#define curl_easy_init g_curl.easy_init
|
||||
#define curl_easy_setopt g_curl.easy_setopt
|
||||
#define curl_easy_getinfo g_curl.easy_getinfo
|
||||
#define curl_easy_cleanup g_curl.easy_cleanup
|
||||
#define curl_multi_init g_curl.multi_init
|
||||
#define curl_multi_add_handle g_curl.multi_add_handle
|
||||
#define curl_multi_perform g_curl.multi_perform
|
||||
#define curl_multi_info_read g_curl.multi_info_read
|
||||
#define curl_multi_wait g_curl.multi_wait
|
||||
#define curl_slist_append g_curl.slist_append
|
||||
#define curl_slist_free_all g_curl.slist_free_all
|
||||
|
||||
#endif // NAETT_CURL_INTERNAL
|
||||
|
||||
#endif // NAETT_CURL_H
|
||||
@@ -2,7 +2,11 @@
|
||||
|
||||
#if __linux__ && !__ANDROID__
|
||||
|
||||
#include <curl/curl.h>
|
||||
// PPSSPP: libcurl is dlopen'd rather than linked, see naett_curl.h. This header stands in
|
||||
// for <curl/curl.h> and redirects the curl_* calls below through function pointers.
|
||||
#define NAETT_CURL_INTERNAL
|
||||
#include "naett_curl.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
@@ -15,9 +19,14 @@ static pthread_t workerThread;
|
||||
static int handleReadFD = 0;
|
||||
static int handleWriteFD = 0;
|
||||
|
||||
static void panic(const char* message) {
|
||||
fprintf(stderr, "%s\n", message);
|
||||
exit(1);
|
||||
// PPSSPP: upstream had a panic() here that called exit(1). Taking the whole application
|
||||
// down because a download failed isn't acceptable for us, so failures now leave the
|
||||
// backend disabled and requests complete with naettGenericError instead.
|
||||
static int workerRunning = 0;
|
||||
|
||||
static void fail(const char* message) {
|
||||
fprintf(stderr, "naett: %s\n", message);
|
||||
workerRunning = 0;
|
||||
}
|
||||
|
||||
static void* curlWorker(void* data) {
|
||||
@@ -34,10 +43,11 @@ static void* curlWorker(void* data) {
|
||||
|
||||
int newHandlePos = 0;
|
||||
|
||||
while (1) {
|
||||
while (workerRunning) {
|
||||
int status = curl_multi_perform(mc, &activeHandles);
|
||||
if (status != CURLM_OK) {
|
||||
panic("CURL processing failure");
|
||||
fail("curl_multi_perform failed, shutting down the HTTP worker");
|
||||
break;
|
||||
}
|
||||
|
||||
struct CURLMsg* message = curl_multi_info_read(mc, &messagesLeft);
|
||||
@@ -45,7 +55,12 @@ static void* curlWorker(void* data) {
|
||||
CURL* handle = message->easy_handle;
|
||||
InternalResponse* res = NULL;
|
||||
curl_easy_getinfo(handle, CURLINFO_PRIVATE, (char**)&res);
|
||||
curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &res->code);
|
||||
// PPSSPP: CURLINFO_RESPONSE_CODE writes a long, and res->code is an int -
|
||||
// upstream passed &res->code directly, which writes 8 bytes into 4 and only
|
||||
// gets away with it because the next field happens to absorb the zeroes.
|
||||
long responseCode = 0;
|
||||
curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &responseCode);
|
||||
res->code = (int)responseCode;
|
||||
res->complete = 1;
|
||||
curl_easy_cleanup(handle);
|
||||
}
|
||||
@@ -72,11 +87,19 @@ static void* curlWorker(void* data) {
|
||||
}
|
||||
|
||||
void naettPlatformInit(naettInitData initData) {
|
||||
if (!naettCurlLoad()) {
|
||||
return;
|
||||
}
|
||||
curl_global_init(CURL_GLOBAL_ALL);
|
||||
CURLM* mc = curl_multi_init();
|
||||
if (!mc) {
|
||||
fail("curl_multi_init failed");
|
||||
return;
|
||||
}
|
||||
int fds[2];
|
||||
if (pipe(fds) != 0) {
|
||||
panic("Failed to open pipe");
|
||||
fail("failed to open pipe");
|
||||
return;
|
||||
}
|
||||
handleReadFD = fds[0];
|
||||
handleWriteFD = fds[1];
|
||||
@@ -87,7 +110,10 @@ void naettPlatformInit(naettInitData initData) {
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
pthread_create(&workerThread, &attr, curlWorker, mc);
|
||||
workerRunning = 1;
|
||||
if (pthread_create(&workerThread, &attr, curlWorker, mc) != 0) {
|
||||
fail("failed to start the HTTP worker thread");
|
||||
}
|
||||
}
|
||||
|
||||
int naettPlatformInitRequest(InternalRequest* req) {
|
||||
@@ -121,19 +147,19 @@ static void setupMethod(CURL* curl, const char* method) {
|
||||
case METHOD('G', 'E', 'T'):
|
||||
case METHOD('C', 'O', 'N'):
|
||||
case METHOD('O', 'P', 'T'):
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L);
|
||||
break;
|
||||
case METHOD('P', 'O', 'S'):
|
||||
case METHOD('P', 'A', 'T'):
|
||||
case METHOD('D', 'E', 'L'):
|
||||
curl_easy_setopt(curl, CURLOPT_POST, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_POST, 1L);
|
||||
break;
|
||||
case METHOD('P', 'U', 'T'):
|
||||
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
|
||||
break;
|
||||
case METHOD('H', 'E', 'A'):
|
||||
case METHOD('T', 'R', 'A'):
|
||||
curl_easy_setopt(curl, CURLOPT_NOBODY, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -177,9 +203,17 @@ static size_t headerCallback(char* buffer, size_t size, size_t nitems, void* use
|
||||
void naettPlatformMakeRequest(InternalResponse* res) {
|
||||
InternalRequest* req = res->request;
|
||||
|
||||
if (!workerRunning) {
|
||||
// No libcurl, or the worker died. Complete the request as failed rather than
|
||||
// leaving the caller waiting forever on a request nobody is going to run.
|
||||
res->code = naettGenericError;
|
||||
res->complete = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
CURL* c = curl_easy_init();
|
||||
curl_easy_setopt(c, CURLOPT_URL, req->url);
|
||||
curl_easy_setopt(c, CURLOPT_CONNECTTIMEOUT_MS, req->options.timeoutMS);
|
||||
curl_easy_setopt(c, CURLOPT_CONNECTTIMEOUT_MS, (long)req->options.timeoutMS);
|
||||
|
||||
curl_easy_setopt(c, CURLOPT_READFUNCTION, readCallback);
|
||||
curl_easy_setopt(c, CURLOPT_READDATA, res);
|
||||
@@ -190,10 +224,10 @@ void naettPlatformMakeRequest(InternalResponse* res) {
|
||||
curl_easy_setopt(c, CURLOPT_HEADERFUNCTION, headerCallback);
|
||||
curl_easy_setopt(c, CURLOPT_HEADERDATA, res);
|
||||
|
||||
curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1);
|
||||
curl_easy_setopt(c, CURLOPT_FOLLOWLOCATION, 1L);
|
||||
|
||||
int bodySize = res->request->options.bodyReader(NULL, 0, res->request->options.bodyReaderData);
|
||||
curl_easy_setopt(c, CURLOPT_POSTFIELDSIZE, bodySize);
|
||||
curl_easy_setopt(c, CURLOPT_POSTFIELDSIZE, (long)bodySize);
|
||||
|
||||
setupMethod(c, req->options.method);
|
||||
|
||||
@@ -228,6 +262,10 @@ void naettPlatformFreeRequest(InternalRequest* req) {
|
||||
}
|
||||
|
||||
void naettPlatformCloseResponse(InternalResponse* res) {
|
||||
if (!naettCurlLoad()) {
|
||||
// Nothing was ever allocated by curl, and the function pointers are all null.
|
||||
return;
|
||||
}
|
||||
curl_slist_free_all(res->headerList);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user