mirror of
https://github.com/m1ngsama/TUT.git
synced 2025-12-24 10:51:46 +00:00
feat: Add HTTP/HTTPS client module
Implement HTTP client with libcurl for fetching web pages: - Support for HTTP and HTTPS protocols - Configurable timeout and user agent - Automatic redirect following - SSL certificate verification - Pimpl pattern for implementation hiding This module provides the foundation for web page retrieval in the terminal browser.
This commit is contained in:
parent
2d2711e250
commit
a2a2aa5126
2 changed files with 148 additions and 0 deletions
111
src/http_client.cpp
Normal file
111
src/http_client.cpp
Normal file
|
|
@ -0,0 +1,111 @@
|
||||||
|
#include "http_client.h"
|
||||||
|
#include <curl/curl.h>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
// 回调函数用于接收数据
|
||||||
|
static size_t write_callback(void* contents, size_t size, size_t nmemb, std::string* userp) {
|
||||||
|
size_t total_size = size * nmemb;
|
||||||
|
userp->append(static_cast<char*>(contents), total_size);
|
||||||
|
return total_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
class HttpClient::Impl {
|
||||||
|
public:
|
||||||
|
CURL* curl;
|
||||||
|
long timeout;
|
||||||
|
std::string user_agent;
|
||||||
|
bool follow_redirects;
|
||||||
|
|
||||||
|
Impl() : timeout(30),
|
||||||
|
user_agent("TUT-Browser/1.0 (Terminal User Interface Browser)"),
|
||||||
|
follow_redirects(true) {
|
||||||
|
curl = curl_easy_init();
|
||||||
|
if (!curl) {
|
||||||
|
throw std::runtime_error("Failed to initialize CURL");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~Impl() {
|
||||||
|
if (curl) {
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
HttpClient::HttpClient() : pImpl(std::make_unique<Impl>()) {}
|
||||||
|
|
||||||
|
HttpClient::~HttpClient() = default;
|
||||||
|
|
||||||
|
HttpResponse HttpClient::fetch(const std::string& url) {
|
||||||
|
HttpResponse response;
|
||||||
|
response.status_code = 0;
|
||||||
|
|
||||||
|
if (!pImpl->curl) {
|
||||||
|
response.error_message = "CURL not initialized";
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重置选项
|
||||||
|
curl_easy_reset(pImpl->curl);
|
||||||
|
|
||||||
|
// 设置URL
|
||||||
|
curl_easy_setopt(pImpl->curl, CURLOPT_URL, url.c_str());
|
||||||
|
|
||||||
|
// 设置写回调
|
||||||
|
std::string response_body;
|
||||||
|
curl_easy_setopt(pImpl->curl, CURLOPT_WRITEFUNCTION, write_callback);
|
||||||
|
curl_easy_setopt(pImpl->curl, CURLOPT_WRITEDATA, &response_body);
|
||||||
|
|
||||||
|
// 设置超时
|
||||||
|
curl_easy_setopt(pImpl->curl, CURLOPT_TIMEOUT, pImpl->timeout);
|
||||||
|
curl_easy_setopt(pImpl->curl, CURLOPT_CONNECTTIMEOUT, 10L);
|
||||||
|
|
||||||
|
// 设置用户代理
|
||||||
|
curl_easy_setopt(pImpl->curl, CURLOPT_USERAGENT, pImpl->user_agent.c_str());
|
||||||
|
|
||||||
|
// 设置是否跟随重定向
|
||||||
|
if (pImpl->follow_redirects) {
|
||||||
|
curl_easy_setopt(pImpl->curl, CURLOPT_FOLLOWLOCATION, 1L);
|
||||||
|
curl_easy_setopt(pImpl->curl, CURLOPT_MAXREDIRS, 10L);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 支持 HTTPS
|
||||||
|
curl_easy_setopt(pImpl->curl, CURLOPT_SSL_VERIFYPEER, 1L);
|
||||||
|
curl_easy_setopt(pImpl->curl, CURLOPT_SSL_VERIFYHOST, 2L);
|
||||||
|
|
||||||
|
// 执行请求
|
||||||
|
CURLcode res = curl_easy_perform(pImpl->curl);
|
||||||
|
|
||||||
|
if (res != CURLE_OK) {
|
||||||
|
response.error_message = curl_easy_strerror(res);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取响应码
|
||||||
|
long http_code = 0;
|
||||||
|
curl_easy_getinfo(pImpl->curl, CURLINFO_RESPONSE_CODE, &http_code);
|
||||||
|
response.status_code = static_cast<int>(http_code);
|
||||||
|
|
||||||
|
// 获取 Content-Type
|
||||||
|
char* content_type = nullptr;
|
||||||
|
curl_easy_getinfo(pImpl->curl, CURLINFO_CONTENT_TYPE, &content_type);
|
||||||
|
if (content_type) {
|
||||||
|
response.content_type = content_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
response.body = std::move(response_body);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpClient::set_timeout(long timeout_seconds) {
|
||||||
|
pImpl->timeout = timeout_seconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpClient::set_user_agent(const std::string& user_agent) {
|
||||||
|
pImpl->user_agent = user_agent;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpClient::set_follow_redirects(bool follow) {
|
||||||
|
pImpl->follow_redirects = follow;
|
||||||
|
}
|
||||||
37
src/http_client.h
Normal file
37
src/http_client.h
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
struct HttpResponse {
|
||||||
|
int status_code;
|
||||||
|
std::string body;
|
||||||
|
std::string content_type;
|
||||||
|
std::string error_message;
|
||||||
|
|
||||||
|
bool is_success() const {
|
||||||
|
return status_code >= 200 && status_code < 300;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class HttpClient {
|
||||||
|
public:
|
||||||
|
HttpClient();
|
||||||
|
~HttpClient();
|
||||||
|
|
||||||
|
// 获取网页内容
|
||||||
|
HttpResponse fetch(const std::string& url);
|
||||||
|
|
||||||
|
// 设置超时(秒)
|
||||||
|
void set_timeout(long timeout_seconds);
|
||||||
|
|
||||||
|
// 设置用户代理
|
||||||
|
void set_user_agent(const std::string& user_agent);
|
||||||
|
|
||||||
|
// 设置是否跟随重定向
|
||||||
|
void set_follow_redirects(bool follow);
|
||||||
|
|
||||||
|
private:
|
||||||
|
class Impl;
|
||||||
|
std::unique_ptr<Impl> pImpl;
|
||||||
|
};
|
||||||
Loading…
Reference in a new issue