diff --git a/doc/json_schema.json b/doc/json_schema.json index b08273fb6..4d3c09ce3 100644 --- a/doc/json_schema.json +++ b/doc/json_schema.json @@ -4078,7 +4078,7 @@ "const": "publicip" }, "url": { - "description": "URL of the public IP detection server to use. Only HTTP is supported\nIf empty, `http://ipinfo.io/json` is requested (`http://v6.ipinfo.io/json` when `ipv6` is set), with HTTP compression and TCP Fast Open enabled. A non-empty URL disables both and makes `ipv6` have no effect", + "description": "URL of the public IP detection server to use. Only HTTP is supported\nIf empty, `http://ipinfo.io/json` is requested (`http://v6.ipinfo.io/json` when `ipv6` is set), with TCP Fast Open enabled. A non-empty URL disables both and makes `ipv6` have no effect", "type": "string", "format": "url" }, diff --git a/src/common/impl/networking_common.c b/src/common/impl/networking_common.c index 732a011c9..9c6372183 100644 --- a/src/common/impl/networking_common.c +++ b/src/common/impl/networking_common.c @@ -1,197 +1,7 @@ -#include "fastfetch.h" -#include "common/library.h" #include "common/networking.h" #include "common/strutil.h" #include "common/debug.h" -#ifdef FF_HAVE_ZLIB - #include - -struct FFZlibLibrary { - FF_LIBRARY_SYMBOL(inflateInit2_) - FF_LIBRARY_SYMBOL(inflate) - FF_LIBRARY_SYMBOL(inflateEnd) - - bool inited; -} zlibData; - -const char* ffNetworkingLoadZlibLibrary(void) { - if (!zlibData.inited) { - zlibData.inited = true; - FF_LIBRARY_LOAD_MESSAGE(zlib, - #ifdef _WIN32 - "zlib1" - #else - "libz" - #endif - FF_LIBRARY_EXTENSION, - 2) - FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(zlib, zlibData, inflateInit2_) - FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(zlib, zlibData, inflate) - FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(zlib, zlibData, inflateEnd) - zlib = nullptr; // don't auto dlclose - } - return zlibData.ffinflateEnd == nullptr ? "Failed to load libz" : nullptr; -} - -// Try to pre-read gzip header to determine uncompressed size -static uint32_t guessGzipOutputSize(const void* data, uint32_t dataSize) { - // gzip file format: http://www.zlib.org/rfc-gzip.html - if (dataSize < 10 || ((const uint8_t*) data)[0] != 0x1f || ((const uint8_t*) data)[1] != 0x8b) { - return 0; - } - - // Uncompressed size in gzip format is stored in the last 4 bytes, but only valid if data is less than 4GB - if (dataSize > 18) { - // Get ISIZE value from the end of file (little endian) - const uint8_t* tail = (const uint8_t*) data + dataSize - 4; - uint32_t uncompressedSize = (uint32_t) tail[0] | ((uint32_t) tail[1] << 8u) | ((uint32_t) tail[2] << 16u) | ((uint32_t) tail[3] << 24u); - - // For valid gzip files, this value is the length of the uncompressed data modulo 2^32 - if (uncompressedSize > 0) { - FF_DEBUG("Read uncompressed size from GZIP trailer: %u bytes", uncompressedSize); - // Add some margin to the estimated size for safety - return uncompressedSize + 64; - } - } - - // If unable to get size from trailer or size is 0, use estimated value - // Typically, text data compression ratio is between 3-5x, we use the larger value - uint32_t estimatedSize = dataSize * 5; - FF_DEBUG("Unable to read exact uncompressed size, estimated as 5x of compressed data: %u bytes", estimatedSize); - return estimatedSize; -} - -// Decompress gzip content -bool ffNetworkingDecompressGzip(FFstrbuf* buffer, char* headerEnd) { - // `headerEnd` itself is non-null per the `nonnull(2)` contract; what it points to is not expressible as an attribute - assert(*headerEnd == '\r'); - - // Calculate header size - uint32_t headerSize = (uint32_t) (headerEnd - buffer->chars); - - *headerEnd = '\0'; // Replace delimiter with null character for easier processing - // Ensure Content-Encoding is in response headers, not in response body - bool hasGzip = strcasestr(buffer->chars, "\nContent-Encoding: gzip") != nullptr; - *headerEnd = '\r'; // Restore delimiter - - if (!hasGzip) { - FF_DEBUG("No gzip compressed content detected, skipping decompression"); - return true; - } - - FF_DEBUG("Gzip compressed content detected, preparing for decompression"); - - const char* bodyStart = headerEnd + 4; // Skip delimiter - - if (buffer->length <= headerSize + 4) { - // No content to decompress - FF_DEBUG("Compressed content size is 0, skipping decompression"); - return true; - } - - // Calculate compressed content size - uint32_t compressedSize = buffer->length - headerSize - 4; - - // Check if content is actually in gzip format (gzip header magic is 0x1f 0x8b) - if (compressedSize < 2 || (uint8_t) bodyStart[0] != 0x1f || (uint8_t) bodyStart[1] != 0x8b) { - FF_DEBUG("Content is not valid gzip format, skipping decompression"); - return false; - } - - // Predict uncompressed size - uint32_t estimatedSize = guessGzipOutputSize(bodyStart, compressedSize); - - // Create decompression buffer with estimated size - FF_STRBUF_AUTO_DESTROY decompressedBuffer = ffStrbufCreateA(estimatedSize > 0 ? estimatedSize : compressedSize * 5); - FF_DEBUG("Created decompression buffer: %u bytes", decompressedBuffer.allocated); - - // Initialize decompression - z_stream zs = { - .zalloc = Z_NULL, - .zfree = Z_NULL, - .opaque = Z_NULL, - .avail_in = (uInt) compressedSize, - .next_in = (Bytef*) bodyStart, - .avail_out = (uInt) ffStrbufGetFree(&decompressedBuffer), - .next_out = (Bytef*) decompressedBuffer.chars, - }; - - // Initialize decompression engine - if (zlibData.ffinflateInit2_(&zs, 16 + MAX_WBITS, ZLIB_VERSION, (int) sizeof(z_stream)) != Z_OK) { - FF_DEBUG("Failed to initialize decompression engine"); - return false; - } - uInt availableOut = zs.avail_out; - - // Perform decompression - int result = zlibData.ffinflate(&zs, Z_FINISH); - - // If output buffer is insufficient, try to extend buffer - while (result == Z_BUF_ERROR || (result != Z_STREAM_END && zs.avail_out == 0)) { - FF_DEBUG("Output buffer insufficient, trying to extend"); - - // Save already decompressed data amount - uint32_t alreadyDecompressed = (uint32_t) (availableOut - zs.avail_out); - decompressedBuffer.length += alreadyDecompressed; - decompressedBuffer.chars[decompressedBuffer.length] = '\0'; - - ffStrbufEnsureFree(&decompressedBuffer, decompressedBuffer.length / 2); - - // Set output parameters to point to new buffer - zs.avail_out = (uInt) ffStrbufGetFree(&decompressedBuffer); - zs.next_out = (Bytef*) (decompressedBuffer.chars + decompressedBuffer.length); - availableOut = zs.avail_out; - - // Decompress again - result = zlibData.ffinflate(&zs, Z_FINISH); - } - - // Check for decompression errors before using result - if (result != Z_STREAM_END) { - FF_DEBUG("Decompression failed with zlib error: %d", result); - zlibData.ffinflateEnd(&zs); - return false; - } - - zlibData.ffinflateEnd(&zs); - - // Calculate decompressed size (from the last inflate call) - uint32_t decompressedSize = (uint32_t) (availableOut - zs.avail_out); - decompressedBuffer.length += decompressedSize; - decompressedBuffer.chars[decompressedBuffer.length] = '\0'; - FF_DEBUG("Successfully decompressed %u bytes compressed data to %u bytes", compressedSize, decompressedBuffer.length); - - // Modify Content-Length header and remove Content-Encoding header - // Use decompressedBuffer.length (total) not decompressedSize (last chunk only) - FF_STRBUF_AUTO_DESTROY newBuffer = ffStrbufCreateA(headerSize + decompressedBuffer.length + 64); - - char* line = nullptr; - size_t len = 0; - while (ffStrbufGetline(&line, &len, buffer)) { - if (ffStrStartsWithIgnCase(line, "Content-Encoding:")) { - continue; - } else if (ffStrStartsWithIgnCase(line, "Content-Length:")) { - ffStrbufAppendF(&newBuffer, "Content-Length: %u\r\n", decompressedBuffer.length); - continue; - } else if (line[0] == '\r') { - ffStrbufAppendS(&newBuffer, "\r\n"); - ffStrbufGetlineRestore(&line, &len, buffer); - break; - } - - ffStrbufAppendS(&newBuffer, line); // Including the trailing \r - ffStrbufAppendC(&newBuffer, '\n'); - } - - ffStrbufAppend(&newBuffer, &decompressedBuffer); - ffStrbufDestroy(buffer); - ffStrbufInitMove(buffer, &newBuffer); - - return true; -} -#endif // FF_HAVE_ZLIB - const char* ffNetworkingFindHeader(const char* headers, uint32_t headerEnd, const char* name, uint32_t* valueLen) { uint32_t nameLen = (uint32_t) strlen(name); uint32_t pos = 0; diff --git a/src/common/impl/networking_linux.c b/src/common/impl/networking_linux.c index 04794483c..ebb13dfba 100644 --- a/src/common/impl/networking_linux.c +++ b/src/common/impl/networking_linux.c @@ -214,12 +214,6 @@ static const char* initNetworkingState(FFNetworkingState* state, const char* hos } ffStrbufAppendS(&state->command, "\r\nConnection: close\r\n"); // Explicitly tell the server we don't need to keep the connection - // If compression needs to be enabled - if (state->compression) { - FF_DEBUG("Enabling HTTP content compression"); - ffStrbufAppendS(&state->command, "Accept-Encoding: gzip\r\n"); - } - ffStrbufAppendS(&state->command, headers); ffStrbufAppendS(&state->command, "\r\n"); @@ -331,26 +325,6 @@ error: const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* host, uint16_t port, const char* path, const char* headers) { FF_DEBUG("Preparing to send HTTP request: host=%s, port=%u, path=%s", host, port, path); - if (state->compression) { - FF_DEBUG("Compression enabled, checking if zlib is available"); - -#ifdef FF_HAVE_ZLIB - const char* zlibError = ffNetworkingLoadZlibLibrary(); - // Only enable compression if zlib library is successfully loaded - if (zlibError == nullptr) { - FF_DEBUG("Successfully loaded zlib library, compression enabled"); - } else { - FF_DEBUG("Failed to load zlib library, compression disabled: %s", zlibError); - state->compression = false; - } -#else - FF_DEBUG("zlib not supported at build time, compression disabled"); - state->compression = false; -#endif - } else { - FF_DEBUG("Compression disabled"); - } - const char* initResult = initNetworkingState(state, host, port, path, headers); if (initResult != nullptr) { FF_DEBUG("Initialization failed: %s", initResult); @@ -612,18 +586,5 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf return "Content length mismatch"; } -// If compression was used, try to decompress -#ifdef FF_HAVE_ZLIB - if (state->compression) { - FF_DEBUG("Content received, checking if compressed"); - if (!ffNetworkingDecompressGzip(buffer, buffer->chars + headerEnd)) { - FF_DEBUG("Decompression failed or invalid compression format"); - return "Failed to decompress or invalid format"; - } else { - FF_DEBUG("Decompression successful or no decompression needed, total length after decompression: %u bytes", buffer->length); - } - } -#endif - return nullptr; } diff --git a/src/common/impl/networking_windows.c b/src/common/impl/networking_windows.c index 6aebe94bd..7c6995bd3 100644 --- a/src/common/impl/networking_windows.c +++ b/src/common/impl/networking_windows.c @@ -52,24 +52,6 @@ static const char* initWsaData(WSADATA* wsaData) { const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* host, uint16_t port, const char* path, const char* headers) { FF_DEBUG("Preparing to send HTTP request: host=%s, port=%u, path=%s", host, port, path); - if (state->compression) { -#ifdef FF_HAVE_ZLIB - const char* zlibError = ffNetworkingLoadZlibLibrary(); - // Only enable compression if zlib library is successfully loaded - if (zlibError == nullptr) { - FF_DEBUG("Successfully loaded zlib library, compression enabled"); - } else { - FF_DEBUG("Failed to load zlib library, compression disabled: %s", zlibError); - state->compression = false; - } -#else - FF_DEBUG("zlib not supported at build time, compression disabled"); - state->compression = false; -#endif - } else { - FF_DEBUG("Compression disabled"); - } - static WSADATA wsaData; if (wsaData.wVersion == 0) { const char* error = initWsaData(&wsaData); @@ -180,13 +162,6 @@ const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* ho ffStrbufAppendF(&state->command, ":%u", port); } ffStrbufAppendS(&state->command, "\r\nConnection: close\r\n"); // Explicitly request connection closure - - // Add compression support if enabled - if (state->compression) { - FF_DEBUG("Enabling HTTP content compression"); - ffStrbufAppendS(&state->command, "Accept-Encoding: gzip\r\n"); - } - ffStrbufAppendS(&state->command, headers); ffStrbufAppendS(&state->command, "\r\n"); @@ -441,18 +416,5 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf return "Content length mismatch"; } -// If compression was used, try to decompress -#ifdef FF_HAVE_ZLIB - if (state->compression) { - FF_DEBUG("Content received, checking if compressed"); - if (!ffNetworkingDecompressGzip(buffer, buffer->chars + headerEnd)) { - FF_DEBUG("Decompression failed or invalid compression format"); - return "Failed to decompress or invalid format"; - } else { - FF_DEBUG("Decompression successful or no decompression needed, total length after decompression: %u bytes", buffer->length); - } - } -#endif - return nullptr; } diff --git a/src/common/networking.h b/src/common/networking.h index 645787bd0..9b2876be4 100644 --- a/src/common/networking.h +++ b/src/common/networking.h @@ -25,7 +25,6 @@ typedef struct FFNetworkingState { FFstrbuf command; uint32_t timeout; bool ipv6; - bool compression; // if true, HTTP content compression will be enabled if supported bool tfo; // if true, TCP Fast Open will be attempted first, and fallback to traditional connection if it fails } FFNetworkingState; diff --git a/src/detection/publicip/publicip.c b/src/detection/publicip/publicip.c index cd850efdc..807d34be7 100644 --- a/src/detection/publicip/publicip.c +++ b/src/detection/publicip/publicip.c @@ -31,7 +31,6 @@ void ffPreparePublicIp(FFPublicIPOptions* options) { state->ipv6 = options->ipv6; if (options->url.length == 0) { - state->compression = true; state->tfo = true; *status = ffNetworkingSendHttpRequest(state, options->ipv6 ? "v6.ipinfo.io" : "ipinfo.io", 80, "/json", nullptr); } else {