Generic HTTP handler
# Conflicts: # src/output/output_mp4.cpp # src/output/output_mp4.h
This commit is contained in:
parent
6f6827607d
commit
9953cd6ee2
10 changed files with 129 additions and 191 deletions
|
@ -1,5 +1,6 @@
|
|||
#include "output_http.h"
|
||||
#include <mist/checksum.h>
|
||||
#include <mist/encode.h>
|
||||
#include <mist/langcodes.h>
|
||||
#include <mist/stream.h>
|
||||
#include <mist/util.h>
|
||||
|
@ -221,8 +222,6 @@ namespace Mist{
|
|||
myConn.close();
|
||||
return;
|
||||
}
|
||||
std::string connHeader = H.GetHeader("Connection");
|
||||
Util::stringToLower(connHeader);
|
||||
if (handler != capa["name"].asStringRef() || H.GetVar("stream") != streamName){
|
||||
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());
|
||||
|
@ -263,8 +262,12 @@ namespace Mist{
|
|||
if (H.GetVar("stop") != ""){targetParams["stop"] = H.GetVar("stop");}
|
||||
if (H.GetVar("startunix") != ""){targetParams["startunix"] = H.GetVar("startunix");}
|
||||
if (H.GetVar("stopunix") != ""){targetParams["stopunix"] = H.GetVar("stopunix");}
|
||||
if (H.GetVar("buffer") != ""){targetParams["buffer"] = H.GetVar("buffer");}
|
||||
// allow setting of play back rate through buffer variable.
|
||||
// allow setting of max lead time through buffer variable.
|
||||
// max lead time is set in MS, but the variable is in integer seconds for simplicity.
|
||||
if (H.GetVar("buffer") != ""){
|
||||
maxSkipAhead = JSON::Value(H.GetVar("buffer")).asInt() * 1000;
|
||||
}
|
||||
// allow setting of play back rate through rate variable or custom HTTP header.
|
||||
// play back rate is set in MS per second, but the variable is a simple multiplier.
|
||||
if (H.GetVar("rate") != ""){
|
||||
long long int multiplier = JSON::Value(H.GetVar("rate")).asInt();
|
||||
|
@ -301,18 +304,58 @@ namespace Mist{
|
|||
}
|
||||
responded = false;
|
||||
preHTTP();
|
||||
if (!myConn){return;}
|
||||
onHTTP();
|
||||
idleLast = Util::bootMS();
|
||||
if (!H.bufferChunks){H.Clean();}
|
||||
}
|
||||
}
|
||||
|
||||
/// Default HTTP handler.
|
||||
/// Only takes care of OPTIONS and HEAD, saving the original request, and calling respondHTTP
|
||||
void HTTPOutput::onHTTP(){
|
||||
const HTTP::Parser reqH = H;
|
||||
bool headersOnly = (reqH.method == "OPTIONS" || reqH.method == "HEAD");
|
||||
H.Clean();
|
||||
respondHTTP(reqH, headersOnly);
|
||||
}
|
||||
|
||||
/// Default implementation of preHTTP simply calls initialize and selectDefaultTracks.
|
||||
void HTTPOutput::preHTTP(){
|
||||
initialize();
|
||||
selectDefaultTracks();
|
||||
}
|
||||
|
||||
/// Sets common HTTP headers. Virtual, so child classes can/will implement further behaviour if needed.
|
||||
/// Child classes are suggested to call the parent implementation and then add their own logic afterwards.
|
||||
void HTTPOutput::respondHTTP(const HTTP::Parser & req, bool headersOnly){
|
||||
//We generally want the CORS headers to be set for all responses
|
||||
H.setCORSHeaders();
|
||||
//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.
|
||||
std::string dl = req.GetVar("dl");
|
||||
//Without a dot, we use the last segment of the bare URL
|
||||
if (dl.find('.') == std::string::npos){
|
||||
dl = HTTP::URL(req.url).getFilePath();
|
||||
size_t lSlash = dl.rfind('/');
|
||||
if (lSlash != std::string::npos){dl = dl.substr(lSlash+1);}
|
||||
}
|
||||
H.SetHeader("Content-Disposition", "attachment; filename=" + Encodings::URL::encode(dl) + ";");
|
||||
//Force max download speed when downloading
|
||||
realTime = 0;
|
||||
}
|
||||
//If there is a method defined, and the first method has a type with two slashes in it,
|
||||
//assume the last two sections are the content type.
|
||||
if (capa.isMember("methods") && capa["methods"].isArray() && capa["methods"].size() && capa["methods"][0u].isMember("type")){
|
||||
const std::string & cType = capa["methods"][0u]["type"].asStringRef();
|
||||
size_t fSlash = cType.find('/');
|
||||
if (fSlash != std::string::npos && cType.rfind('/') != fSlash){
|
||||
H.SetHeader("Content-Type", cType.substr(fSlash+1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void builPipedPart(JSON::Value &p, char *argarr[], int &argnum, JSON::Value &argset){
|
||||
jsonForEach(argset, it){
|
||||
if (it->isMember("option") && p.isMember(it.key())){
|
||||
|
@ -488,8 +531,7 @@ namespace Mist{
|
|||
/// 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");
|
||||
bool HTTPOutput::parseRange(std::string header, uint64_t &byteStart, uint64_t &byteEnd){
|
||||
if (header.size() < 6 || header.substr(0, 6) != "bytes="){
|
||||
byteEnd = 0;
|
||||
WARN_MSG("Invalid range header: %s", header.c_str());
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue