Socket library updates to support detecting sockets passed as FDs, removed use of peek() in HTTP request handler, fixed 100% CPU usage problem for unfinished HTTP requests
This commit is contained in:
parent
3cb03392e1
commit
6a6dd5d7ed
7 changed files with 145 additions and 162 deletions
|
@ -528,6 +528,7 @@ namespace Mist{
|
|||
}
|
||||
|
||||
if (!keepGoing()){
|
||||
INFO_MSG("Aborting page load due to shutdown");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,10 @@ namespace Mist {
|
|||
if (config->getString("ip").size()){
|
||||
myConn.setHost(config->getString("ip"));
|
||||
}
|
||||
firstRun = true;
|
||||
if (config->getString("prequest").size()){
|
||||
myConn.Received().prepend(config->getString("prequest"));
|
||||
}
|
||||
config->activate();
|
||||
}
|
||||
|
||||
|
@ -33,14 +37,19 @@ namespace Mist {
|
|||
capa["forward"]["ip"]["help"] = "IP of forwarded connection.";
|
||||
capa["forward"]["ip"]["type"] = "str";
|
||||
capa["forward"]["ip"]["option"] = "--ip";
|
||||
capa["forward"]["ip"]["name"] = "Previous request";
|
||||
capa["forward"]["ip"]["help"] = "Data to pretend arrived on the socket before parsing the socket.";
|
||||
capa["forward"]["ip"]["type"] = "str";
|
||||
capa["forward"]["ip"]["option"] = "--prequest";
|
||||
cfg->addOption("streamname", JSON::fromString("{\"arg\":\"string\",\"short\":\"s\",\"long\":\"stream\",\"help\":\"The name of the stream that this connector will transmit.\"}"));
|
||||
cfg->addOption("ip", JSON::fromString("{\"arg\":\"string\",\"short\":\"I\",\"long\":\"ip\",\"help\":\"IP address of connection on stdio.\"}"));
|
||||
cfg->addOption("prequest", JSON::fromString("{\"arg\":\"string\",\"short\":\"R\",\"long\":\"prequest\",\"help\":\"Data to pretend arrived on the socket before parsing the socket.\"}"));
|
||||
cfg->addBasicConnectorOptions(capa);
|
||||
config = cfg;
|
||||
}
|
||||
|
||||
void HTTPOutput::onFail(const std::string & msg, bool critical){
|
||||
INFO_MSG("Failing '%s': %s: %s", streamName.c_str(), H.url.c_str(), msg.c_str());
|
||||
INFO_MSG("Failing '%s': %s", H.url.c_str(), msg.c_str());
|
||||
if (!webSock){
|
||||
H.Clean(); //make sure no parts of old requests are left in any buffers
|
||||
H.SetHeader("Server", "MistServer/" PACKAGE_VERSION);
|
||||
|
@ -165,80 +174,49 @@ namespace Mist {
|
|||
}
|
||||
|
||||
void HTTPOutput::requestHandler(){
|
||||
//Handle onIdle function caller, if needed
|
||||
if (idleInterval && (Util::bootMS() > idleLast + idleInterval)){
|
||||
onIdle();
|
||||
idleLast = Util::bootMS();
|
||||
}
|
||||
//Handle websockets
|
||||
if (webSock){
|
||||
if (webSock->readFrame()){
|
||||
onWebsocketFrame();
|
||||
idleLast = Util::bootMS();
|
||||
}else{
|
||||
if (!isBlocking && !parseData){
|
||||
Util::sleep(100);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!isBlocking && !parseData){Util::sleep(100);}
|
||||
return;
|
||||
}
|
||||
if (myConn.Received().size() && myConn.spool()){
|
||||
DEBUG_MSG(DLVL_DONTEVEN, "onRequest");
|
||||
onRequest();
|
||||
}else{
|
||||
if (!myConn.Received().size()){
|
||||
if (myConn.peek() && H.Read(myConn)){
|
||||
std::string handler = getHandler();
|
||||
DEBUG_MSG(DLVL_MEDIUM, "Received request: %s => %s (%s)", H.getUrl().c_str(), handler.c_str(), H.GetVar("stream").c_str());
|
||||
if (!handler.size()){
|
||||
H.Clean();
|
||||
H.SetHeader("Server", "MistServer/" PACKAGE_VERSION);
|
||||
H.SetBody("<!DOCTYPE html><html><head><title>Unsupported Media Type</title></head><body><h1>Unsupported Media Type</h1>The server isn't quite sure what you wanted to receive from it.</body></html>");
|
||||
H.SendResponse("415", "Unsupported Media Type", myConn);
|
||||
myConn.close();
|
||||
return;
|
||||
}
|
||||
if (handler != capa["name"].asStringRef() || H.GetVar("stream") != streamName){
|
||||
DEBUG_MSG(DLVL_MEDIUM, "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");
|
||||
nProxy.userClient.finish();
|
||||
statsPage.finish();
|
||||
reConnector(handler);
|
||||
H.Clean();
|
||||
if (myConn.connected()){
|
||||
FAIL_MSG("Request failed - no connector started");
|
||||
myConn.close();
|
||||
}
|
||||
return;
|
||||
}else{
|
||||
H.Clean();
|
||||
myConn.Received().clear();
|
||||
myConn.spool();
|
||||
DEBUG_MSG(DLVL_DONTEVEN, "onRequest");
|
||||
onRequest();
|
||||
}
|
||||
}else{
|
||||
H.Clean();
|
||||
if (myConn.Received().size()){
|
||||
myConn.Received().clear();
|
||||
myConn.spool();
|
||||
DEBUG_MSG(DLVL_DONTEVEN, "onRequest");
|
||||
onRequest();
|
||||
}
|
||||
if (!myConn.Received().size()){
|
||||
if (!isBlocking && !parseData){
|
||||
Util::sleep(100);
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
if (!isBlocking && !parseData){
|
||||
Util::sleep(100);
|
||||
}
|
||||
}
|
||||
//If we can't read anything more and we're non-blocking, sleep some.
|
||||
if (!firstRun && !myConn.spool()){
|
||||
if (!isBlocking && !parseData){Util::sleep(100);}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void HTTPOutput::onRequest(){
|
||||
firstRun = false;
|
||||
|
||||
while (H.Read(myConn)){
|
||||
std::string handler = getHandler();
|
||||
INFO_MSG("Received request: %s => %s (%s)", H.getUrl().c_str(), handler.c_str(), H.GetVar("stream").c_str());
|
||||
if (!handler.size()){
|
||||
H.Clean();
|
||||
H.SetHeader("Server", "MistServer/" PACKAGE_VERSION);
|
||||
H.SetBody("<!DOCTYPE html><html><head><title>Unsupported Media Type</title></head><body><h1>Unsupported Media Type</h1>The server isn't quite sure what you wanted to receive from it.</body></html>");
|
||||
H.SendResponse("415", "Unsupported Media Type", myConn);
|
||||
myConn.close();
|
||||
return;
|
||||
}
|
||||
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());
|
||||
streamName = H.GetVar("stream");
|
||||
nProxy.userClient.finish();
|
||||
statsPage.finish();
|
||||
reConnector(handler);
|
||||
onFail("Server error - could not start connector", true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (H.hasHeader("User-Agent")){
|
||||
UA = H.GetHeader("User-Agent");
|
||||
}
|
||||
|
@ -255,7 +233,6 @@ namespace Mist {
|
|||
crc = checksum::crc32(0, mixed_ua.data(), mixed_ua.size());
|
||||
}
|
||||
|
||||
INFO_MSG("Received request %s", H.getUrl().c_str());
|
||||
//Handle upgrade to websocket if the output supports it
|
||||
if (doesWebsockets() && H.GetHeader("Upgrade") == "websocket"){
|
||||
INFO_MSG("Switching to Websocket mode");
|
||||
|
@ -309,13 +286,11 @@ namespace Mist {
|
|||
}
|
||||
|
||||
///\brief Handles requests by starting a corresponding output process.
|
||||
///\param H The request to be handled
|
||||
///\param conn The connection to the client that issued the request.
|
||||
///\param connector The type of connector to be invoked.
|
||||
void HTTPOutput::reConnector(std::string & connector){
|
||||
//taken from CheckProtocols (controller_connectors.cpp)
|
||||
char * argarr[20];
|
||||
for (int i=0; i<20; i++){argarr[i] = 0;}
|
||||
char * argarr[32];
|
||||
for (int i=0; i<32; i++){argarr[i] = 0;}
|
||||
int id = -1;
|
||||
JSON::Value pipedCapa;
|
||||
JSON::Value p;//properties of protocol
|
||||
|
@ -358,6 +333,8 @@ namespace Mist {
|
|||
|
||||
//build arguments for starting output process
|
||||
std::string tmparg = Util::getMyPath() + std::string("MistOut") + connector;
|
||||
std::string tmpPrequest;
|
||||
if (H.url.size()){tmpPrequest = H.BuildRequest();}
|
||||
int argnum = 0;
|
||||
argarr[argnum++] = (char*)tmparg.c_str();
|
||||
std::string temphost=getConnectedHost();
|
||||
|
@ -366,6 +343,8 @@ namespace Mist {
|
|||
argarr[argnum++] = (char*)(temphost.c_str());
|
||||
argarr[argnum++] = (char*)"--stream";
|
||||
argarr[argnum++] = (char*)(streamName.c_str());
|
||||
argarr[argnum++] = (char*)"--prequest";
|
||||
argarr[argnum++] = (char*)(tmpPrequest.c_str());
|
||||
//set the debug level if non-default
|
||||
if (Util::Config::printDebugLevel != DEBUG){
|
||||
argarr[argnum++] = (char*)"--debug";
|
||||
|
|
|
@ -11,7 +11,6 @@ namespace Mist {
|
|||
HTTPOutput(Socket::Connection & conn);
|
||||
virtual ~HTTPOutput();
|
||||
static void init(Util::Config * cfg);
|
||||
void onRequest();
|
||||
virtual void onFail(const std::string & msg, bool critical = false);
|
||||
virtual void onHTTP(){};
|
||||
virtual void onIdle(){};
|
||||
|
@ -26,6 +25,7 @@ namespace Mist {
|
|||
std::string getHandler();
|
||||
bool parseRange(uint64_t & byteStart, uint64_t & byteEnd);
|
||||
protected:
|
||||
bool firstRun;
|
||||
HTTP::Parser H;
|
||||
HTTP::Websocket * webSock;
|
||||
uint32_t idleInterval;
|
||||
|
|
|
@ -36,12 +36,13 @@ namespace Mist {
|
|||
|
||||
OutHTTP::OutHTTP(Socket::Connection & conn) : HTTPOutput(conn){
|
||||
stayConnected = false;
|
||||
if (myConn.getPureSocket() >= 0){
|
||||
//If this connection is a socket and not already connected to stdio, connect it to stdio.
|
||||
if (myConn.getPureSocket() != -1 && myConn.getSocket() != STDIN_FILENO && myConn.getSocket() != STDOUT_FILENO){
|
||||
std::string host = getConnectedHost();
|
||||
dup2(myConn.getSocket(), STDIN_FILENO);
|
||||
dup2(myConn.getSocket(), STDOUT_FILENO);
|
||||
myConn.drop();
|
||||
myConn = Socket::Connection(fileno(stdout),fileno(stdin) );
|
||||
myConn = Socket::Connection(STDOUT_FILENO, STDIN_FILENO);
|
||||
myConn.setHost(host);
|
||||
}
|
||||
if (config->getOption("wrappers",true).size() == 0 || config->getString("wrappers") == ""){
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue