1
#if defined(HAVE_CONFIG_H)
8
#include "resip/stack/HeaderTypes.hxx"
9
#include "resip/stack/SipMessage.hxx"
10
#include "resip/stack/MsgHeaderScanner.hxx"
11
#include "rutil/WinLeakCheck.hxx"
16
///////////////////////////////////////////////////////////////////////////////
17
// Any character could be used as the chunk terminating sentinel, as long as
18
// it would otherwise be character category "other". The null character
19
// was chosen because it is unlikely to occur naturally -- but it's OK if it
22
enum { chunkTermSentinelChar = '\0' };
31
ccDoubleQuotationMark,
40
typedef char CharCategory;
43
MsgHeaderScanner::allocateBuffer(int size)
45
return new char[size + MaxNumCharsChunkOverflow];
50
CharCategory category;
51
MsgHeaderScanner::TextPropBitMask textPropBitMask;
54
static CharInfo charInfoArray[UCHAR_MAX+1];
56
static inline int c2i(unsigned char c)
58
return static_cast<int>(c);
61
static void initCharInfoArray()
63
for(unsigned int charIndex = 0; charIndex <= UCHAR_MAX; ++charIndex)
65
charInfoArray[charIndex].category = ccOther;
66
charInfoArray[charIndex].textPropBitMask = 0;
69
for(const char *charPtr = "abcdefghijklmnopqrstuvwxyz"
70
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-.!%*_+`'~";
74
charInfoArray[c2i(*charPtr)].category = ccFieldName;
77
charInfoArray[c2i(' ')].category = ccWhitespace;
78
charInfoArray[c2i('\t')].category = ccWhitespace;
79
charInfoArray[c2i(':')].category = ccColon;
80
charInfoArray[c2i('"')].category = ccDoubleQuotationMark;
81
charInfoArray[c2i('<')].category = ccLeftAngleBracket;
82
charInfoArray[c2i('>')].category = ccRightAngleBracket;
83
charInfoArray[c2i('\\')].category = ccBackslash;
84
charInfoArray[c2i(',')].category = ccComma;
85
charInfoArray[c2i('\r')].category = ccCarriageReturn;
86
charInfoArray[c2i('\n')].category = ccLineFeed;
87
// Assert: "chunkTermSentinelChar"'s category is still the default "ccOther".
88
charInfoArray[c2i(chunkTermSentinelChar)].category = ccChunkTermSentinel;
89
// Init text property bit masks.
90
charInfoArray[c2i('\r')].textPropBitMask =
91
MsgHeaderScanner::tpbmContainsLineBreak;
92
charInfoArray[c2i('\n')].textPropBitMask =
93
MsgHeaderScanner::tpbmContainsLineBreak;
94
charInfoArray[c2i(' ')].textPropBitMask =
95
MsgHeaderScanner::tpbmContainsWhitespace;
96
charInfoArray[c2i('\t')].textPropBitMask =
97
MsgHeaderScanner::tpbmContainsWhitespace;
98
charInfoArray[c2i('\\')].textPropBitMask =
99
MsgHeaderScanner::tpbmContainsBackslash;
100
charInfoArray[c2i('%')].textPropBitMask =
101
MsgHeaderScanner::tpbmContainsPercent;
102
charInfoArray[c2i(';')].textPropBitMask =
103
MsgHeaderScanner::tpbmContainsSemicolon;
104
charInfoArray[c2i('(')].textPropBitMask =
105
MsgHeaderScanner::tpbmContainsParen;
106
charInfoArray[c2i(')')].textPropBitMask =
107
MsgHeaderScanner::tpbmContainsParen;
110
///////////////////////////////////////////////////////////////////////////////
111
// States marked '1' scan normal values. States marked 'N' scan multi-values.
116
sHalfLineBreakAtMsgStart,
118
sHalfLineBreakAfterStatusLine,
119
sAfterLineBreakAfterStatusLine,
121
sScanWhitespaceAfter1FieldName,
122
sScanWhitespaceAfterNFieldName,
123
sScanWhitespaceOr1Value,
124
sScanWhitespaceOrNValue,
125
sHalfLineBreakInWhitespaceBefore1Value,
126
sHalfLineBreakInWhitespaceBeforeNValue,
127
sAfterLineBreakInWhitespaceBefore1Value,
128
sAfterLineBreakInWhitespaceBeforeNValue,
131
sHalfLineBreakIn1Value,
132
sHalfLineBreakInNValue,
133
sAfterLineBreakIn1Value,
134
sAfterLineBreakInNValue,
136
sAfterEscCharInQuotesInNValue,
137
sHalfLineBreakInQuotesInNValue,
138
sAfterLineBreakInQuotesInNValue,
140
sHalfLineBreakInAnglesInNValue,
141
sAfterLineBreakInAnglesInNValue,
142
sHalfLineBreakAfterLineBreak,
148
// For each '1' state, the 'N' state is "deltaOfNStateFrom1State" larger.
149
enum { deltaOfNStateFrom1State = 1 };
153
enum TransitionActionEnum {
155
taTermStatusLine, // The current character terminates the status
157
taTermFieldName, // The current character terminates a field name.
158
// If the field supports multi-values, shift
159
// the state machine into multi-value scanning.
160
taBeyondEmptyValue, // The current character terminates an empty value.
161
// Implies taStartText.
162
taTermValueAfterLineBreak,
163
// The previous two characters are a linebreak
164
// terminating a value. Implies taStartText.
165
taTermValue, // The current character terminates a value.
166
taStartText, // The current character starts a text unit.
167
// (The status line, a field name, or a value.)
168
taEndHeader, // The current character mEnds_ the header.
169
taChunkTermSentinel, // Either the current character terminates the
170
// current chunk or it is an ordinary character.
171
taError // The input is erroneous.
173
typedef char TransitionAction;
176
struct TransitionInfo
178
TransitionAction action;
182
static TransitionInfo stateMachine[numStates][numCharCategories];
184
inline void specTransition(State state,
185
CharCategory charCategory,
186
TransitionAction action,
189
stateMachine[c2i(state)][c2i(charCategory)].action = action;
190
stateMachine[c2i(state)][c2i(charCategory)].nextState = nextState;
193
static void specDefaultTransition(State state,
194
TransitionAction action,
197
for (int charCategory = 0;
198
charCategory < numCharCategories;
201
specTransition(state, charCategory, action, nextState);
203
specTransition(state, ccCarriageReturn, taError, state);
204
specTransition(state, ccLineFeed, taError, state);
205
specTransition(state, ccChunkTermSentinel, taChunkTermSentinel, state);
208
static void specHalfLineBreakState(State halfLineBreakState,
209
State afterLineBreakState)
211
specDefaultTransition(halfLineBreakState, taError, halfLineBreakState);
212
specTransition(halfLineBreakState, ccLineFeed, taNone, afterLineBreakState);
216
// Single-value (1) scanning and multi-value (N) scanning involves several nearly
218
// "stateDelta" is either 0 or "deltaOfNStateFrom1State".
220
static void specXValueStates(int stateDelta)
222
specDefaultTransition(sScanWhitespaceAfter1FieldName + stateDelta,
224
sScanWhitespaceAfter1FieldName + stateDelta);
225
specTransition(sScanWhitespaceAfter1FieldName + stateDelta,
228
sScanWhitespaceAfter1FieldName + stateDelta);
229
specTransition(sScanWhitespaceAfter1FieldName + stateDelta,
232
sScanWhitespaceOr1Value + stateDelta);
233
specDefaultTransition(sScanWhitespaceOr1Value + stateDelta,
235
sScan1Value + stateDelta);
236
specTransition(sScanWhitespaceOr1Value + stateDelta,
239
sScanWhitespaceOr1Value + stateDelta);
240
if (stateDelta == deltaOfNStateFrom1State)
242
specTransition(sScanWhitespaceOr1Value + stateDelta,
245
sScanWhitespaceOr1Value + stateDelta);
246
specTransition(sScanWhitespaceOr1Value + stateDelta,
249
sScanNValueInAngles);
250
specTransition(sScanWhitespaceOr1Value + stateDelta,
251
ccDoubleQuotationMark,
253
sScanNValueInQuotes);
255
specTransition(sScanWhitespaceOr1Value + stateDelta,
258
sHalfLineBreakInWhitespaceBefore1Value + stateDelta);
259
specHalfLineBreakState(sHalfLineBreakInWhitespaceBefore1Value + stateDelta,
260
sAfterLineBreakInWhitespaceBefore1Value + stateDelta);
261
specDefaultTransition(sAfterLineBreakInWhitespaceBefore1Value + stateDelta,
263
sAfterLineBreakInWhitespaceBefore1Value + stateDelta);
264
specTransition(sAfterLineBreakInWhitespaceBefore1Value + stateDelta,
268
specTransition(sAfterLineBreakInWhitespaceBefore1Value + stateDelta,
271
sScanWhitespaceOr1Value + stateDelta);
272
specTransition(sAfterLineBreakInWhitespaceBefore1Value + stateDelta,
275
sHalfLineBreakAfterLineBreak);
276
specDefaultTransition(sScan1Value + stateDelta,
278
sScan1Value + stateDelta);
279
if (stateDelta == deltaOfNStateFrom1State)
281
specTransition(sScan1Value + stateDelta,
284
sScanWhitespaceOr1Value + stateDelta);
285
specTransition(sScan1Value + stateDelta,
288
sScanNValueInAngles);
289
specTransition(sScan1Value + stateDelta,
290
ccDoubleQuotationMark,
292
sScanNValueInQuotes);
294
specTransition(sScan1Value + stateDelta,
297
sHalfLineBreakIn1Value + stateDelta);
298
specHalfLineBreakState(sHalfLineBreakIn1Value + stateDelta,
299
sAfterLineBreakIn1Value + stateDelta);
300
specDefaultTransition(sAfterLineBreakIn1Value + stateDelta,
302
sAfterLineBreakIn1Value + stateDelta);
303
specTransition(sAfterLineBreakIn1Value + stateDelta,
305
taTermValueAfterLineBreak,
307
specTransition(sAfterLineBreakIn1Value + stateDelta,
310
sScan1Value + stateDelta);
311
specTransition(sAfterLineBreakIn1Value + stateDelta,
313
taTermValueAfterLineBreak,
314
sHalfLineBreakAfterLineBreak);
317
static void initStateMachine()
319
// By convention, error transitions maintain the same state.
320
specDefaultTransition(sMsgStart, taStartText, sScanStatusLine);
321
specTransition(sMsgStart,
324
sHalfLineBreakAtMsgStart);
325
specTransition(sMsgStart, ccLineFeed, taError, sMsgStart);
326
specHalfLineBreakState(sHalfLineBreakAtMsgStart, sMsgStart);
327
specDefaultTransition(sScanStatusLine, taNone, sScanStatusLine);
328
specTransition(sScanStatusLine,
331
sHalfLineBreakAfterStatusLine);
332
specHalfLineBreakState(sHalfLineBreakAfterStatusLine,
333
sAfterLineBreakAfterStatusLine);
334
specDefaultTransition(sAfterLineBreakAfterStatusLine,
336
sAfterLineBreakAfterStatusLine);
337
specTransition(sAfterLineBreakAfterStatusLine,
341
specTransition(sAfterLineBreakAfterStatusLine,
344
sAfterLineBreakAfterStatusLine);
345
specTransition(sAfterLineBreakAfterStatusLine,
348
sHalfLineBreakAfterLineBreak);
349
specDefaultTransition(sScanFieldName, taError, sScanFieldName);
350
specTransition(sScanFieldName, ccFieldName, taNone, sScanFieldName);
351
specTransition(sScanFieldName,
354
sScanWhitespaceAfter1FieldName);
355
specTransition(sScanFieldName,
358
sScanWhitespaceOr1Value);
360
specXValueStates(deltaOfNStateFrom1State);
361
specDefaultTransition(sScanNValueInQuotes, taNone, sScanNValueInQuotes);
362
specTransition(sScanNValueInQuotes,
363
ccDoubleQuotationMark,
366
specTransition(sScanNValueInQuotes,
369
sAfterEscCharInQuotesInNValue);
370
specTransition(sScanNValueInQuotes,
373
sHalfLineBreakInQuotesInNValue);
374
specDefaultTransition(sAfterEscCharInQuotesInNValue,
376
sScanNValueInQuotes);
377
specHalfLineBreakState(sHalfLineBreakInQuotesInNValue,
378
sAfterLineBreakInQuotesInNValue);
379
specDefaultTransition(sAfterLineBreakInQuotesInNValue,
381
sAfterLineBreakInQuotesInNValue);
382
specTransition(sAfterLineBreakInQuotesInNValue,
385
sScanNValueInQuotes);
386
specDefaultTransition(sScanNValueInAngles, taNone, sScanNValueInAngles);
387
specTransition(sScanNValueInAngles,
391
specTransition(sScanNValueInAngles,
394
sHalfLineBreakInAnglesInNValue);
395
specHalfLineBreakState(sHalfLineBreakInAnglesInNValue,
396
sAfterLineBreakInAnglesInNValue);
397
specDefaultTransition(sAfterLineBreakInAnglesInNValue,
399
sAfterLineBreakInAnglesInNValue);
400
specTransition(sAfterLineBreakInAnglesInNValue,
403
sScanNValueInAngles);
404
specHalfLineBreakState(sHalfLineBreakAfterLineBreak, sMsgStart);
406
// Most half-line-break states do nothing when they read a line feed,
407
// but sHalfLineBreakAfterLineBreak must end the message header scanning.
409
specTransition(sHalfLineBreakAfterLineBreak,
412
sMsgStart); // Arbitrary but possibly handy.
416
#if defined(RESIP_MSG_HEADER_SCANNER_DEBUG)
418
static void printText(const char * text,
419
unsigned int textLength)
421
const char *charPtr = text;
422
for (unsigned int counter = 0; counter < textLength; ++charPtr, ++counter)
427
case '\\': printf("\\\\");
429
case '\r': printf("\\r");
431
case '\n': printf("\\n");
433
case '\t': printf("\\t");
435
case '\0': printf("\\0");
443
categorySymbol(CharCategory c)
447
case ccChunkTermSentinel: return "TERM";
448
case ccOther: return "*";
449
case ccFieldName: return "FName";
450
case ccWhitespace: return "WS";
451
case ccColon: return "\\\":\\\"";
452
case ccDoubleQuotationMark: return "\\\"";
453
case ccLeftAngleBracket: return "\\\"<\\\"";
454
case ccRightAngleBracket: return "\\\">\\\"";
455
case ccBackslash: return "\\\"\\\\\\\"";
456
case ccComma: return "\\\",\\\"";
457
case ccCarriageReturn: return "CR";
458
case ccLineFeed: return "LF";
464
categoryName(CharCategory c)
468
case ccChunkTermSentinel: return "ccChunkTermSentinel";
469
case ccOther: return "ccOther";
470
case ccFieldName: return "ccFieldName";
471
case ccWhitespace: return "ccWhitespace";
472
case ccColon: return "ccColon";
473
case ccDoubleQuotationMark: return "ccDoubleQuotationMark";
474
case ccLeftAngleBracket: return "ccLeftAngleBracket";
475
case ccRightAngleBracket: return "ccRightAngleBracket";
476
case ccBackslash: return "ccBackslash";
477
case ccComma: return "ccComma";
478
case ccCarriageReturn: return "ccCarriageReturn";
479
case ccLineFeed: return "ccLineFeed";
485
cleanName(const char * name)
487
// Remove leading type-noise from name
488
static char *leaders[] = {
491
"taChunkTerm", // hack to make ChunkTermSentinel smaller
494
const int nLeaders = sizeof(leaders)/sizeof(*leaders);
496
for(int i = 0 ; i < nLeaders ; i++)
498
unsigned int l = strlen(leaders[i]);
499
if (strstr(name,leaders[i]) == name &&
507
return &name[offset];
511
stateName(State state)
513
const char *stateName;
517
stateName = "sMsgStart";
519
case sHalfLineBreakAtMsgStart:
520
stateName = "sHalfLineBreakAtMsgStart";
522
case sScanStatusLine:
523
stateName = "sScanStatusLine";
525
case sHalfLineBreakAfterStatusLine:
526
stateName = "sHalfLineBreakAfterStatusLine";
528
case sAfterLineBreakAfterStatusLine:
529
stateName = "sAfterLineBreakAfterStatusLine";
532
stateName = "sScanFieldName";
534
case sScanWhitespaceAfter1FieldName:
535
stateName = "sScanWhitespaceAfter1FieldName";
537
case sScanWhitespaceAfterNFieldName:
538
stateName = "sScanWhitespaceAfterNFieldName";
540
case sScanWhitespaceOr1Value:
541
stateName = "sScanWhitespaceOr1Value";
543
case sScanWhitespaceOrNValue:
544
stateName = "sScanWhitespaceOrNValue";
546
case sHalfLineBreakInWhitespaceBefore1Value:
547
stateName = "sHalfLineBreakInWhitespaceBefore1Value";
549
case sHalfLineBreakInWhitespaceBeforeNValue:
550
stateName = "sHalfLineBreakInWhitespaceBeforeNValue";
552
case sAfterLineBreakInWhitespaceBefore1Value:
553
stateName = "sAfterLineBreakInWhitespaceBefore1Value";
555
case sAfterLineBreakInWhitespaceBeforeNValue:
556
stateName = "sAfterLineBreakInWhitespaceBeforeNValue";
559
stateName = "sScan1Value";
562
stateName = "sScanNValue";
564
case sHalfLineBreakIn1Value:
565
stateName = "sHalfLineBreakIn1Value";
567
case sHalfLineBreakInNValue:
568
stateName = "sHalfLineBreakInNValue";
570
case sAfterLineBreakIn1Value:
571
stateName = "sAfterLineBreakIn1Value";
573
case sAfterLineBreakInNValue:
574
stateName = "sAfterLineBreakInNValue";
576
case sScanNValueInQuotes:
577
stateName = "sScanNValueInQuotes";
579
case sAfterEscCharInQuotesInNValue:
580
stateName = "sAfterEscCharInQuotesInNValue";
582
case sHalfLineBreakInQuotesInNValue:
583
stateName = "sHalfLineBreakInQuotesInNValue";
585
case sAfterLineBreakInQuotesInNValue:
586
stateName = "sAfterLineBreakInQuotesInNValue";
588
case sScanNValueInAngles:
589
stateName = "sScanNValueInAngles";
591
case sHalfLineBreakInAnglesInNValue:
592
stateName = "sHalfLineBreakInAnglesInNValue";
594
case sAfterLineBreakInAnglesInNValue:
595
stateName = "sAfterLineBreakInAnglesInNValue";
597
case sHalfLineBreakAfterLineBreak:
598
stateName = "sHalfLineBreakAfterLineBreak";
601
stateName = "<unknown>";
607
trActionName(TransitionAction transitionAction)
609
const char *transitionActionName;
610
switch (transitionAction)
613
transitionActionName = "taNone";
615
case taTermStatusLine:
616
transitionActionName = "taTermStatusLine";
618
case taTermFieldName:
619
transitionActionName = "taTermFieldName";
621
case taBeyondEmptyValue:
622
transitionActionName = "taBeyondEmptyValue";
624
case taTermValueAfterLineBreak:
625
transitionActionName = "taTermValueAfterLineBreak";
628
transitionActionName = "taTermValue";
631
transitionActionName = "taStartText";
634
transitionActionName = "taEndHeader";
636
case taChunkTermSentinel:
637
transitionActionName = "taChunkTermSentinel";
640
transitionActionName = "taError";
643
transitionActionName = "<unknown>";
645
return transitionActionName;
649
printStateTransition(State state,
651
TransitionAction transitionAction)
653
printf(" %s['", cleanName(stateName(state)));
654
printText(&character, 1);
655
printf("']: %s\n", cleanName(trActionName(transitionAction)));
657
#if !defined(RESIP_MSG_HEADER_SCANNER_DEBUG)
658
static const char* stateName(const char*)
659
{ return "RECOMPILE_WITH_SCANNER_DEBUG"; }
660
static const char* trActionName(const char*)
661
{ return stateName(0); }
663
/// START OF MEMBER METHODS
668
MsgHeaderScanner::dumpStateMachine(int fd)
670
FILE *fp = fdopen(fd,"w");
673
fprintf(stderr,"MsgHeaderScanner:: unable to open output file\n");
676
// Force instance so things are initialized -- YUCK!
677
MsgHeaderScanner scanner;(void)scanner;
678
fprintf(fp,"digraph MsgHeaderScannerFSM {\n");
679
fprintf(fp,"\tnode[shape=record\n\t\tfontsize=8\n\t\tfontname=\"Helvetica\"\n\t]\n");
680
fprintf(fp,"\tedge [ fontsize=6 fontname=\"Helvetica\"]\n");
682
fprintf(fp,"\tgraph [ ratio=0.8\n\t\tfontsize=6 compound=true ]");
683
for(int state = 0 ; state < numStates; ++state)
686
" %s [ label = \"%d|%s\" ]\n",
687
cleanName(stateName(state)),
689
cleanName(stateName(state))
691
for(int category = 0 ; category < numCharCategories; ++category)
693
// Skip Verbose Error or Empty Transitions
694
if (stateMachine[state][category].nextState == state &&
695
(stateMachine[state][category].action == taError ||
696
stateMachine[state][category].action == taNone
700
" %s -> %s [label=\"%s\\n%s\" ]\n",
701
cleanName(stateName(state)),
702
cleanName(stateName(stateMachine[state][category].nextState)),
703
categorySymbol(category),
704
cleanName(trActionName(stateMachine[state][category].action)));
713
#endif //defined(RESIP_MSG_HEADER_SCANNER_DEBUG)
717
#if defined(RESIP_MSG_HEADER_SCANNER_DEBUG)
719
static const char *const multiValuedFieldNameArray[] = {
728
"subscription-state",
741
"proxy-authenticate",
742
"proxy-authorization",
750
lookupMsgHeaderFieldInfo(
751
char * fieldName, //inout
752
unsigned int *fieldNameLength, //inout
753
MsgHeaderScanner::TextPropBitMask fieldNameTextPropBitMask,
754
int *fieldKind, //out
755
bool *isMultiValueAllowed) //out
757
*isMultiValueAllowed = false;
758
const char *const *multiValuedFieldNamePtr = multiValuedFieldNameArray;
761
const char *multiValuedFieldName = *multiValuedFieldNamePtr;
762
if (!multiValuedFieldName)
766
if (strncmp(fieldName, multiValuedFieldName, *fieldNameLength) == 0)
768
*isMultiValueAllowed = true;
771
++multiValuedFieldNamePtr;
777
processMsgHeaderStatusLine(
780
unsigned int lineTextLength,
781
MsgHeaderScanner::TextPropBitMask lineTextPropBitMask)
783
printf("status line: ");
784
printText(lineText, lineTextLength);
791
processMsgHeaderFieldNameAndValue(
794
const char * fieldName,
795
unsigned int fieldNameLength,
797
unsigned int valueTextLength,
798
MsgHeaderScanner::TextPropBitMask valueTextPropBitMask)
800
printText(fieldName, fieldNameLength);
802
printText(valueText, valueTextLength);
806
#else //!defined(RESIP_MSG_HEADER_SCANNER_DEBUG) } {
809
// Determine a field's kind and whether it allows (comma separated) multi-values.
810
// "fieldName" is not empty and contains only legal characters.
811
// The text in "fieldName" may be canonicalized (eg, translating % escapes),
812
// including shrinking it if necessary.
815
lookupMsgHeaderFieldInfo(char * fieldName,
816
unsigned int *fieldNameLength,
817
MsgHeaderScanner::TextPropBitMask fieldNameTextPropBitMask,
819
bool *isMultiValueAllowed)
821
//.jacob. Don't ignore fieldNameTextPropBitMask.
822
*fieldKind = Headers::getType(fieldName, *fieldNameLength);
823
*isMultiValueAllowed =
824
Headers::isCommaTokenizing(static_cast<Headers::Type>(*fieldKind));
828
// "lineText" contains no carriage returns and no line feeds.
829
// Return true on success, false on failure.
832
processMsgHeaderStatusLine(SipMessage * msg,
834
unsigned int lineTextLength,
835
MsgHeaderScanner::TextPropBitMask lineTextPropBitMask)
837
//.jacob. Don't ignore valueTextPropBitMask, and don't always return true.
838
msg->setStartLine(lineText, lineTextLength);
842
// This function is called once for a field with one value. (The value could be
843
// several values, but separated by something other than commas.)
844
// This function is called once for a field with 0 comma-separated values, with
846
// This function is called N times for a field with N comma-separated values,
847
// but with the same value of "fieldName" each time.
848
// "fieldName" is not empty and contains only legal characters.
849
// "valueText" may be empty, has no leading whitespace, may contain trailing
850
// whitespace, contains carriage returns and line feeds only in correct pairs
851
// and followed by whitespace, and, if the field is multi-valued, contains
852
// balanced '<'/'>' and '"' pairs, contains ',' only within '<'/'>' or '"'
853
// pairs, and respects '\\'s within '"' pairs.
854
// The text in "valueText" may be canonicalized (eg, translating % escapes),
855
// including shrinking it if necessary.
858
processMsgHeaderFieldNameAndValue(SipMessage * msg,
860
const char * fieldName,
861
unsigned int fieldNameLength,
863
unsigned int valueTextLength,
864
MsgHeaderScanner::TextPropBitMask valueTextPropBitMask)
866
//.jacob. Don't ignore valueTextPropBitMask, particularly for '\r' & '\n'.
867
msg->addHeader(static_cast<Headers::Type>(fieldKind),
874
#endif //!defined(RESIP_MSG_HEADER_SCANNER_DEBUG) }
876
bool MsgHeaderScanner::mInitialized = false;
878
MsgHeaderScanner::MsgHeaderScanner()
888
MsgHeaderScanner::prepareForMessage(SipMessage * msg)
892
mPrevScanChunkNumSavedTextChars = 0;
897
MsgHeaderScanner::prepareForFrag(SipMessage * msg, bool hasStartLine)
906
mState = sAfterLineBreakAfterStatusLine;
908
mPrevScanChunkNumSavedTextChars = 0;
912
MsgHeaderScanner::ScanChunkResult
913
MsgHeaderScanner::scanChunk(char * chunk,
914
unsigned int chunkLength,
915
char ** unprocessedCharPtr)
917
MsgHeaderScanner::ScanChunkResult result;
918
CharInfo* localCharInfoArray = charInfoArray;
919
TransitionInfo (*localStateMachine)[numCharCategories] = stateMachine;
920
State localState = mState;
921
char *charPtr = chunk + mPrevScanChunkNumSavedTextChars;
922
char *termCharPtr = chunk + chunkLength;
923
char saveChunkTermChar = *termCharPtr;
924
*termCharPtr = chunkTermSentinelChar;
925
char *textStartCharPtr;
926
MsgHeaderScanner::TextPropBitMask localTextPropBitMask = mTextPropBitMask;
927
if (mPrevScanChunkNumSavedTextChars == 0)
929
textStartCharPtr = 0;
933
textStartCharPtr = chunk;
935
--charPtr; // The loop starts by advancing "charPtr", so pre-adjust it.
938
// BEGIN message header character scan block BEGIN
939
// The code in this block is executed once per message header character.
940
// This entire file is designed specifically to minimize this block's size.
942
CharInfo *charInfo = &localCharInfoArray[((unsigned char) (*charPtr))];
943
CharCategory charCategory = charInfo->category;
944
localTextPropBitMask |= charInfo->textPropBitMask;
945
determineTransitionFromCharCategory:
946
TransitionInfo *transitionInfo =
947
&(localStateMachine[(unsigned)localState][(size_t)charCategory]);
948
TransitionAction transitionAction = transitionInfo->action;
949
#if defined(RESIP_MSG_HEADER_SCANNER_DEBUG)
950
printStateTransition(localState, *charPtr, transitionAction);
952
localState = transitionInfo->nextState;
953
if (transitionAction == taNone) continue;
954
// END message header character scan block END
955
// The loop remainder is executed about 4-5 times per message header line.
956
switch (transitionAction)
958
case taTermStatusLine:
959
if (!processMsgHeaderStatusLine(mMsg,
961
(unsigned int)(charPtr - textStartCharPtr),
962
localTextPropBitMask))
964
result = MsgHeaderScanner::scrError;
965
*unprocessedCharPtr = charPtr;
968
textStartCharPtr = 0;
970
case taTermFieldName:
972
mFieldNameLength = (unsigned int)(charPtr - textStartCharPtr);
973
bool isMultiValueAllowed;
974
lookupMsgHeaderFieldInfo(textStartCharPtr,
976
localTextPropBitMask,
978
&isMultiValueAllowed);
979
mFieldName = textStartCharPtr;
980
textStartCharPtr = 0;
981
if (isMultiValueAllowed)
983
localState += deltaOfNStateFrom1State;
987
case taBeyondEmptyValue:
988
processMsgHeaderFieldNameAndValue(mMsg,
996
goto performStartTextAction;
997
case taTermValueAfterLineBreak:
998
processMsgHeaderFieldNameAndValue(mMsg,
1003
(unsigned int)((charPtr - textStartCharPtr) - 2),
1004
localTextPropBitMask); //^:CRLF
1006
goto performStartTextAction;
1008
processMsgHeaderFieldNameAndValue(mMsg,
1013
(unsigned int)(charPtr - textStartCharPtr),
1014
localTextPropBitMask);
1015
textStartCharPtr = 0;
1019
performStartTextAction:
1020
textStartCharPtr = charPtr;
1021
localTextPropBitMask = 0;
1024
// textStartCharPtr is not 0. Not currently relevant.
1025
result = MsgHeaderScanner::scrEnd;
1026
*unprocessedCharPtr = charPtr + 1; // The current char is processed.
1029
case taChunkTermSentinel:
1030
if (charPtr == termCharPtr)
1032
// The chunk has been consumed. Save some state and request another.
1033
mState = localState;
1034
if (textStartCharPtr == 0)
1036
mPrevScanChunkNumSavedTextChars = 0;
1040
mPrevScanChunkNumSavedTextChars = (unsigned int)(termCharPtr - textStartCharPtr);
1042
mTextPropBitMask = localTextPropBitMask;
1043
result = MsgHeaderScanner::scrNextChunk;
1044
*unprocessedCharPtr = termCharPtr - mPrevScanChunkNumSavedTextChars;
1049
// The character is not the sentinel. Treat it like any other.
1050
charCategory = ccOther;
1051
goto determineTransitionFromCharCategory;
1055
result = MsgHeaderScanner::scrError;
1056
*unprocessedCharPtr = charPtr;
1061
*termCharPtr = saveChunkTermChar;
1066
MsgHeaderScanner::initialize()
1068
initCharInfoArray();
1078
#if defined(RESIP_MSG_HEADER_SCANNER_DEBUG) && defined(MSG_SCANNER_STANDALONE)
1082
main(unsigned int numArgs,
1083
const char * * argVector)
1085
::resip::MsgHeaderScanner scanner;
1086
scanner.prepareForMessage(0);
1090
"allow: foo, bar, \"don,\\\"xyz\r\n zy\", buzz\r\n\r\n";
1091
unsigned int textLength = strlen(text);
1093
strcpy(chunk, text);
1094
::resip::MsgHeaderScanner::ScanChunkResult scanChunkResult;
1095
char *unprocessedCharPtr;
1096
scanChunkResult = scanner.scanChunk(chunk, 21, &unprocessedCharPtr);
1097
if (scanChunkResult == ::resip::MsgHeaderScanner::scrNextChunk)
1099
printf("Scanning another chunk '.");
1100
::resip::printText(unprocessedCharPtr, 1);
1103
scanner.scanChunk(unprocessedCharPtr,
1104
(chunk + textLength) - unprocessedCharPtr,
1105
&unprocessedCharPtr);
1107
if (scanChunkResult != ::resip::MsgHeaderScanner::scrEnd)
1109
printf("Error %d at character %d.\n",
1111
unprocessedCharPtr - chunk);
1116
#endif //!defined(RESIP_MSG_HEADER_SCANNER_DEBUG) }
1118
/* ====================================================================
1119
* The Vovida Software License, Version 1.0
1121
* Copyright (c) 2000-2005
1123
* Redistribution and use in source and binary forms, with or without
1124
* modification, are permitted provided that the following conditions
1127
* 1. Redistributions of source code must retain the above copyright
1128
* notice, this list of conditions and the following disclaimer.
1130
* 2. Redistributions in binary form must reproduce the above copyright
1131
* notice, this list of conditions and the following disclaimer in
1132
* the documentation and/or other materials provided with the
1135
* 3. The names "VOCAL", "Vovida Open Communication Application Library",
1136
* and "Vovida Open Communication Application Library (VOCAL)" must
1137
* not be used to endorse or promote products derived from this
1138
* software without prior written permission. For written
1139
* permission, please contact vocal@vovida.org.
1141
* 4. Products derived from this software may not be called "VOCAL", nor
1142
* may "VOCAL" appear in their name, without prior written
1143
* permission of Vovida Networks, Inc.
1145
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
1146
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1147
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
1148
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
1149
* NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
1150
* IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
1151
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1152
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
1153
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
1154
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1155
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
1156
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
1159
* ====================================================================
1161
* This software consists of voluntary contributions made by Vovida
1162
* Networks, Inc. and many individuals on behalf of Vovida Networks,
1163
* Inc. For more information on Vovida Networks, Inc., please see
1164
* <http://www.vovida.org/>.