📄 msgheaderscanner.cxx
字号:
processMsgHeaderStatusLine(
SipMessage * msg,
char * lineText,
unsigned int lineTextLength,
MsgHeaderScanner::TextPropBitMask lineTextPropBitMask)
{
printf("status line: ");
printText(lineText, lineTextLength);
printf("\n");
return true;
}
static
void
processMsgHeaderFieldNameAndValue(
SipMessage * msg,
int fieldKind,
const char * fieldName,
unsigned int fieldNameLength,
char * valueText,
unsigned int valueTextLength,
MsgHeaderScanner::TextPropBitMask valueTextPropBitMask)
{
printText(fieldName, fieldNameLength);
printf(": [[[[");
printText(valueText, valueTextLength);
printf("]]]]\n");
}
#else //!defined(RESIP_MSG_HEADER_SCANNER_DEBUG) } {
// Determine a field's kind and whether it allows (comma separated) multi-values.
// "fieldName" is not empty and contains only legal characters.
// The text in "fieldName" may be canonicalized (eg, translating % escapes),
// including shrinking it if necessary.
inline void
lookupMsgHeaderFieldInfo(char * fieldName,
unsigned int *fieldNameLength,
MsgHeaderScanner::TextPropBitMask fieldNameTextPropBitMask,
int *fieldKind,
bool *isMultiValueAllowed)
{
//.jacob. Don't ignore fieldNameTextPropBitMask.
*fieldKind = Headers::getType(fieldName, *fieldNameLength);
*isMultiValueAllowed =
Headers::isCommaTokenizing(static_cast<Headers::Type>(*fieldKind));
}
// "lineText" contains no carriage returns and no line feeds.
// Return true on success, false on failure.
inline bool
processMsgHeaderStatusLine(SipMessage * msg,
char * lineText,
unsigned int lineTextLength,
MsgHeaderScanner::TextPropBitMask lineTextPropBitMask)
{
//.jacob. Don't ignore valueTextPropBitMask, and don't always return true.
msg->setStartLine(lineText, lineTextLength);
return true;
}
// This function is called once for a field with one value. (The value could be
// several values, but separated by something other than commas.)
// This function is called once for a field with 0 comma-separated values, with
// an empty value.
// This function is called N times for a field with N comma-separated values,
// but with the same value of "fieldName" each time.
// "fieldName" is not empty and contains only legal characters.
// "valueText" may be empty, has no leading whitespace, may contain trailing
// whitespace, contains carriage returns and line feeds only in correct pairs
// and followed by whitespace, and, if the field is multi-valued, contains
// balanced '<'/'>' and '"' pairs, contains ',' only within '<'/'>' or '"'
// pairs, and respects '\\'s within '"' pairs.
// The text in "valueText" may be canonicalized (eg, translating % escapes),
// including shrinking it if necessary.
inline void
processMsgHeaderFieldNameAndValue(SipMessage * msg,
int fieldKind,
const char * fieldName,
unsigned int fieldNameLength,
char * valueText,
unsigned int valueTextLength,
MsgHeaderScanner::TextPropBitMask valueTextPropBitMask)
{
//.jacob. Don't ignore valueTextPropBitMask, particularly for '\r' & '\n'.
msg->addHeader(static_cast<Headers::Type>(fieldKind),
fieldName,
fieldNameLength,
valueText,
valueTextLength);
}
#endif //!defined(RESIP_MSG_HEADER_SCANNER_DEBUG) }
bool MsgHeaderScanner::mInitialized = false;
MsgHeaderScanner::MsgHeaderScanner()
{
if (!mInitialized)
{
mInitialized = true;
initialize();
}
}
void
MsgHeaderScanner::prepareForMessage(SipMessage * msg)
{
mMsg = msg;
mState = sMsgStart;
mPrevScanChunkNumSavedTextChars = 0;
}
void
MsgHeaderScanner::prepareForFrag(SipMessage * msg, bool hasStartLine)
{
mMsg = msg;
if (hasStartLine)
{
mState = sMsgStart;
}
else
{
mState = sAfterLineBreakAfterStatusLine;
}
mPrevScanChunkNumSavedTextChars = 0;
}
MsgHeaderScanner::ScanChunkResult
MsgHeaderScanner::scanChunk(char * chunk,
unsigned int chunkLength,
char ** unprocessedCharPtr)
{
MsgHeaderScanner::ScanChunkResult result;
CharInfo* localCharInfoArray = charInfoArray;
TransitionInfo (*localStateMachine)[numCharCategories] = stateMachine;
State localState = mState;
char *charPtr = chunk + mPrevScanChunkNumSavedTextChars;
char *termCharPtr = chunk + chunkLength;
char saveChunkTermChar = *termCharPtr;
*termCharPtr = chunkTermSentinelChar;
char *textStartCharPtr;
MsgHeaderScanner::TextPropBitMask localTextPropBitMask = mTextPropBitMask;
if (mPrevScanChunkNumSavedTextChars == 0)
{
textStartCharPtr = 0;
}
else
{
textStartCharPtr = chunk;
}
--charPtr; // The loop starts by advancing "charPtr", so pre-adjust it.
for (;;)
{
// BEGIN message header character scan block BEGIN
// The code in this block is executed once per message header character.
// This entire file is designed specifically to minimize this block's size.
++charPtr;
CharInfo *charInfo = &localCharInfoArray[((unsigned char) (*charPtr))];
CharCategory charCategory = charInfo->category;
localTextPropBitMask |= charInfo->textPropBitMask;
determineTransitionFromCharCategory:
TransitionInfo *transitionInfo =
&(localStateMachine[localState][charCategory]);
TransitionAction transitionAction = transitionInfo->action;
#if defined(RESIP_MSG_HEADER_SCANNER_DEBUG)
printStateTransition(localState, *charPtr, transitionAction);
#endif
localState = transitionInfo->nextState;
if (transitionAction == taNone) continue;
// END message header character scan block END
// The loop remainder is executed about 4-5 times per message header line.
switch (transitionAction)
{
case taTermStatusLine:
if (!processMsgHeaderStatusLine(mMsg,
textStartCharPtr,
charPtr - textStartCharPtr,
localTextPropBitMask))
{
result = MsgHeaderScanner::scrError;
*unprocessedCharPtr = charPtr;
goto endOfFunction;
}
textStartCharPtr = 0;
break;
case taTermFieldName:
{
mFieldNameLength = charPtr - textStartCharPtr;
bool isMultiValueAllowed;
lookupMsgHeaderFieldInfo(textStartCharPtr,
&mFieldNameLength,
localTextPropBitMask,
&mFieldKind,
&isMultiValueAllowed);
mFieldName = textStartCharPtr;
textStartCharPtr = 0;
if (isMultiValueAllowed)
{
localState += deltaOfNStateFrom1State;
}
}
break;
case taBeyondEmptyValue:
processMsgHeaderFieldNameAndValue(mMsg,
mFieldKind,
mFieldName,
mFieldNameLength,
0,
0,
0);
goto performStartTextAction;
case taTermValueAfterLineBreak:
processMsgHeaderFieldNameAndValue(mMsg,
mFieldKind,
mFieldName,
mFieldNameLength,
textStartCharPtr,
(charPtr - textStartCharPtr) - 2,
localTextPropBitMask); //^:CRLF
goto performStartTextAction;
case taTermValue:
processMsgHeaderFieldNameAndValue(mMsg,
mFieldKind,
mFieldName,
mFieldNameLength,
textStartCharPtr,
charPtr - textStartCharPtr,
localTextPropBitMask);
textStartCharPtr = 0;
break;
case taStartText:
performStartTextAction:
textStartCharPtr = charPtr;
localTextPropBitMask = 0;
break;
case taEndHeader:
// textStartCharPtr is not 0. Not currently relevant.
result = MsgHeaderScanner::scrEnd;
*unprocessedCharPtr = charPtr + 1; // The current char is processed.
goto endOfFunction;
break;
case taChunkTermSentinel:
if (charPtr == termCharPtr)
{
// The chunk has been consumed. Save some state and request another.
mState = localState;
if (textStartCharPtr == 0)
{
mPrevScanChunkNumSavedTextChars = 0;
}
else
{
mPrevScanChunkNumSavedTextChars = termCharPtr - textStartCharPtr;
}
mTextPropBitMask = localTextPropBitMask;
result = MsgHeaderScanner::scrNextChunk;
*unprocessedCharPtr = termCharPtr - mPrevScanChunkNumSavedTextChars;
goto endOfFunction;
}
else
{
// The character is not the sentinel. Treat it like any other.
charCategory = ccOther;
goto determineTransitionFromCharCategory;
}
break;
default:
result = MsgHeaderScanner::scrError;
*unprocessedCharPtr = charPtr;
goto endOfFunction;
}//switch
}//for
endOfFunction:
*termCharPtr = saveChunkTermChar;
return result;
}
bool
MsgHeaderScanner::initialize()
{
initCharInfoArray();
initStateMachine();
return true;
}
} //namespace resip
#if defined(RESIP_MSG_HEADER_SCANNER_DEBUG) && defined(MSG_SCANNER_STANDALONE)
extern
int
main(unsigned int numArgs,
const char * * argVector)
{
::resip::MsgHeaderScanner scanner;
scanner.prepareForMessage(0);
char *text =
"status\r\n"
"bobby: dummy\r\n"
"allow: foo, bar, \"don,\\\"xyz\r\n zy\", buzz\r\n\r\n";
unsigned int textLength = strlen(text);
char chunk[10000];
strcpy(chunk, text);
::resip::MsgHeaderScanner::ScanChunkResult scanChunkResult;
char *unprocessedCharPtr;
scanChunkResult = scanner.scanChunk(chunk, 21, &unprocessedCharPtr);
if (scanChunkResult == ::resip::MsgHeaderScanner::scrNextChunk)
{
printf("Scanning another chunk '.");
::resip::printText(unprocessedCharPtr, 1);
printf("'\n");
scanChunkResult =
scanner.scanChunk(unprocessedCharPtr,
(chunk + textLength) - unprocessedCharPtr,
&unprocessedCharPtr);
}
if (scanChunkResult != ::resip::MsgHeaderScanner::scrEnd)
{
printf("Error %d at character %d.\n",
scanChunkResult,
unprocessedCharPtr - chunk);
}
return 0;
}
#endif //!defined(RESIP_MSG_HEADER_SCANNER_DEBUG) }
/* ====================================================================
* The Vovida Software License, Version 1.0
*
* Copyright (c) 2000-2005
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The names "VOCAL", "Vovida Open Communication Application Library",
* and "Vovida Open Communication Application Library (VOCAL)" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact vocal@vovida.org.
*
* 4. Products derived from this software may not be called "VOCAL", nor
* may "VOCAL" appear in their name, without prior written
* permission of Vovida Networks, Inc.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
* NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
* IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* ====================================================================
*
* This software consists of voluntary contributions made by Vovida
* Networks, Inc. and many individuals on behalf of Vovida Networks,
* Inc. For more information on Vovida Networks, Inc., please see
* <http://www.vovida.org/>.
*
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -