Various output fixes:

- Fixed several possible segfaults when selecting non-existing tracks in HLS
- Fixed error when requesting a stream with no compatible HLS tracks
- Fix a possible segfault when playing back an invalid track
- Fixed HLS cache control logic
- Fixed slow lookup of blank hostnames (now skips lookup entirely)
- HLS output replies with 204 rather than 200 for OPTIONS requests
- Removed out-of-the-box compatibility with iOS 10 and lower in the HTML output, in favor of better iOS 11+ support.
This commit is contained in:
Marco van Dijk 2023-06-16 17:20:13 +02:00 committed by Thulinma
parent 456fd2d555
commit 2ee0259483
4 changed files with 39 additions and 25 deletions

View file

@ -242,6 +242,7 @@ void Socket::hostBytesToStr(const char *bytes, size_t len, std::string &target){
/// Returns empty string if no reasonable match could be made.
std::string Socket::resolveHostToBestExternalAddrGuess(const std::string &host, int family,
const std::string &hint){
if (!host.size()){return "";}
struct addrinfo *result, *rp, hints;
std::string newaddr;

View file

@ -812,6 +812,7 @@ namespace Mist{
if (!isInitialized){initialize();}
buffer.clear();
thisPacket.null();
if (!M){return false;}
if (toKey){
size_t mainTrack = getMainSelectedTrack();
if (mainTrack == INVALID_TRACK_ID){
@ -831,12 +832,14 @@ namespace Mist{
MEDIUM_MSG("Seeking to %" PRIu64 "ms (%s)", pos, toKey ? "sync" : "direct");
std::set<size_t> seekTracks;
for (std::map<size_t, Comms::Users>::iterator it = userSelect.begin(); it != userSelect.end(); it++){
seekTracks.insert(it->first);
if (M.trackValid(it->first)){seekTracks.insert(it->first);}
}
//Seek all seek positions, first
for (std::set<size_t>::iterator it = seekTracks.begin(); it != seekTracks.end(); it++){
if (userSelect[*it]){
userSelect[*it].setKeyNum(M.getKeyNumForTime(*it, pos));
}
}
bool ret = seekTracks.size();
for (std::set<size_t>::iterator it = seekTracks.begin(); it != seekTracks.end(); it++){
ret &= seek(*it, pos, false);
@ -1985,6 +1988,10 @@ namespace Mist{
// depending on whether this is probably bad and the current debug level, print a message
size_t printLevel = (probablyBad ? DLVL_WARN : DLVL_INFO);
//The rest of the operations depends on userSelect, so we ignore it if it doesn't exist.
if (!M || !M.getValidTracks().count(trackId)){
DEBUG_MSG(printLevel, "Dropping invalid track %zu: %s", trackId, reason.c_str());
return;
}
if (!userSelect.count(trackId)){
if (M.hasEmbeddedFrames(trackId)){
DEBUG_MSG(printLevel, "Dropping %s track %zu (raw): %s", meta.getCodec(trackId).c_str(), trackId, reason.c_str());

View file

@ -68,11 +68,18 @@ namespace Mist{
<< "\r\n";
}
}
if (!vidTracks && audioId != INVALID_TRACK_ID){
if (!vidTracks){
if (audioId != INVALID_TRACK_ID){
// Audio only playlist
result << "#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=" << (M.getBps(audioId) * 8);
result << ",CODECS=\"" << Util::codecString(M.getCodec(audioId), M.getInit(audioId)) << "\"";
result << "\r\n";
result << audioId << "/index.m3u8" << tknStr << "\r\n";
}else{
// No compatible tracks at all
return "";
}
}
return result.str();
}
@ -260,7 +267,12 @@ namespace Mist{
H.SetHeader("Content-Type", "text/xml");
H.SetHeader("Server", APPIDENT);
H.setCORSHeaders();
if (method == "OPTIONS" || method == "HEAD"){
if (method == "OPTIONS"){
H.SendResponse("204", "No content", myConn);
responded = true;
return;
}
if (method == "HEAD"){
H.SendResponse("200", "OK", myConn);
responded = true;
return;
@ -274,19 +286,20 @@ namespace Mist{
return;
}// crossdomain.xml
if (H.method == "OPTIONS"){
if (method == "OPTIONS"){
bool isTS = (HTTP::URL(H.url).getExt().substr(0, 3) != "m3u");
H.Clean();
H.setCORSHeaders();
if (isTS){
H.SetHeader("Content-Type", "video/mp2t");
}else{
H.SetHeader("Content-Type", "application/vnd.apple.mpegurl");
}
if (isTS && (!(Comms::tknMode & 0x04) || config->getOption("chunkpath"))){
if (isTS && !(!(Comms::tknMode & 0x04) || config->getOption("chunkpath"))){
uint64_t dura = 120000;
if (M && M.getValidTracks().size()){
size_t mTrk = M.mainTrack();
if (mTrk != INVALID_TRACK_ID){dura = M.getDuration(dura);}
if (mTrk != INVALID_TRACK_ID){dura = M.getDuration(mTrk);}
}
H.SetHeader("Cache-Control",
"public, max-age=" +
@ -298,7 +311,7 @@ namespace Mist{
H.SetHeader("Cache-Control", "no-store");
}
H.SetBody("");
H.SendResponse("200", "OK", myConn);
H.SendResponse("204", "No content", myConn);
responded = true;
return;
}
@ -374,14 +387,14 @@ namespace Mist{
H.SetHeader("Content-Type", "video/mp2t");
H.setCORSHeaders();
if (!(Comms::tknMode & 0x04) || config->getOption("chunkpath")){
H.SetHeader("Cache-Control", "no-store");
}else{
H.SetHeader("Cache-Control",
"public, max-age=" +
JSON::Value(M.getDuration(getMainSelectedTrack()) / 1000).asString() +
", immutable");
H.SetHeader("Pragma", "");
H.SetHeader("Expires", "");
}else{
H.SetHeader("Cache-Control", "no-store");
}
if (method == "OPTIONS" || method == "HEAD"){
H.SendResponse("200", "OK", myConn);
@ -418,6 +431,10 @@ namespace Mist{
std::string manifest;
if (request.find("/") == std::string::npos){
manifest = liveIndex();
if (manifest == ""){
onFail("No HLS compatible tracks found");
return;
}
}else{
size_t idx = atoi(request.substr(0, request.find("/")).c_str());
if (!M.getValidTracks().count(idx)){

View file

@ -426,17 +426,6 @@ namespace Mist{
"src=\"player.js\"></script><script>var mv ={reference:false}; mistPlay('" +
streamName + "',{host:'" + fullURL.getUrl() + "',target:document.getElementById('" + streamName +
"'),MistVideoObject:mv" + forceType + devSkin + "});" + seekTo + "</script></div></body></html>");
if ((uAgent.find("iPad") != std::string::npos) || (uAgent.find("iPod") != std::string::npos) ||
(uAgent.find("iPhone") != std::string::npos)){
if (uAgent.find("OS 11") == std::string::npos && uAgent.find("OS 12") == std::string::npos &&
uAgent.find("OS 13") == std::string::npos && uAgent.find("OS 14") == std::string::npos &&
uAgent.find("OS 15") == std::string::npos && uAgent.find("OS 16") == std::string::npos){
H.SetHeader("Location", hlsUrl);
H.SendResponse("307", "HLS redirect", myConn);
responded = true;
return;
}
}
H.SendResponse("200", "OK", myConn);
responded = true;
H.Clean();