📄 parser.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
/*++
Module Name:
parser.cpp
Abstract:
This module encode and decode ssdp notify and search messages.
Author:
Ting Cai (tingcai) creation-date-07-25-99
--*/
/* Note:
Use midl memory routines for SSDP_REQUEST
*/
#include <ssdppch.h>
#pragma hdrstop
#include "ipexport.h"
#include "ssdpparserp.h"
#define HTTP_VERSION_STR "HTTP/1.1"
#define END_HEADERS_SIZE 3
const char * szEndOfHeaders = "\n\r\n";
#define HEADER_END_SIZE 4
const char * szHeaderEnd = "\r\n\r\n";
BOOL IsStrDigits(LPSTR pszStr);
VOID strtrim(CHAR ** pszStr);
static const CHAR c_szMaxAge[] = "max-age";
static const DWORD c_cchMaxAge = celems(c_szMaxAge) - 1;
static const CHAR c_szExtHeader[] = "EXT:\r\n";
extern CHAR g_pszExtensionURI[500];
extern CHAR g_pszHeaderPrefix[10];
extern CHAR g_pszNlsHeader[50];
// Keep in sync with SSDP_METHOD in ssdp.idl
CHAR *SsdpMethodStr[] =
{
"NOTIFY",
"M-SEARCH",
"SUBSCRIBE",
"UNSUBSCRIBE",
"INVALID",
};
// Keep in sync with SSDP_HEADER in ssdp.idl
CHAR *SsdpHeaderStr[] =
{
"Host",
"NT",
"NTS",
"ST",
"Man",
"MX",
"Location",
"AL",
"USN",
"Cache-Control",
"Callback",
"Timeout",
"Scope",
"SID",
"SEQ",
"Content-Length",
"Content-Type",
"Server",
"Ext",
"Opt",
g_pszNlsHeader
};
BOOL ComposeSsdp(char* pszFirstLine1, char* pszFirstLine2, char* pszFirstLine3, SSDP_REQUEST *Source, SSDP_HEADER* pIncludeHeaders, int nHeaders, CHAR **pszBytes)
{
INT iLength = 0;
INT iNumOfBytes = 0;
CHAR * szBytes;
INT i;
SSDP_HEADER Header;
////////////////////////////////////
// Step 1. calculate size of SSDP message
////////////////////////////////////
// calculate size of first line
assert(pszFirstLine1 && pszFirstLine2 && pszFirstLine3);
iLength += strlen(pszFirstLine1) + strlen(SP) +
strlen(pszFirstLine2) + strlen(SP) +
strlen(pszFirstLine3) + strlen(CRLF);
// calculate size of headers
for (i = 0, Header = pIncludeHeaders[0]; i < nHeaders; Header = pIncludeHeaders[++i])
{
assert(Header < NUM_OF_HEADERS);
__assume(Header < NUM_OF_HEADERS);
// for NLS header include prefix + dash
if(SSDP_NLS == Header && g_pszHeaderPrefix[0])
iLength += strlen(g_pszHeaderPrefix) + strlen(DASH);
// header name + colon + crlf
iLength += strlen(SsdpHeaderStr[Header]) + strlen(COLON) + strlen(CRLF);
// value for headers other than EXT
if(SSDP_EXT != Header)
{
assert(Source->Headers[Header] != NULL);
iLength += strlen(Source->Headers[Header]);
}
}
// terminating CRLF
iLength += strlen(CRLF);
////////////////////////////////////
// Step 2. compose SSDP message
////////////////////////////////////
// allocate memory for the message
if(NULL == (szBytes = (CHAR *) malloc(sizeof(CHAR) * iLength + 1)))
{
TraceTag(ttidSsdpParser, "Failed to allocate memory for the ssdp message.");
return FALSE;
}
// write first line
iNumOfBytes += sprintf(szBytes + iNumOfBytes, "%s%s%s%s%s%s", pszFirstLine1, SP, pszFirstLine2, SP, pszFirstLine3, CRLF);
// write headers
for (i = 0, Header = pIncludeHeaders[0]; i < nHeaders; Header = pIncludeHeaders[++i])
{
assert(Header < NUM_OF_HEADERS);
// prefix + dash for NLS header
if(SSDP_NLS == Header && g_pszHeaderPrefix[0])
iNumOfBytes += sprintf(szBytes + iNumOfBytes, "%s%s", g_pszHeaderPrefix, DASH);
// header name + colon
iNumOfBytes += sprintf(szBytes + iNumOfBytes, "%s%s", SsdpHeaderStr[Header], COLON);
// value for headers other than EXT
if(SSDP_EXT != Header)
{
assert(Source->Headers[Header] != NULL);
PREFAST_SUPPRESS(69, "sprintf returns number of bytes written, strcpy doesn't");
iNumOfBytes += sprintf(szBytes + iNumOfBytes, "%s", Source->Headers[Header]);
}
// crlf
PREFAST_SUPPRESS(69, "sprintf returns number of bytes written, strcpy doesn't");
iNumOfBytes += sprintf(szBytes + iNumOfBytes, "%s", CRLF);
}
// write terminating CRLF
PREFAST_SUPPRESS(69, "sprintf returns number of bytes written, strcpy doesn't");
iNumOfBytes += sprintf(szBytes + iNumOfBytes, "%s",CRLF);
Assert(iNumOfBytes <= iLength);
*pszBytes = szBytes;
return TRUE;
}
// SSDP response
BOOL ComposeSsdpResponse(SSDP_REQUEST *Source, SSDP_HEADER* pIncludeHeaders, int nHeaders, CHAR **pszBytes)
{
return ComposeSsdp(HTTP_VERSION_STR, "200", "OK", Source, pIncludeHeaders, nHeaders, pszBytes);
}
// SSDP request (NOTIFY or M-SEARCH)
BOOL ComposeSsdpRequest(SSDP_REQUEST *Source, SSDP_HEADER* pIncludeHeaders, int nHeaders, CHAR **pszBytes)
{
return ComposeSsdp(SsdpMethodStr[Source->Method], Source->RequestUri, HTTP_VERSION_STR, Source, pIncludeHeaders, nHeaders, pszBytes);
}
// Pre-Conditions:
// Result->Headers[CONTENT_LENGTH] contains only digits.
// pContent points to the first char "\r\n\r\n".
// Return Value:
// returns FALSE if there not enough content.
BOOL ParseContent(const char *pContent, SSDP_REQUEST *Result)
{
if(!Result->Headers[CONTENT_LENGTH])
{
return TRUE;
}
long lContentLength = atol(Result->Headers[CONTENT_LENGTH]);
if (lContentLength == 0)
{
// If it can't be conver to a number or it is 0.
TraceTag(ttidSsdpParser, "Content-Length is 0.");
return TRUE;
}
else
{
// better, but may break WinME: if ((long)strlen(pContent) != lContentLength)
if (((long) strlen(pContent) + 1) < lContentLength)
{
TraceTag(ttidSsdpParser, "Not enough bytes for content as specified in "
"Content-Length: %d vs %d", strlen(pContent) + 1,
lContentLength);
return FALSE;
}
// lContentLength is length of actual string so the condition below will always be true
__assume(lContentLength < ULONG_MAX);
Result->Content = (CHAR*) SsdpAlloc(lContentLength + 1);
if (Result->Content == NULL)
{
// To-Do: ?
TraceTag(ttidSsdpParser, "Failed to allocate memory for Content");
return FALSE;
}
else
{
strncpy(Result->Content,pContent, lContentLength);
// NTRAID#NTBUG-166137-2000/08/18-danielwe: Add the NULL terminator
Result->Content[lContentLength] = 0;
return TRUE;
}
}
}
BOOL VerifySsdpMethod(CHAR *szMethod, SSDP_REQUEST *Result)
{
INT i;
for (i = 0; i < NUM_OF_METHODS; i++)
{
if (_stricmp(SsdpMethodStr[i],szMethod) == 0)
{
Result->Method = (SSDP_METHOD)i;
break;
}
}
if (i == NUM_OF_METHODS)
{
TraceTag(ttidSsdpParser, "Parser could not find method . "
"Received %s", szMethod);
Result->status = HTTP_STATUS_BAD_METHOD;
return FALSE;
}
return TRUE;
}
CHAR * ParseRequestLine(CHAR * szMessage, SSDP_REQUEST *Result)
{
CHAR *token;
// Get the HTTP method
token = strtok(szMessage," \t\n");
if (token == NULL)
{
TraceTag(ttidSsdpParser, "Parser could not locate the seperator, "
"space, tab or eol");
return NULL;
}
if (!VerifySsdpMethod(token, Result))
return NULL;
// Get the Request-URI
token = strtok(NULL," ");
if (token == NULL)
{
TraceTag(ttidSsdpParser, "Parser could not find the url in the "
"message.");
return NULL;
}
// Ingore the name space parsing for now, get the string after the last '/'.
Result->RequestUri = (CHAR*) SsdpAlloc(strlen(token) + 1);
if (Result->RequestUri == NULL)
{
TraceTag(ttidSsdpParser, "Parser could not allocate memory for url.");
return NULL;
}
// Record the service.
strcpy(Result->RequestUri, token);
// Get the version number
token = strtok(NULL," \t\r");
// To-Do: Record the version number when necessary.
if (token == NULL)
{
TraceTag(ttidSsdpParser, "Failed to get the version in the request "
"header.");
FreeSsdpRequest(Result);
return NULL;
}
if (_stricmp(token, "HTTP/1.1") != 0)
{
TraceTag(ttidSsdpParser, "The version specified in the request "
"message is not HTTP/1.1");
FreeSsdpRequest(Result);
return NULL;
}
return (token + strlen(token) + 1);
}
// VerifyRequestLine
BOOL VerifyRequestLine(SSDP_REQUEST *Result)
{
if (0 != _stricmp(Result->RequestUri, "*"))
{
TraceTag(ttidSsdpParser, "Requested resource is not * in SSDP request");
return FALSE;
}
return TRUE;
}
BOOL VerifySsdpHeaders(SSDP_REQUEST *Result)
{
// M_SEARCH
if (Result->Method == SSDP_M_SEARCH)
{
// MAN
if(Result->Headers[SSDP_MAN] == NULL || 0 != _stricmp("\"ssdp:discover\"", Result->Headers[SSDP_MAN]))
{
TraceTag(ttidSsdpParser, "MAN header must be \"ssdp:discover\" for M-SEARCH");
return FALSE;
}
// MX header
if(Result->Headers[SSDP_MX] == NULL || Result->Headers[SSDP_MX][0] == '\x0')
{
TraceTag(ttidSsdpParser, "MX header missing or empty for M-SEARCH");
return FALSE;
}
if(Result->Headers[SSDP_MX] == NULL || IsStrDigits(Result->Headers[SSDP_MX]) == FALSE)
{
TraceTag(ttidSsdpParser, "MX header should be all digits for M-SEARCH");
return FALSE;
}
// ST header
if(Result->Headers[SSDP_ST] == NULL || Result->Headers[SSDP_ST][0] == '\x0')
{
TraceTag(ttidSsdpParser, "ST header missing or empty for M-SEARCH");
return FALSE;
}
}
// NOTIFY
if (Result->Method == SSDP_NOTIFY)
{
// NT header
if (Result->Headers[SSDP_NT] == NULL || Result->Headers[SSDP_NT][0] == '\x0')
{
TraceTag(ttidSsdpParser, "NT header missing or empty for a NOTIFY message.");
return FALSE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -