Completed new sessions system
Co-authored-by: Thulinma <jaron@vietors.com>
This commit is contained in:
parent
074e757028
commit
8ac486b815
36 changed files with 991 additions and 620 deletions
|
@ -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*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(){
|
||||
|
|
|
@ -12,6 +12,8 @@ namespace Mist{
|
|||
virtual void initialSeek();
|
||||
bool isReadyForPlay();
|
||||
void onRequest();
|
||||
std::string getConnectedHost();
|
||||
std::string getConnectedBinHost();
|
||||
|
||||
private:
|
||||
size_t udpSize;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
//}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue