TEST( UrlParserTest, ParseIP ) { std::string url( "http://127.0.0.1/param1=abc-123" ); UrlParser urlParser( url.c_str(), url.size() ); checkResult( "http", urlParser.getScheme(), urlParser.getSchemeLen() ); checkResult( "127.0.0.1", urlParser.getAuthority(), urlParser.getAuthorityLen() ); checkResult( "127.0.0", urlParser.getDomain(), urlParser.getDomainLen() ); }
TEST( UrlParserTest, ParseUserInfoPort ) { std::string url( "http://*****:*****@www.example.com:8080/param1=abc-123" ); UrlParser urlParser( url.c_str(), url.size() ); checkResult( "http", urlParser.getScheme(), urlParser.getSchemeLen() ); checkResult( "username:[email protected]:8080", urlParser.getAuthority(), urlParser.getAuthorityLen() ); checkResult( "example.com", urlParser.getDomain(), urlParser.getDomainLen() ); }
TEST( UrlParserTest, ParsePortSchemeNone ) { std::string url( "www.example.com:8080/param1=abc-123" ); UrlParser urlParser( url.c_str(), url.size() ); checkResult( NULL, urlParser.getScheme(), urlParser.getSchemeLen() ); checkResult( "www.example.com:8080", urlParser.getAuthority(), urlParser.getAuthorityLen() ); checkResult( "example.com", urlParser.getDomain(), urlParser.getDomainLen() ); }
TEST( UrlParserTest, ParseSchemeHttps ) { std::string url( "https://www.example.com/param1=abc-123" ); UrlParser urlParser( url.c_str(), url.size() ); checkResult( "https", urlParser.getScheme(), urlParser.getSchemeLen() ); checkResult( "www.example.com", urlParser.getAuthority(), urlParser.getAuthorityLen() ); checkResult( "example.com", urlParser.getDomain(), urlParser.getDomainLen() ); }
TEST( UrlParserTest, ParseIDN ) { std::string url( "http://www.xn--relgeroskilde-5fb0y.dk/" ); UrlParser urlParser( url.c_str(), url.size() ); checkResult( "http", urlParser.getScheme(), urlParser.getSchemeLen() ); checkResult( "www.xn--relgeroskilde-5fb0y.dk", urlParser.getAuthority(), urlParser.getAuthorityLen() ); checkResult( "xn--relgeroskilde-5fb0y.dk", urlParser.getDomain(), urlParser.getDomainLen() ); }
TEST( UrlParserTest, ParseSLDUnknown ) { std::string url( "http://subdomain.example.fuel.aero/param1=abc-123" ); UrlParser urlParser( url.c_str(), url.size() ); checkResult( "http", urlParser.getScheme(), urlParser.getSchemeLen() ); checkResult( "subdomain.example.fuel.aero", urlParser.getAuthority(), urlParser.getAuthorityLen() ); checkResult( "fuel.aero", urlParser.getDomain(), urlParser.getDomainLen() ); }
TEST( UrlParserTest, ParseTLDNone ) { std::string url( "http://ok/" ); UrlParser urlParser( url.c_str(), url.size() ); checkResult( "http", urlParser.getScheme(), urlParser.getSchemeLen() ); checkResult( "ok", urlParser.getAuthority(), urlParser.getAuthorityLen() ); checkResult( NULL, urlParser.getDomain(), urlParser.getDomainLen() ); }
TEST( UrlParserTest, ParseSubdomainMultiple ) { std::string url( "http://abc.def.ghi.jkl.example.com/param1=abc-123" ); UrlParser urlParser( url.c_str(), url.size() ); checkResult( "http", urlParser.getScheme(), urlParser.getSchemeLen() ); checkResult( "abc.def.ghi.jkl.example.com", urlParser.getAuthority(), urlParser.getAuthorityLen() ); checkResult( "example.com", urlParser.getDomain(), urlParser.getDomainLen() ); }
QTSS_Error HTTPRequest::ParseURI(StringParser* parser) { // read in the complete URL into fRequestAbsURI parser->ConsumeUntil(&fAbsoluteURI, sURLStopConditions); StringParser urlParser(&fAbsoluteURI); // we always should have a slash before the URI // If not, that indicates this is a full URI if (fAbsoluteURI.Ptr[0] != '/') { //if it is a full URL, store the scheme and host name urlParser.ConsumeLength(&fAbsoluteURIScheme, 7); //consume "http://" urlParser.ConsumeUntil(&fHostHeader, '/'); } // whatever is in this position is the relative URI StrPtrLen relativeURI(urlParser.GetCurrentPosition(), urlParser.GetDataReceivedLen() - urlParser.GetDataParsedLen()); // read this URI into fRequestRelURI fRelativeURI = relativeURI; // Allocate memory for fRequestPath UInt32 len = fRelativeURI.Len; len++; //char* relativeURIDecoded = NEW char[len]; char relativeURIDecoded[512] = { 0 }; SInt32 theBytesWritten = StringTranslator::DecodeURL(fRelativeURI.Ptr, fRelativeURI.Len, relativeURIDecoded, len); //if negative, an error occurred, reported as an QTSS_Error //we also need to leave room for a terminator. if ((theBytesWritten < 0) || ((UInt32)theBytesWritten == len)) { fStatusCode = httpBadRequest; return QTSS_BadArgument; } fRequestPath = NULL; ////fRequestPath = NEW char[theBytesWritten + 1]; ////::memcpy(fRequestPath, relativeURIDecoded + 1, theBytesWritten); //////delete relativeURIDecoded; ////fRequestPath[theBytesWritten] = '\0'; return QTSS_NoErr; }
QTSS_Error HTTPRequest::ParseURI(StringParser* parser) { // read in the complete URL into fRequestAbsURI parser->ConsumeUntil(&fAbsoluteURI, sURLStopConditions); StringParser urlParser(&fAbsoluteURI); // we always should have a slash before the URI // If not, that indicates this is a full URI if (fAbsoluteURI.Ptr[0] != '/') { //if it is a full URL, store the scheme and host name urlParser.ConsumeLength(&fAbsoluteURIScheme, 7); //consume "http://" urlParser.ConsumeUntil(&fHostHeader, '/'); } StrPtrLen queryString; //this->SetVal(qtssRTSPReqQueryString, queryString.Ptr, queryString.Len); if ( parser->GetDataRemaining() > 0 ) { if ( parser->PeekFast() == '?' ) { // we've got some CGI param parser->ConsumeLength(&queryString, 1); // toss '?' // consume the rest of the line.. parser->ConsumeUntilWhitespace(&queryString); if(queryString.Len) { if (fQueryString != NULL) { delete [] fQueryString; fQueryString = NULL; } fQueryString = NEW char[queryString.Len + 1]; ::memcpy(fQueryString, queryString.Ptr, queryString.Len); fQueryString[queryString.Len] = '\0'; //this->SetVal(qtssRTSPReqQueryString, queryString.Ptr, queryString.Len); } } }
//returns: SyntaxError if there was an error in the uri. Or InternalServerError QTSS_Error RTSPRequest::ParseURI(StringParser &parser) { //read in the complete URL, set it to be the qtssAbsoluteURLParam StrPtrLen theAbsURL; // RTSPRequestInterface::sPathURLStopConditions stop on ? as well as sURLStopConditions parser.ConsumeUntil(&theAbsURL, sURLStopConditions ); // set qtssRTSPReqAbsoluteURL to the URL throught the path component; will be : <protocol>://<host-addr>/<path> this->SetVal(qtssRTSPReqAbsoluteURL, &theAbsURL); StringParser urlParser(&theAbsURL); //we always should have a slash before the uri. //If not, that indicates this is a full URI. Also, this could be a '*' OPTIONS request if ((*theAbsURL.Ptr != '/') && (*theAbsURL.Ptr != '*')) { //if it is a full URL, store the host name off in a separate parameter StrPtrLen theRTSPString; urlParser.ConsumeLength(&theRTSPString, 7); //consume "rtsp://" //assign the host field here to the proper QTSS param StrPtrLen theHost; urlParser.ConsumeUntil(&theHost, '/'); fHeaderDictionary.SetVal(qtssHostHeader, &theHost); } // don't allow non-aggregate operations indicated by a url/media track=id // might need this for rate adapt if (qtssSetupMethod != fMethod && qtssOptionsMethod != fMethod && qtssSetParameterMethod != fMethod) // any method not a setup, options, or setparameter is not allowed to have a "/trackID=" in the url. if (qtssSetupMethod != fMethod) // any method not a setup is not allowed to have a "/trackID=" in the url. { StrPtrLenDel tempCStr(theAbsURL.GetAsCString()); StrPtrLen nonaggregate(tempCStr.FindString("/trackID=")); if (nonaggregate.Len > 0) // check for non-aggregate method and return error return QTSSModuleUtils::SendErrorResponse(this, qtssClientAggregateOptionAllowed, qtssMsgBadRTSPMethod, &theAbsURL); } // don't allow non-aggregate operations like a setup on a playing session if (qtssSetupMethod == fMethod) // if it is a setup but we are playing don't allow it { RTSPSession* theSession = (RTSPSession*)this->GetSession(); if (theSession != NULL && theSession->IsPlaying()) return QTSSModuleUtils::SendErrorResponse(this, qtssClientAggregateOptionAllowed, qtssMsgBadRTSPMethod, &theAbsURL); } // // In case there is no URI at all... we have to fake it. static char* sSlashURI = "/"; //whatever is in this position in the URL must be the URI. Store that //in the qtssURLParam. Confused? UInt32 uriLen = urlParser.GetDataReceivedLen() - urlParser.GetDataParsedLen(); if (uriLen > 0) this->SetVal(qtssRTSPReqURI, urlParser.GetCurrentPosition(), urlParser.GetDataReceivedLen() - urlParser.GetDataParsedLen()); else // // This might happen if there is nothing after the host at all, not even // a '/'. This is legal (RFC 2326, Sec 3.2). If so, just pretend that there // is a '/' this->SetVal(qtssRTSPReqURI, sSlashURI, 1); // parse the query string from the url if present. // init qtssRTSPReqQueryString dictionary to an empty string StrPtrLen queryString; this->SetVal(qtssRTSPReqQueryString, queryString.Ptr, queryString.Len); if ( parser.GetDataRemaining() > 0 ) { if ( parser.PeekFast() == '?' ) { // we've got some CGI param parser.ConsumeLength(&queryString, 1); // toss '?' // consume the rest of the line.. parser.ConsumeUntilWhitespace(&queryString); this->SetVal(qtssRTSPReqQueryString, queryString.Ptr, queryString.Len); } } // // If the is a '*', return right now because '*' is not a path // so the below functions don't make any sense. if ((*theAbsURL.Ptr == '*') && (theAbsURL.Len == 1)) { this->SetValue(qtssRTSPReqFilePath, 0, theAbsURL.Ptr, theAbsURL.Len, QTSSDictionary::kDontObeyReadOnly); return QTSS_NoErr; } //path strings are statically allocated. Therefore, if they are longer than //this length we won't be able to handle the request. StrPtrLen* theURLParam = this->GetValue(qtssRTSPReqURI); if (theURLParam->Len > RTSPRequestInterface::kMaxFilePathSizeInBytes) return QTSSModuleUtils::SendErrorResponse(this, qtssClientBadRequest, qtssMsgURLTooLong, theURLParam); //decode the URL, put the result in the separate buffer for the file path, //set the file path StrPtrLen to the proper value SInt32 theBytesWritten = StringTranslator::DecodeURL(theURLParam->Ptr, theURLParam->Len, fFilePath, RTSPRequestInterface::kMaxFilePathSizeInBytes); //if negative, an error occurred, reported as an QTSS_Error //we also need to leave room for a terminator. if ((theBytesWritten < 0) || (theBytesWritten == RTSPRequestInterface::kMaxFilePathSizeInBytes)) { return QTSSModuleUtils::SendErrorResponse(this, qtssClientBadRequest, qtssMsgURLInBadFormat, theURLParam); } // Convert from a / delimited path to a local file system path StringTranslator::DecodePath(fFilePath, theBytesWritten); //setup the proper QTSS param fFilePath[theBytesWritten] = '\0'; //this->SetVal(qtssRTSPReqFilePath, fFilePath, theBytesWritten); this->SetValue(qtssRTSPReqFilePath, 0, fFilePath, theBytesWritten, QTSSDictionary::kDontObeyReadOnly); return QTSS_NoErr; }