//-------------------------------------------------------------------------- // // Module Name: LaunStub.Cpp // // Brief Description: // This module contains the code that parses HTTP-based // response from the ULS server. // // Author: Chu, Lon-Chan (lonchanc) // // Copyright (c) 1996 Microsoft Corporation // //-------------------------------------------------------------------------- #include "precomp.h" #include "launstub.h" PTSTR LocalStrDup ( PTSTR pszToDup ) { UINT uLen; PTSTR psz = NULL; if (pszToDup) { uLen = lstrlen (pszToDup); psz = (PTSTR) new TCHAR[uLen + 1]; if (psz) { lstrcpy (psz, pszToDup); } } return psz; } ULONG DecStrToInt ( PTSTR psz ) { ULONG ul = 0; WORD w; if (psz) { while ((w = (WORD) *psz++) != NULL) { if (TEXT ('0') <= w && w <= TEXT ('9')) { w -= TEXT ('0'); ul = ul * 10 + w; } else { break; } } } return ul; } ULONG HexStrToInt ( PTSTR psz ) { ULONG ul = 0; WORD w; if (psz) { while ((w = (WORD) *psz++) != NULL) { if (TEXT ('0') <= w && w <= TEXT ('9')) { w -= TEXT ('0'); } else if (TEXT ('a') <= w && w <= TEXT ('f')) { w -= (TEXT ('a') - 10); } else if (TEXT ('A') <= w && w <= TEXT ('F')) { w -= (TEXT ('A') - 10); } else { break; } ul = (ul << 4) + w; } } return ul; } BOOL IsWhiteSpace ( TCHAR c ) { return (c == TEXT (' ') || c == TEXT ('\t') || c == TEXT ('\r') || c == TEXT ('\n')); } enum { // beta 3 strings ATTR_HR, ATTR_PORT, ATTR_HA, ATTR_HC, ATTR_CID, ATTR_UID, ATTR_URL, ATTR_IP, ATTR_MT, B3ATTR_COUNT }; static PTSTR g_B3Attr[B3ATTR_COUNT] = { // beta 3 strings TEXT ("HR"), TEXT ("PORT"), TEXT ("HA"), TEXT ("HC"), TEXT ("CID"), TEXT ("UID"), TEXT ("URL"), TEXT ("IP"), TEXT ("MT"), }; enum { // beta 4 strings ATTR_HRESULT, ATTR_HCLIENT, ATTR_HAPPLICATION, ATTR_NAPPS, ATTR_IPADDRESS, ATTR_PORTNUM, ATTR_APPID, ATTR_PROTID, ATTR_USERID, ATTR_MIMETYPE, ATTR_APPMIME, ATTR_PROTMIME, ATTR_QUERYURL, B4ATTR_COUNT }; static PTSTR g_B4Attr[B4ATTR_COUNT] = { // beta 4 strings TEXT ("hresult"), TEXT ("hclient"), TEXT ("happlication"), TEXT ("napps"), TEXT ("ipaddress"), TEXT ("portnum"), TEXT ("appid"), TEXT ("protid"), TEXT ("userid"), TEXT ("mimetype"), TEXT ("appmime"), TEXT ("protmime"), TEXT ("queryurl"), }; typedef struct tagULPCMD { PTSTR pszCmd; ULONG nCmdId; } ULPCMD; static ULPCMD g_B3Cmd[] = { { TEXT ("ON"), CLIENT_MESSAGE_ID_LOGON }, { TEXT ("OFF"), CLIENT_MESSAGE_ID_LOGOFF }, { TEXT ("KA"), CLIENT_MESSAGE_ID_KEEPALIVE }, { TEXT ("RES"), CLIENT_MESSAGE_ID_RESOLVE }, }; static ULPCMD g_B4Cmd[] = { { TEXT ("on"), CLIENT_MESSAGE_ID_LOGON }, { TEXT ("off"), CLIENT_MESSAGE_ID_LOGOFF }, { TEXT ("ka"), CLIENT_MESSAGE_ID_KEEPALIVE }, { TEXT ("res"), CLIENT_MESSAGE_ID_RESOLVE }, }; /* @doc EXTERNAL ULCLIENT @api HRESULT | CULSLaunch_Stub::ParseUlsHttpRespFile | Parses a HTTP-based response from the ULS server. @parm PTSTR | pszUlsFile | A pointer to the HTTP-based response file name string. @parm ULS_HTTP_RESP * | pResp | A pointer to the generic HTTP response structure. @rdesc Returns ULS_SUCCESS if this operation succeeds. @comm This method parses the responses from the commands defined in the g_B3Cmd array. The attributes this method understands are listed in the g_B3Attr array. */ STDMETHODIMP CULSLaunch_Stub::ParseUlsHttpRespFile ( PTSTR pszUlsFile, ULS_HTTP_RESP *pResp ) { HANDLE hf = INVALID_HANDLE_VALUE; HRESULT hr; PTSTR pszBuf = NULL; ULONG cbFileSize; // clean up the structure first ZeroMemory (pResp, sizeof (ULS_HTTP_RESP)); pResp->cbSize = sizeof (ULS_HTTP_RESP); // open the uls file hf = CreateFile (pszUlsFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN | // FILE_FLAG_DELETE_ON_CLOSE, NULL); 0, NULL); if (hf == INVALID_HANDLE_VALUE) { return ULS_E_INVALID_HANDLE; } // get the size of the uls file cbFileSize = GetFileSize (hf, NULL); if (! cbFileSize) { return ULS_E_INVALID_HANDLE; } // round up to align with the paragraph boundary cbFileSize = ((cbFileSize + 4) & (~ 0x0F)) + 0x10; // allocate a buffer to hold the entire uls file pszBuf = (PTSTR) new TCHAR[cbFileSize]; if (! pszBuf) { hr = ULS_E_OUTOFMEMORY; goto MyExit; } // read the file in if (! ReadFile (hf, pszBuf, cbFileSize, &cbFileSize, NULL)) { hr = ULS_E_IO_ERROR; goto MyExit; } // parse the uls buffer hr = ParseUlsHttpRespBuffer (pszBuf, cbFileSize, pResp); if (hr != ULS_SUCCESS) { goto MyExit; } MyExit: if (hf != INVALID_HANDLE_VALUE) CloseHandle (hf); delete [] pszBuf; if (hr != ULS_SUCCESS && pResp) { FreeUlsHttpResp (pResp); } return hr; } /* @doc EXTERNAL ULCLIENT @api HRESULT | CULSLaunch_Stub::ParseUlsHttpRespBuffer | Parses a HTTP-based response from the ULS server. @parm PTSTR | pszBuf | A pointer to the buffer holding the entire HTTP-based response data. @parm ULONG | cbBufSize | The size in byte of the buffer. @parm ULS_HTTP_RESP * | pResp | A pointer to the generic HTTP response structure. @rdesc Returns ULS_SUCCESS if this operation succeeds. @comm This method parses the responses from the commands defined in the g_B3Cmd array. The attributes this method understands are listed in the g_B3Attr array. */ STDMETHODIMP CULSLaunch_Stub::ParseUlsHttpRespBuffer ( PTSTR pszBuf, ULONG cbBufSize, ULS_HTTP_RESP *pResp ) { HRESULT hr; #ifdef SANITY_CHECK // sanity check if (MyIsBadReadPtr (pszBuf, cbBufSize) || MyIsBadWritePtr (pResp, sizeof (ULS_HTTP_RESP))) { return ULS_E_INVALID_POINTER; } #endif hr = ParseB3HttpRespBuffer (pszBuf, cbBufSize, pResp); if (hr == ULS_E_INVALID_FORMAT) { ZeroMemory (pResp, sizeof (ULS_HTTP_RESP)); pResp->cbSize = sizeof (ULS_HTTP_RESP); hr = ParseB4HttpRespBuffer (pszBuf, cbBufSize, pResp); } return hr; } HRESULT CULSLaunch_Stub::ParseB3HttpRespBuffer // beta 3 implementation ( PTSTR pszBuf, ULONG cbBufSize, ULS_HTTP_RESP *pResp ) { PTSTR psz; int i; // get mime type psz = (LPTSTR)_StrChr (pszBuf, TEXT ('<')); if (! psz) return ULS_E_INVALID_FORMAT; pszBuf = psz + 1; psz = (LPTSTR)_StrChr (pszBuf, TEXT ('>')); if (! psz) return ULS_E_INVALID_FORMAT; *psz = TEXT ('\0'); lstrcpyn (pResp->szMimeType, pszBuf, MAX_MIME_TYPE_LENGTH); // get to the type of response pszBuf = psz + 1; psz = (LPTSTR)_StrChr (pszBuf, TEXT ('<')); if (! psz) return ULS_E_INVALID_FORMAT; pszBuf = psz + 1; psz = (LPTSTR)_StrChr (pszBuf, TEXT ('[')); if (! psz) return ULS_E_INVALID_FORMAT; pszBuf = psz + 1; psz = (LPTSTR)_StrChr (pszBuf, TEXT (']')); if (! psz) return ULS_E_INVALID_FORMAT; *psz = TEXT ('\0'); pResp->nCmdId = (ULONG) -1; for (i = 0; i < sizeof (g_B3Cmd) / sizeof (g_B3Cmd[0]); i++) { if (! lstrcmpi (pszBuf, g_B3Cmd[i].pszCmd)) { pResp->nCmdId = g_B3Cmd[i].nCmdId; break; } } if (pResp->nCmdId == (ULONG) -1) return ULS_E_INVALID_FORMAT; // skip any white space for (pszBuf = psz + 1; *pszBuf; pszBuf++) { if (! IsWhiteSpace (*pszBuf)) break; } // main loop while (*pszBuf && *pszBuf != TEXT ('>')) { // locate the equal sign psz = (LPTSTR)_StrChr (pszBuf, TEXT ('=')); if (! psz) return ULS_E_INVALID_FORMAT; *psz = TEXT ('\0'); // search for attribute for (i = 0; i < sizeof (g_B3Attr) / sizeof (g_B3Attr[0]); i++) { if (! lstrcmpi (pszBuf, g_B3Attr[i])) { break; } } if (i >= sizeof (g_B3Attr) / sizeof (g_B3Attr[0])) return ULS_E_INVALID_FORMAT; // locate the attribute value for (pszBuf = psz + 1; *pszBuf; pszBuf++) { if (! IsWhiteSpace (*pszBuf)) break; } for (psz = pszBuf + 1; *psz; psz++) { if (IsWhiteSpace (*psz)) break; } *psz = TEXT ('\0'); // now the attribute value is a null-terminated string pointed by pszBuf // parse the attribute value switch (i) { case ATTR_HR: pResp->hr = HexStrToInt (pszBuf); break; case ATTR_PORT: pResp->nPort = DecStrToInt (pszBuf); break; case ATTR_HA: pResp->dwAppSession = HexStrToInt (pszBuf); break; case ATTR_HC: pResp->dwClientSession = HexStrToInt (pszBuf); break; case ATTR_CID: pResp->dwClientId = HexStrToInt (pszBuf); break; case ATTR_UID: ASSERT(!pResp->pszUID); pResp->pszUID = LocalStrDup (pszBuf); break; case ATTR_URL: ASSERT(!pResp->pszURL); pResp->pszURL = LocalStrDup (pszBuf); break; case ATTR_IP: lstrcpyn (pResp->szIPAddress, pszBuf, MAX_IP_ADDRESS_STRING_LENGTH); break; case ATTR_MT: // already got it break; } // skip any white space for (pszBuf = psz + 1; *pszBuf; pszBuf++) { if (! IsWhiteSpace (*pszBuf)) break; } } return ULS_SUCCESS; } HRESULT CULSLaunch_Stub::ParseB4HttpRespBuffer // beta 4 implementation ( PTSTR pszBuf, ULONG cbBufSize, ULS_HTTP_RESP *pResp ) { PTSTR psz, pszSave; int i; // get mime type psz = (LPTSTR)_StrChr (pszBuf, TEXT ('[')); if (! psz) { return ULS_E_INVALID_FORMAT; } pszBuf = psz + 1; psz = (LPTSTR)_StrChr (pszBuf, TEXT (']')); if (! psz) { return ULS_E_INVALID_FORMAT; } *psz = TEXT ('\0'); // now pszBuf is ptr to the string inside [], such on, off, ka, res. pResp->nCmdId = (ULONG) -1; for (i = 0; i < sizeof (g_B4Cmd) / sizeof (g_B4Cmd[0]); i++) { if (! lstrcmpi (pszBuf, g_B4Cmd[i].pszCmd)) { pResp->nCmdId = g_B4Cmd[i].nCmdId; break; } } // to see if this cmd is something I don't know if (pResp->nCmdId == (ULONG) -1) { return ULS_E_INVALID_FORMAT; } // update the buf ptr pszBuf = psz + 1; // main loop while (*pszBuf) { // locate a \r \n while (*pszBuf != TEXT ('\r') && *pszBuf != TEXT ('\n')) { pszBuf++; } // skip any white space including \r \n while (*pszBuf) { if (! IsWhiteSpace (*pszBuf)) { break; } pszBuf++; } // end of file if (! *pszBuf) { return ULS_SUCCESS; } // locate the equal sign psz = (LPTSTR)_StrChr (pszBuf, TEXT ('=')); if (! psz) { continue; // cannot goto NextLine because psz==NULL } // to make pszBuf ptr to the attr name *psz = TEXT ('\0'); // search for attribute for (i = 0; i < sizeof (g_B4Attr) / sizeof (g_B4Attr[0]); i++) { if (! lstrcmpi (pszBuf, g_B4Attr[i])) { break; } } // is this attribute valid? if not, ignore it! if (i >= sizeof (g_B4Attr) / sizeof (g_B4Attr[0])) { goto NextLine; } // locate pszBuf now ptr to attr value pszBuf = psz + 1; // get to the end of line for (psz = pszBuf; *psz; psz++) { if (*psz == TEXT ('\r') || *psz == TEXT ('\n')) { break; } } // deal with attrname=\r\nEOF if (! *psz) { return ULS_SUCCESS; } // make the attr value is a null-terminated string pointed by pszBuf *psz = TEXT ('\0'); // parse the attribute value switch (i) { case ATTR_HRESULT: pResp->hr = HexStrToInt (pszBuf); break; case ATTR_PORTNUM: pResp->nPort = DecStrToInt (pszBuf); break; case ATTR_HAPPLICATION: pResp->dwAppSession = HexStrToInt (pszBuf); break; case ATTR_HCLIENT: pResp->dwClientSession = HexStrToInt (pszBuf); break; case ATTR_USERID: pszSave = pResp->pszUID; pResp->pszUID = LocalStrDup (pszBuf); if (pResp->pszUID) { delete [] pszSave; } else { pResp->pszUID = pszSave; // restore } break; case ATTR_QUERYURL: pszSave = pResp->pszURL; pResp->pszURL = LocalStrDup (pszBuf); if (pResp->pszURL) { delete [] pszSave; } else { pResp->pszURL = pszSave; // restore } break; case ATTR_IPADDRESS: lstrcpyn (pResp->szIPAddress, pszBuf, sizeof (pResp->szIPAddress) / sizeof (pResp->szIPAddress[0])); break; case ATTR_MIMETYPE: lstrcpyn (pResp->szMimeType, pszBuf, sizeof (pResp->szMimeType) / sizeof (pResp->szMimeType[0])); break; case ATTR_APPMIME: lstrcpyn (pResp->szAppMime, pszBuf, sizeof (pResp->szAppMime) / sizeof (pResp->szAppMime[0])); break; case ATTR_PROTMIME: lstrcpyn (pResp->szProtMime, pszBuf, sizeof (pResp->szProtMime) / sizeof (pResp->szProtMime[0])); break; case ATTR_APPID: lstrcpyn (pResp->szAppId, pszBuf, sizeof (pResp->szAppId) / sizeof (pResp->szAppId[0])); break; case ATTR_PROTID: lstrcpyn (pResp->szProtId, pszBuf, sizeof (pResp->szProtId) / sizeof (pResp->szProtId[0])); break; case ATTR_NAPPS: pResp->nApps = DecStrToInt (pszBuf); break; default: break; } NextLine: // make sure we are at \r \n *psz = TEXT ('\r'); pszBuf = psz; } return ULS_SUCCESS; } /* @doc EXTERNAL ULCLIENT @api HRESULT | CULSLaunch_Stub::FreeUlsHttpResp | Frees internal resources in a generic HTTP-based response structure. @parm ULS_HTTP_RESP * | pResp | A pointer to the generic HTTP response structure. @rdesc Returns ULS_SUCCESS if this operation succeeds. @comm The internal resources must be created by the ParseUlsHttpRespFile method or the ParseUlsHttpRespBuffer method. */ STDMETHODIMP CULSLaunch_Stub::FreeUlsHttpResp ( ULS_HTTP_RESP *pResp ) { if (pResp->pszUID) { delete [] pResp->pszUID; pResp->pszUID = NULL; } if (pResp->pszURL) { delete [] pResp->pszURL; pResp->pszURL = NULL; } return ULS_SUCCESS; }