Allow HTTP connectors to be reused without full restart, better X-Real-IP/X-Forwarded-For handling
This commit is contained in:
parent
1c539fbcd9
commit
9451ab5f11
3 changed files with 56 additions and 42 deletions
|
@ -2368,6 +2368,8 @@ namespace Mist{
|
||||||
return capa["name"].asStringRef();
|
return capa["name"].asStringRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Writes data to statConn once per second, or more often if force==true.
|
||||||
|
/// Also handles push status updates
|
||||||
void Output::stats(bool force){
|
void Output::stats(bool force){
|
||||||
// cancel stats update if not initialized
|
// cancel stats update if not initialized
|
||||||
if (!isInitialized){return;}
|
if (!isInitialized){return;}
|
||||||
|
|
|
@ -22,7 +22,9 @@ namespace Mist{
|
||||||
//General
|
//General
|
||||||
idleInterval = 0;
|
idleInterval = 0;
|
||||||
idleLast = 0;
|
idleLast = 0;
|
||||||
if (config->getString("ip").size()){myConn.setHost(config->getString("ip"));}
|
if (config->getString("ip").size()){
|
||||||
|
myConn.setHost(config->getString("ip"));
|
||||||
|
}
|
||||||
if (config->getString("prequest").size()){
|
if (config->getString("prequest").size()){
|
||||||
myConn.Received().prepend(config->getString("prequest"));
|
myConn.Received().prepend(config->getString("prequest"));
|
||||||
}
|
}
|
||||||
|
@ -47,11 +49,11 @@ namespace Mist{
|
||||||
capa["forward"]["ip"]["help"] = "IP of forwarded connection.";
|
capa["forward"]["ip"]["help"] = "IP of forwarded connection.";
|
||||||
capa["forward"]["ip"]["type"] = "str";
|
capa["forward"]["ip"]["type"] = "str";
|
||||||
capa["forward"]["ip"]["option"] = "--ip";
|
capa["forward"]["ip"]["option"] = "--ip";
|
||||||
capa["forward"]["ip"]["name"] = "Previous request";
|
capa["forward"]["prequest"]["name"] = "Previous request";
|
||||||
capa["forward"]["ip"]["help"] =
|
capa["forward"]["prequest"]["help"] =
|
||||||
"Data to pretend arrived on the socket before parsing the socket.";
|
"Data to pretend arrived on the socket before parsing the socket.";
|
||||||
capa["forward"]["ip"]["type"] = "str";
|
capa["forward"]["prequest"]["type"] = "str";
|
||||||
capa["forward"]["ip"]["option"] = "--prequest";
|
capa["forward"]["prequest"]["option"] = "--prequest";
|
||||||
cfg->addOption("streamname", JSON::fromString("{\"arg\":\"string\",\"short\":\"s\",\"long\":"
|
cfg->addOption("streamname", JSON::fromString("{\"arg\":\"string\",\"short\":\"s\",\"long\":"
|
||||||
"\"stream\",\"help\":\"The name of the stream "
|
"\"stream\",\"help\":\"The name of the stream "
|
||||||
"that this connector will transmit.\"}"));
|
"that this connector will transmit.\"}"));
|
||||||
|
@ -277,12 +279,15 @@ namespace Mist{
|
||||||
bool sawRequest = false;
|
bool sawRequest = false;
|
||||||
while (H.Read(myConn)){
|
while (H.Read(myConn)){
|
||||||
sawRequest = true;
|
sawRequest = true;
|
||||||
|
|
||||||
|
//First, figure out which handler we need to use
|
||||||
std::string handler = getHandler();
|
std::string handler = getHandler();
|
||||||
if (handler != capa["name"].asStringRef() || H.GetVar("stream") != streamName){
|
if (handler != capa["name"].asStringRef() || H.GetVar("stream") != streamName){
|
||||||
INFO_MSG("Received request: %s => %s (%s)", H.getUrl().c_str(), handler.c_str(), H.GetVar("stream").c_str());
|
INFO_MSG("Received request: %s => %s (%s)", H.getUrl().c_str(), handler.c_str(), H.GetVar("stream").c_str());
|
||||||
}else{
|
}else{
|
||||||
MEDIUM_MSG("Received request: %s => %s (%s)", H.getUrl().c_str(), handler.c_str(), H.GetVar("stream").c_str());
|
MEDIUM_MSG("Received request: %s => %s (%s)", H.getUrl().c_str(), handler.c_str(), H.GetVar("stream").c_str());
|
||||||
}
|
}
|
||||||
|
//None found? Abort the request with a 415 response status code.
|
||||||
if (!handler.size()){
|
if (!handler.size()){
|
||||||
H.Clean();
|
H.Clean();
|
||||||
H.SetHeader("Server", APPIDENT);
|
H.SetHeader("Server", APPIDENT);
|
||||||
|
@ -295,6 +300,32 @@ namespace Mist{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check the real and/or forwarded IP address if the proxy is trusted
|
||||||
|
// Warns if proxy is not trusted and these headers are set
|
||||||
|
fwdHostStr.clear();
|
||||||
|
fwdHostBin.clear();
|
||||||
|
if (H.hasHeader("X-Real-IP") || H.hasHeader("X-Forwarded-For")){
|
||||||
|
if (H.hasHeader("X-Real-IP")){
|
||||||
|
fwdHostStr = H.GetHeader("X-Real-IP");
|
||||||
|
}
|
||||||
|
if (H.hasHeader("X-Forwarded-For")){
|
||||||
|
fwdHostStr = H.GetHeader("X-Forwarded-For");
|
||||||
|
if (fwdHostStr.find(',') != std::string::npos){fwdHostStr.erase(fwdHostStr.find(','));}
|
||||||
|
}
|
||||||
|
std::string trueHostStr = Output::getConnectedHost();
|
||||||
|
if (!fwdHostStr.size() || !isTrustedProxy(trueHostStr)){
|
||||||
|
if (fwdHostStr.size() && fwdHostStr != trueHostStr){
|
||||||
|
WARN_MSG("Host %s is attempting to act as a proxy for %s, but not trusted", trueHostStr.c_str(), fwdHostStr.c_str());
|
||||||
|
}
|
||||||
|
fwdHostStr.clear();
|
||||||
|
}else{
|
||||||
|
Socket::Connection tmp;
|
||||||
|
tmp.setHost(fwdHostStr);
|
||||||
|
fwdHostBin = tmp.getBinHost();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
tkn.clear();
|
tkn.clear();
|
||||||
// Read the session token
|
// Read the session token
|
||||||
if (Comms::tknMode & 0x01){
|
if (Comms::tknMode & 0x01){
|
||||||
|
@ -327,12 +358,15 @@ namespace Mist{
|
||||||
if (handler != capa["name"].asStringRef() || H.GetVar("stream") != streamName || (statComm && (statComm.getHost() != getConnectedBinHost() || statComm.getTkn() != tkn))){
|
if (handler != capa["name"].asStringRef() || H.GetVar("stream") != streamName || (statComm && (statComm.getHost() != getConnectedBinHost() || statComm.getTkn() != tkn))){
|
||||||
MEDIUM_MSG("Switching from %s (%s) to %s (%s)", capa["name"].asStringRef().c_str(),
|
MEDIUM_MSG("Switching from %s (%s) to %s (%s)", capa["name"].asStringRef().c_str(),
|
||||||
streamName.c_str(), handler.c_str(), H.GetVar("stream").c_str());
|
streamName.c_str(), handler.c_str(), H.GetVar("stream").c_str());
|
||||||
|
//Prepare switch
|
||||||
|
disconnect();
|
||||||
streamName = H.GetVar("stream");
|
streamName = H.GetVar("stream");
|
||||||
userSelect.clear();
|
|
||||||
if (statComm){statComm.setStatus(COMM_STATUS_DISCONNECT | statComm.getStatus());}
|
if (handler != capa["name"].asStringRef()){
|
||||||
reConnector(handler);
|
reConnector(handler);
|
||||||
onFail("Server error - could not start connector", true);
|
onFail("Server error - could not start connector", true);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*LTS-START*/
|
/*LTS-START*/
|
||||||
|
@ -408,6 +442,7 @@ namespace Mist{
|
||||||
preHTTP();
|
preHTTP();
|
||||||
if (!myConn){return;}
|
if (!myConn){return;}
|
||||||
onHTTP();
|
onHTTP();
|
||||||
|
stats(true);
|
||||||
idleLast = Util::bootMS();
|
idleLast = Util::bootMS();
|
||||||
// Prevent the clean as well as the loop when we're in the middle of handling a request now
|
// Prevent the clean as well as the loop when we're in the middle of handling a request now
|
||||||
if (!wantRequest){return;}
|
if (!wantRequest){return;}
|
||||||
|
@ -930,10 +965,10 @@ namespace Mist{
|
||||||
if (H.url.size()){tmpPrequest = H.BuildRequest();}
|
if (H.url.size()){tmpPrequest = H.BuildRequest();}
|
||||||
int argnum = 0;
|
int argnum = 0;
|
||||||
argarr[argnum++] = (char *)tmparg.c_str();
|
argarr[argnum++] = (char *)tmparg.c_str();
|
||||||
std::string temphost = getConnectedHost();
|
|
||||||
std::string debuglevel = JSON::Value(Util::printDebugLevel).asString();
|
std::string debuglevel = JSON::Value(Util::printDebugLevel).asString();
|
||||||
|
std::string trueHostStr = Output::getConnectedHost();
|
||||||
argarr[argnum++] = (char *)"--ip";
|
argarr[argnum++] = (char *)"--ip";
|
||||||
argarr[argnum++] = (char *)(temphost.c_str());
|
argarr[argnum++] = (char *)(trueHostStr.c_str());
|
||||||
argarr[argnum++] = (char *)"--stream";
|
argarr[argnum++] = (char *)"--stream";
|
||||||
argarr[argnum++] = (char *)(streamName.c_str());
|
argarr[argnum++] = (char *)(streamName.c_str());
|
||||||
argarr[argnum++] = (char *)"--prequest";
|
argarr[argnum++] = (char *)"--prequest";
|
||||||
|
@ -950,38 +985,14 @@ namespace Mist{
|
||||||
execv(argarr[0], argarr);
|
execv(argarr[0], argarr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*LTS-START*/
|
|
||||||
std::string HTTPOutput::getConnectedHost(){
|
std::string HTTPOutput::getConnectedHost(){
|
||||||
std::string host = Output::getConnectedHost();
|
if (fwdHostStr.size()){return fwdHostStr;}
|
||||||
std::string xRealIp = H.GetHeader("X-Real-IP");
|
return Output::getConnectedHost();
|
||||||
|
|
||||||
if (!xRealIp.size() || !isTrustedProxy(host)){
|
|
||||||
static bool msg = false;
|
|
||||||
if (xRealIp.size() && !msg && xRealIp != host){
|
|
||||||
WARN_MSG("Host %s is attempting to act as a proxy, but not trusted", host.c_str());
|
|
||||||
msg = true;
|
|
||||||
}
|
|
||||||
return host;
|
|
||||||
}
|
|
||||||
return xRealIp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string HTTPOutput::getConnectedBinHost(){
|
std::string HTTPOutput::getConnectedBinHost(){
|
||||||
// Do first check with connected host because of simplicity
|
if (fwdHostBin.size()){return fwdHostBin;}
|
||||||
std::string host = Output::getConnectedHost();
|
return Output::getConnectedBinHost();
|
||||||
std::string xRealIp = H.GetHeader("X-Real-IP");
|
|
||||||
|
|
||||||
if (!xRealIp.size() || !isTrustedProxy(host)){
|
|
||||||
static bool msg = false;
|
|
||||||
if (xRealIp.size() && !msg && xRealIp != host){
|
|
||||||
WARN_MSG("Host %s is attempting to act as a proxy, but not trusted", host.c_str());
|
|
||||||
msg = true;
|
|
||||||
}
|
|
||||||
return Output::getConnectedBinHost();
|
|
||||||
}
|
|
||||||
|
|
||||||
Socket::Connection binConn;
|
|
||||||
binConn.setHost(xRealIp);
|
|
||||||
return binConn.getBinHost();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HTTPOutput::isTrustedProxy(const std::string &ip){
|
bool HTTPOutput::isTrustedProxy(const std::string &ip){
|
||||||
|
@ -1009,7 +1020,6 @@ namespace Mist{
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
/*LTS-END*/
|
|
||||||
|
|
||||||
/// Parses a "Range: " header, setting byteStart and byteEnd.
|
/// Parses a "Range: " header, setting byteStart and byteEnd.
|
||||||
/// Assumes byteStart and byteEnd are initialized to their minimum respectively maximum values
|
/// Assumes byteStart and byteEnd are initialized to their minimum respectively maximum values
|
||||||
|
|
|
@ -42,6 +42,8 @@ namespace Mist{
|
||||||
size_t prevVidTrack; ///< Previously selected main video track
|
size_t prevVidTrack; ///< Previously selected main video track
|
||||||
bool stayLive; ///< Whether or not we're trying to stay on the live-most point, for live streams
|
bool stayLive; ///< Whether or not we're trying to stay on the live-most point, for live streams
|
||||||
|
|
||||||
|
std::string fwdHostStr; ///< Forwarded string IP, if non-empty
|
||||||
|
std::string fwdHostBin; ///< Forwarded binary IP, if non-empty
|
||||||
bool responded;
|
bool responded;
|
||||||
HTTP::Parser H;
|
HTTP::Parser H;
|
||||||
HTTP::Websocket *webSock;
|
HTTP::Websocket *webSock;
|
||||||
|
|
Loading…
Add table
Reference in a new issue