diff --git a/lib/http_parser.cpp b/lib/http_parser.cpp index 7a087f70..08d11b7e 100644 --- a/lib/http_parser.cpp +++ b/lib/http_parser.cpp @@ -20,13 +20,6 @@ void HTTP::Parser::Clean(){ vars.clear(); } -/// Re-initializes the HTTP::Parser, leaving the internal data buffer alone, then tries to parse a new request or response. -/// Does the same as HTTP::Parser::Clean(), then returns HTTP::Parser::parse(). -bool HTTP::Parser::CleanForNext(){ - Clean(); - return parse(); -} - /// Returns a string containing a valid HTTP 1.0 or 1.1 request, ready for sending. /// The request is build from internal variables set before this call is made. /// To be precise, method, url, protocol, headers and body are used. @@ -115,34 +108,20 @@ void HTTP::Parser::SetVar(std::string i, std::string v){ } } -/// Attempt to read a whole HTTP request or response from Socket::Connection. -/// \param sock The socket to use. -/// \param nonblock When true, will not block even if the socket is blocking. -/// \return True of a whole request or response was read, false otherwise. -bool HTTP::Parser::Read(Socket::Connection & sock, bool nonblock){ - if (nonblock && (sock.ready() < 1)){return parse();} - sock.read(HTTPbuffer); - return parse(); -}//HTTPReader::ReadSocket +/// Attempt to read a whole HTTP request or response from a std::string buffer. +/// If a whole request could be read, it is removed from the front of the given buffer. +/// \param strbuf The buffer to read from. +/// \return True if a whole request or response was read, false otherwise. +bool HTTP::Parser::Read(std::string & strbuf){ + return parse(strbuf); +}//HTTPReader::Read -/// Reads a full set of HTTP responses/requests from file F. -/// \return Always false. Use HTTP::Parser::CleanForNext() to parse the contents of the file. -bool HTTP::Parser::Read(FILE * F){ - //returned true als hele http packet gelezen is - int b = 1; - char buffer[500]; - while (b > 0){ - b = fread(buffer, 1, 500, F); - HTTPbuffer.append(buffer, b); - } - return false; -}//HTTPReader::ReadSocket - -/// Attempt to read a whole HTTP response or request from the internal data buffer. +/// Attempt to read a whole HTTP response or request from a data buffer. /// If succesful, fills its own fields with the proper data and removes the response/request -/// from the internal data buffer. +/// from the data buffer. +/// \param HTTPbuffer The data buffer to read from. /// \return True on success, false otherwise. -bool HTTP::Parser::parse(){ +bool HTTP::Parser::parse(std::string & HTTPbuffer){ size_t f; std::string tmpA, tmpB, tmpC; while (HTTPbuffer != ""){ @@ -194,16 +173,6 @@ bool HTTP::Parser::parse(){ return false; //we should never get here... }//HTTPReader::parse -/// Sends data as response to conn. -/// The response is automatically first build using HTTP::Parser::BuildResponse(). -/// \param conn The Socket::Connection to send the response over. -/// \param code The HTTP response code. Usually you want 200. -/// \param message The HTTP response message. Usually you want "OK". -void HTTP::Parser::SendResponse(Socket::Connection & conn, std::string code, std::string message){ - std::string tmp = BuildResponse(code, message); - conn.write(tmp); -} - #include /// Parses GET or POST-style variable data. /// Saves to internal variable structure using HTTP::Parser::SetVar. @@ -237,31 +206,16 @@ void HTTP::Parser::parseVars(std::string data){ } } -/// Sends data as HTTP/1.1 bodypart to conn. -/// HTTP/1.1 chunked encoding is automatically applied if needed. -/// \param conn The Socket::Connection to send the part over. -/// \param buffer The buffer to send. -/// \param len The length of the buffer. -void HTTP::Parser::SendBodyPart(Socket::Connection & conn, char * buffer, int len){ - std::string tmp; - tmp.append(buffer, len); - SendBodyPart(conn, tmp); -} - -/// Sends data as HTTP/1.1 bodypart to conn. -/// HTTP/1.1 chunked encoding is automatically applied if needed. -/// \param conn The Socket::Connection to send the part over. -/// \param bodypart The data to send. -void HTTP::Parser::SendBodyPart(Socket::Connection & conn, std::string bodypart){ +/// Converts a string to chunked format if protocol is HTTP/1.1 - does nothing otherwise. +/// \param bodypart The data to convert - will be converted in-place. +void HTTP::Parser::Chunkify(std::string & bodypart){ if (protocol == "HTTP/1.1"){ static char len[10]; - int sizelen; - sizelen = snprintf(len, 10, "%x\r\n", (unsigned int)bodypart.size()); - conn.write(len, sizelen); - conn.write(bodypart); - conn.write(len+sizelen-2, 2); - }else{ - conn.write(bodypart); + int sizelen = snprintf(len, 10, "%x\r\n", (unsigned int)bodypart.size()); + //prepend the chunk size and \r\n + bodypart.insert(0, len, sizelen); + //append \r\n + bodypart.append("\r\n", 2); } } diff --git a/lib/http_parser.h b/lib/http_parser.h index 124b9686..609e7d28 100644 --- a/lib/http_parser.h +++ b/lib/http_parser.h @@ -6,7 +6,6 @@ #include #include #include -#include "socket.h" /// Holds all HTTP processing related code. namespace HTTP{ @@ -14,8 +13,7 @@ namespace HTTP{ class Parser{ public: Parser(); - bool Read(Socket::Connection & sock, bool nonblock = true); - bool Read(FILE * F); + bool Read(std::string & strbuf); std::string GetHeader(std::string i); std::string GetVar(std::string i); void SetHeader(std::string i, std::string v); @@ -25,11 +23,8 @@ namespace HTTP{ void SetBody(char * buffer, int len); std::string BuildRequest(); std::string BuildResponse(std::string code, std::string message); - void SendResponse(Socket::Connection & conn, std::string code, std::string message); - void SendBodyPart(Socket::Connection & conn, char * buffer, int len); - void SendBodyPart(Socket::Connection & conn, std::string bodypart); + void Chunkify(std::string & bodypart); void Clean(); - bool CleanForNext(); static std::string urlunescape(const std::string & in); static std::string urlencode(const std::string & in); std::string body; @@ -40,9 +35,9 @@ namespace HTTP{ private: bool seenHeaders; bool seenReq; - bool parse(); + bool parse(std::string & HTTPbuffer); void parseVars(std::string data); - std::string HTTPbuffer; + std::string read_buffer; std::map headers; std::map vars; void Trim(std::string & s); diff --git a/src/conn_http.cpp b/src/conn_http.cpp index bd8a2cb1..129814c0 100644 --- a/src/conn_http.cpp +++ b/src/conn_http.cpp @@ -32,6 +32,7 @@ namespace Connector_HTTP{ /// Returns AMF-format metadata for Adobe HTTP Dynamic Streaming. std::string GetMetaData( ) { + /// \todo Make this actually do what it should - even though it seems to be ignored completely by all media players. AMF::Object amfreply("container", AMF::AMF0_DDV_CONTAINER); amfreply.addContent(AMF::Object("onMetaData",AMF::AMF0_STRING)); amfreply.addContent(AMF::Object("",AMF::AMF0_ECMA_ARRAY)); @@ -95,31 +96,32 @@ namespace Connector_HTTP{ void Progressive(FLV::Tag & tag, HTTP::Parser HTTP_S, Socket::Connection & conn, DTSC::Stream & Strm){ static bool progressive_has_sent_header = false; if (!progressive_has_sent_header){ - HTTP_S.Clean();//troep opruimen die misschien aanwezig is... - HTTP_S.SetHeader("Content-Type", "video/x-flv");//FLV files hebben altijd dit content-type. + HTTP_S.Clean();//make sure no parts of old requests are left in any buffers + HTTP_S.SetHeader("Content-Type", "video/x-flv");//Send the correct content-type for FLV files //HTTP_S.SetHeader("Transfer-Encoding", "chunked"); HTTP_S.protocol = "HTTP/1.0"; - HTTP_S.SendResponse(conn, "200", "OK");//geen SetBody = unknown length! Dat willen we hier. - //HTTP_S.SendBodyPart(CONN_fd, FLVHeader, 13);//schrijf de FLV header - conn.write(FLV::Header, 13); + conn.Send(HTTP_S.BuildResponse("200", "OK"));//no SetBody = unknown length - this is intentional, we will stream the entire file + conn.Send(std::string(FLV::Header, 13));//write FLV header static FLV::Tag tmp; + //write metadata tmp.DTSCMetaInit(Strm); - conn.write(tmp.data, tmp.len); + conn.Send(std::string(tmp.data, tmp.len)); + //write video init data, if needed if (Strm.metadata.getContentP("video") && Strm.metadata.getContentP("video")->getContentP("init")){ tmp.DTSCVideoInit(Strm); - conn.write(tmp.data, tmp.len); + conn.Send(std::string(tmp.data, tmp.len)); } + //write audio init data, if needed if (Strm.metadata.getContentP("audio") && Strm.metadata.getContentP("audio")->getContentP("init")){ tmp.DTSCAudioInit(Strm); - conn.write(tmp.data, tmp.len); + conn.Send(std::string(tmp.data, tmp.len)); } progressive_has_sent_header = true; #if DEBUG >= 1 fprintf(stderr, "Sent progressive FLV header\n"); #endif } - //HTTP_S.SendBodyPart(CONN_fd, tag->data, tag->len);//schrijf deze FLV tag onbewerkt weg - conn.write(tag.data, tag.len); + conn.Send(std::string(tag.data, tag.len));//write the tag contents } /// Handles Flash Dynamic HTTP streaming requests @@ -129,6 +131,9 @@ namespace Connector_HTTP{ if (Strm.getPacket(0).getContentP("keyframe")){ if (FlashBuf != ""){ Flash_FragBuffer.push(FlashBuf); + while (Flash_FragBuffer.size() > 2){ + Flash_FragBuffer.pop(); + } #if DEBUG >= 4 fprintf(stderr, "Received a fragment. Now %i in buffer.\n", (int)Flash_FragBuffer.size()); #endif @@ -165,96 +170,102 @@ namespace Connector_HTTP{ int temp; int Flash_RequestPending = 0; unsigned int lastStats = 0; - //int CurrentFragment = -1; later herbruiken? + conn.setBlocking(false);//do not block on conn.spool() when no data is available while (conn.connected()){ //only parse input if available or not yet init'ed - if (HTTP_R.Read(conn, ready4data)){ - handler = HANDLER_PROGRESSIVE; - #if DEBUG >= 4 - std::cout << "Received request: " << HTTP_R.url << std::endl; - #endif - if ((HTTP_R.url.find("Seg") != std::string::npos) && (HTTP_R.url.find("Frag") != std::string::npos)){handler = HANDLER_FLASH;} - if (HTTP_R.url.find("f4m") != std::string::npos){handler = HANDLER_FLASH;} - if (HTTP_R.url == "/crossdomain.xml"){ - handler = HANDLER_NONE; - HTTP_S.Clean(); - HTTP_S.SetHeader("Content-Type", "text/xml"); - HTTP_S.SetBody(""); - HTTP_S.SendResponse(conn, "200", "OK"); - #if DEBUG >= 3 - printf("Sending crossdomain.xml file\n"); + if (conn.spool()){ + if (HTTP_R.Read(conn.Received())){ + handler = HANDLER_PROGRESSIVE; + #if DEBUG >= 4 + std::cout << "Received request: " << HTTP_R.url << std::endl; #endif - } - if (HTTP_R.url.length() > 10 && HTTP_R.url.substr(0, 7) == "/embed_" && HTTP_R.url.substr(HTTP_R.url.length() - 3, 3) == ".js"){ - streamname = HTTP_R.url.substr(7, HTTP_R.url.length() - 10); - JSON::Value ServConf = JSON::fromFile("/tmp/mist/streamlist"); - std::string response; - handler = HANDLER_NONE; - HTTP_S.Clean(); - HTTP_S.SetHeader("Content-Type", "application/javascript"); - response = "// Generating embed code for stream " + streamname + "\n\n"; - if (ServConf["streams"].isMember(streamname)){ - std::string streamurl = "http://" + HTTP_S.GetHeader("Host") + "/" + streamname + ".flv"; - response += "// Stream URL: " + streamurl + "\n\n"; - response += "document.write('');\n"; - }else{ - response += "// Stream not available at this server.\nalert(\"This stream is currently not available at this server.\\\\nPlease try again later!\");"; - } - response += ""; - HTTP_S.SetBody(response); - HTTP_S.SendResponse(conn, "200", "OK"); - #if DEBUG >= 3 - printf("Sending embed code for %s\n", streamname.c_str()); - #endif - } - if (handler == HANDLER_FLASH){ - if (HTTP_R.url.find("f4m") == std::string::npos){ - Movie = HTTP_R.url.substr(1); - Movie = Movie.substr(0,Movie.find("/")); - Quality = HTTP_R.url.substr( HTTP_R.url.find("/",1)+1 ); - Quality = Quality.substr(0, Quality.find("Seg")); - temp = HTTP_R.url.find("Seg") + 3; - Segment = atoi( HTTP_R.url.substr(temp,HTTP_R.url.find("-",temp)-temp).c_str()); - temp = HTTP_R.url.find("Frag") + 4; - ReqFragment = atoi( HTTP_R.url.substr(temp).c_str() ); - #if DEBUG >= 4 - printf( "Quality: %s, Seg %d Frag %d\n", Quality.c_str(), Segment, ReqFragment); - #endif - Flash_RequestPending++; - }else{ - Movie = HTTP_R.url.substr(1); - Movie = Movie.substr(0,Movie.find("/")); + if ((HTTP_R.url.find("Seg") != std::string::npos) && (HTTP_R.url.find("Frag") != std::string::npos)){handler = HANDLER_FLASH;} + if (HTTP_R.url.find("f4m") != std::string::npos){handler = HANDLER_FLASH;} + if (HTTP_R.url == "/crossdomain.xml"){ + handler = HANDLER_NONE; HTTP_S.Clean(); - HTTP_S.SetHeader("Content-Type","text/xml"); - HTTP_S.SetHeader("Cache-Control","no-cache"); - std::string manifest = BuildManifest(Movie); - #if DEBUG >= 4 - printf("Manifest: %s\n", manifest.c_str()); - #endif - HTTP_S.SetBody(manifest); - HTTP_S.SendResponse(conn, "200", "OK"); + HTTP_S.SetHeader("Content-Type", "text/xml"); + HTTP_S.SetBody(""); + conn.Send(HTTP_S.BuildResponse("200", "OK")); #if DEBUG >= 3 - printf("Sent manifest\n"); + printf("Sending crossdomain.xml file\n"); #endif } - #if DEBUG >= 4 - printf( "Movie: %s\n", Movie.c_str()); + if (HTTP_R.url.length() > 10 && HTTP_R.url.substr(0, 7) == "/embed_" && HTTP_R.url.substr(HTTP_R.url.length() - 3, 3) == ".js"){ + streamname = HTTP_R.url.substr(7, HTTP_R.url.length() - 10); + JSON::Value ServConf = JSON::fromFile("/tmp/mist/streamlist"); + std::string response; + handler = HANDLER_NONE; + HTTP_S.Clean(); + HTTP_S.SetHeader("Content-Type", "application/javascript"); + response = "// Generating embed code for stream " + streamname + "\n\n"; + if (ServConf["streams"].isMember(streamname)){ + std::string streamurl = "http://" + HTTP_S.GetHeader("Host") + "/" + streamname + ".flv"; + response += "// Stream URL: " + streamurl + "\n\n"; + response += "document.write('');\n"; + }else{ + response += "// Stream not available at this server.\nalert(\"This stream is currently not available at this server.\\\\nPlease try again later!\");"; + } + response += ""; + HTTP_S.SetBody(response); + conn.Send(HTTP_S.BuildResponse("200", "OK")); + #if DEBUG >= 3 + printf("Sending embed code for %s\n", streamname.c_str()); + #endif + } + if (handler == HANDLER_FLASH){ + if (HTTP_R.url.find("f4m") == std::string::npos){ + Movie = HTTP_R.url.substr(1); + Movie = Movie.substr(0,Movie.find("/")); + Quality = HTTP_R.url.substr( HTTP_R.url.find("/",1)+1 ); + Quality = Quality.substr(0, Quality.find("Seg")); + temp = HTTP_R.url.find("Seg") + 3; + Segment = atoi( HTTP_R.url.substr(temp,HTTP_R.url.find("-",temp)-temp).c_str()); + temp = HTTP_R.url.find("Frag") + 4; + ReqFragment = atoi( HTTP_R.url.substr(temp).c_str() ); + #if DEBUG >= 4 + printf( "Quality: %s, Seg %d Frag %d\n", Quality.c_str(), Segment, ReqFragment); + #endif + Flash_RequestPending++; + }else{ + Movie = HTTP_R.url.substr(1); + Movie = Movie.substr(0,Movie.find("/")); + HTTP_S.Clean(); + HTTP_S.SetHeader("Content-Type","text/xml"); + HTTP_S.SetHeader("Cache-Control","no-cache"); + std::string manifest = BuildManifest(Movie); + #if DEBUG >= 4 + printf("Manifest: %s\n", manifest.c_str()); + #endif + HTTP_S.SetBody(manifest); + conn.Send(HTTP_S.BuildResponse("200", "OK")); + #if DEBUG >= 3 + printf("Sent manifest\n"); + #endif + } + #if DEBUG >= 4 + printf( "Movie: %s\n", Movie.c_str()); + #endif + streamname = Movie; + ready4data = true; + }//FLASH handler + if (handler == HANDLER_PROGRESSIVE){ + //we assume the URL is the stream name with a 3 letter extension + std::string extension = HTTP_R.url.substr(HTTP_R.url.size()-4); + streamname = HTTP_R.url.substr(0, HTTP_R.url.size()-4);//strip the extension + /// \todo VoD streams will need support for position reading from the URL parameters + ready4data = true; + #if DEBUG >= 4 + printf( "Opening progressive stream: %s\n", streamname.c_str()); + #endif + }//PROGRESSIVE handler + HTTP_R.Clean(); //clean for any possinble next requests + }else{ + #if DEBUG >= 3 + fprintf(stderr, "Could not parse the following:\n%s\n", conn.Received().c_str()); #endif - streamname = Movie; - ready4data = true; - }//FLASH handler - if (handler == HANDLER_PROGRESSIVE){ - //we assume the URL is the stream name with a 3 letter extension - std::string extension = HTTP_R.url.substr(HTTP_R.url.size()-4); - streamname = HTTP_R.url.substr(0, HTTP_R.url.size()-4);//strip the extension - /// \todo VoD streams will need support for position reading from the URL parameters - ready4data = true; - #if DEBUG >= 4 - printf( "Opening progressive stream: %s\n", streamname.c_str()); - #endif - }//PROGRESSIVE handler - HTTP_R.CleanForNext(); //clean for any possinble next requests + } } if (ready4data){ if (!inited){ @@ -277,22 +288,18 @@ namespace Connector_HTTP{ HTTP_S.SetHeader("Content-Type","video/mp4"); HTTP_S.SetBody(MP4::mdatFold(Flash_FragBuffer.front())); Flash_FragBuffer.pop(); - HTTP_S.SendResponse(conn, "200", "OK");//schrijf de HTTP response header + conn.Send(HTTP_S.BuildResponse("200", "OK")); Flash_RequestPending--; #if DEBUG >= 3 fprintf(stderr, "Sending a video fragment. %i left in buffer, %i requested\n", (int)Flash_FragBuffer.size(), Flash_RequestPending); #endif } - if (inited){ - unsigned int now = time(0); - if (now != lastStats){ - lastStats = now; - std::string stat = "S "+conn.getStats("HTTP"); - ss.write(stat); - } + unsigned int now = time(0); + if (now != lastStats){ + lastStats = now; + ss.Send("S "+conn.getStats("HTTP")); } - if (ss.canRead()){ - ss.spool(); + if (ss.spool() || ss.Received() != ""){ if (Strm.parsePacket(ss.Received())){ tag.DTSCLoader(Strm); if (handler == HANDLER_FLASH){ diff --git a/src/controller.cpp b/src/controller.cpp index 2f4ca242..9a36b559 100644 --- a/src/controller.cpp +++ b/src/controller.cpp @@ -88,7 +88,6 @@ void WriteFile( std::string Filename, std::string contents ) { class ConnectedUser{ public: - std::string writebuffer; Socket::Connection C; HTTP::Parser H; bool Authorized; @@ -439,7 +438,7 @@ int main(int argc, char ** argv){ uplink->H.Clean(); uplink->H.SetBody("command="+HTTP::Parser::urlencode(Response.toString())); uplink->H.BuildRequest(); - uplink->writebuffer += uplink->H.BuildResponse("200", "OK"); + uplink->C.Send(uplink->H.BuildResponse("200", "OK")); uplink->H.Clean(); //Log("UPLK", "Sending server data to uplink."); }else{ @@ -459,8 +458,7 @@ int main(int argc, char ** argv){ buffers.erase(it); break; } - it->spool(); - if (it->Received() != ""){ + if (it->spool()){ size_t newlines = it->Received().find("\n\n"); while (newlines != std::string::npos){ Request = it->Received().substr(0, newlines); @@ -489,85 +487,84 @@ int main(int argc, char ** argv){ users.erase(it); break; } - if (it->writebuffer != ""){ - it->C.iwrite(it->writebuffer); - } - if (it->H.Read(it->C)){ - Response.null(); //make sure no data leaks from previous requests - if (it->clientMode){ - // In clientMode, requests are reversed. These are connections we initiated to GearBox. - // They are assumed to be authorized, but authorization to gearbox is still done. - // This authorization uses the compiled-in username and password (account). - Request = JSON::fromString(it->H.body); - if (Request["authorize"]["status"] != "OK"){ - if (Request["authorize"].isMember("challenge")){ - it->logins++; - if (it->logins > 2){ - Log("UPLK", "Max login attempts passed - dropping connection to uplink."); - it->C.close(); - }else{ - Response["config"] = Storage["config"]; - Response["streams"] = Storage["streams"]; - Response["log"] = Storage["log"]; - Response["statistics"] = Storage["statistics"]; - Response["authorize"]["username"] = TOSTRING(COMPILED_USERNAME); - Log("UPLK", "Responding to login challenge: " + (std::string)Request["authorize"]["challenge"]); - Response["authorize"]["password"] = md5(TOSTRING(COMPILED_PASSWORD) + (std::string)Request["authorize"]["challenge"]); - it->H.Clean(); - it->H.SetBody("command="+HTTP::Parser::urlencode(Response.toString())); - it->H.BuildRequest(); - it->writebuffer += it->H.BuildResponse("200", "OK"); - it->H.Clean(); - Log("UPLK", "Attempting login to uplink."); + if (it->C.spool()){ + if (it->H.Read(it->C.Received())){ + Response.null(); //make sure no data leaks from previous requests + if (it->clientMode){ + // In clientMode, requests are reversed. These are connections we initiated to GearBox. + // They are assumed to be authorized, but authorization to gearbox is still done. + // This authorization uses the compiled-in username and password (account). + Request = JSON::fromString(it->H.body); + if (Request["authorize"]["status"] != "OK"){ + if (Request["authorize"].isMember("challenge")){ + it->logins++; + if (it->logins > 2){ + Log("UPLK", "Max login attempts passed - dropping connection to uplink."); + it->C.close(); + }else{ + Response["config"] = Storage["config"]; + Response["streams"] = Storage["streams"]; + Response["log"] = Storage["log"]; + Response["statistics"] = Storage["statistics"]; + Response["authorize"]["username"] = TOSTRING(COMPILED_USERNAME); + Log("UPLK", "Responding to login challenge: " + (std::string)Request["authorize"]["challenge"]); + Response["authorize"]["password"] = md5(TOSTRING(COMPILED_PASSWORD) + (std::string)Request["authorize"]["challenge"]); + it->H.Clean(); + it->H.SetBody("command="+HTTP::Parser::urlencode(Response.toString())); + it->H.BuildRequest(); + it->C.Send(it->H.BuildResponse("200", "OK")); + it->H.Clean(); + Log("UPLK", "Attempting login to uplink."); + } + } + }else{ + if (Request.isMember("config")){CheckConfig(Request["config"], Storage["config"]);} + if (Request.isMember("streams")){CheckStreams(Request["streams"], Storage["streams"]);} + if (Request.isMember("clearstatlogs")){ + Storage["log"].null(); + Storage["statistics"].null(); } } }else{ - if (Request.isMember("config")){CheckConfig(Request["config"], Storage["config"]);} - if (Request.isMember("streams")){CheckStreams(Request["streams"], Storage["streams"]);} - if (Request.isMember("clearstatlogs")){ + Request = JSON::fromString(it->H.GetVar("command")); + std::cout << "Request: " << Request.toString() << std::endl; + Authorize(Request, Response, (*it)); + if (it->Authorized){ + //Parse config and streams from the request. + if (Request.isMember("config")){CheckConfig(Request["config"], Storage["config"]);} + if (Request.isMember("streams")){CheckStreams(Request["streams"], Storage["streams"]);} + if (Request.isMember("save")){ + WriteFile("config.json", Storage.toString()); + Log("CONF", "Config written to file on request through API"); + } + //sent current configuration, no matter if it was changed or not + //Response["streams"] = Storage["streams"]; + Response["config"] = Storage["config"]; + Response["streams"] = Storage["streams"]; + //add required data to the current unix time to the config, for syncing reasons + Response["config"]["time"] = (long long int)time(0); + if (!Response["config"].isMember("serverid")){Response["config"]["serverid"] = "";} + //sent any available logs and statistics + Response["log"] = Storage["log"]; + Response["statistics"] = Storage["statistics"]; + //clear log and statistics to prevent useless data transfer Storage["log"].null(); Storage["statistics"].null(); } - } - }else{ - Request = JSON::fromString(it->H.GetVar("command")); - std::cout << "Request: " << Request.toString() << std::endl; - Authorize(Request, Response, (*it)); - if (it->Authorized){ - //Parse config and streams from the request. - if (Request.isMember("config")){CheckConfig(Request["config"], Storage["config"]);} - if (Request.isMember("streams")){CheckStreams(Request["streams"], Storage["streams"]);} - if (Request.isMember("save")){ - WriteFile("config.json", Storage.toString()); - Log("CONF", "Config written to file on request through API"); + jsonp = ""; + if (it->H.GetVar("callback") != ""){jsonp = it->H.GetVar("callback");} + if (it->H.GetVar("jsonp") != ""){jsonp = it->H.GetVar("jsonp");} + it->H.Clean(); + it->H.protocol = "HTTP/1.0"; + it->H.SetHeader("Content-Type", "text/javascript"); + if (jsonp == ""){ + it->H.SetBody(Response.toString()+"\n\n"); + }else{ + it->H.SetBody(jsonp+"("+Response.toString()+");\n\n"); } - //sent current configuration, no matter if it was changed or not - //Response["streams"] = Storage["streams"]; - Response["config"] = Storage["config"]; - Response["streams"] = Storage["streams"]; - //add required data to the current unix time to the config, for syncing reasons - Response["config"]["time"] = (long long int)time(0); - if (!Response["config"].isMember("serverid")){Response["config"]["serverid"] = "";} - //sent any available logs and statistics - Response["log"] = Storage["log"]; - Response["statistics"] = Storage["statistics"]; - //clear log and statistics to prevent useless data transfer - Storage["log"].null(); - Storage["statistics"].null(); + it->C.Send(it->H.BuildResponse("200", "OK")); + it->H.Clean(); } - jsonp = ""; - if (it->H.GetVar("callback") != ""){jsonp = it->H.GetVar("callback");} - if (it->H.GetVar("jsonp") != ""){jsonp = it->H.GetVar("jsonp");} - it->H.Clean(); - it->H.protocol = "HTTP/1.0"; - it->H.SetHeader("Content-Type", "text/javascript"); - if (jsonp == ""){ - it->H.SetBody(Response.toString()+"\n\n"); - }else{ - it->H.SetBody(jsonp+"("+Response.toString()+");\n\n"); - } - it->writebuffer += it->H.BuildResponse("200", "OK"); - it->H.Clean(); } } }