Static Webview - RTC - UDP - TCP - WSS

This commit is contained in:
2026-10-03 01:22:41 -07:00
parent 058104d93f
commit 75224df058
19 changed files with 1994 additions and 284 deletions

View File

@ -11,6 +11,7 @@
#include <chrono>
#include <sstream>
#include <algorithm>
#include <cctype>
#include <fstream>
#ifdef _WIN32
@ -299,14 +300,52 @@ namespace HttpRequestWrapper {
#ifdef DEBUG_NETWORK
kinc_log(KINC_LOG_LEVEL_INFO, "Destroying HTTP request client");
#endif
should_abort_ = true;
int s = active_socket_.exchange(-1);
if (s >= 0) {
#ifdef _WIN32
::shutdown(static_cast<SOCKET>(s), SD_BOTH);
#else
::shutdown(s, SHUT_RDWR);
#endif
}
if (request_future_.valid()) {
request_future_.wait();
}
#ifdef WITH_SSL
cleanupSSL();
#endif
if (isolate_ != nullptr) {
v8::Locker locker{isolate_};
v8::Isolate::Scope isolate_scope(isolate_);
v8::HandleScope handle_scope(isolate_);
on_ready_state_change_.Reset();
on_load_.Reset();
on_error_.Reset();
on_timeout_.Reset();
on_abort_.Reset();
on_progress_.Reset();
on_load_start_.Reset();
on_load_end_.Reset();
}
}
void HttpRequestClient::open(const std::string& method, const std::string& url, bool async) {
if (request_future_.valid()) {
should_abort_ = true;
int s = active_socket_.exchange(-1);
if (s >= 0) {
#ifdef _WIN32
::shutdown(static_cast<SOCKET>(s), SD_BOTH);
#else
::shutdown(s, SHUT_RDWR);
#endif
}
request_future_.wait();
}
std::lock_guard<std::mutex> lock(state_mutex_);
method_ = method;
url_ = url;
async_ = async;
@ -350,10 +389,11 @@ namespace HttpRequestWrapper {
#endif
request_data_ = data;
should_abort_ = false;
if (async_) {
// use thread pool
GlobalThreadPool::getInstance().enqueue([this]() {
request_future_ = GlobalThreadPool::getInstance().enqueue([this]() {
this->performRequest();
});
} else {
@ -364,11 +404,21 @@ namespace HttpRequestWrapper {
void HttpRequestClient::abort() {
std::lock_guard<std::mutex> lock(state_mutex_);
if (ready_state_ == DONE) {
return;
}
should_abort_ = true;
int s = active_socket_.exchange(-1);
if (s >= 0) {
#ifdef _WIN32
::shutdown(static_cast<SOCKET>(s), SD_BOTH);
#else
::shutdown(s, SHUT_RDWR);
#endif
}
setReadyState(DONE);
#ifdef DEBUG_NETWORK
kinc_log(KINC_LOG_LEVEL_INFO, "HTTP request aborted");
@ -437,6 +487,26 @@ namespace HttpRequestWrapper {
on_load_end_.Reset(isolate_, callback);
}
static size_t response_end(const std::string& response, const std::string& method) {
size_t header_end = response.find("\r\n\r\n");
if (header_end == std::string::npos) return std::string::npos;
std::string lower(response, 0, header_end);
for (char& c : lower) c = (char)std::tolower((unsigned char)c);
int status = atoi(lower.c_str() + lower.find(' ') + 1);
if (status == 204 || status == 304 || method == "HEAD" || method == "head") {
return header_end + 4;
}
size_t pos = lower.find("content-length:");
if (pos != std::string::npos) {
return header_end + 4 + strtoull(lower.c_str() + pos + 15, nullptr, 10);
}
if (lower.find("transfer-encoding:") != std::string::npos) {
size_t term = response.find("0\r\n\r\n", header_end + 4);
return term == std::string::npos ? std::string::npos : term + 5;
}
return std::string::npos;
}
void HttpRequestClient::performRequest() {
active_operation_ = true;
@ -497,7 +567,8 @@ namespace HttpRequestWrapper {
#ifdef DEBUG_NETWORK
kinc_log(KINC_LOG_LEVEL_INFO, "Acquiring connection for HTTP request");
#endif
SOCKET sock = g_connection_pool.acquire_connection(host, port, is_https);
SOCKET sock = g_connection_pool.acquire_connection(host, port, is_https, &should_abort_);
active_socket_ = static_cast<int>(sock);
if (sock == INVALID_SOCKET) {
response_.error = "Failed to acquire connection";
#ifdef DEBUG_NETWORK
@ -523,27 +594,36 @@ namespace HttpRequestWrapper {
::setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
#endif
}
#ifdef DEBUG_NETWORK
kinc_log(KINC_LOG_LEVEL_INFO, "Connected successfully to %s:%d", host.c_str(), port);
#endif
#ifdef WITH_SSL
if (is_https) {
#ifdef DEBUG_NETWORK
kinc_log(KINC_LOG_LEVEL_INFO, "Performing SSL handshake");
#endif
ssl_socket_ = static_cast<int>(sock);
if (!performSSLHandshake(static_cast<int>(sock), host)) {
response_.error = "SSL handshake failed";
active_socket_ = -1;
closesocket(sock);
setReadyState(DONE);
handleError(response_.error);
active_operation_ = false;
return;
}
#ifdef DEBUG_NETWORK
kinc_log(KINC_LOG_LEVEL_INFO, "SSL handshake completed successfully");
#endif
}
#endif
std::string request_data = formatHttpRequest(method_, path, host, request_data_);
#ifdef DEBUG_NETWORK
kinc_log(KINC_LOG_LEVEL_INFO, "Sending HTTP request (%zu bytes):", request_data.length());
kinc_log(KINC_LOG_LEVEL_INFO, "Request preview: %.200s", request_data.c_str());
#endif
int bytes_sent = 0;
#ifdef WITH_SSL
@ -565,20 +645,34 @@ namespace HttpRequestWrapper {
return;
}
#ifdef DEBUG_NETWORK
kinc_log(KINC_LOG_LEVEL_INFO, "HTTP request sent successfully");
#endif
char buffer[4096];
int bytes_received;
std::string response_data;
int total_bytes = 0;
bool body_complete = false;
#ifdef DEBUG_NETWORK
kinc_log(KINC_LOG_LEVEL_INFO, "Starting to receive HTTP response");
#endif
while (true) {
size_t end = response_end(response_data, method_);
if (end != std::string::npos && response_data.size() >= end) {
body_complete = true;
break;
}
#ifdef WITH_SSL
if (is_https) {
#ifdef DEBUG_NETWORK
kinc_log(KINC_LOG_LEVEL_INFO, "Calling sslRead for %zu bytes", sizeof(buffer) - 1);
#endif
bytes_received = sslRead(buffer, sizeof(buffer) - 1);
#ifdef DEBUG_NETWORK
kinc_log(KINC_LOG_LEVEL_INFO, "sslRead returned %d bytes", bytes_received);
#endif
} else {
bytes_received = ::recv(sock, buffer, sizeof(buffer) - 1, 0);
}
@ -587,16 +681,21 @@ namespace HttpRequestWrapper {
#endif
if (bytes_received <= 0) {
#ifdef DEBUG_NETWORK
kinc_log(KINC_LOG_LEVEL_INFO, "Breaking from response reading loop, bytes_received: %d", bytes_received);
#endif
break;
}
buffer[bytes_received] = '\0';
response_data += buffer;
response_data.append(buffer, bytes_received);
total_bytes += bytes_received;
#ifdef DEBUG_NETWORK
kinc_log(KINC_LOG_LEVEL_INFO, "Received %d bytes (total: %d)", bytes_received, total_bytes);
#endif
}
#ifdef DEBUG_NETWORK
kinc_log(KINC_LOG_LEVEL_INFO, "Finished receiving data, total bytes: %d", total_bytes);
#endif
#ifdef WITH_SSL
if (is_https) {
@ -604,24 +703,40 @@ namespace HttpRequestWrapper {
}
#endif
// return connection to pool for reuse instead of closing
g_connection_pool.release_connection(host, port, sock, is_https);
active_socket_ = -1;
if (bytes_received == SOCKET_ERROR) {
response_.error = "Failed to receive response";
closesocket(sock);
setReadyState(DONE);
handleError(response_.error);
active_operation_ = false;
return;
}
if (should_abort_.load()) {
closesocket(sock);
active_operation_ = false;
return;
}
if (body_complete) {
g_connection_pool.release_connection(host, port, sock, is_https);
} else {
closesocket(sock);
}
#ifdef DEBUG_NETWORK
kinc_log(KINC_LOG_LEVEL_INFO, "Raw HTTP response data (%zu bytes):", response_data.length());
kinc_log(KINC_LOG_LEVEL_INFO, "Response preview: %.200s", response_data.c_str());
#endif
parseHttpResponse(response_data);
#ifdef DEBUG_NETWORK
kinc_log(KINC_LOG_LEVEL_INFO, "Parsed response - status: %d, body length: %zu", response_.status, response_.responseText.length());
kinc_log(KINC_LOG_LEVEL_INFO, "Response body preview: %.200s", response_.responseText.c_str());
#endif
setReadyState(HEADERS_RECEIVED);
@ -661,6 +776,7 @@ namespace HttpRequestWrapper {
}
void HttpRequestClient::handleError(const std::string& error) {
if (should_abort_.load()) return; // abort() already fired its event
std::lock_guard<std::mutex> lock(event_queue_mutex_);
event_queue_.push(Event(HTTP_ERROR, error));
}
@ -832,7 +948,9 @@ namespace HttpRequestWrapper {
bool HttpRequestClient::parseUrl(const std::string& url, std::string& host, int& port, std::string& path, bool& is_https) {
if (url.find("://") == std::string::npos) {
#ifdef DEBUG_NETWORK
kinc_log(KINC_LOG_LEVEL_INFO, "Detected local file path: %s", url.c_str());
#endif
host = "localhost";
port = 0;
path = url;
@ -841,7 +959,9 @@ namespace HttpRequestWrapper {
}
if (url.substr(0, 7) == "file://") {
#ifdef DEBUG_NETWORK
kinc_log(KINC_LOG_LEVEL_INFO, "Detected file:// URL: %s", url.c_str());
#endif
host = "localhost";
port = 0; // Special port to indicate local file
path = url.substr(7); // Remove "file://" prefix
@ -852,7 +972,9 @@ namespace HttpRequestWrapper {
std::regex url_regex(R"(^(https?):\/\/([^\/\s:]+)(?::(\d+))?(\/[^\s]*)?(?:\?[^\s]*)?(?:#[^\s]*)?$)");
std::smatch matches;
#ifdef DEBUG_NETWORK
kinc_log(KINC_LOG_LEVEL_INFO, "Parsing HTTP URL: %s", url.c_str());
#endif
if (!std::regex_match(url, matches, url_regex)) {
// fallback parsing for simpler URLs
@ -900,8 +1022,10 @@ namespace HttpRequestWrapper {
port = is_https ? 443 : 80;
}
kinc_log(KINC_LOG_LEVEL_INFO, "URL parsed successfully - scheme: %s, host: %s, port: %d, path: %s",
#ifdef DEBUG_NETWORK
kinc_log(KINC_LOG_LEVEL_INFO, "URL parsed successfully - scheme: %s, host: %s, port: %d, path: %s",
scheme.c_str(), host.c_str(), port, path.c_str());
#endif
return true;
}
@ -911,7 +1035,7 @@ namespace HttpRequestWrapper {
request << method << " " << path << " HTTP/1.1\r\n";
request << "Host: " << host << "\r\n";
request << "Connection: close\r\n";
request << "Connection: keep-alive\r\n";
request << "User-Agent: LNXCORE/1.0\r\n";
request << "Accept: */*\r\n";
request << "Accept-Encoding: identity\r\n";
@ -935,8 +1059,10 @@ namespace HttpRequestWrapper {
}
std::string request_str = request.str();
#ifdef DEBUG_NETWORK
kinc_log(KINC_LOG_LEVEL_INFO, "Formatted HTTP request (%zu bytes):", request_str.length());
kinc_log(KINC_LOG_LEVEL_INFO, "Request headers: %s", request_str.substr(0, request_str.find("\r\n\r\n")).c_str());
#endif
return request_str;
}
@ -1011,11 +1137,15 @@ namespace HttpRequestWrapper {
response_.headers[header_name] = header_value;
header_count++;
#ifdef DEBUG_NETWORK
kinc_log(KINC_LOG_LEVEL_INFO, "Header: %s = %s", header_name.c_str(), header_value.c_str());
#endif
}
}
#ifdef DEBUG_NETWORK
kinc_log(KINC_LOG_LEVEL_INFO, "Parsed %d headers", header_count);
#endif
std::ostringstream body_stream;
std::string body_line;
@ -1030,12 +1160,16 @@ namespace HttpRequestWrapper {
}
response_.responseText = body_stream.str();
#ifdef DEBUG_NETWORK
kinc_log(KINC_LOG_LEVEL_INFO, "Parsed body: %zu lines, %zu bytes", body_lines, response_.responseText.length());
#endif
#ifdef DEBUG_NETWORK
if (!response_.responseText.empty()) {
std::string preview = response_.responseText.substr(0, 100);
kinc_log(KINC_LOG_LEVEL_INFO, "Response body preview: %s", preview.c_str());
}
#endif
}
void HttpRequestClient::loadLocalFile(const std::string& path) {
@ -2394,4 +2528,4 @@ void bind_httprequest_class(Isolate* isolate, const Global<Context>& context) {
global->Set(current_context, String::NewFromUtf8(isolate, "XMLHttpRequest").ToLocalChecked(), xhrFunc);
}
#endif
#endif