void RTSPRequest::ParseModeSubHeader(StrPtrLen* inModeSubHeader) { static StrPtrLen sModeSubHeader("mode"); static StrPtrLen sReceiveMode("receive"); static StrPtrLen sRecordMode("record"); StringParser theSubHeaderParser(inModeSubHeader); // Skip over to the first port StrPtrLen theFirstBit; theSubHeaderParser.GetThru(&theFirstBit, '='); theFirstBit.TrimWhitespace(); // Make sure this is the client port subheader if (theFirstBit.EqualIgnoreCase(sModeSubHeader)) do { theSubHeaderParser.ConsumeWhitespace(); StrPtrLen theMode; theSubHeaderParser.ConsumeWord(&theMode); if ( theMode.EqualIgnoreCase(sReceiveMode) || theMode.EqualIgnoreCase(sRecordMode) ) { fTransportMode = qtssRTPTransportModeRecord; break; } } while (false); }
void RTSPRequest::ParseAddrSubHeader(StrPtrLen* inSubHeader, StrPtrLen* inHeaderName, UInt32* outAddr) { if (!inSubHeader || !inHeaderName || !outAddr) return; StringParser theSubHeaderParser(inSubHeader); // Skip over to the value StrPtrLen theFirstBit; theSubHeaderParser.GetThru(&theFirstBit, '='); theFirstBit.TrimWhitespace(); // First make sure this is the proper subheader if (!theFirstBit.EqualIgnoreCase(*inHeaderName)) return; //Find the IP address theSubHeaderParser.ConsumeUntilDigit(); //Set the addr string param. StrPtrLen theAddr(theSubHeaderParser.GetCurrentPosition(), theSubHeaderParser.GetDataRemaining()); //Convert the string to a UInt32 IP address char theTerminator = theAddr.Ptr[theAddr.Len]; theAddr.Ptr[theAddr.Len] = '\0'; *outAddr = SocketUtils::ConvertStringToAddr(theAddr.Ptr); theAddr.Ptr[theAddr.Len] = theTerminator; }
void RTSPRequest::ParseRetransmitHeader() { StringParser theRetransmitParser(fHeaderDictionary.GetValue(qtssXRetransmitHeader)); StrPtrLen theProtName; Bool16 foundRetransmitProt = false; do { theRetransmitParser.ConsumeWhitespace(); theRetransmitParser.ConsumeWord(&theProtName); theProtName.TrimTrailingWhitespace(); foundRetransmitProt = theProtName.EqualIgnoreCase(RTSPProtocol::GetRetransmitProtocolName()); } while ( (!foundRetransmitProt) && (theRetransmitParser.GetThru(NULL, ',')) ); if (!foundRetransmitProt) return; // // We are using Reliable RTP as the transport for this stream, // but if there was a previous transport header that indicated TCP, // do not set the transport to be reliable UDP if (fTransportType == qtssRTPTransportTypeUDP) fTransportType = qtssRTPTransportTypeReliableUDP; StrPtrLen theProtArg; while (theRetransmitParser.GetThru(&theProtArg, '=')) { // // Parse out params static const StrPtrLen kWindow("window"); theProtArg.TrimWhitespace(); if (theProtArg.EqualIgnoreCase(kWindow)) { theRetransmitParser.ConsumeWhitespace(); fWindowSize = theRetransmitParser.ConsumeInteger(NULL); // Save out the window size argument as a string so we // can easily put it into the response // (we never muck with this header) fWindowSizeStr.Ptr = theProtArg.Ptr; fWindowSizeStr.Len = theRetransmitParser.GetCurrentPosition() - theProtArg.Ptr; } theRetransmitParser.GetThru(NULL, ';'); //Skip past ';' } }
void RTSPRequest::ParseTimeToLiveSubHeader(StrPtrLen* inTimeToLiveSubHeader) { static StrPtrLen sTimeToLiveSubHeader("ttl"); StringParser theSubHeaderParser(inTimeToLiveSubHeader); // Skip over to the first part StrPtrLen theFirstBit; theSubHeaderParser.GetThru(&theFirstBit, '='); theFirstBit.TrimWhitespace(); // Make sure this is the ttl subheader if (!theFirstBit.EqualIgnoreCase(sTimeToLiveSubHeader)) return; // Parse out the time to live... theSubHeaderParser.ConsumeWhitespace(); fTtl = (UInt16)theSubHeaderParser.ConsumeInteger(NULL); }
void RTSPRequest::ParsePrebufferHeader() { StringParser thePrebufferParser(fHeaderDictionary.GetValue(qtssXPreBufferHeader)); StrPtrLen thePrebufferArg; while (thePrebufferParser.GetThru(&thePrebufferArg, '=')) { thePrebufferArg.TrimWhitespace(); static const StrPtrLen kMaxTimeSubHeader("maxtime"); if (thePrebufferArg.EqualIgnoreCase(kMaxTimeSubHeader)) { thePrebufferParser.ConsumeWhitespace(); fPrebufferAmt = thePrebufferParser.ConsumeFloat(); } thePrebufferParser.GetThru(NULL, ';'); //Skip past ';' } }
void RTSPRequest::ParseClientPortSubHeader(StrPtrLen* inClientPortSubHeader) { static StrPtrLen sClientPortSubHeader("client_port"); static StrPtrLen sErrorMessage("Received invalid client_port field: "); StringParser theSubHeaderParser(inClientPortSubHeader); // Skip over to the first port StrPtrLen theFirstBit; theSubHeaderParser.GetThru(&theFirstBit, '='); theFirstBit.TrimWhitespace(); // Make sure this is the client port subheader if (!theFirstBit.EqualIgnoreCase(sClientPortSubHeader)) return; // Store the two client ports as integers theSubHeaderParser.ConsumeWhitespace(); fClientPortA = (UInt16)theSubHeaderParser.ConsumeInteger(NULL); theSubHeaderParser.GetThru(NULL,'-'); theSubHeaderParser.ConsumeWhitespace(); fClientPortB = (UInt16)theSubHeaderParser.ConsumeInteger(NULL); if (fClientPortB != fClientPortA + 1) // an error in the port values { // The following to setup and log the error as a message level 2. StrPtrLen *userAgentPtr = fHeaderDictionary.GetValue(qtssUserAgentHeader); ResizeableStringFormatter errorPortMessage; errorPortMessage.Put(sErrorMessage); if (userAgentPtr != NULL) errorPortMessage.Put(*userAgentPtr); errorPortMessage.PutSpace(); errorPortMessage.Put(*inClientPortSubHeader); errorPortMessage.PutTerminator(); QTSSModuleUtils::LogError(qtssMessageVerbosity,qtssMsgNoMessage, 0, errorPortMessage.GetBufPtr(), NULL); //fix the rtcp port and hope it works. fClientPortB = fClientPortA + 1; } }
void RTSPRequest::ParseTransportHeader() { static char* sRTPAVPTransportStr = "RTP/AVP"; StringParser theTransParser(fHeaderDictionary.GetValue(qtssTransportHeader)); //transport header from client: Transport: RTP/AVP;unicast;client_port=5000-5001\r\n // Transport: RTP/AVP;multicast;ttl=15;destination=229.41.244.93;client_port=5000-5002\r\n // Transport: RTP/AVP/TCP;unicast\r\n // // A client may send multiple transports to the server, comma separated. // In this case, the server should just pick one and use that. while (theTransParser.GetDataRemaining() > 0) { (void)theTransParser.ConsumeWhitespace(); (void)theTransParser.ConsumeUntil(&fFirstTransport, ','); if (fFirstTransport.NumEqualIgnoreCase(sRTPAVPTransportStr, ::strlen(sRTPAVPTransportStr))) break; if (theTransParser.PeekFast() == ',') theTransParser.Expect(','); } StringParser theFirstTransportParser(&fFirstTransport); StrPtrLen theTransportSubHeader; (void)theFirstTransportParser.GetThru(&theTransportSubHeader, ';'); while (theTransportSubHeader.Len > 0) { // Extract the relevent information from the relevent subheader. // So far we care about 3 sub-headers if (!this->ParseNetworkModeSubHeader(&theTransportSubHeader)) { theTransportSubHeader.TrimWhitespace(); switch (*theTransportSubHeader.Ptr) { case 'r': // rtp/avp/??? Is this tcp or udp? case 'R': // RTP/AVP/??? Is this TCP or UDP? { if ( theTransportSubHeader.EqualIgnoreCase("RTP/AVP/TCP") ) fTransportType = qtssRTPTransportTypeTCP; break; } case 'c': //client_port sub-header case 'C': //client_port sub-header { this->ParseClientPortSubHeader(&theTransportSubHeader); break; } case 'd': //destination sub-header case 'D': //destination sub-header { static StrPtrLen sDestinationSubHeader("destination"); //Parse the header, extract the destination address this->ParseAddrSubHeader(&theTransportSubHeader, &sDestinationSubHeader, &fDestinationAddr); break; } case 's': //source sub-header case 'S': //source sub-header { //Same as above code static StrPtrLen sSourceSubHeader("source"); this->ParseAddrSubHeader(&theTransportSubHeader, &sSourceSubHeader, &fSourceAddr); break; } case 't': //time-to-live sub-header case 'T': //time-to-live sub-header { this->ParseTimeToLiveSubHeader(&theTransportSubHeader); break; } case 'm': //mode sub-header case 'M': //mode sub-header { this->ParseModeSubHeader(&theTransportSubHeader); break; } } } // Move onto the next parameter (void)theFirstTransportParser.GetThru(&theTransportSubHeader, ';'); } }
//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; }