ui布局自适应

This commit is contained in:
tianmo committed 2026-11-09 10:08:29 +08:00
1 parent 98f44890f8
commit 3587129b90
40 files changed
+929 -142

No files matched your search

+193 -12
View File
@@ -3,11 +3,18 @@
#include "encoding.hpp"
#include <algorithm>
#include <cerrno>
#include <cctype>
#include <cstring>
#include <fstream>
#include <sstream>
#include <thread>
#ifdef __APPLE__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
#ifdef _WIN32
#define NOMINMAX
#include <winsock2.h>
@@ -19,6 +26,11 @@ constexpr Socket kInvalidSocket = INVALID_SOCKET;
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#ifdef __APPLE__
#include <CoreFoundation/CoreFoundation.h>
#include <Security/SecImportExport.h>
#include <Security/SecureTransport.h>
#endif
using Socket = int;
constexpr Socket kInvalidSocket = -1;
#endif
@@ -37,6 +49,119 @@ void close_socket(Socket socket) {
#endif
}
struct ConnectionStream {
Socket socket = kInvalidSocket;
#ifdef __APPLE__
SSLContextRef tls = nullptr;
#endif
};
#ifdef __APPLE__
OSStatus socket_read(SSLConnectionRef reference, void* data, std::size_t* length) {
const Socket socket = *static_cast<const Socket*>(reference);
const long count = recv(socket, static_cast<char*>(data), static_cast<int>(*length), 0);
if (count > 0) {
*length = static_cast<std::size_t>(count);
return noErr;
}
*length = 0;
if (count == 0) return errSSLClosedGraceful;
return errno == EAGAIN || errno == EWOULDBLOCK ? errSSLWouldBlock : errSSLInternal;
}
OSStatus socket_write(SSLConnectionRef reference, const void* data, std::size_t* length) {
const Socket socket = *static_cast<const Socket*>(reference);
const long count = send(socket, static_cast<const char*>(data), static_cast<int>(*length), 0);
if (count > 0) {
*length = static_cast<std::size_t>(count);
return noErr;
}
*length = 0;
return errno == EAGAIN || errno == EWOULDBLOCK ? errSSLWouldBlock : errSSLInternal;
}
void* load_identity(const std::filesystem::path& path, std::string& error) {
std::ifstream input(path, std::ios::binary);
if (!input) {
error = "无法读取 HTTPS 身份证书";
return nullptr;
}
const std::string bytes((std::istreambuf_iterator<char>(input)), std::istreambuf_iterator<char>());
CFDataRef data = CFDataCreate(kCFAllocatorDefault, reinterpret_cast<const UInt8*>(bytes.data()),
static_cast<CFIndex>(bytes.size()));
const void* keys[] = {kSecImportExportPassphrase};
const void* values[] = {CFSTR("spine-connector-local")};
CFDictionaryRef options = CFDictionaryCreate(kCFAllocatorDefault, keys, values, 1,
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFArrayRef items = nullptr;
const OSStatus status = SecPKCS12Import(data, options, &items);
CFRelease(options);
CFRelease(data);
if (status != errSecSuccess || !items || CFArrayGetCount(items) == 0) {
if (items) CFRelease(items);
error = "无法读取 HTTPS 身份证书";
return nullptr;
}
CFDictionaryRef item = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(items, 0));
CFTypeRef identity = CFDictionaryGetValue(item, kSecImportItemIdentity);
if (identity) CFRetain(identity);
CFRelease(items);
if (!identity) error = "HTTPS 身份证书缺少私钥";
return const_cast<void*>(identity);
}
#endif
bool open_stream(ConnectionStream& stream, void* identity, std::string& error) {
if (!identity) return true;
#ifdef __APPLE__
SSLContextRef context = SSLCreateContext(kCFAllocatorDefault, kSSLServerSide, kSSLStreamType);
if (!context) {
error = "无法创建 HTTPS 服务";
return false;
}
SSLSetIOFuncs(context, socket_read, socket_write);
SSLSetConnection(context, &stream.socket);
SSLSetProtocolVersionMin(context, kTLSProtocol12);
const void* certificates[] = {identity};
CFArrayRef certificate_array = CFArrayCreate(kCFAllocatorDefault, certificates, 1, &kCFTypeArrayCallBacks);
const OSStatus certificate_status = SSLSetCertificate(context, certificate_array);
CFRelease(certificate_array);
if (certificate_status != noErr) {
CFRelease(context);
error = "无法配置 HTTPS 身份证书";
return false;
}
OSStatus status;
do {
status = SSLHandshake(context);
} while (status == errSSLWouldBlock);
if (status != noErr) {
CFRelease(context);
return false;
}
stream.tls = context;
return true;
#else
(void)stream;
error = "当前平台不支持 HTTPS 连接器";
return false;
#endif
}
void close_stream(ConnectionStream& stream) {
#ifdef __APPLE__
if (stream.tls) {
SSLClose(stream.tls);
CFRelease(stream.tls);
stream.tls = nullptr;
}
#endif
if (stream.socket != kInvalidSocket) {
close_socket(stream.socket);
stream.socket = kInvalidSocket;
}
}
std::string lowercase(std::string value) {
std::transform(value.begin(), value.end(), value.begin(), [](unsigned char c) { return static_cast<char>(std::tolower(c)); });
return value;
@@ -56,21 +181,49 @@ std::string status_text(int status) {
}
}
void send_all(Socket socket, const std::string& data) {
int read_stream(ConnectionStream& stream, char* buffer, int length) {
#ifdef __APPLE__
if (stream.tls) {
std::size_t received = 0;
const OSStatus status = SSLRead(stream.tls, buffer, static_cast<std::size_t>(length), &received);
if (status == errSSLClosedGraceful || status == errSSLClosedNoNotify) return static_cast<int>(received);
if (status != noErr && status != errSSLWouldBlock) return -1;
return static_cast<int>(received);
}
#endif
return recv(stream.socket, buffer, length, 0);
}
void send_all(ConnectionStream& stream, const std::string& data) {
std::size_t sent = 0;
while (sent < data.size()) {
const int count = send(socket, data.data() + sent, static_cast<int>((std::min)(data.size() - sent, static_cast<std::size_t>(1 << 20))), 0);
int count;
#ifdef __APPLE__
if (stream.tls) {
std::size_t written = 0;
const OSStatus status = SSLWrite(stream.tls, data.data() + sent,
(std::min)(data.size() - sent, static_cast<std::size_t>(1 << 20)), &written);
if (status != noErr && status != errSSLWouldBlock) return;
count = static_cast<int>(written);
} else {
count = send(stream.socket, data.data() + sent,
static_cast<int>((std::min)(data.size() - sent, static_cast<std::size_t>(1 << 20))), 0);
}
#else
count = send(stream.socket, data.data() + sent,
static_cast<int>((std::min)(data.size() - sent, static_cast<std::size_t>(1 << 20))), 0);
#endif
if (count <= 0) return;
sent += static_cast<std::size_t>(count);
}
}
bool parse_request(Socket socket, HttpRequest& request, int& error_status) {
bool parse_request(ConnectionStream& stream, HttpRequest& request, int& error_status) {
std::string buffer;
char chunk[8192];
std::size_t header_end = std::string::npos;
while ((header_end = buffer.find("\r\n\r\n")) == std::string::npos) {
const int count = recv(socket, chunk, sizeof(chunk), 0);
const int count = read_stream(stream, chunk, sizeof(chunk));
if (count <= 0) return false;
buffer.append(chunk, count);
if (buffer.size() > kMaxHeaders) { error_status = 413; return false; }
@@ -109,7 +262,7 @@ bool parse_request(Socket socket, HttpRequest& request, int& error_status) {
if (content_length > kMaxBody) { error_status = 413; return false; }
request.body = buffer.substr(header_end + 4);
while (request.body.size() < content_length) {
const int count = recv(socket, chunk, sizeof(chunk), 0);
const int count = read_stream(stream, chunk, sizeof(chunk));
if (count <= 0) return false;
request.body.append(chunk, count);
}
@@ -117,11 +270,20 @@ bool parse_request(Socket socket, HttpRequest& request, int& error_status) {
return true;
}
void serve_client(Socket client, const RequestHandler& handler) {
void serve_client(Socket client, void* identity, const RequestHandler& handler) {
ConnectionStream stream{client};
std::string tls_error;
if (!open_stream(stream, identity, tls_error)) {
close_stream(stream);
return;
}
HttpRequest request;
int error_status = 400;
HttpResponse response;
if (parse_request(client, request, error_status)) {
if (parse_request(stream, request, error_status)) {
#ifdef __APPLE__
request.secure = stream.tls != nullptr;
#endif
try { response = handler(request); }
catch (const std::exception& error) {
response.status = 500;
@@ -138,9 +300,9 @@ void serve_client(Socket client, const RequestHandler& handler) {
output << "HTTP/1.1 " << response.status << ' ' << status_text(response.status) << "\r\n";
for (const auto& [name, value] : response.headers) output << name << ": " << value << "\r\n";
output << "\r\n";
send_all(client, output.str());
send_all(client, response.body);
close_socket(client);
send_all(stream, output.str());
send_all(stream, response.body);
close_stream(stream);
}
} // namespace
@@ -148,8 +310,21 @@ void serve_client(Socket client, const RequestHandler& handler) {
HttpServer::HttpServer() = default;
HttpServer::~HttpServer() { stop(); }
bool HttpServer::start(unsigned short port, RequestHandler handler, std::string& error) {
bool HttpServer::start(unsigned short port, RequestHandler handler, std::string& error,
const std::filesystem::path& identity) {
if (running_) return true;
#ifdef __APPLE__
if (!identity.empty()) {
void* loaded = load_identity(identity, error);
if (loaded) tls_identity_ = std::shared_ptr<void>(loaded, [](void* value) { CFRelease(value); });
if (!tls_identity_) return false;
}
#else
if (!identity.empty()) {
error = "当前平台不支持 HTTPS 连接器";
return false;
}
#endif
#ifdef _WIN32
WSADATA data{};
if (WSAStartup(MAKEWORD(2, 2), &data) != 0) { error = "无法初始化网络服务"; return false; }
@@ -182,7 +357,9 @@ void HttpServer::accept_loop() {
if (running_) continue;
break;
}
std::thread(serve_client, client, handler_).detach();
std::thread([client, identity = tls_identity_, handler = handler_] {
serve_client(client, identity.get(), handler);
}).detach();
}
}
@@ -206,3 +383,7 @@ void HttpServer::stop() {
}
} // namespace connector
#ifdef __APPLE__
#pragma clang diagnostic pop
#endif