mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-22 02:34:26 +08:00
增加http代理功能 (#2988)
支持通过http代理拉流, 避免内外网复杂网络环境时需要专门配置防火墙,现在只需要配置一台代理内网的服务器. --------- Co-authored-by: xia-chu <771730766@qq.com>
This commit is contained in:
parent
a13b8417e5
commit
d593267f61
@ -11,7 +11,7 @@
|
||||
#include <cinttypes>
|
||||
#include "Parser.h"
|
||||
#include "strCoding.h"
|
||||
#include "macros.h"
|
||||
#include "Util/base64.h"
|
||||
#include "Network/sockutil.h"
|
||||
#include "Common/macros.h"
|
||||
|
||||
@ -325,6 +325,25 @@ void splitUrl(const std::string &url, std::string &host, uint16_t &port) {
|
||||
host = url.substr(0, pos);
|
||||
checkHost(host);
|
||||
}
|
||||
|
||||
void parseProxyUrl(const std::string &proxy_url, std::string &proxy_host, uint16_t &proxy_port, std::string &proxy_auth) {
|
||||
// 判断是否包含http://, 如果是则去掉
|
||||
std::string host;
|
||||
auto pos = proxy_url.find("://");
|
||||
if (pos != string::npos) {
|
||||
host = proxy_url.substr(pos + 3);
|
||||
} else {
|
||||
host = proxy_url;
|
||||
}
|
||||
// 判断是否包含用户名和密码
|
||||
pos = host.rfind('@');
|
||||
if (pos != string::npos) {
|
||||
proxy_auth = encodeBase64(host.substr(0, pos));
|
||||
host = host.substr(pos + 1, host.size());
|
||||
}
|
||||
splitUrl(host, proxy_host, proxy_port);
|
||||
}
|
||||
|
||||
#if 0
|
||||
//测试代码
|
||||
static onceToken token([](){
|
||||
|
@ -21,6 +21,8 @@ namespace mediakit {
|
||||
std::string findSubString(const char *buf, const char *start, const char *end, size_t buf_size = 0);
|
||||
// 把url解析为主机地址和端口号,兼容ipv4/ipv6/dns
|
||||
void splitUrl(const std::string &url, std::string &host, uint16_t &port);
|
||||
// 解析proxy url,仅支持http
|
||||
void parseProxyUrl(const std::string &proxy_url, std::string &proxy_host, uint16_t &proxy_port, std::string &proxy_auth);
|
||||
|
||||
struct StrCaseCompare {
|
||||
bool operator()(const std::string &__x, const std::string &__y) const { return strcasecmp(__x.data(), __y.data()) < 0; }
|
||||
|
@ -353,6 +353,7 @@ const string kBeatIntervalMS = "beat_interval_ms";
|
||||
const string kBenchmarkMode = "benchmark_mode";
|
||||
const string kWaitTrackReady = "wait_track_ready";
|
||||
const string kPlayTrack = "play_track";
|
||||
const string kProxyUrl = "proxy_url";
|
||||
} // namespace Client
|
||||
|
||||
} // namespace mediakit
|
||||
|
@ -403,6 +403,8 @@ extern const std::string kWaitTrackReady;
|
||||
// rtsp播放指定track,可选项有0(不指定,默认)、1(视频)、2(音频)
|
||||
// 设置方法:player[Client::kPlayTrack] = 0/1/2;
|
||||
extern const std::string kPlayTrack;
|
||||
//设置代理url,目前只支持http协议
|
||||
extern const std::string kProxyUrl;
|
||||
} // namespace Client
|
||||
} // namespace mediakit
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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");
|
||||
|
@ -22,6 +22,7 @@ FlvPlayer::FlvPlayer(const EventPoller::Ptr &poller) {
|
||||
void FlvPlayer::play(const string &url) {
|
||||
TraceL << "play http-flv: " << url;
|
||||
_play_result = false;
|
||||
setProxyUrl((*this)[Client::kProxyUrl]);
|
||||
setHeaderTimeout((*this)[Client::kTimeoutMS].as<int>());
|
||||
setBodyTimeout((*this)[Client::kMediaTimeoutMS].as<int>());
|
||||
setMethod("GET");
|
||||
|
Loading…
Reference in New Issue
Block a user