Generalized byte range request parsing

This commit is contained in:
Thulinma 2018-01-24 19:21:23 +01:00
parent fc707da6b0
commit 105b1677d1
4 changed files with 76 additions and 73 deletions

View file

@ -351,4 +351,76 @@ namespace Mist {
execv(argarr[0], argarr); execv(argarr[0], argarr);
} }
/// Parses a "Range: " header, setting byteStart and byteEnd.
/// Assumes byteStart and byteEnd are initialized to their minimum respectively maximum values when the function is called.
/// On error, byteEnd is set to zero and the function return false.
bool HTTPOutput::parseRange(uint64_t & byteStart, uint64_t & byteEnd){
std::string header = H.GetHeader("Range");
if (header.size() < 6 || header.substr(0, 6) != "bytes="){
byteEnd = 0;
WARN_MSG("Invalid range header: %s", header.c_str());
return false;
}
header.erase(0, 6);
//Do parsing of the rest of the header...
if (header.size() && header[0] == '-'){
//negative range = count from end
byteStart = 0;
for (unsigned int i = 1; i < header.size(); ++i){
if (header[i] >= '0' && header[i] <= '9'){
byteStart *= 10;
byteStart += header[i] - '0';
continue;
}
break;
}
if (byteStart > byteEnd){
//entire file if starting before byte zero
byteStart = 0;
}else{
//start byteStart bytes before byteEnd
byteStart = byteEnd - byteStart;
}
MEDIUM_MSG("Range request: %" PRIu64 "-%" PRIu64 " (%s)", byteStart, byteEnd, header.c_str());
return true;
}
//Positive range
long long size = byteEnd;
byteEnd = 0;
byteStart = 0;
unsigned int i = 0;
for (; i < header.size(); ++i){
if (header[i] >= '0' && header[i] <= '9'){
byteStart *= 10;
byteStart += header[i] - '0';
continue;
}
break;
}
if (header[i] != '-'){
WARN_MSG("Invalid range header: %s", header.c_str());
byteEnd = 0;
return false;
}
++i;
if (i < header.size()){
for (; i < header.size(); ++i){
if (header[i] >= '0' && header[i] <= '9'){
byteEnd *= 10;
byteEnd += header[i] - '0';
continue;
}
break;
}
if (byteEnd > size){
byteEnd = size;
}
}else{
byteEnd = size;
}
MEDIUM_MSG("Range request: %" PRIu64 "-%" PRIu64 " (%s)", byteStart, byteEnd, header.c_str());
return true;
}
} }

View file

@ -17,6 +17,7 @@ namespace Mist {
static bool listenMode(){return false;} static bool listenMode(){return false;}
void reConnector(std::string & connector); void reConnector(std::string & connector);
std::string getHandler(); std::string getHandler();
bool parseRange(uint64_t & byteStart, uint64_t & byteEnd);
protected: protected:
HTTP::Parser H; HTTP::Parser H;
}; };

View file

@ -424,77 +424,6 @@ namespace Mist {
//That's technically legal, of course. //That's technically legal, of course.
} }
/// Parses a "Range: " header, setting byteStart, byteEnd and seekPoint using data from metadata and tracks to do
/// the calculations.
/// On error, byteEnd is set to zero.
void OutProgressiveMP4::parseRange(std::string header, uint64_t & byteStart, uint64_t & byteEnd, uint64_t & seekPoint, uint64_t headerSize) {
if (header.size() < 6 || header.substr(0, 6) != "bytes=") {
byteEnd = 0;
WARN_MSG("Invalid range header: %s", header.c_str());
return;
}
header.erase(0, 6);
if (header.size() && header[0] == '-'){
//negative range = count from end
byteStart = 0;
for (unsigned int i = 1; i < header.size(); ++i){
if (header[i] >= '0' && header[i] <= '9'){
byteStart *= 10;
byteStart += header[i] - '0';
continue;
}
break;
}
if (byteStart > byteEnd){
//entire file if starting before byte zero
byteStart = 0;
findSeekPoint(byteStart, seekPoint, headerSize);
return;
}else{
//start byteStart bytes before byteEnd
byteStart = byteEnd - byteStart;
findSeekPoint(byteStart, seekPoint, headerSize);
return;
}
}else{
long long size = byteEnd;
byteEnd = 0;
byteStart = 0;
unsigned int i = 0;
for ( ; i < header.size(); ++i){
if (header[i] >= '0' && header[i] <= '9'){
byteStart *= 10;
byteStart += header[i] - '0';
continue;
}
break;
}
if (header[i] != '-') {
WARN_MSG("Invalid range header: %s", header.c_str());
byteEnd = 0;
return;
}
++i;
if (i < header.size()){
for ( ; i < header.size(); ++i){
if (header[i] >= '0' && header[i] <= '9'){
byteEnd *= 10;
byteEnd += header[i] - '0';
continue;
}
break;
}
if (byteEnd > size) {
byteEnd = size;
}
}else{
byteEnd = size;
}
MEDIUM_MSG("Range request: %" PRIu64 "-%" PRIu64 " (%s)", byteStart, byteEnd, header.c_str());
findSeekPoint(byteStart, seekPoint, headerSize);
return;
}
}
void OutProgressiveMP4::onHTTP() { void OutProgressiveMP4::onHTTP() {
if(H.method == "OPTIONS" || H.method == "HEAD"){ if(H.method == "OPTIONS" || H.method == "HEAD"){
H.Clean(); H.Clean();
@ -527,7 +456,9 @@ namespace Mist {
sortSet.insert(temp); sortSet.insert(temp);
} }
if (H.GetHeader("Range") != ""){ if (H.GetHeader("Range") != ""){
parseRange(H.GetHeader("Range"), byteStart, byteEnd, seekPoint, headerSize); if (parseRange(byteStart, byteEnd)){
findSeekPoint(byteStart, seekPoint, headerSize);
}
rangeType = H.GetHeader("Range")[0]; rangeType = H.GetHeader("Range")[0];
} }
H.Clean(); //make sure no parts of old requests are left in any buffers H.Clean(); //make sure no parts of old requests are left in any buffers

View file

@ -27,7 +27,6 @@ namespace Mist {
OutProgressiveMP4(Socket::Connection & conn); OutProgressiveMP4(Socket::Connection & conn);
~OutProgressiveMP4(); ~OutProgressiveMP4();
static void init(Util::Config * cfg); static void init(Util::Config * cfg);
void parseRange(std::string header, uint64_t & byteStart, uint64_t & byteEnd, uint64_t & seekPoint, uint64_t headerSize);
uint64_t mp4HeaderSize(uint64_t & fileSize); uint64_t mp4HeaderSize(uint64_t & fileSize);
std::string DTSCMeta2MP4Header(uint64_t & size); std::string DTSCMeta2MP4Header(uint64_t & size);
void findSeekPoint(uint64_t byteStart, uint64_t & seekPoint, uint64_t headerSize); void findSeekPoint(uint64_t byteStart, uint64_t & seekPoint, uint64_t headerSize);