Completed new sessions system

Co-authored-by: Thulinma <jaron@vietors.com>
This commit is contained in:
Marco van Dijk 2022-03-16 13:46:14 +01:00 committed by Thulinma
parent 074e757028
commit 8ac486b815
36 changed files with 991 additions and 620 deletions

View file

@ -92,7 +92,7 @@ namespace Mist{
firstTime = 0;
firstPacketTime = 0xFFFFFFFFFFFFFFFFull;
lastPacketTime = 0;
sid = "";
tkn = "";
parseData = false;
wantRequest = true;
sought = false;
@ -111,7 +111,6 @@ namespace Mist{
lastPushUpdate = 0;
previousFile = "";
currentFile = "";
sessionMode = 0xFFFFFFFFFFFFFFFFull;
lastRecv = Util::bootSecs();
if (myConn){
@ -230,7 +229,7 @@ namespace Mist{
bool Output::isReadyForPlay(){
// If a protocol does not support any codecs, we assume you know what you're doing
if (!capa.isMember("codecs")){return true;}
if (!isInitialized){initialize();}
if (!isInitialized){return false;}
meta.reloadReplacedPagesIfNeeded();
if (getSupportedTracks().size()){
size_t minTracks = 2;
@ -277,6 +276,7 @@ namespace Mist{
/// Assumes streamName class member has been set already.
/// Will start input if not currently active, calls onFail() if this does not succeed.
void Output::reconnect(){
Comms::sessionConfigCache();
thisPacket.null();
if (config->hasOption("noinput") && config->getBool("noinput")){
Util::sanitizeName(streamName);
@ -347,11 +347,10 @@ namespace Mist{
isInitialized = true;
//Connect to stats reporting, if not connected already
if (!statComm){
statComm.reload(streamName, getConnectedHost(), sid, capa["name"].asStringRef(), reqUrl, sessionMode);
stats(true);
}
stats(true);
//Abort if the stats code shut us down just now
if (!isInitialized){return;}
//push inputs do not need to wait for stream to be ready for playback
if (isPushing()){return;}
@ -1216,7 +1215,7 @@ namespace Mist{
/// request URL (if any)
/// ~~~~~~~~~~~~~~~
int Output::run(){
sessionMode = Util::getGlobalConfig("sessionMode").asInt();
Comms::sessionConfigCache();
/*LTS-START*/
// Connect to file target, if needed
if (isFileTarget()){
@ -1257,6 +1256,7 @@ namespace Mist{
/*LTS-END*/
DONTEVEN_MSG("MistOut client handler started");
while (keepGoing() && (wantRequest || parseData)){
Comms::sessionConfigCache();
if (wantRequest){requestHandler();}
if (parseData){
if (!isInitialized){
@ -1779,27 +1779,35 @@ namespace Mist{
}
}
if (!statComm){statComm.reload(streamName, getConnectedHost(), sid, capa["name"].asStringRef(), reqUrl, sessionMode);}
if (!statComm){return;}
if (statComm.getExit()){
onFail("Shutting down since this session is not allowed to view this stream");
return;
// Disable stats for HTTP internal output
if (Comms::sessionStreamInfoMode == SESS_HTTP_DISABLED && capa["name"].asStringRef() == "HTTP"){return;}
// Set the token to the pid for outputs which do not generate it in the requestHandler
if (!tkn.size()){ tkn = JSON::Value(getpid()).asString(); }
if (!statComm){
statComm.reload(streamName, getConnectedBinHost(), tkn, getStatsName(), reqUrl);
}
if (!statComm || statComm.getExit()){
onFail("Shutting down since this session is not allowed to view this stream");
statComm.unload();
return;
}
lastStats = now;
VERYHIGH_MSG("Writing stats: %s, %s, %s, %" PRIu64 ", %" PRIu64, getConnectedHost().c_str(), streamName.c_str(),
sid.c_str(), myConn.dataUp(), myConn.dataDown());
tkn.c_str(), myConn.dataUp(), myConn.dataDown());
/*LTS-START*/
if (statComm.getStatus() & COMM_STATUS_REQDISCONNECT){
onFail("Shutting down on controller request");
statComm.unload();
return;
}
/*LTS-END*/
statComm.setNow(now);
statComm.setConnector(getStatsName());
connStats(now, statComm);
statComm.setLastSecond(thisPacket ? thisPacket.getTime() : 0);
statComm.setLastSecond(thisPacket ? thisPacket.getTime()/1000 : 0);
statComm.setPid(getpid());
/*LTS-START*/

View file

@ -130,8 +130,7 @@ namespace Mist{
Comms::Connections statComm;
bool isBlocking; ///< If true, indicates that myConn is blocking.
std::string sid; ///< Random identifier used to split connections into sessions
uint64_t sessionMode;
std::string tkn; ///< Random identifier used to split connections into sessions
uint64_t nextKeyTime();
// stream delaying variables

View file

@ -222,24 +222,17 @@ namespace Mist{
void OutCMAF::sendHlsMasterManifest(){
selectDefaultTracks();
std::string sessId = "";
if (hasSessionIDs()){
std::string ua = UA + JSON::Value(getpid()).asString();
crc = checksum::crc32(0, ua.data(), ua.size());
sessId = JSON::Value(crc).asString();
}
// check for forced "no low latency" parameter
bool noLLHLS = H.GetVar("llhls").size() ? H.GetVar("llhls") == "0" : false;
// Populate the struct that will help generate the master playlist
const HLS::MasterData masterData ={
hasSessionIDs(),
false,//hasSessionIDs, unused
noLLHLS,
hlsMediaFormat == ".ts",
getMainSelectedTrack(),
H.GetHeader("User-Agent"),
sessId,
(Comms::tknMode & 0x04)?tkn:"",
systemBoot,
bootMsOffset,
};
@ -261,11 +254,8 @@ namespace Mist{
// Chunkpath & Session ID logic
std::string urlPrefix = "";
std::string sessId = "";
if (config->getString("chunkpath").size()){
urlPrefix = HTTP::URL(config->getString("chunkpath")).link("./" + H.url).link("./").getUrl();
}else{
sessId = H.GetVar("sessId");
}
// check for forced "no low latency" parameter
@ -279,7 +269,7 @@ namespace Mist{
noLLHLS,
hlsMediaFormat,
M.getEncryption(requestTid),
sessId,
(Comms::tknMode & 0x04)?tkn:"",
timingTid,
requestTid,
M.biggestFragment(timingTid) / 1000,
@ -346,6 +336,16 @@ namespace Mist{
std::string url = H.url.substr(H.url.find('/', 6) + 1);
HTTP::URL req(reqUrl);
if (tkn.size()){
if (Comms::tknMode & 0x08){
const std::string koekjes = H.GetHeader("Cookie");
std::stringstream cookieHeader;
cookieHeader << "tkn=" << tkn << "; Max-Age=" << SESS_TIMEOUT;
H.SetHeader("Set-Cookie", cookieHeader.str());
}
}
// Send a dash manifest for any URL with .mpd in the path
if (req.getExt() == "mpd"){
sendDashManifest();
@ -438,6 +438,7 @@ namespace Mist{
H.SendResponse("400", "Bad Request: Could not parse the url", myConn);
return;
}
std::string headerData =
CMAF::keyHeader(M, idx, startTime, targetTime, fragmentIndex, false, false);

View file

@ -11,7 +11,7 @@ const std::string hlsMediaFormat = ".ts";
namespace Mist{
bool OutHLS::isReadyForPlay(){
if (!isInitialized){initialize();}
if (!isInitialized){return false;}
meta.reloadReplacedPagesIfNeeded();
if (!M.getValidTracks().size()){return false;}
uint32_t mainTrack = M.mainTrack();
@ -110,25 +110,17 @@ namespace Mist{
///\return The master playlist file for (LL)HLS.
void OutHLS::sendHlsMasterManifest(){
selectDefaultTracks();
std::string sessId = "";
if (hasSessionIDs()){
std::string ua = UA + JSON::Value(getpid()).asString();
crc = checksum::crc32(0, ua.data(), ua.size());
sessId = JSON::Value(crc).asString();
}
// check for forced "no low latency" parameter
bool noLLHLS = H.GetVar("llhls").size() ? H.GetVar("llhls") == "0" : false;
// Populate the struct that will help generate the master playlist
const HLS::MasterData masterData ={
hasSessionIDs(),
false,//hasSessionIDs, unused
noLLHLS,
hlsMediaFormat == ".ts",
getMainSelectedTrack(),
H.GetHeader("User-Agent"),
sessId,
(Comms::tknMode & 0x04)?tkn:"",
systemBoot,
bootMsOffset,
};
@ -150,11 +142,8 @@ namespace Mist{
// Chunkpath & Session ID logic
std::string urlPrefix = "";
std::string sessId = "";
if (config->getString("chunkpath").size()){
urlPrefix = HTTP::URL(config->getString("chunkpath")).link("./" + H.url).link("./").getUrl();
}else{
sessId = H.GetVar("sessId");
}
// check for forced "no low latency" parameter
@ -168,7 +157,7 @@ namespace Mist{
noLLHLS,
hlsMediaFormat,
M.getEncryption(requestTid),
sessId,
(Comms::tknMode & 0x04)?tkn:"",
timingTid,
requestTid,
M.biggestFragment(timingTid) / 1000,
@ -226,6 +215,15 @@ namespace Mist{
bootMsOffset = 0;
if (M.getLive()){bootMsOffset = M.getBootMsOffset();}
if (tkn.size()){
if (Comms::tknMode & 0x08){
const std::string koekjes = H.GetHeader("Cookie");
std::stringstream cookieHeader;
cookieHeader << "tkn=" << tkn << "; Max-Age=" << SESS_TIMEOUT;
H.SetHeader("Set-Cookie", cookieHeader.str());
}
}
if (H.url == "/crossdomain.xml"){
H.SetHeader("Content-Type", "text/xml");
H.SetHeader("Server", APPIDENT);

View file

@ -217,7 +217,9 @@ namespace Mist{
myConn.close();
return;
}
if (handler != capa["name"].asStringRef() || H.GetVar("stream") != streamName){
//Check if we need to change binary and/or reconnect
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(),
streamName.c_str(), handler.c_str(), H.GetVar("stream").c_str());
streamName = H.GetVar("stream");
@ -268,21 +270,32 @@ namespace Mist{
realTime = 0;
}
}
// Get session ID cookie or generate a random one if it wasn't set
if (!sid.size()){
// Read the session token
if (Comms::tknMode & 0x01){
// Get session token from the request url
if (H.GetVar("tkn") != ""){
tkn = H.GetVar("tkn");
} else if (H.GetVar("sid") != ""){
tkn = H.GetVar("sid");
} else if (H.GetVar("sessId") != ""){
tkn = H.GetVar("sessId");
}
}
if ((Comms::tknMode & 0x02) && !tkn.size()){
// Get session token from the request cookie
std::map<std::string, std::string> storage;
const std::string koekjes = H.GetHeader("Cookie");
HTTP::parseVars(koekjes, storage);
if (storage.count("sid")){
// Get sid cookie, which is used to divide connections into sessions
sid = storage.at("sid");
}else{
// Else generate one
const std::string newSid = UA + JSON::Value(getpid()).asString();
sid = JSON::Value(checksum::crc32(0, newSid.data(), newSid.size())).asString();
H.SetHeader("sid", sid.c_str());
HTTP::parseVars(koekjes, storage, "; ");
if (storage.count("tkn")){
tkn = storage.at("tkn");
}
}
// Generate a session token if it is being sent as a cookie or url parameter and we couldn't read one
if (!tkn.size() && Comms::tknMode > 3){
const std::string newTkn = UA + JSON::Value(getpid()).asString();
tkn = JSON::Value(checksum::crc32(0, newTkn.data(), newTkn.size())).asString();
HIGH_MSG("Generated tkn '%s'", tkn.c_str());
}
// Handle upgrade to websocket if the output supports it
std::string upgradeHeader = H.GetHeader("Upgrade");
Util::stringToLower(upgradeHeader);
@ -290,7 +303,9 @@ namespace Mist{
INFO_MSG("Switching to Websocket mode");
setBlocking(false);
preWebsocketConnect();
webSock = new HTTP::Websocket(myConn, H);
HTTP::Parser req = H;
H.Clean();
webSock = new HTTP::Websocket(myConn, req, H);
if (!(*webSock)){
delete webSock;
webSock = 0;
@ -333,6 +348,14 @@ namespace Mist{
void HTTPOutput::respondHTTP(const HTTP::Parser & req, bool headersOnly){
//We generally want the CORS headers to be set for all responses
H.setCORSHeaders();
H.SetHeader("Server", APPIDENT);
if (tkn.size()){
if (Comms::tknMode & 0x08){
std::stringstream cookieHeader;
cookieHeader << "tkn=" << tkn << "; Max-Age=" << SESS_TIMEOUT;
H.SetHeader("Set-Cookie", cookieHeader.str());
}
}
//Set attachment header to force download, if applicable
if (req.GetVar("dl").size()){
//If we want to download, and the string contains a dot, use as-is.
@ -395,6 +418,8 @@ namespace Mist{
///\brief Handles requests by starting a corresponding output process.
///\param connector The type of connector to be invoked.
void HTTPOutput::reConnector(std::string &connector){
// Clear tkn in order to deal with reverse proxies
tkn = "";
// taken from CheckProtocols (controller_connectors.cpp)
char *argarr[32];
for (int i = 0; i < 32; i++){argarr[i] = 0;}

View file

@ -76,11 +76,11 @@ namespace Mist{
std::string method = H.method;
// send logo icon
if (H.url.length() > 4 && H.url.substr(H.url.length() - 4, 4) == ".ico"){
sendIcon();
sendIcon(false);
return;
}
if (H.url.length() > 6 && H.url.substr(H.url.length() - 5, 5) == ".html"){
HTMLResponse();
HTMLResponse(H, false);
return;
}
if (H.url.size() >= 3 && H.url.substr(H.url.size() - 3) == ".js"){
@ -337,9 +337,9 @@ namespace Mist{
}
}
void OutHTTP::HTMLResponse(){
std::string method = H.method;
HTTP::URL fullURL(H.GetHeader("Host"));
void OutHTTP::HTMLResponse(const HTTP::Parser & req, bool headersOnly){
HTTPOutput::respondHTTP(req, headersOnly);
HTTP::URL fullURL(req.GetHeader("Host"));
if (!fullURL.protocol.size()){fullURL.protocol = getProtocolForPort(fullURL.getPort());}
if (config->getString("pubaddr") != ""){
HTTP::URL altURL(config->getString("pubaddr"));
@ -349,24 +349,22 @@ namespace Mist{
fullURL.path = altURL.path;
}
if (mistPath.size()){fullURL = mistPath;}
std::string uAgent = H.GetHeader("User-Agent");
std::string uAgent = req.GetHeader("User-Agent");
std::string forceType = "";
if (H.GetVar("forcetype").size()){
forceType = ",forceType:\"" + H.GetVar("forcetype") + "\"";
forceType = ",forceType:\"" + req.GetVar("forcetype") + "\"";
}
std::string devSkin = "";
if (H.GetVar("dev").size()){devSkin = ",skin:\"dev\"";}
H.SetVar("stream", "");
H.SetVar("dev", "");
if (req.GetVar("dev").size()){devSkin = ",skin:\"dev\"";}
devSkin += ",urlappend:\"" + H.allVars() + "\"";
H.SetVar("stream", streamName);
std::string seekTo = "";
if (H.GetVar("t").size()){
if (req.GetVar("t").size()){
uint64_t autoSeekTime = 0;
std::string sTime = H.GetVar("t");
std::string sTime = req.GetVar("t");
unsigned long long h = 0, m = 0, s = 0;
autoSeekTime = JSON::Value(sTime).asInt();
if (sscanf(sTime.c_str(), "%llum%llus", &m, &s) == 2){autoSeekTime = m * 60 + s;}
@ -385,13 +383,10 @@ namespace Mist{
streamName + "\").addEventListener(\"initialized\",f);";
}
}
H.Clean();
H.SetHeader("Content-Type", "text/html");
H.SetHeader("X-UA-Compatible", "IE=edge");
H.SetHeader("Server", APPIDENT);
H.setCORSHeaders();
if (method == "OPTIONS" || method == "HEAD"){
if (headersOnly){
H.SendResponse("200", "OK", myConn);
responded = true;
H.Clean();
@ -427,6 +422,7 @@ namespace Mist{
}
H.SendResponse("200", "OK", myConn);
responded = true;
H.Clean();
}
JSON::Value OutHTTP::getStatusJSON(std::string &reqHost, const std::string &useragent){
@ -634,23 +630,31 @@ namespace Mist{
// loop over the added sources, add them to json_resp["sources"]
for (std::set<JSON::Value, sourceCompare>::iterator it = sources.begin(); it != sources.end(); it++){
if ((*it)["simul_tracks"].asInt() > 0){json_resp["source"].append(*it);}
if ((*it)["simul_tracks"].asInt() > 0){
if (Comms::tknMode & 0x04){
JSON::Value tmp;
tmp = (*it);
tmp["url"] = tmp["url"].asStringRef() + "?tkn=" + tkn;
tmp["relurl"] = tmp["relurl"].asStringRef() + "?tkn=" + tkn;
json_resp["source"].append(tmp);
}else{
json_resp["source"].append(*it);
}
}
}
return json_resp;
}
void OutHTTP::onHTTP(){
void OutHTTP::respondHTTP(const HTTP::Parser & req, bool headersOnly){
origStreamName = streamName;
std::string method = H.method;
if (H.GetHeader("X-Mst-Path").size()){mistPath = H.GetHeader("X-Mst-Path");}
if (req.GetHeader("X-Mst-Path").size()){mistPath = req.GetHeader("X-Mst-Path");}
// Handle certbot validations
if (H.url.substr(0, 28) == "/.well-known/acme-challenge/"){
if (req.url.substr(0, 28) == "/.well-known/acme-challenge/"){
std::string cbToken = H.url.substr(28);
jsonForEach(config->getOption("certbot", true), it){
if (it->asStringRef().substr(0, cbToken.size() + 1) == cbToken + ":"){
H.Clean();
H.SetHeader("Content-Type", "text/plain");
H.SetHeader("Server", APPIDENT);
H.setCORSHeaders();
@ -661,9 +665,7 @@ namespace Mist{
return;
}
}
H.Clean();
H.SetHeader("Content-Type", "text/plain");
H.SetHeader("Server", APPIDENT);
H.setCORSHeaders();
H.SetBody("No matching validation found for token '" + cbToken + "'");
H.SendResponse("404", "Not found", myConn);
@ -672,12 +674,11 @@ namespace Mist{
return;
}
if (H.url == "/crossdomain.xml"){
H.Clean();
if (req.url == "/crossdomain.xml"){
H.SetHeader("Content-Type", "text/xml");
H.SetHeader("Server", APPIDENT);
H.setCORSHeaders();
if (method == "OPTIONS" || method == "HEAD"){
if (headersOnly){
H.SendResponse("200", "OK", myConn);
responded = true;
H.Clean();
@ -693,12 +694,11 @@ namespace Mist{
return;
}// crossdomain.xml
if (H.url == "/clientaccesspolicy.xml"){
H.Clean();
if (req.url == "/clientaccesspolicy.xml"){
H.SetHeader("Content-Type", "text/xml");
H.SetHeader("Server", APPIDENT);
H.setCORSHeaders();
if (method == "OPTIONS" || method == "HEAD"){
if (headersOnly){
H.SendResponse("200", "OK", myConn);
responded = true;
H.Clean();
@ -716,8 +716,7 @@ namespace Mist{
return;
}// clientaccesspolicy.xml
if (H.url == "/flashplayer.swf"){
H.Clean();
if (req.url == "/flashplayer.swf"){
H.SetHeader("Content-Type", "application/x-shockwave-flash");
H.SetHeader("Server", APPIDENT);
H.SetBody((const char *)FlashMediaPlayback_101_swf, FlashMediaPlayback_101_swf_len);
@ -725,8 +724,7 @@ namespace Mist{
responded = true;
return;
}
if (H.url == "/oldflashplayer.swf"){
H.Clean();
if (req.url == "/oldflashplayer.swf"){
H.SetHeader("Content-Type", "application/x-shockwave-flash");
H.SetHeader("Server", APPIDENT);
H.SetBody((const char *)FlashMediaPlayback_swf, FlashMediaPlayback_swf_len);
@ -735,20 +733,21 @@ namespace Mist{
return;
}
// send logo icon
if (H.url.length() > 4 && H.url.substr(H.url.length() - 4, 4) == ".ico"){
sendIcon();
if (req.url.length() > 4 && req.url.substr(req.url.length() - 4, 4) == ".ico"){
sendIcon(headersOnly);
return;
}
// send generic HTML page
if (H.url.length() > 6 && H.url.substr(H.url.length() - 5, 5) == ".html"){
HTMLResponse();
if (req.url.length() > 6 && req.url.substr(req.url.length() - 5, 5) == ".html"){
HTMLResponse(req, headersOnly);
return;
}
// send smil MBR index
if (H.url.length() > 6 && H.url.substr(H.url.length() - 5, 5) == ".smil"){
std::string reqHost = HTTP::URL(H.GetHeader("Host")).host;
if (req.url.length() > 6 && req.url.substr(req.url.length() - 5, 5) == ".smil"){
HTTPOutput::respondHTTP(req, headersOnly);
std::string reqHost = HTTP::URL(req.GetHeader("Host")).host;
std::string port, url_rel;
std::string trackSources; // this string contains all track sources for MBR smil
{
@ -782,11 +781,8 @@ namespace Mist{
}
}
H.Clean();
H.SetHeader("Content-Type", "application/smil");
H.SetHeader("Server", APPIDENT);
H.setCORSHeaders();
if (method == "OPTIONS" || method == "HEAD"){
if (headersOnly){
H.SendResponse("200", "OK", myConn);
responded = true;
H.Clean();
@ -800,24 +796,22 @@ namespace Mist{
return;
}
if ((H.url.length() > 9 && H.url.substr(0, 6) == "/info_" && H.url.substr(H.url.length() - 3, 3) == ".js") ||
(H.url.length() > 9 && H.url.substr(0, 6) == "/json_" && H.url.substr(H.url.length() - 3, 3) == ".js")){
if (websocketHandler()){return;}
std::string reqHost = HTTP::URL(H.GetHeader("Host")).host;
std::string useragent = H.GetVar("ua");
if (!useragent.size()){useragent = H.GetHeader("User-Agent");}
if ((req.url.length() > 9 && req.url.substr(0, 6) == "/info_" && req.url.substr(req.url.length() - 3, 3) == ".js") ||
(req.url.length() > 9 && req.url.substr(0, 6) == "/json_" && req.url.substr(req.url.length() - 3, 3) == ".js")){
HTTPOutput::respondHTTP(req, headersOnly);
if (websocketHandler(req, headersOnly)){return;}
std::string reqHost = HTTP::URL(req.GetHeader("Host")).host;
std::string useragent = req.GetVar("ua");
if (!useragent.size()){useragent = req.GetHeader("User-Agent");}
std::string response;
std::string rURL = H.url;
if (method != "OPTIONS" && method != "HEAD"){initialize();}
H.Clean();
H.SetHeader("Server", APPIDENT);
H.setCORSHeaders();
std::string rURL = req.url;
if (headersOnly){initialize();}
if (rURL.substr(0, 6) != "/json_"){
H.SetHeader("Content-Type", "application/javascript");
}else{
H.SetHeader("Content-Type", "application/json");
}
if (method == "OPTIONS" || method == "HEAD"){
if (headersOnly){
H.SendResponse("200", "OK", myConn);
responded = true;
H.Clean();
@ -837,9 +831,9 @@ namespace Mist{
return;
}// embed code generator
if ((H.url == "/player.js") || ((H.url.substr(0, 7) == "/embed_") && (H.url.length() > 10) &&
(H.url.substr(H.url.length() - 3, 3) == ".js"))){
HTTP::URL fullURL(H.GetHeader("Host"));
if ((req.url == "/player.js") || ((req.url.substr(0, 7) == "/embed_") && (req.url.length() > 10) &&
(req.url.substr(H.url.length() - 3, 3) == ".js"))){
HTTP::URL fullURL(req.GetHeader("Host"));
if (!fullURL.protocol.size()){fullURL.protocol = getProtocolForPort(fullURL.getPort());}
if (config->getString("pubaddr") != ""){
HTTP::URL altURL(config->getString("pubaddr"));
@ -850,12 +844,17 @@ namespace Mist{
}
if (mistPath.size()){fullURL = mistPath;}
std::string response;
std::string rURL = H.url;
H.Clean();
std::string rURL = req.url;
if ((rURL.substr(0, 7) == "/embed_") && (rURL.length() > 10) &&
(rURL.substr(rURL.length() - 3, 3) == ".js")){
HTTPOutput::respondHTTP(req, headersOnly);
}
H.SetHeader("Server", APPIDENT);
H.setCORSHeaders();
H.SetHeader("Content-Type", "application/javascript; charset=utf-8");
if (method == "OPTIONS" || method == "HEAD"){
if (headersOnly){
H.SendResponse("200", "OK", myConn);
responded = true;
H.Clean();
@ -933,14 +932,13 @@ namespace Mist{
return;
}
if (H.url.substr(0, 7) == "/skins/"){
if (req.url.substr(0, 7) == "/skins/"){
std::string response;
std::string url = H.url;
H.Clean();
std::string url = req.url;
H.SetHeader("Server", APPIDENT);
H.setCORSHeaders();
H.SetHeader("Content-Type", "text/css");
if (method == "OPTIONS" || method == "HEAD"){
if (headersOnly){
H.SendResponse("200", "OK", myConn);
responded = true;
H.Clean();
@ -970,13 +968,12 @@ namespace Mist{
H.Clean();
return;
}
if (H.url == "/videojs.js"){
if (req.url == "/videojs.js"){
std::string response;
H.Clean();
H.SetHeader("Server", APPIDENT);
H.setCORSHeaders();
H.SetHeader("Content-Type", "application/javascript");
if (method == "OPTIONS" || method == "HEAD"){
if (headersOnly){
H.SendResponse("200", "OK", myConn);
responded = true;
H.Clean();
@ -992,13 +989,12 @@ namespace Mist{
H.Clean();
return;
}
if (H.url == "/dashjs.js"){
if (req.url == "/dashjs.js"){
std::string response;
H.Clean();
H.SetHeader("Server", APPIDENT);
H.setCORSHeaders();
H.SetHeader("Content-Type", "application/javascript");
if (method == "OPTIONS" || method == "HEAD"){
if (headersOnly){
H.SendResponse("200", "OK", myConn);
responded = true;
H.Clean();
@ -1016,13 +1012,12 @@ namespace Mist{
H.Clean();
return;
}
if (H.url == "/webrtc.js"){
if (req.url == "/webrtc.js"){
std::string response;
H.Clean();
H.SetHeader("Server", APPIDENT);
H.setCORSHeaders();
H.SetHeader("Content-Type", "application/javascript");
if (method == "OPTIONS" || method == "HEAD"){
if (headersOnly){
H.SendResponse("200", "OK", myConn);
responded = true;
H.Clean();
@ -1038,13 +1033,12 @@ namespace Mist{
H.Clean();
return;
}
if (H.url == "/flv.js"){
if (req.url == "/flv.js"){
std::string response;
H.Clean();
H.SetHeader("Server", "MistServer/" PACKAGE_VERSION);
H.setCORSHeaders();
H.SetHeader("Content-Type", "application/javascript");
if (method == "OPTIONS" || method == "HEAD"){
if (headersOnly){
H.SendResponse("200", "OK", myConn);
H.Clean();
return;
@ -1058,13 +1052,12 @@ namespace Mist{
H.Clean();
return;
}
if (H.url == "/hlsjs.js"){
if (req.url == "/hlsjs.js"){
std::string response;
H.Clean();
H.SetHeader("Server", "MistServer/" PACKAGE_VERSION);
H.setCORSHeaders();
H.SetHeader("Content-Type", "application/javascript");
if (method == "OPTIONS" || method == "HEAD"){
if (headersOnly){
H.SendResponse("200", "OK", myConn);
H.Clean();
return;
@ -1084,7 +1077,7 @@ namespace Mist{
H.SetHeader("Server", "MistServer/" PACKAGE_VERSION);
H.setCORSHeaders();
H.SetHeader("Content-Type", "application/javascript");
if (method == "OPTIONS" || method == "HEAD"){
if (headersOnly){
H.SendResponse("200", "OK", myConn);
H.Clean();
return;
@ -1100,15 +1093,13 @@ namespace Mist{
}
}
void OutHTTP::sendIcon(){
std::string method = H.method;
H.Clean();
void OutHTTP::sendIcon(bool headersOnly){
#include "../icon.h"
H.SetHeader("Content-Type", "image/x-icon");
H.SetHeader("Server", APPIDENT);
H.SetHeader("Content-Length", icon_len);
H.setCORSHeaders();
if (method == "OPTIONS" || method == "HEAD"){
if (headersOnly){
H.SendResponse("200", "OK", myConn);
responded = true;
H.Clean();
@ -1120,16 +1111,16 @@ namespace Mist{
H.Clean();
}
bool OutHTTP::websocketHandler(){
bool OutHTTP::websocketHandler(const HTTP::Parser & req, bool headersOnly){
stayConnected = true;
std::string reqHost = HTTP::URL(H.GetHeader("Host")).host;
if (H.GetHeader("X-Mst-Path").size()){mistPath = H.GetHeader("X-Mst-Path");}
std::string useragent = H.GetVar("ua");
if (!useragent.size()){useragent = H.GetHeader("User-Agent");}
std::string upgradeHeader = H.GetHeader("Upgrade");
std::string reqHost = HTTP::URL(req.GetHeader("Host")).host;
if (req.GetHeader("X-Mst-Path").size()){mistPath = req.GetHeader("X-Mst-Path");}
std::string useragent = req.GetVar("ua");
if (!useragent.size()){useragent = req.GetHeader("User-Agent");}
std::string upgradeHeader = req.GetHeader("Upgrade");
Util::stringToLower(upgradeHeader);
if (upgradeHeader != "websocket"){return false;}
HTTP::Websocket ws(myConn, H);
HTTP::Websocket ws(myConn, req, H);
if (!ws){return false;}
setBlocking(false);
// start the stream, if needed

View file

@ -10,10 +10,10 @@ namespace Mist{
virtual void onFail(const std::string &msg, bool critical = false);
/// preHTTP is disabled in the internal HTTP output, since most don't need the stream alive to work
virtual void preHTTP(){};
void HTMLResponse();
void onHTTP();
void sendIcon();
bool websocketHandler();
void HTMLResponse(const HTTP::Parser & req, bool headersOnly);
void respondHTTP(const HTTP::Parser & req, bool headersOnly);
void sendIcon(bool headersOnly);
bool websocketHandler(const HTTP::Parser & req, bool headersOnly);
JSON::Value getStatusJSON(std::string &reqHost, const std::string &useragent = "");
bool stayConnected;
virtual bool onFinish(){return stayConnected;}

View file

@ -141,6 +141,18 @@ namespace Mist{
}
}
std::string OutSDP::getConnectedHost(){
if (!sdpState.tracks.size()) { return Output::getConnectedHost(); }
std::string hostname;
uint32_t port;
sdpState.tracks[0].data.GetDestination(hostname, port);
return hostname;
}
std::string OutSDP::getConnectedBinHost(){
if (!sdpState.tracks.size()) { return Output::getConnectedBinHost(); }
return sdpState.tracks[0].data.getBinDestination();
}
void OutSDP::sendNext(){
char *dataPointer = 0;
size_t dataLen = 0;

View file

@ -16,6 +16,8 @@ namespace Mist{
void sendNext();
void sendHeader();
bool onFinish();
std::string getConnectedHost();
std::string getConnectedBinHost();
private:
void initTracks(uint32_t & port, std::string targetIP);

View file

@ -239,6 +239,18 @@ namespace Mist{
}
}
std::string OutTS::getConnectedHost(){
if (!pushOut) { return Output::getConnectedHost(); }
std::string hostname;
uint32_t port;
pushSock.GetDestination(hostname, port);
return hostname;
}
std::string OutTS::getConnectedBinHost(){
if (!pushOut) { return Output::getConnectedBinHost(); }
return pushSock.getBinDestination();
}
bool OutTS::listenMode(){return !(config->getString("target").size());}
void OutTS::onRequest(){

View file

@ -12,6 +12,8 @@ namespace Mist{
virtual void initialSeek();
bool isReadyForPlay();
void onRequest();
std::string getConnectedHost();
std::string getConnectedBinHost();
private:
size_t udpSize;

View file

@ -178,6 +178,20 @@ namespace Mist{
}
OutTSRIST::~OutTSRIST(){}
std::string OutTSRIST::getConnectedHost(){
if (!pushOut) { return Output::getConnectedHost(); }
return target.host;
}
std::string OutTSRIST::getConnectedBinHost(){
if (!pushOut) { return Output::getConnectedBinHost(); }
std::string binHost = Socket::getBinForms(target.host);
if (binHost.size() > 16){ binHost = binHost.substr(0, 16); }
if (binHost.size() < 16){
binHost = std::string("\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001", 16);
}
return binHost;
}
void OutTSRIST::init(Util::Config *cfg){
Output::init(cfg);
@ -319,7 +333,7 @@ namespace Mist{
}
}
void OutTSRIST::connStats(uint64_t now, Comms::Statistics &statComm){
void OutTSRIST::connStats(uint64_t now, Comms::Connections &statComm){
if (!myConn){return;}
statComm.setUp(upBytes);
statComm.setDown(0);

View file

@ -16,9 +16,11 @@ namespace Mist{
bool isReadyForPlay(){return true;}
virtual void requestHandler();
static void listener(Util::Config &conf, int (*callback)(Socket::Connection &S));
std::string getConnectedHost();
std::string getConnectedBinHost();
protected:
virtual void connStats(uint64_t now, Comms::Statistics &statComm);
virtual void connStats(uint64_t now, Comms::Connections &statComm);
//virtual std::string getConnectedHost(){
// return srtConn.remotehost;
//}