//returns: StatusLineTooLong, SyntaxError, BadMethod QTSS_Error RTSPRequest::ParseFirstLine(StringParser &parser) { //first get the method StrPtrLen theParsedData; parser.ConsumeWord(&theParsedData); this->SetVal(qtssRTSPReqMethodStr, theParsedData.Ptr, theParsedData.Len); //THIS WORKS UNDER THE ASSUMPTION THAT: //valid HTTP/1.1 headers are: GET, HEAD, POST, PUT, OPTIONS, DELETE, TRACE fMethod = RTSPProtocol::GetMethod(theParsedData); if (fMethod == qtssIllegalMethod) return QTSSModuleUtils::SendErrorResponse(this, qtssClientBadRequest, qtssMsgBadRTSPMethod, &theParsedData); //no longer assume this is a space... instead, just consume whitespace parser.ConsumeWhitespace(); //now parse the uri QTSS_Error err = ParseURI(parser); if (err != QTSS_NoErr) return err; //no longer assume this is a space... instead, just consume whitespace parser.ConsumeWhitespace(); //if there is a version, consume the version string StrPtrLen versionStr; parser.ConsumeUntil(&versionStr, StringParser::sEOLMask); //check the version if (versionStr.Len > 0) fVersion = RTSPProtocol::GetVersion(versionStr); //go past the end of line if (!parser.ExpectEOL()) return QTSSModuleUtils::SendErrorResponse(this, qtssClientBadRequest, qtssMsgNoRTSPVersion,&theParsedData); return QTSS_NoErr; }
//throws eHTTPNoMoreData and eHTTPOutOfBuffer QTSS_Error RTSPRequest::ParseHeaders(StringParser& parser) { StrPtrLen theKeyWord; Bool16 isStreamOK; //Repeat until we get a \r\n\r\n, which signals the end of the headers while ((parser.PeekFast() != '\r') && (parser.PeekFast() != '\n')) { //First get the header identifier isStreamOK = parser.GetThru(&theKeyWord, ':'); if (!isStreamOK) return QTSSModuleUtils::SendErrorResponse(this, qtssClientBadRequest, qtssMsgNoColonAfterHeader, this->GetValue(qtssRTSPReqFullRequest)); theKeyWord.TrimWhitespace(); //Look up the proper header enumeration based on the header string. //Use the enumeration to look up the dictionary ID of this header, //and set that dictionary attribute to be whatever is in the body of the header UInt32 theHeader = RTSPProtocol::GetRequestHeader(theKeyWord); StrPtrLen theHeaderVal; parser.ConsumeUntil(&theHeaderVal, StringParser::sEOLMask); StrPtrLen theEOL; if ((parser.PeekFast() == '\r') || (parser.PeekFast() == '\n')) { isStreamOK = true; parser.ConsumeEOL(&theEOL); } else isStreamOK = false; while((parser.PeekFast() == ' ') || (parser.PeekFast() == '\t')) { theHeaderVal.Len += theEOL.Len; StrPtrLen temp; parser.ConsumeUntil(&temp, StringParser::sEOLMask); theHeaderVal.Len += temp.Len; if ((parser.PeekFast() == '\r') || (parser.PeekFast() == '\n')) { isStreamOK = true; parser.ConsumeEOL(&theEOL); } else isStreamOK = false; } // If this is an unknown header, ignore it. Otherwise, set the proper // dictionary attribute if (theHeader != qtssIllegalHeader) { Assert(theHeader < qtssNumHeaders); theHeaderVal.TrimWhitespace(); fHeaderDictionary.SetVal(theHeader, &theHeaderVal); } if (!isStreamOK) return QTSSModuleUtils::SendErrorResponse(this, qtssClientBadRequest, qtssMsgNoEOLAfterHeader); //some headers require some special processing. If this code begins //to get out of control, we made need to come up with a function pointer table switch (theHeader) { case qtssSessionHeader: ParseSessionHeader(); break; case qtssTransportHeader: ParseTransportHeader(); break; case qtssRangeHeader: ParseRangeHeader(); break; case qtssIfModifiedSinceHeader: ParseIfModSinceHeader();break; case qtssXRetransmitHeader: ParseRetransmitHeader();break; case qtssContentLengthHeader: ParseContentLengthHeader();break; case qtssSpeedHeader: ParseSpeedHeader(); break; case qtssXTransportOptionsHeader: ParseTransportOptionsHeader();break; case qtssXPreBufferHeader: ParsePrebufferHeader();break; case qtssXDynamicRateHeader: ParseDynamicRateHeader(); break; case qtssXRandomDataSizeHeader: ParseRandomDataSizeHeader(); break; case qtss3GPPAdaptationHeader: fRequest3GPP.ParseAdpationHeader(&fHeaderDictionary); break; case qtss3GPPLinkCharHeader: fRequest3GPP.ParseLinkCharHeader(&fHeaderDictionary); break; case qtssBandwidthHeader: ParseBandwidthHeader(); break; default: break; } } // Tell the session what the request body length is for this request // so that it can prevent people from reading past the end of the request. StrPtrLen* theContentLengthBody = fHeaderDictionary.GetValue(qtssContentLengthHeader); if (theContentLengthBody->Len > 0) { StringParser theHeaderParser(fHeaderDictionary.GetValue(qtssContentLengthHeader)); theHeaderParser.ConsumeWhitespace(); this->GetSession()->SetRequestBodyLength(theHeaderParser.ConsumeInteger(NULL)); } isStreamOK = parser.ExpectEOL(); Assert(isStreamOK); return QTSS_NoErr; }