Darwin-Streaming-Server/CommonUtilitiesLib/UserAgentParser.cpp

184 lines
6.8 KiB
C++
Raw Normal View History

/*
*
* @APPLE_LICENSE_HEADER_START@
*
* Copyright (c) 1999-2008 Apple Inc. All Rights Reserved.
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*
*/
/*
File: UserAgentParser.cpp
Contains: Parse the User-Agent: entry of an RTSP request.
*/
#include "StringParser.h"
#include "StringFormatter.h"
#include "StrPtrLen.h"
#include "UserAgentParser.h"
UserAgentParser::UserAgentFields UserAgentParser::sFieldIDs[] =
{ /* fAttrName, len, id */
{ "qtid", strlen("qtid"), eQtid },
{ "qtver", strlen("qtver"), eQtver },
{ "lang", strlen("lang"), eLang },
{ "os", strlen("os"), eOs },
{ "osver", strlen("osver"), eOsver },
{ "cpu", strlen("cpu"), eCpu }
};
UInt8 UserAgentParser::sEOLWhitespaceEqualMask[] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, //0-9 // \t is a stop
1, 0, 0, 1, 0, 0, 0, 0, 0, 0, //10-19 //'\r' & '\n' are stop conditions
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //20-29
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, //30-39 ' ' is a stop
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //40-49
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //50-59
0, 1, 0, 0, 0, 0, 0, 0, 0, 0, //60-69 '=' is a stop
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //70-79
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //80-89
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //90-99
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //100-109
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //110-119
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //120-129
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //130-139
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //140-149
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //150-159
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //160-169
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //170-179
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //180-189
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //190-199
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //200-209
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //210-219
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //220-229
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //230-239
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //240-249
0, 0, 0, 0, 0, 0 //250-255
};
UInt8 UserAgentParser::sEOLSemicolonCloseParenMask[] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, //0-9 // \t is a stop
1, 0, 0, 1, 0, 0, 0, 0, 0, 0, //10-19 //'\r' & '\n' are stop conditions
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //20-29
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //30-39
0, 1, 0, 0, 0, 0, 0, 0, 0, 0, //40-49 ')' is a stop
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, //50-59 ';' is a stop
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //60-69
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //70-79
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //80-89
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //90-99
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //100-109
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //110-119
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //120-129
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //130-139
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //140-149
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //150-159
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //160-169
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //170-179
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //180-189
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //190-199
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //200-209
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //210-219
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //220-229
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //230-239
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //240-249
0, 0, 0, 0, 0, 0 //250-255
};
void UserAgentParser::Parse(StrPtrLen *inStream)
{
StrPtrLen tempID;
StrPtrLen tempData;
StringParser parser(inStream);
StrPtrLen startFields;
memset(&fFieldData,0,sizeof(fFieldData) );
parser.ConsumeUntil(&startFields, '(' ); // search for '(' if not found does nothing
// parse through everything between the '(' and ')'.
while (startFields.Len != 0)
{
//stop when we reach an empty line.
tempID.Set(NULL,0);
tempData.Set(NULL,0);
parser.ConsumeLength(NULL, 1); // step past '(' or ';' if not found or at end of line does nothing
parser.ConsumeWhitespace(); // search for non-white space if not found does nothing
parser.ConsumeUntil(&tempID, sEOLWhitespaceEqualMask ); // search for end of id (whitespace or =)if not found does nothing
if (tempID.Len == 0) break;
parser.ConsumeUntil(NULL, '=' ); // find the '='
parser.ConsumeLength(NULL, 1); // step past if not found or at end of line does nothing
parser.ConsumeUntil(&tempData, sEOLSemicolonCloseParenMask ); // search for end of data if not found does nothing
if (tempData.Len == 0) break;
StrPtrLen testID;
UInt32 fieldID;
for (short testField = 0; testField < UserAgentParser::eNumAttributes; testField++)
{
testID.Set(sFieldIDs[testField].fFieldName,sFieldIDs[testField].fLen);
fieldID = sFieldIDs[testField].fID;
if ( (fFieldData[fieldID].fFound == false) && testID.Equal(tempID) )
{
fFieldData[fieldID].fData = tempData;
fFieldData[fieldID].fFound = true;
}
}
}
// If we parsed the OS field but not the OSVer field then check and see if
// the OS field contains the OS version. If it does copy it from there.
// (e.g. 'os=Mac%209.2.2' or 'os=Windows%20NT%204.0'.)
if (fFieldData[eOs].fFound && !fFieldData[eOsver].fFound)
{
UInt16 len = (UInt16)fFieldData[eOs].fData.Len;
char* cp = (char*)fFieldData[eOs].fData.Ptr;
// skip up to the blank space if it exists.
// (i.e. the blank is URL encoded as '%20')
while(*cp != '%')
{
len--;
if (*cp == '\0' || len == 0)
{
// no blank space...so we're all done.
return;
}
cp++;
}
// skip over the blank space.
cp += 3; len -= 3;
// the remaining string is the OS version.
fFieldData[eOsver].fData.Set(cp, len);
fFieldData[eOsver].fFound = true;
// and truncate the version from the OS field.
fFieldData[eOs].fData.Len -= len+3;
}
}