From 0c6cd9bfc699063afdf4fe3603f8d50157a221e1 Mon Sep 17 00:00:00 2001 From: Thulinma Date: Thu, 11 Jan 2018 15:00:24 +0100 Subject: [PATCH] Added crappy "HiIpcam" IP cam support --- lib/http_parser.cpp | 65 ++++++++++++++++++++++++++++++++-------- lib/http_parser.h | 2 +- lib/sdp.cpp | 2 ++ src/input/input_rtsp.cpp | 12 ++++++-- 4 files changed, 65 insertions(+), 16 deletions(-) diff --git a/lib/http_parser.cpp b/lib/http_parser.cpp index b4a1d52e..a43bed9e 100644 --- a/lib/http_parser.cpp +++ b/lib/http_parser.cpp @@ -38,15 +38,17 @@ HTTP::URL::URL(const std::string &url){ }else{ path = url.substr(first_slash); } - size_t hmark = path.find('#'); - if (hmark != std::string::npos){ - frag = Encodings::URL::decode(path.substr(hmark + 1)); - path.erase(hmark); - } - size_t qmark = path.find('?'); - if (qmark != std::string::npos){ - args = path.substr(qmark + 1); - path.erase(qmark); + if (protocol != "rtsp"){ + size_t hmark = path.find('#'); + if (hmark != std::string::npos){ + frag = Encodings::URL::decode(path.substr(hmark + 1)); + path.erase(hmark); + } + size_t qmark = path.find('?'); + if (qmark != std::string::npos){ + args = path.substr(qmark + 1); + path.erase(qmark); + } } if (path.size()){ if (path[0] == '/'){path.erase(0, 1);} @@ -172,7 +174,11 @@ std::string HTTP::URL::getUrl() const{ } if (port.size() && getPort() != getDefaultPort()){ret += ":" + port;} ret += "/"; - if (path.size()){ret += Encodings::URL::encode(path, "=");} + if (protocol == "rtsp"){ + if (path.size()){ret += Encodings::URL::encode(path, "=#?&");} + }else{ + if (path.size()){ret += Encodings::URL::encode(path, "=");} + } if (args.size()){ret += "?" + args;} if (frag.size()){ret += "#" + Encodings::URL::encode(frag, "=");} return ret; @@ -193,7 +199,11 @@ std::string HTTP::URL::getProxyUrl() const{ } if (port.size() && getPort() != getDefaultPort()){ret += ":" + port;} ret += "/"; - if (path.size()){ret += Encodings::URL::encode(path);} + if (protocol == "rtsp"){ + if (path.size()){ret += Encodings::URL::encode(path, "=#?&");} + }else{ + if (path.size()){ret += Encodings::URL::encode(path, "=");} + } if (args.size()){ret += "?" + args;} return ret; } @@ -216,7 +226,11 @@ std::string HTTP::URL::getBareUrl() const{ } if (port.size() && getPort() != getDefaultPort()){ret += ":" + port;} ret += "/"; - if (path.size()){ret += Encodings::URL::encode(path);} + if (protocol == "rtsp"){ + if (path.size()){ret += Encodings::URL::encode(path, "=#?&");} + }else{ + if (path.size()){ret += Encodings::URL::encode(path, "=");} + } return ret; } @@ -399,8 +413,29 @@ std::string &HTTP::Parser::BuildRequest(){ /// Creates and sends a valid HTTP 1.0 or 1.1 request. /// The request is build from internal variables set before this call is made. /// To be precise, method, url, protocol, headers and body are used. -void HTTP::Parser::SendRequest(Socket::Connection &conn, const std::string &reqbody){ +void HTTP::Parser::SendRequest(Socket::Connection &conn, const std::string &reqbody, bool allAtOnce){ /// \todo Include GET/POST variable parsing? + if (allAtOnce){ + /// \TODO Make this less duplicated / more pretty. + + std::map::iterator it; + if (protocol.size() < 5 || protocol[4] != '/'){protocol = "HTTP/1.0";} + builder = method + " " + url + " " + protocol + "\r\n"; + if (reqbody.size()){SetHeader("Content-Length", reqbody.length());} + for (it = headers.begin(); it != headers.end(); it++){ + if ((*it).first != "" && (*it).second != ""){ + builder += (*it).first + ": " + (*it).second + "\r\n"; + } + } + builder += "\r\n"; + if (reqbody.size()){ + builder += reqbody; + }else{ + builder += body; + } + conn.SendNow(builder); + return; + } std::map::iterator it; if (protocol.size() < 5 || protocol[4] != '/'){protocol = "HTTP/1.0";} builder = method + " " + url + " " + protocol + "\r\n"; @@ -801,6 +836,10 @@ bool HTTP::Parser::parse(std::string &HTTPbuffer){ length = atoi(GetHeader("Content-Length").c_str()); if (body.capacity() < length){body.reserve(length);} } + if (GetHeader("Content-length") != ""){ + length = atoi(GetHeader("Content-length").c_str()); + if (body.capacity() < length){body.reserve(length);} + } if (GetHeader("Transfer-Encoding") == "chunked"){ getChunks = true; doingChunk = 0; diff --git a/lib/http_parser.h b/lib/http_parser.h index 53dccbbe..13ee3c21 100644 --- a/lib/http_parser.h +++ b/lib/http_parser.h @@ -36,7 +36,7 @@ namespace HTTP{ std::string &BuildRequest(); std::string &BuildResponse(); std::string &BuildResponse(std::string code, std::string message); - void SendRequest(Socket::Connection &conn, const std::string &reqbody = ""); + void SendRequest(Socket::Connection &conn, const std::string &reqbody = "", bool allAtOnce = false); void SendResponse(std::string code, std::string message, Socket::Connection &conn); void StartResponse(std::string code, std::string message, Parser &request, Socket::Connection &conn, bool bufferAllChunks = false); diff --git a/lib/sdp.cpp b/lib/sdp.cpp index f3bd7e13..43a6efcb 100644 --- a/lib/sdp.cpp +++ b/lib/sdp.cpp @@ -341,6 +341,7 @@ namespace SDP{ } void State::parseSDP(const std::string &sdp){ + DONTEVEN_MSG("Parsing %llu-byte SDP", sdp.size()); std::stringstream ss(sdp); std::string to; uint64_t trackNo = 0; @@ -349,6 +350,7 @@ namespace SDP{ while (std::getline(ss, to, '\n')){ if (!to.empty() && *to.rbegin() == '\r'){to.erase(to.size() - 1, 1);} if (to.empty()){continue;} + DONTEVEN_MSG("Parsing SDP line: %s", to.c_str()); // All tracks start with a media line if (to.substr(0, 2) == "m="){ diff --git a/src/input/input_rtsp.cpp b/src/input/input_rtsp.cpp index db0090a4..1a1396b5 100755 --- a/src/input/input_rtsp.cpp +++ b/src/input/input_rtsp.cpp @@ -98,7 +98,7 @@ namespace Mist{ sndH.SetHeader(it->first, it->second); } } - sndH.SendRequest(tcpCon); + sndH.SendRequest(tcpCon, "", true); } bool InputRTSP::checkArguments(){ @@ -129,6 +129,8 @@ namespace Mist{ void InputRTSP::parseStreamHeader(){ std::map extraHeaders; + sendCommand("OPTIONS", url.getUrl(), ""); + parsePacket(); extraHeaders["Accept"] = "application/sdp"; sendCommand("DESCRIBE", url.getUrl(), "", &extraHeaders); parsePacket(); @@ -215,7 +217,10 @@ namespace Mist{ if (recH.hasHeader("Content-Location")){ url = HTTP::URL(recH.GetHeader("Content-Location")); } - if (recH.hasHeader("Content-Base")){url = HTTP::URL(recH.GetHeader("Content-Base"));} + if (recH.hasHeader("Content-Base") && recH.GetHeader("Content-Base") != "" && recH.GetHeader("Content-Base") != url.getUrl()){ + INFO_MSG("Changing base URL from %s to %s", url.getUrl().c_str(), recH.GetHeader("Content-Base").c_str()); + url = HTTP::URL(recH.GetHeader("Content-Base")); + } if (recH.hasHeader("Session")){ session = recH.GetHeader("Session"); if (session.find(';') != std::string::npos){ @@ -224,12 +229,15 @@ namespace Mist{ } if (recH.hasHeader("Content-Type") && recH.GetHeader("Content-Type") == "application/sdp"){ + INFO_MSG("Received SDP"); seenSDP = true; sdpState.parseSDP(recH.body); recH.Clean(); + INFO_MSG("SDP contained %llu tracks", myMeta.tracks.size()); return true; } if (recH.hasHeader("Transport")){ + INFO_MSG("Received setup response"); uint32_t trackNo = sdpState.parseSetup(recH, url.host, ""); if (trackNo){ INFO_MSG("Parsed transport for track: %lu", trackNo);