增加http代理功能 (#2988)

支持通过http代理拉流, 避免内外网复杂网络环境时需要专门配置防火墙,现在只需要配置一台代理内网的服务器.

---------

Co-authored-by: xia-chu <771730766@qq.com>
This commit is contained in:
alexliyu7352
2023-11-23 11:09:01 +08:00
committed by GitHub
parent a13b8417e5
commit d593267f61
11 changed files with 115 additions and 17 deletions

View File

@@ -22,6 +22,7 @@ HlsPlayer::HlsPlayer(const EventPoller::Ptr &poller) {
void HlsPlayer::play(const string &url) {
_play_result = false;
_play_url = url;
setProxyUrl((*this)[Client::kProxyUrl]);
fetchIndexFile();
}
@@ -88,6 +89,7 @@ void HlsPlayer::fetchSegment() {
weak_ptr<HlsPlayer> weak_self = static_pointer_cast<HlsPlayer>(shared_from_this());
if (!_http_ts_player) {
_http_ts_player = std::make_shared<HttpTSPlayer>(getPoller());
_http_ts_player->setProxyUrl((*this)[Client::kProxyUrl]);
_http_ts_player->setOnCreateSocket([weak_self](const EventPoller::Ptr &poller) {
auto strong_self = weak_self.lock();
if (strong_self) {

View File

@@ -78,12 +78,15 @@ void HttpClient::sendRequest(const string &url) {
printer.pop_back();
_header.emplace("Cookie", printer);
}
if (!alive() || host_changed) {
startConnect(host, port, _wait_header_ms / 1000.0f);
if (isUsedProxy()) {
startConnect(_proxy_host, _proxy_port, _wait_header_ms / 1000.0f);
} else {
SockException ex;
onConnect_l(ex);
if (!alive() || host_changed) {
startConnect(host, port, _wait_header_ms / 1000.0f);
} else {
SockException ex;
onConnect_l(ex);
}
}
}
@@ -158,15 +161,23 @@ void HttpClient::onConnect_l(const SockException &ex) {
onResponseCompleted_l(ex);
return;
}
_StrPrinter printer;
printer << _method + " " << _path + " HTTP/1.1\r\n";
for (auto &pr : _header) {
printer << pr.first + ": ";
printer << pr.second + "\r\n";
//不使用代理或者代理服务器已经连接成功
if (_proxy_connected || !isUsedProxy()) {
printer << _method + " " << _path + " HTTP/1.1\r\n";
for (auto &pr : _header) {
printer << pr.first + ": ";
printer << pr.second + "\r\n";
}
_header.clear();
_path.clear();
} else {
printer << "CONNECT " << _last_host << " HTTP/1.1\r\n";
printer << "Proxy-Connection: keep-alive\r\n";
if (!_proxy_auth.empty()) {
printer << "Proxy-Authorization: Basic " << _proxy_auth << "\r\n";
}
}
_header.clear();
_path.clear();
SockSender::send(printer << "\r\n");
onFlush();
}
@@ -401,4 +412,28 @@ void HttpClient::setCompleteTimeout(size_t timeout_ms) {
_wait_complete_ms = timeout_ms;
}
bool HttpClient::isUsedProxy() const {
return _used_proxy;
}
bool HttpClient::isProxyConnected() const {
return _proxy_connected;
}
void HttpClient::setProxyUrl(string proxy_url) {
_proxy_url = std::move(proxy_url);
if (!_proxy_url.empty()) {
parseProxyUrl(_proxy_url, _proxy_host, _proxy_port, _proxy_auth);
_used_proxy = true;
} else {
_used_proxy = false;
}
}
bool HttpClient::checkProxyConnected(const char *data, size_t len) {
auto ret = strstr(data, "HTTP/1.1 200 Connection established");
_proxy_connected = ret != nullptr;
return _proxy_connected;
}
} /* namespace mediakit */

View File

@@ -141,6 +141,11 @@ public:
*/
void setCompleteTimeout(size_t timeout_ms);
/**
* 设置http代理url
*/
void setProxyUrl(std::string proxy_url);
protected:
/**
* 收到http回复头
@@ -181,11 +186,16 @@ protected:
void onFlush() override;
void onManager() override;
void clearResponse();
bool checkProxyConnected(const char *data, size_t len);
bool isUsedProxy() const;
bool isProxyConnected() const;
private:
void onResponseCompleted_l(const toolkit::SockException &ex);
void onConnect_l(const toolkit::SockException &ex);
void checkCookie(HttpHeader &headers);
void clearResponse();
private:
//for http response
@@ -215,6 +225,13 @@ private:
toolkit::Ticker _wait_header;
toolkit::Ticker _wait_body;
toolkit::Ticker _wait_complete;
bool _used_proxy = false;
bool _proxy_connected = false;
uint16_t _proxy_port;
std::string _proxy_url;
std::string _proxy_host;
std::string _proxy_auth;
};
} /* namespace mediakit */

View File

@@ -15,13 +15,30 @@ using namespace toolkit;
namespace mediakit {
void HttpClientImp::onConnect(const SockException &ex) {
if (!isHttps()) {
//https 302跳转 http时需要关闭ssl
if (isUsedProxy() && !isProxyConnected()) {
// 连接代理服务器
setDoNotUseSSL();
HttpClient::onConnect(ex);
} else {
TcpClientWithSSL<HttpClient>::onConnect(ex);
if (!isHttps()) {
// https 302跳转 http时需要关闭ssl
setDoNotUseSSL();
HttpClient::onConnect(ex);
} else {
TcpClientWithSSL<HttpClient>::onConnect(ex);
}
}
}
ssize_t HttpClientImp::onRecvHeader(const char *data, size_t len) {
if (isUsedProxy() && !isProxyConnected()) {
if (checkProxyConnected(data, len)) {
clearResponse();
onConnect(SockException(Err_success, "proxy connected"));
return 0;
}
}
return HttpClient::onRecvHeader(data, len);
}
} /* namespace mediakit */

View File

@@ -24,6 +24,7 @@ public:
protected:
void onConnect(const toolkit::SockException &ex) override;
ssize_t onRecvHeader(const char *data, size_t len) override;
};
} /* namespace mediakit */

View File

@@ -21,6 +21,7 @@ void TsPlayer::play(const string &url) {
TraceL << "play http-ts: " << url;
_play_result = false;
_benchmark_mode = (*this)[Client::kBenchmarkMode].as<int>();
setProxyUrl((*this)[Client::kProxyUrl]);
setHeaderTimeout((*this)[Client::kTimeoutMS].as<int>());
setBodyTimeout((*this)[Client::kMediaTimeoutMS].as<int>());
setMethod("GET");