📄 srmpsend.cxx
字号:
// Initially allocate a large buffer to hopefully eliminate need for reallocs in most cases.
if (pUserHeader->SoapIsIncluded())
cbAlloc += pSoapBodySection->GetDataLengthInWCHARs();
if (!xmlEncode.AllocMem(cbAlloc))
return NULL;
xmlEncode.Append((CHAR*)cszXMLHeader,SVSUTIL_CONSTSTRLEN(cszXMLHeader)*sizeof(WCHAR));
xmlEncode.Append((CHAR*)cszEnvelopeStartNS,SVSUTIL_CONSTSTRLEN(cszEnvelopeStartNS)*sizeof(WCHAR));
xmlEncode.StartTag(cszHeaderNS);
// <HEADER> section
if (! SendPath(&xmlEncode,pImage))
return NULL;
if (! SendProps(&xmlEncode,pImage))
return NULL;
if (! SendServices(&xmlEncode,pImage))
return NULL;
if (! SendStream(&xmlEncode,pImage))
return NULL;
if (! SendStreamRcpt(&xmlEncode,pImage))
return NULL;
if (! SendDeliveryRcpt(&xmlEncode,pImage))
return NULL;
if (! SendCommitRcpt(&xmlEncode,pImage))
return NULL;
if (! SendMsmq(&xmlEncode,pImage))
return NULL;
if (! SendUserHeader(&xmlEncode,pImage))
return NULL;
if (! xmlEncode.EndTag(cszHeaderNS))
return NULL;
// <BODY> section
if (! xmlEncode.StartTag(cszBodyNS))
return NULL;
if (pUserHeader->SoapIsIncluded()) {
if (pSoapBodySection->GetPointerToData()) {
if (!xmlEncode.Encode(pSoapBodySection->GetPointerToData()))
return NULL;
}
}
if (! xmlEncode.EndTag(cszBodyNS))
return NULL;
if (! xmlEncode.EndTag(cszEnvelopeNS))
return NULL;
if (! xmlEncode.Append((char*)L"\0",sizeof(WCHAR)))
return NULL;
#if defined (DEBUG) || defined (_DEBUG)
svsutil_validateXML((BSTR)xmlEncode.pBuffer);
#endif
// covert SOAP Envelope to UTF8
DWORD cp = CP_UTF8;
if (0 == (*pccSendBuffer = WideCharToMultiByte(cp, 0, (WCHAR*)xmlEncode.pBuffer, -1, NULL, 0, 0, 0))) {
cp = CP_ACP;
if (0 == (*pccSendBuffer = WideCharToMultiByte(cp, 0, (WCHAR*)xmlEncode.pBuffer, -1, NULL, 0, 0, 0)))
return NULL;
}
if (NULL == (szSendBuffer = (CHAR*) g_funcAlloc(*pccSendBuffer,g_pvAllocData)))
return NULL;
WideCharToMultiByte(cp, 0, (WCHAR*)xmlEncode.pBuffer, -1, szSendBuffer, *pccSendBuffer, 0, 0);
*pccSendBuffer -= 1;
return szSendBuffer;
}
BOOL IsBodyIncluded(ScPacketImage *pImage) {
CUserHeader *pUserHeader = pImage->sect.pUserHeader;
CCompoundMessageHeader *pCompoundMessageHeader = pImage->sect.pCompoundMessageHeader;
CPropertyHeader *pPropHeader = pImage->sect.pPropHeader;
if (pUserHeader->SrmpIsIncluded())
return (pCompoundMessageHeader && pCompoundMessageHeader->GetBodySizeInBytes() != 0);
return (pPropHeader->GetBodySize() != 0);
}
#define BOUNDARY_VALUE "MSMQ - SOAP boundary, %d"
const char cszApplicationContentType[] = "application/octet-stream";
const char cszMultipartContentType[] = "multipart/related";
#define MIME_ID_FMT_A "%.*s" GUID_FORMAT_A
// MIME_ID_FMT_A
int BuildHttpHeadersAndMimeBody(ScPacketImage *pImage, CHAR *szSoapEnv, DWORD ccSoapEnv, BOOL fSecure, PSrmpIOCTLPacket pIOPacket, DWORD ccHeaders, SVSSimpleBuffer &cBodyBuf) {
CUserHeader *pUserHeader = pImage->sect.pUserHeader;
CPropertyHeader *pPropHeader = pImage->sect.pPropHeader;
const UCHAR* szBody = NULL;
DWORD cbBody = 0;
const UCHAR* szExtension = NULL;
DWORD cbExtension = 0;
PSTR szLastWritten;
pIOPacket->fSSL = fSecure;
SVSUTIL_ASSERT(pIOPacket->pszHeaders); // write buffer passed into us by caller
if (IsBodyIncluded(pImage)) {
CCompoundMessageHeader *pCompoundMessageHeader = pImage->sect.pCompoundMessageHeader;
szBody = pUserHeader->SrmpIsIncluded() ? pCompoundMessageHeader->GetPointerToBody() : pPropHeader->GetBodyPtr();
cbBody = pUserHeader->SrmpIsIncluded() ? pCompoundMessageHeader->GetBodySizeInBytes() : pPropHeader->GetBodySize();
}
if (pPropHeader->GetMsgExtensionSize()) {
szExtension = pPropHeader->GetMsgExtensionPtr();
cbExtension = pPropHeader->GetMsgExtensionSize();
}
if (szBody || szExtension) { // complex data type
srand (GetTickCount());
DWORD dwBoundaryId = rand();
DWORD cbAlloc = ccSoapEnv + cbBody + cbExtension + 2048;
// Get all we need at once so there's no chance of needing to realloc.
// For this reason we also don't check return values from StringCch functions.
if (! cBodyBuf.AllocMem(cbAlloc))
return FALSE;
// MIME Body
StringCchPrintfExA((CHAR*)cBodyBuf.pBuffer,cBodyBuf.BufferRemaining(),&szLastWritten,NULL,0,
BOUNDARY_HYPHEN BOUNDARY_VALUE "\r\n"
"Content-Type: %s; charset=UTF-8\r\nContent-Length: %d\r\n\r\n",
dwBoundaryId,cszTextXML,ccSoapEnv);
cBodyBuf.uiNextIn = (UCHAR*)szLastWritten - cBodyBuf.pBuffer;
cBodyBuf.Append(szSoapEnv,ccSoapEnv);
if (szBody) {
StringCchPrintfExA((CHAR*)cBodyBuf.pBuffer + cBodyBuf.uiNextIn,
cBodyBuf.BufferRemaining(),&szLastWritten,NULL,0,
BOUNDARY_HYPHEN BOUNDARY_VALUE "\r\n"
"Content-Type: %s\r\n"
"Content-Length: %d\r\n"
"Content-Id: " MIME_ID_FMT_A "\r\n\r\n",
dwBoundaryId,cszApplicationContentType,
cbBody,
ccMimeBodyIdLen, cszMimeBodyId,
GUID_ELEMENTS((&gMachine->guid)));
cBodyBuf.uiNextIn = (UCHAR*)szLastWritten - cBodyBuf.pBuffer;
memcpy(cBodyBuf.pBuffer+cBodyBuf.uiNextIn,szBody,cbBody);
cBodyBuf.uiNextIn += cbBody;
}
if (szExtension) {
StringCchPrintfExA((CHAR*)cBodyBuf.pBuffer + cBodyBuf.uiNextIn,
cBodyBuf.BufferRemaining(),&szLastWritten,NULL,0,
BOUNDARY_HYPHEN BOUNDARY_VALUE "\r\n"
"Content-Type: %s\r\n"
"Content-Length: %d\r\n"
"Content-Id: " MIME_ID_FMT_A "\r\n\r\n",
dwBoundaryId,cszApplicationContentType,
cbExtension,
ccMimeExtensionIdLen,cszMimeExtensionId,
GUID_ELEMENTS((&gMachine->guid)));
cBodyBuf.uiNextIn = (UCHAR*)szLastWritten - cBodyBuf.pBuffer;
memcpy(cBodyBuf.pBuffer+cBodyBuf.uiNextIn,szExtension,cbExtension);
cBodyBuf.uiNextIn += cbExtension;
}
StringCchPrintfExA((CHAR*)cBodyBuf.pBuffer + cBodyBuf.uiNextIn,
cBodyBuf.BufferRemaining(),&szLastWritten,NULL,0,
BOUNDARY_HYPHEN BOUNDARY_VALUE BOUNDARY_HYPHEN "\r\n",dwBoundaryId);
cBodyBuf.uiNextIn = (UCHAR*)szLastWritten - cBodyBuf.pBuffer;
// HTTP headers
StringCchPrintfExA(pIOPacket->pszHeaders,ccHeaders,&szLastWritten,NULL,0,
"Content-Type: %s; boundary=\"" BOUNDARY_VALUE "\"; type=text/xml\r\n"
"SOAPAction: \"MSMQMessage\"\r\n"
"Proxy-Accept: NonInteractiveClient\r\n",
cszMultipartContentType,dwBoundaryId
);
pIOPacket->cbHeaders = szLastWritten - pIOPacket->pszHeaders;
pIOPacket->pszPost = (CHAR*)cBodyBuf.pBuffer;
pIOPacket->cbPost = cBodyBuf.uiNextIn;
pIOPacket->contentType = CONTENT_TYPE_MIME;
}
else { // simple type
StringCchPrintfExA(pIOPacket->pszHeaders,ccHeaders,&szLastWritten,NULL,0,
"Content-Type: %s\r\n"
"SOAPAction: \"MSMQMessage\"\r\n"
"Proxy-Accept: NonInteractiveClient\r\n",
cszTextXML
);
pIOPacket->cbHeaders = szLastWritten - pIOPacket->pszHeaders;
pIOPacket->pszPost = szSoapEnv;
pIOPacket->cbPost = ccSoapEnv;
pIOPacket->contentType = CONTENT_TYPE_XML;
}
return TRUE;
}
int ScSession::SendHttpMsg(CHAR *szURL, BOOL fSecure, PSrmpIOCTLPacket pIOPacket) {
HANDLE hRequest;
DWORD dwFlags = 0;
int iStatusCode=500;
CSrmpCallBack openCallback;
dwFlags = (g_fUseWininet ? INTERNET_FLAG_KEEP_CONNECTION : 0);
dwFlags |= (fSecure ? INTERNET_FLAG_SECURE : 0);
gMem->Lock();
if (glServiceState != SERVICE_STATE_ON) {
openCallback.Failed();
gMem->Unlock();
return 503;
}
hRequest = HttpOpenRequestA(hInternetConnect,"POST",szURL,NULL,NULL,NULL,dwFlags,(DWORD)&openCallback);
if (!hRequest) {
openCallback.Failed();
scerror_DebugOutM(VERBOSE_MASK_SRMP,(L"HttpOpenRequest fails, GLE=0x%08x\r\n",GetLastError()));
}
gMem->Unlock();
if (hRequest) {
DWORD cbStatus = sizeof(iStatusCode);
if (!HttpSendRequestA(hRequest,pIOPacket->pszHeaders,pIOPacket->cbHeaders,pIOPacket->pszPost,pIOPacket->cbPost))
openCallback.Wait(30000);
if (openCallback.dwError == 0) {
if (!HttpQueryInfo(hRequest,HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &iStatusCode,&cbStatus,NULL))
iStatusCode = 500;
}
#if defined (SC_VERBOSE)
else
scerror_DebugOut(VERBOSE_MASK_SRMP,L"HttpSendRequest fails, openCallback.dwResult=%d, GLE=0x%08x\r\n",openCallback.dwResult,openCallback.dwError);
#endif
gMem->Lock();
InternetCloseHandle(hRequest);
hRequest = 0;
gMem->Unlock();
}
return iStatusCode;
}
void CALLBACK SrmpCallback(HINTERNET hInternet,DWORD_PTR dwContext,DWORD dwInternetStatus,LPVOID lpvStatusInformation,DWORD dwStatusInformationLength) {
CSrmpCallBack* pThis = (CSrmpCallBack*)(dwContext);
switch(dwInternetStatus) {
case INTERNET_STATUS_REQUEST_COMPLETE: {
INTERNET_ASYNC_RESULT* pAsyncResult = reinterpret_cast<INTERNET_ASYNC_RESULT*>(lpvStatusInformation);
pThis->dwError = pAsyncResult->dwError;
pThis->dwResult = pAsyncResult->dwResult;
SetEvent(pThis->hEventComplete);
}
break;
case INTERNET_STATUS_HANDLE_CLOSING:
SetEvent(pThis->hEventClosed);
break;
}
}
BOOL IsDirectHttpFormatName(const QUEUE_FORMAT* pQueueFormat) {
DIRECT_TOKEN_TYPE ddt;
if (pQueueFormat->GetType() == QUEUE_FORMAT_TYPE_DIRECT &&
ParseDirectTokenString(pQueueFormat->DirectID(),ddt)) {
return (ddt == DT_HTTP || ddt == DT_HTTPS);
}
return FALSE;
}
BOOL QueueFormatToUri(SVSXMLEncode *pXmlEncode, QUEUE_FORMAT *pqf) {
WCHAR szBuf[MAX_PATH];
WCHAR *pszTrav = szBuf;
WCHAR *szURI = NULL;
WCHAR *szFormatName = NULL;
BOOL fRet = FALSE;
switch (pqf->GetType()) {
case QUEUE_FORMAT_TYPE_DIRECT : {
DWORD ccFormatName = SCUTIL_DIRECT_PREFIX_SZ + wcslen(pqf->DirectID()) + 1;
if (ccFormatName > SVSUTIL_CONSTSTRLEN(szBuf)) {
if (NULL == (szFormatName = (WCHAR*) g_funcAlloc(sizeof(WCHAR)*ccFormatName,g_pvAllocData)))
goto done;
}
else
szFormatName = szBuf;
wcscpy(szFormatName,SCUTIL_DIRECT_PREFIX);
wcscpy(szFormatName+SCUTIL_DIRECT_PREFIX_SZ,pqf->DirectID());
}
break;
case QUEUE_FORMAT_TYPE_PUBLIC : {
wcscpy(szBuf,MSMQ_SC_FORMAT_PUBLIC);
const GUID *pGuid = &pqf->PublicID();
wsprintf (szBuf+wcslen(MSMQ_SC_FORMAT_PUBLIC),GUID_FORMAT,GUID_ELEMENTS(pGuid));
szFormatName = szBuf;
}
break;
case QUEUE_FORMAT_TYPE_PRIVATE: {
wcscpy(szBuf,MSMQ_SC_FORMAT_PRIVATE);
pszTrav += wcslen(MSMQ_SC_FORMAT_PRIVATE);
const OBJECTID *pObj = &pqf->PrivateID();
const GUID *pGuid = &pObj->Lineage;
pszTrav += wsprintf (pszTrav,GUID_FORMAT FN_PRIVATE_SEPERATOR,GUID_ELEMENTS(pGuid));
wsprintf(pszTrav,L"%x",pObj->Uniquifier);
szFormatName = szBuf;
}
break;
default:
SVSUTIL_ASSERT(0);
}
gMem->Lock();
if (gMachine->RouteLocalReverseLookup(szFormatName,&szURI)) {
// if we've hit a reverse in lookup table then we originally received
// message as a free-form URI. Send it out like this too.
gMem->Unlock();
fRet = pXmlEncode->Encode(szURI);
goto done;
}
gMem->Unlock();
// send direct HTTP without modifications.
if (IsDirectHttpFormatName(pqf))
fRet = pXmlEncode->Encode(pqf->DirectID());
// append MSMQ: in front of remaining types.
else if (pXmlEncode->Encode(cszMSMQPrefix,ccMSMQPrefix))
fRet = pXmlEncode->Encode(szBuf);
done:
SVSUTIL_ASSERT(! gMem->IsLocked());
if (szFormatName != szBuf)
g_funcFree(szFormatName,g_pvFreeData);
return fRet;
}
BOOL CreateViaList(SVSXMLEncode *pXmlEncode, CDataHeader *pViaHeader, BOOL fSkipFirstElement) {
int iLen = pViaHeader->GetDataLengthInWCHARs();
WCHAR *szStart = (WCHAR*) pViaHeader->GetData();
WCHAR *pszTrav;
if (fSkipFirstElement) {
// skip past 1st entry, which is current machine (not forwarded along) in some cases.
int ccFirstElement = wcslen(szStart) + 1;
szStart += ccFirstElement;
iLen -= ccFirstElement;
SVSUTIL_ASSERT(iLen > 0); // if there's only one element in fwd list, this function shouldn't have been called.
}
pszTrav = szStart;
// VIA list is stored as a NULL separated multi-string. Elements
// may be set to \0 to indicate an empty tag.
while (pszTrav - szStart < iLen) {
if (*pszTrav) {
if (! pXmlEncode->SetElement(cszVia,pszTrav))
return FALSE;
}
else if (! pXmlEncode->SetEmptyElement(cszVia))
return FALSE;
pszTrav += wcslen(pszTrav)+1;
}
SVSUTIL_ASSERT(pszTrav-szStart == iLen);
return TRUE;
}
DWORD GetExpiresFromPacketImage(ScPacketImage *pImage) {
DWORD dwDelta;
DWORD dwTimeout;
CBaseHeader *pBaseHeader = pImage->sect.pBaseHeader;
CUserHeader *pUserHeader = pImage->sect.pUserHeader;
dwDelta = pUserHeader->GetTimeToLiveDelta();
if (dwDelta == INFINITE)
dwTimeout = INFINITE;
else
dwTimeout = dwDelta + pBaseHeader->GetAbsoluteTimeToQueue();
return min(dwTimeout, LONG_MAX);
}
//
// <Path> Section.
//
BOOL SendPath(SVSXMLEncode *pXmlEncode, ScPacketImage *pImage) {
CPropertyHeader *pPropHeader = pImage->sect.pPropHeader;
CUserHeader *pUserHeader = pImage->sect.pUserHeader;
QUEUE_FORMAT qf;
OBJECTID MessageId;
if (! pXmlEncode->Append((CHAR*)cszPathNS,SVSUTIL_CONSTSTRLEN(cszPathNS)*sizeof(WCHAR)) ||
! pXmlEncode->Append((CHAR*)cszMustUnderstandNS,SVSUTIL_CONSTSTRLEN(cszMustUnderstandNS)*sizeof(WCHAR)))
return FALSE;
// <action>
if (! pXmlEncode->StartTag(cszAction))
return FALSE;
// even if there's no title we put <action>MSMQ:</action>, required since <action> is a required field. Like XP.
if (! pXmlEncode->Encode(cszMSMQPrefix))
return FALSE;
if (pPropHeader->GetTitleLength()) {
if (! pXmlEncode->Encode(pPropHeader->GetTitlePtr()))
return FALSE;
}
if (! pXmlEncode->EndTag(cszAction))
return FALSE;
//<to>
pUserHeader->GetDestinationQueue(&qf);
if (! pXmlEncode->StartTag(cszTo))
return FALSE;
if (!QueueFormatToUri(pXmlEncode,&qf))
return FALSE;
if (! pXmlEncode->EndTag(cszTo))
return FALSE;
// <id>
pUserHeader->GetMessageID(&MessageId);
if (! SetMsgID(pXmlEncode,&MessageId))
return FALSE;
if (pImage->flags.fSoapExtIncluded) {
CSoapExtSection *pSoapExt = pImage->sect.pSoapExtHeaderSection;
if (pSoapExt->GetFromLengthInWCHARs()) {
if (! pXmlEncode->SetElement(cszFrom,pSoapExt->GetFrom(),pSoapExt->GetFromLengthInWCHARs()))
return FALSE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -