| /* |
| * The Apache Software License, Version 1.1 |
| * |
| * Copyright (c) 1999-2000 The Apache Software Foundation. All rights |
| * reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * |
| * 3. The end-user documentation included with the redistribution, |
| * if any, must include the following acknowledgment: |
| * "This product includes software developed by the |
| * Apache Software Foundation (http://www.apache.org/)." |
| * Alternately, this acknowledgment may appear in the software itself, |
| * if and wherever such third-party acknowledgments normally appear. |
| * |
| * 4. The names "Xerces" and "Apache Software Foundation" must |
| * not be used to endorse or promote products derived from this |
| * software without prior written permission. For written |
| * permission, please contact apache\@apache.org. |
| * |
| * 5. Products derived from this software may not be called "Apache", |
| * nor may "Apache" appear in their name, without prior written |
| * permission of the Apache Software Foundation. |
| * |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR |
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| * ==================================================================== |
| * |
| * This software consists of voluntary contributions made by many |
| * individuals on behalf of the Apache Software Foundation, and was |
| * originally based on software copyright (c) 1999, International |
| * Business Machines, Inc., http://www.ibm.com . For more information |
| * on the Apache Software Foundation, please see |
| * <http://www.apache.org/>. |
| */ |
| |
| /* |
| * $Log$ |
| * Revision 1.3 2000/06/03 00:29:03 andyh |
| * COM Wrapper changes from Curt Arnold |
| * |
| * Revision 1.2 2000/03/30 02:00:09 abagchi |
| * Initial checkin of working code with Copyright Notice |
| * |
| */ |
| |
| #include "stdafx.h" |
| |
| #include "xml4com.h" |
| #include "XMLHttpRequest.h" |
| #include "XMLDOMDocument.h" |
| |
| // I need to make sure the file is registered with long filenames |
| HRESULT WINAPI CXMLHttpRequest::UpdateRegistry(BOOL bRegister) |
| { |
| USES_CONVERSION; |
| |
| TCHAR file[MAX_PATH]; |
| if (::GetModuleFileName(_Module.m_hInst, file, MAX_PATH)) { |
| WIN32_FIND_DATA d; |
| memset(&d,0,sizeof(WIN32_FIND_DATA)); |
| HANDLE h = FindFirstFile(file,&d); |
| if (h != INVALID_HANDLE_VALUE) { |
| TCHAR *name = _tcsrchr(file,_T('\\')); |
| TCHAR newFile[MAX_PATH] = _T(""); |
| _tcsncpy(newFile,file,name-file); |
| _tcscat(newFile,_T("\\")); |
| _tcscat(newFile,d.cFileName); |
| FindClose(h); |
| |
| _ATL_REGMAP_ENTRY regmap[2] = {{NULL,NULL},{NULL,NULL}}; |
| regmap[0].szKey = OLESTR("XMLMODULE"); |
| regmap[0].szData = T2OLE(newFile); |
| return _Module.UpdateRegistryFromResource((UINT) IDR_XMLHTTPREQUEST, bRegister,regmap); |
| } |
| } |
| return E_FAIL; |
| } |
| |
| CXMLHttpRequest::CXMLHttpRequest() |
| :m_pOnReadyStateChange (NULL) |
| ,m_bAbort (false) |
| ,m_hThread (NULL) |
| ,m_lReadyState (0) |
| ,m_bAsync (false) |
| ,m_Method (_T("")) |
| ,m_HostName (_T("")) |
| ,m_Port (INTERNET_DEFAULT_HTTP_PORT) |
| ,m_URLPath (_T("")) |
| ,m_User (_T("")) |
| ,m_Password (_T("")) |
| ,m_dwStatus (0) |
| ,m_StatusText (_T("")) |
| ,m_ResponseHeaders (_T("")) |
| ,m_HwndParent (NULL) |
| ,m_pBody (NULL) |
| ,m_lBodyLength (0) |
| ,m_pResponseBody (NULL) |
| ,m_lResponseBodyLength (0) |
| ,m_Error (_T("")) |
| ,m_bSuccess (true) |
| { |
| } |
| |
| HRESULT CXMLHttpRequest::FinalConstruct() |
| { |
| // create monitor window |
| RECT rc; |
| memset(&rc,0,sizeof(RECT)); |
| if (NULL == Create(NULL, rc, _T("XML HTTP Request Monitor Window"), 0)) |
| return E_FAIL; |
| |
| return S_OK; |
| } |
| |
| void CXMLHttpRequest::FinalRelease() |
| { |
| if (NULL != m_hThread) { |
| m_bAbort = true; |
| ::WaitForSingleObject(m_hThread, INFINITE); |
| ::CloseHandle(m_hThread); |
| m_hThread = NULL; |
| } |
| |
| if (m_pOnReadyStateChange != NULL) { |
| m_pOnReadyStateChange->Release(); |
| m_pOnReadyStateChange = NULL; |
| } |
| |
| DestroyWindow(); |
| |
| delete [] m_pBody; |
| m_pBody = NULL; |
| m_lBodyLength = 0; |
| |
| delete [] m_pResponseBody; |
| m_pResponseBody = NULL; |
| m_lResponseBodyLength = 0; |
| } |
| |
| LRESULT CXMLHttpRequest::OnReadyStateChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) |
| { |
| ATLTRACE(_T("CXMLHttpRequest::OnReadyStateChange\n")); |
| |
| bHandled = TRUE; |
| |
| m_lReadyState = wParam; |
| if (NULL != m_pOnReadyStateChange) { |
| CComVariant varResult; |
| DISPPARAMS disp = { NULL, NULL, 0, 0 }; |
| m_pOnReadyStateChange->Invoke(DISPID_VALUE, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, &varResult, NULL, NULL); |
| } |
| |
| return 1L; |
| } |
| |
| |
| STDMETHODIMP CXMLHttpRequest::InterfaceSupportsErrorInfo(REFIID riid) |
| { |
| if (IsEqualGUID(IID_IXMLHttpRequest,riid)) |
| return S_OK; |
| return S_FALSE; |
| } |
| |
| STDMETHODIMP CXMLHttpRequest::open(BSTR bstrMethod, BSTR bstrUrl,VARIANT varAsync,VARIANT bstrUser,VARIANT bstrPassword) |
| { |
| ATLTRACE(_T("CXMLHttpRequest::open\n")); |
| |
| // do not open if there is a send active |
| if (NULL != m_hThread) { |
| DWORD exitCode = 0; |
| BOOL rc = ::GetExitCodeThread(m_hThread, &exitCode); |
| if (!rc || STILL_ACTIVE == exitCode) |
| return E_FAIL; |
| |
| ::CloseHandle(m_hThread); |
| m_hThread = NULL; |
| } |
| |
| if (V_VT(&varAsync) != VT_BOOL) |
| return E_INVALIDARG; |
| |
| _bstr_t method = bstrMethod; |
| if (0 == method.length()) |
| return E_INVALIDARG; |
| |
| _bstr_t url = bstrUrl; |
| if (0 == url.length()) |
| return E_INVALIDARG; |
| |
| TCHAR hostName[INTERNET_MAX_PATH_LENGTH] = _T(""); |
| TCHAR strPathName[INTERNET_MAX_PATH_LENGTH] = _T(""); |
| URL_COMPONENTS urlComponents; |
| memset(&urlComponents, 0, sizeof(URL_COMPONENTS)); |
| urlComponents.dwStructSize = sizeof(URL_COMPONENTS); |
| urlComponents.lpszHostName = hostName; |
| urlComponents.dwHostNameLength = INTERNET_MAX_PATH_LENGTH; |
| urlComponents.lpszUrlPath = strPathName; |
| urlComponents.dwUrlPathLength = INTERNET_MAX_PATH_LENGTH; |
| |
| if (!InternetCrackUrl(url, url.length(), 0, &urlComponents)) |
| return E_INVALIDARG; |
| |
| m_Method = method; |
| m_HostName = hostName; |
| if (urlComponents.nPort != 0) |
| m_Port = urlComponents.nPort; |
| |
| m_URLPath = strPathName; |
| m_bAsync = (VARIANT_TRUE == V_BOOL(&varAsync)) ? true : false; |
| if (VT_BSTR == V_VT(&bstrUser)) |
| m_User = V_BSTR(&bstrUser); |
| else |
| m_User = _T(""); |
| |
| if (VT_BSTR == V_VT(&bstrPassword) && m_User.length() > 0) |
| m_Password = V_BSTR(&bstrPassword); |
| else |
| m_Password = _T(""); |
| |
| return S_OK; |
| } |
| |
| STDMETHODIMP CXMLHttpRequest::setRequestHeader(BSTR bstrHeader, BSTR bstrValue) |
| { |
| ATLTRACE(_T("CXMLHttpRequest::setRequestHeader\n")); |
| |
| if (NULL == bstrHeader || NULL == bstrValue) |
| return E_INVALIDARG; |
| |
| // check if there is a send active |
| if (NULL != m_hThread) { |
| DWORD exitCode = 0; |
| BOOL rc = ::GetExitCodeThread(m_hThread, &exitCode); |
| if (!rc || STILL_ACTIVE == exitCode) |
| return E_PENDING; |
| |
| ::CloseHandle(m_hThread); |
| m_hThread = NULL; |
| } |
| |
| m_RequestHeaderMap.Remove(bstrHeader); |
| m_RequestHeaderMap.Add(bstrHeader,bstrValue); |
| return S_OK; |
| } |
| |
| STDMETHODIMP CXMLHttpRequest::getResponseHeader(BSTR bstrHeader, BSTR * pbstrValue) |
| { |
| ATLTRACE(_T("CXMLHttpRequest::getResponseHeader\n")); |
| |
| if (NULL == pbstrValue) |
| return E_POINTER; |
| |
| *pbstrValue = NULL; |
| |
| if (NULL == bstrHeader) |
| return E_INVALIDARG; |
| |
| // check if there is a send active |
| if (NULL != m_hThread) { |
| DWORD exitCode = 0; |
| BOOL rc = ::GetExitCodeThread(m_hThread, &exitCode); |
| if (!rc || STILL_ACTIVE == exitCode) |
| return E_PENDING; |
| |
| ::CloseHandle(m_hThread); |
| m_hThread = NULL; |
| } |
| |
| if (0 == m_ResponseHeaders.length()) |
| return S_FALSE; |
| |
| _bstr_t value; |
| _bstr_t header(bstrHeader); |
| header += _T(": "); |
| _tcslwr(header); |
| TCHAR *pHeaders = new TCHAR[m_ResponseHeaders.length() + sizeof(TCHAR)]; |
| _tcscpy(pHeaders,m_ResponseHeaders); |
| _tcslwr(pHeaders); |
| TCHAR *pStart = _tcsstr(pHeaders,header); |
| if (pStart) { |
| pStart += header.length(); |
| TCHAR *pEnd = _tcsstr(pStart,_T("\r\n")); |
| if (pEnd) { |
| TCHAR *pHeader = new TCHAR[pEnd-pStart + sizeof(TCHAR)]; |
| _tcsncpy(pHeader,static_cast<LPCTSTR> (m_ResponseHeaders) + (pStart-pHeaders),pEnd-pStart); |
| value = pHeader; |
| delete [] pHeader; |
| } |
| } |
| delete[] pHeaders; |
| |
| if (0 == value.length()) |
| return S_FALSE; |
| |
| *pbstrValue = value.copy(); |
| |
| return S_OK; |
| } |
| |
| STDMETHODIMP CXMLHttpRequest::getAllResponseHeaders(BSTR * pbstrHeaders) |
| { |
| ATLTRACE(_T("CXMLHttpRequest::getAllResponseHeaders\n")); |
| |
| if (NULL == pbstrHeaders) |
| return E_POINTER; |
| |
| *pbstrHeaders = NULL; |
| |
| if (NULL == pbstrHeaders) |
| return E_INVALIDARG; |
| |
| // check if there is a send active |
| if (NULL != m_hThread) { |
| DWORD exitCode = 0; |
| BOOL rc = ::GetExitCodeThread(m_hThread, &exitCode); |
| if (!rc || STILL_ACTIVE == exitCode) |
| return E_PENDING; |
| |
| ::CloseHandle(m_hThread); |
| m_hThread = NULL; |
| } |
| |
| *pbstrHeaders = m_ResponseHeaders.copy(); |
| return S_OK; |
| } |
| |
| STDMETHODIMP CXMLHttpRequest::send(VARIANT varBody) |
| { |
| ATLTRACE(_T("CXMLHttpRequest::send\n")); |
| |
| if (V_VT(&varBody) != VT_BSTR && |
| V_VT(&varBody) != VT_DISPATCH && |
| V_VT(&varBody) != (VT_ARRAY | VT_VARIANT) && |
| V_VT(&varBody) != (VT_ARRAY | VT_UI1) && |
| V_VT(&varBody) != VT_UNKNOWN) |
| return E_INVALIDARG; |
| |
| // do not start another thread if there is another active |
| if (NULL != m_hThread) { |
| DWORD exitCode = 0; |
| BOOL rc = ::GetExitCodeThread(m_hThread, &exitCode); |
| if (!rc || STILL_ACTIVE == exitCode) |
| return E_PENDING; |
| |
| ::CloseHandle(m_hThread); |
| m_hThread = NULL; |
| } |
| |
| HRESULT hr = S_OK; |
| m_bSuccess = true; |
| m_bAbort = false; |
| delete [] m_pBody; |
| m_pBody = NULL; |
| m_lBodyLength = 0; |
| delete [] m_pResponseBody; |
| m_pResponseBody = NULL; |
| m_lResponseBodyLength = 0; |
| m_dwStatus = 0; |
| m_StatusText = _T(""); |
| m_ResponseHeaders = _T(""); |
| |
| if (V_VT(&varBody) == VT_BSTR) { |
| _bstr_t body = V_BSTR(&varBody); |
| m_lBodyLength = body.length() + 1; |
| m_pBody = new BYTE[m_lBodyLength]; |
| memset(m_pBody,0,m_lBodyLength); |
| memcpy(m_pBody,static_cast<char*> (body),body.length()); |
| } |
| else |
| if (V_VT(&varBody) == VT_UNKNOWN) { |
| CComQIPtr<IStream,&IID_IStream> pS(V_UNKNOWN(&varBody)); |
| if (!pS) |
| return E_INVALIDARG; |
| |
| CComBSTR b; |
| hr = b.ReadFromStream(pS); |
| if (S_OK != hr) |
| return hr; |
| |
| _bstr_t body = b; |
| m_lBodyLength = body.length() + 1; |
| m_pBody = new BYTE[m_lBodyLength]; |
| memset(m_pBody,0,m_lBodyLength); |
| memcpy(m_pBody,static_cast<char*> (body),body.length()); |
| } |
| else |
| if (V_VT(&varBody) == VT_DISPATCH) { |
| CComQIPtr<IXMLDOMDocument,&IID_IXMLDOMDocument> pDoc(V_DISPATCH(&varBody)); |
| if (!pDoc) |
| return E_INVALIDARG; |
| |
| BSTR b = NULL; |
| hr = pDoc->get_xml(&b); |
| if (S_OK != hr) |
| return hr; |
| |
| _bstr_t body = b; |
| ::SysFreeString(b); |
| |
| m_lBodyLength = body.length() + 1; |
| m_pBody = new BYTE[m_lBodyLength]; |
| memset(m_pBody,0,m_lBodyLength); |
| memcpy(m_pBody,static_cast<char*> (body),body.length()); |
| } |
| else |
| if (V_VT(&varBody) == (VT_ARRAY | VT_VARIANT)) { |
| SAFEARRAY *pArray = reinterpret_cast<SAFEARRAY *> (varBody.byref); |
| if (NULL == pArray) |
| return E_INVALIDARG; |
| |
| long lLBoundVar = 0; |
| long lUBoundVar = 0; |
| |
| UINT dims = ::SafeArrayGetDim(pArray); |
| if (dims == 0) |
| return E_INVALIDARG; |
| |
| hr = ::SafeArrayGetLBound(pArray, dims, &lLBoundVar); |
| if (S_OK != hr) |
| return hr; |
| |
| hr = ::SafeArrayGetUBound(pArray, dims, &lUBoundVar); |
| if (S_OK != hr) |
| return hr; |
| |
| if (lUBoundVar >= lLBoundVar) { |
| VARIANT *pIndex = NULL; |
| hr = ::SafeArrayAccessData(pArray, reinterpret_cast<void **> (&pIndex)); |
| if (S_OK != hr) |
| return hr; |
| |
| m_lBodyLength = lUBoundVar-lLBoundVar+1; |
| m_pBody = new BYTE[m_lBodyLength]; |
| for (long i = 0; i <= lUBoundVar-lLBoundVar; ++i) { |
| VARIANT var = pIndex[i]; |
| if (V_VT(&var) != VT_UI1) { |
| hr = E_INVALIDARG; |
| break; |
| } |
| m_pBody[i] = V_UI1(&var); |
| } |
| |
| ::SafeArrayUnaccessData(pArray); |
| if (S_OK != hr) { |
| delete [] m_pBody; |
| m_pBody = NULL; |
| m_lBodyLength = 0; |
| return hr; |
| } |
| } |
| } |
| else |
| if (V_VT(&varBody) == (VT_ARRAY | VT_UI1)) { |
| SAFEARRAY *pArray = reinterpret_cast<SAFEARRAY *> (varBody.byref); |
| if (NULL == pArray) |
| return E_INVALIDARG; |
| |
| long lLBoundVar = 0; |
| long lUBoundVar = 0; |
| |
| UINT dims = ::SafeArrayGetDim(pArray); |
| if (dims == 0) |
| return E_INVALIDARG; |
| |
| hr = ::SafeArrayGetLBound(pArray, dims, &lLBoundVar); |
| if (S_OK != hr) |
| return hr; |
| |
| hr = ::SafeArrayGetUBound(pArray, dims, &lUBoundVar); |
| if (S_OK != hr) |
| return hr; |
| |
| if (lUBoundVar >= lLBoundVar) { |
| BYTE *pIndex = NULL; |
| hr = ::SafeArrayAccessData(pArray, reinterpret_cast<void **> (&pIndex)); |
| if (S_OK != hr) |
| return hr; |
| |
| m_lBodyLength = lUBoundVar-lLBoundVar+1; |
| m_pBody = new BYTE[m_lBodyLength]; |
| for (long i = 0; i <= lUBoundVar-lLBoundVar; ++i) |
| m_pBody[i] = pIndex[i]; |
| |
| ::SafeArrayUnaccessData(pArray); |
| } |
| } |
| |
| m_HwndParent = GetParentWindow(); |
| |
| UINT nthreadID = 0; |
| m_hThread = reinterpret_cast<HANDLE> (_beginthreadex(NULL, |
| 0, |
| CXMLHttpRequest::SendThread, |
| (void *) this, |
| 0, |
| &nthreadID)); |
| if (NULL == m_hThread) |
| return E_FAIL; |
| |
| if (m_bAsync) |
| return S_OK; |
| |
| bool bWait = true; |
| while (bWait) { |
| DWORD dwEvt = MsgWaitForMultipleObjects(1,&m_hThread,FALSE,INFINITE,QS_ALLINPUT); |
| switch(dwEvt) { |
| case WAIT_OBJECT_0: |
| bWait = false; |
| break; |
| case WAIT_OBJECT_0 + 1: |
| { |
| MSG msg; |
| while(::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) { |
| if (WM_CLOSE == msg.message || WM_QUIT == msg.message) { |
| bWait = false; |
| m_bAbort = true; |
| break; |
| } |
| else { |
| PeekMessage(&msg, NULL, 0, 0, PM_REMOVE); |
| TranslateMessage(&msg); |
| DispatchMessage(&msg); |
| } |
| } |
| break; |
| } |
| default: |
| m_bAbort = true; |
| bWait = false; |
| break; |
| } |
| } |
| |
| return S_OK; |
| } |
| |
| UINT APIENTRY CXMLHttpRequest::SendThread(void *pParm) |
| { |
| ATLTRACE(_T("CXMLHttpRequest::SendThread\n")); |
| |
| CXMLHttpRequest *pCtx = reinterpret_cast<CXMLHttpRequest *> (pParm); |
| if (NULL == pCtx) |
| return 0; |
| |
| HINTERNET hOpen = NULL; |
| HINTERNET hConnect = NULL; |
| HINTERNET hRequest = NULL; |
| |
| hOpen = InternetOpen(_T("XMLHTTP/1.0"),INTERNET_OPEN_TYPE_PRECONFIG, |
| NULL,NULL,0); |
| if (NULL == hOpen) { |
| DWORD res = GetLastError(); |
| pCtx->m_Error = CXMLHttpRequest::GetErrorMsg(res); |
| pCtx->m_bSuccess = false; |
| } |
| |
| if (!pCtx->m_bAbort && pCtx->m_bSuccess) { |
| if (INTERNET_INVALID_STATUS_CALLBACK == InternetSetStatusCallback(hOpen, |
| CXMLHttpRequest::InternetStatusCallback)) { |
| pCtx->m_Error = _T("Invalid Internet Status Callback function."); |
| pCtx->m_bSuccess = false; |
| } |
| } |
| |
| bool bPromptForAuthentication = true; |
| if (!pCtx->m_bAbort && pCtx->m_bSuccess) { |
| LPTSTR lpszUserName = NULL; |
| LPTSTR lpszPassword = NULL; |
| if (pCtx->m_User.length() > 0) { |
| bPromptForAuthentication = false; |
| lpszUserName = pCtx->m_User; |
| if (pCtx->m_Password.length() > 0) |
| lpszPassword = pCtx->m_Password; |
| } |
| hConnect = InternetConnect(hOpen,pCtx->m_HostName,pCtx->m_Port,lpszUserName,lpszPassword, |
| INTERNET_SERVICE_HTTP,0,reinterpret_cast<DWORD> (pCtx)); |
| if (NULL == hConnect) { |
| DWORD res = GetLastError(); |
| pCtx->m_Error = CXMLHttpRequest::GetErrorMsg(res); |
| pCtx->m_bSuccess = false; |
| } |
| } |
| |
| if (!pCtx->m_bAbort && pCtx->m_bSuccess) { |
| DWORD dwFlags = (443 == pCtx->m_Port) ? INTERNET_FLAG_SECURE : 0; |
| dwFlags |= INTERNET_FLAG_NO_CACHE_WRITE; |
| hRequest = HttpOpenRequest(hConnect,pCtx->m_Method, |
| pCtx->m_URLPath,NULL,NULL,NULL, |
| dwFlags,reinterpret_cast<DWORD> (pCtx)); |
| if (NULL == hRequest) { |
| DWORD res = GetLastError(); |
| pCtx->m_bSuccess = false; |
| pCtx->m_Error = CXMLHttpRequest::GetErrorMsg(res); |
| } |
| } |
| |
| BOOL rc = TRUE; |
| |
| if (!pCtx->m_bAbort && pCtx->m_bSuccess && pCtx->m_RequestHeaderMap.GetSize() > 0) { |
| _bstr_t requestHeaders; |
| for (int i = 0 ; i < pCtx->m_RequestHeaderMap.GetSize(); ++i) { |
| requestHeaders += pCtx->m_RequestHeaderMap.GetKeyAt(i); |
| requestHeaders += _T(": "); |
| requestHeaders += pCtx->m_RequestHeaderMap.GetValueAt(i); |
| requestHeaders += _T("\r\n"); |
| } |
| rc = HttpAddRequestHeaders(hRequest,requestHeaders,-1,HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE); |
| if (!rc) { |
| DWORD res = GetLastError(); |
| pCtx->m_bSuccess = false; |
| pCtx->m_Error = CXMLHttpRequest::GetErrorMsg(res); |
| } |
| } |
| |
| DWORD dwLen = 0; |
| DWORD dwError = ERROR_SUCCESS; |
| do { |
| if (!pCtx->m_bAbort && pCtx->m_bSuccess) { |
| rc = HttpSendRequest(hRequest,NULL,0,pCtx->m_pBody,pCtx->m_lBodyLength); |
| if (!rc) { |
| DWORD res = GetLastError(); |
| pCtx->m_bSuccess = false; |
| pCtx->m_Error = CXMLHttpRequest::GetErrorMsg(res); |
| break; |
| } |
| } |
| if (!pCtx->m_bAbort && pCtx->m_bSuccess) { |
| dwLen = sizeof(DWORD); |
| rc = HttpQueryInfo(hRequest, |
| HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, |
| &pCtx->m_dwStatus,&dwLen,NULL); |
| if (!rc) { |
| DWORD res = GetLastError(); |
| pCtx->m_bSuccess = false; |
| pCtx->m_Error = CXMLHttpRequest::GetErrorMsg(res); |
| break; |
| } |
| } |
| if (!pCtx->m_bAbort && pCtx->m_bSuccess && |
| bPromptForAuthentication && |
| (HTTP_STATUS_PROXY_AUTH_REQ == pCtx->m_dwStatus || |
| HTTP_STATUS_DENIED == pCtx->m_dwStatus)) |
| dwError = InternetErrorDlg(pCtx->m_HwndParent, |
| hRequest, |
| ERROR_INTERNET_INCORRECT_PASSWORD, |
| FLAGS_ERROR_UI_FILTER_FOR_ERRORS | |
| FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS | |
| FLAGS_ERROR_UI_FLAGS_GENERATE_DATA, |
| NULL); |
| else |
| break; |
| |
| } while (ERROR_INTERNET_FORCE_RETRY == dwError && |
| !pCtx->m_bAbort && pCtx->m_bSuccess); |
| |
| if (!pCtx->m_bAbort && pCtx->m_bSuccess) { |
| dwLen = 1024; |
| TCHAR *pBuff = new TCHAR[dwLen]; |
| rc = HttpQueryInfo(hRequest,HTTP_QUERY_RAW_HEADERS_CRLF,pBuff,&dwLen,NULL); |
| if (!rc) { |
| DWORD res = GetLastError(); |
| if (ERROR_INSUFFICIENT_BUFFER == res) { |
| delete [] pBuff; |
| pBuff = new TCHAR[dwLen]; |
| rc = HttpQueryInfo(hRequest,HTTP_QUERY_RAW_HEADERS_CRLF,pBuff,&dwLen,NULL); |
| if (!rc) { |
| res = GetLastError(); |
| pCtx->m_bSuccess = false; |
| pCtx->m_Error = CXMLHttpRequest::GetErrorMsg(res); |
| } |
| } |
| else { |
| pCtx->m_bSuccess = false; |
| pCtx->m_Error = CXMLHttpRequest::GetErrorMsg(res); |
| } |
| } |
| if (rc) |
| pCtx->m_ResponseHeaders = pBuff; |
| |
| delete [] pBuff; |
| } |
| |
| if (!pCtx->m_bAbort && pCtx->m_bSuccess) { |
| dwLen = 1024; |
| TCHAR *pBuff = new TCHAR[dwLen]; |
| rc = HttpQueryInfo(hRequest,HTTP_QUERY_STATUS_TEXT,pBuff,&dwLen,NULL); |
| if (!rc) { |
| DWORD res = GetLastError(); |
| if (ERROR_INSUFFICIENT_BUFFER == res) { |
| delete [] pBuff; |
| pBuff = new TCHAR[dwLen]; |
| rc = HttpQueryInfo(hRequest,HTTP_QUERY_STATUS_TEXT,pBuff,&dwLen,NULL); |
| if (!rc) |
| _tcscpy(pBuff,_T("Unknown")); |
| } |
| else |
| _tcscpy(pBuff,_T("Unknown")); |
| } |
| pCtx->m_StatusText = pBuff; |
| delete [] pBuff; |
| |
| if (HTTP_STATUS_OK != pCtx->m_dwStatus) { |
| TCHAR errBuff[MAX_PATH] = _T(""); |
| wsprintf(errBuff,_T("HTTP Status Code: %d, Reason: "),pCtx->m_dwStatus); |
| pCtx->m_Error = errBuff; |
| pCtx->m_Error += pCtx->m_StatusText; |
| pCtx->m_bSuccess = false; |
| } |
| } |
| |
| if (!pCtx->m_bAbort && pCtx->m_bSuccess) { |
| PBYTE buffer[255]; |
| DWORD dwRead = 0; |
| delete [] pCtx->m_pResponseBody; |
| pCtx->m_pResponseBody = NULL; |
| pCtx->m_lResponseBodyLength = 0; |
| while (rc = InternetReadFile(hRequest,buffer,255,&dwRead)) { |
| if (!rc || pCtx->m_bAbort || 0 == dwRead) |
| break; |
| |
| PBYTE tmp = new BYTE[pCtx->m_lResponseBodyLength + dwRead]; |
| if (pCtx->m_pResponseBody) { |
| memcpy(tmp,pCtx->m_pResponseBody,pCtx->m_lResponseBodyLength); |
| delete [] pCtx->m_pResponseBody; |
| } |
| |
| memcpy(tmp+pCtx->m_lResponseBodyLength,buffer,dwRead); |
| pCtx->m_pResponseBody = tmp; |
| pCtx->m_lResponseBodyLength += dwRead; |
| } |
| if (!rc) { |
| DWORD res = GetLastError(); |
| pCtx->m_Error = _T("Error reading response: ") + CXMLHttpRequest::GetErrorMsg(res); |
| pCtx->m_bSuccess = false; |
| } |
| } |
| |
| if (hRequest != NULL) |
| InternetCloseHandle(hRequest); |
| |
| if (hConnect != NULL) |
| InternetCloseHandle(hConnect); |
| |
| if (hOpen) |
| InternetCloseHandle(hOpen); |
| |
| if (!pCtx->m_bAbort && pCtx->m_bAsync) |
| ::PostMessage(pCtx->m_hWnd,MSG_READY_STATE_CHANGE,4,0); |
| |
| return 0; |
| } |
| |
| HWND CXMLHttpRequest::GetParentWindow() |
| { |
| HWND hWnd = GetDesktopWindow(); |
| |
| CComPtr<IServiceProvider> pSP; |
| HRESULT hr = GetSite(IID_IServiceProvider, reinterpret_cast<LPVOID *> (&pSP)); |
| if (S_OK != hr) |
| return hWnd; |
| |
| CComPtr<IWebBrowser2> pWB; |
| hr = pSP->QueryService(SID_SWebBrowserApp,IID_IWebBrowser2, |
| reinterpret_cast<LPVOID *> (&pWB)); |
| if (S_OK != hr) |
| return hWnd; |
| |
| long lWnd = 0; |
| hr = pWB->get_HWND(&lWnd); |
| if (S_OK != hr) |
| return hWnd; |
| |
| return reinterpret_cast<HWND> (lWnd); |
| } |
| |
| void CALLBACK CXMLHttpRequest::InternetStatusCallback(HINTERNET hInternet, |
| DWORD dwContext, |
| DWORD dwInternetStatus, |
| LPVOID lpvStatusInformation, |
| DWORD dwStatusInformationLength) |
| { |
| ATLTRACE(_T("CXMLHttpRequest::InternetStatusCallback - dwInternetStatus %d\n"),dwInternetStatus); |
| } |
| |
| STDMETHODIMP CXMLHttpRequest::abort() |
| { |
| ATLTRACE(_T("CXMLHttpRequest::abort\n")); |
| m_bAbort = true; |
| return S_OK; |
| } |
| |
| STDMETHODIMP CXMLHttpRequest::get_status(long * plStatus) |
| { |
| ATLTRACE(_T("CXMLHttpRequest::get_status\n")); |
| |
| if (NULL == plStatus) |
| return E_POINTER; |
| |
| *plStatus = 0; |
| |
| // check if there is a send active |
| if (NULL != m_hThread) { |
| DWORD exitCode = 0; |
| BOOL rc = ::GetExitCodeThread(m_hThread, &exitCode); |
| if (!rc || STILL_ACTIVE == exitCode) |
| return E_PENDING; |
| |
| ::CloseHandle(m_hThread); |
| m_hThread = NULL; |
| } |
| |
| *plStatus = m_dwStatus; |
| return S_OK; |
| } |
| |
| STDMETHODIMP CXMLHttpRequest::get_statusText( BSTR * pbstrStatus) |
| { |
| ATLTRACE(_T("CXMLHttpRequest::get_statusText\n")); |
| |
| if (NULL == pbstrStatus) |
| return E_POINTER; |
| |
| *pbstrStatus = NULL; |
| |
| // check if there is a send active |
| if (NULL != m_hThread) { |
| DWORD exitCode = 0; |
| BOOL rc = ::GetExitCodeThread(m_hThread, &exitCode); |
| if (!rc || STILL_ACTIVE == exitCode) |
| return E_PENDING; |
| |
| ::CloseHandle(m_hThread); |
| m_hThread = NULL; |
| } |
| |
| *pbstrStatus = m_StatusText.copy(); |
| return S_OK; |
| } |
| |
| STDMETHODIMP CXMLHttpRequest::get_responseXML(IDispatch **ppBody) |
| { |
| ATLTRACE(_T("CXMLHttpRequest::get_responseXML\n")); |
| |
| if (NULL == ppBody) |
| return E_POINTER; |
| |
| *ppBody = NULL; |
| |
| // check if there is a send active |
| if (NULL != m_hThread) { |
| DWORD exitCode = 0; |
| BOOL rc = ::GetExitCodeThread(m_hThread, &exitCode); |
| if (!rc || STILL_ACTIVE == exitCode) |
| return E_PENDING; |
| |
| ::CloseHandle(m_hThread); |
| m_hThread = NULL; |
| } |
| |
| BSTR text = NULL; |
| HRESULT hr = get_responseText(&text); |
| if (S_OK != hr || NULL == text) |
| return hr; |
| |
| CXMLDOMDocumentObj *pObj = NULL; |
| hr = CXMLDOMDocumentObj::CreateInstance(&pObj); |
| if (S_OK == hr) { |
| pObj->AddRef(); |
| VARIANT_BOOL isSuccessful = VARIANT_FALSE; |
| hr = pObj->loadXML(text, &isSuccessful); |
| if (S_OK == hr && VARIANT_TRUE == isSuccessful) { |
| *ppBody = pObj; |
| (*ppBody)->AddRef(); |
| } |
| pObj->Release(); |
| } |
| |
| ::SysFreeString(text); |
| |
| return hr; |
| } |
| |
| STDMETHODIMP CXMLHttpRequest::get_responseText(BSTR *pVal) |
| { |
| ATLTRACE(_T("CXMLHttpRequest::get_responseText\n")); |
| |
| if (NULL == pVal) |
| return E_POINTER; |
| |
| *pVal = NULL; |
| |
| // check if there is a send active |
| if (NULL != m_hThread) { |
| DWORD exitCode = 0; |
| BOOL rc = ::GetExitCodeThread(m_hThread, &exitCode); |
| if (!rc || STILL_ACTIVE == exitCode) |
| return E_PENDING; |
| |
| ::CloseHandle(m_hThread); |
| m_hThread = NULL; |
| } |
| |
| if (NULL == m_pResponseBody) |
| return S_OK; |
| |
| TCHAR *psz = new TCHAR[m_lResponseBodyLength+1]; |
| ZeroMemory(psz,m_lResponseBodyLength+1); |
| CopyMemory(psz,m_pResponseBody,m_lResponseBodyLength); |
| |
| *pVal = SysAllocStringByteLen(psz,m_lResponseBodyLength); |
| delete [] psz; |
| |
| return S_OK; |
| } |
| |
| STDMETHODIMP CXMLHttpRequest::get_responseBody(VARIANT *pVal) |
| { |
| ATLTRACE(_T("CXMLHttpRequest::get_responseBody\n")); |
| |
| if (NULL == pVal) |
| return E_POINTER; |
| |
| ::VariantInit(pVal); |
| V_VT(pVal) = VT_NULL; |
| |
| // check if there is a send active |
| if (NULL != m_hThread) { |
| DWORD exitCode = 0; |
| BOOL rc = ::GetExitCodeThread(m_hThread, &exitCode); |
| if (!rc || STILL_ACTIVE == exitCode) |
| return E_PENDING; |
| |
| ::CloseHandle(m_hThread); |
| m_hThread = NULL; |
| } |
| |
| if (NULL == m_pResponseBody) |
| return S_OK; |
| |
| return CXMLHttpRequest::InitializeVarFromByte(*pVal, m_pResponseBody,m_lResponseBodyLength); |
| } |
| |
| STDMETHODIMP CXMLHttpRequest::get_responseStream(VARIANT *pVal) |
| { |
| ATLTRACE(_T("CXMLHttpRequest::get_responseStream\n")); |
| |
| if (NULL == pVal) |
| return E_POINTER; |
| |
| ::VariantInit(pVal); |
| V_VT(pVal) = VT_NULL; |
| |
| // check if there is a send active |
| if (NULL != m_hThread) { |
| DWORD exitCode = 0; |
| BOOL rc = ::GetExitCodeThread(m_hThread, &exitCode); |
| if (!rc || STILL_ACTIVE == exitCode) |
| return E_PENDING; |
| |
| ::CloseHandle(m_hThread); |
| m_hThread = NULL; |
| } |
| |
| if (NULL == m_pResponseBody) |
| return S_OK; |
| |
| //Create an IStream from global memory |
| CComPtr<IStream> pStm; |
| HRESULT hr = CreateStreamOnHGlobal(NULL, TRUE, &pStm); |
| if (S_OK != hr) |
| return hr; |
| |
| hr = pStm->Write(m_pResponseBody, m_lResponseBodyLength, NULL); |
| if (S_OK != hr) |
| return hr; |
| |
| LARGE_INTEGER dlibMove; |
| memset(&dlibMove,0,sizeof(LARGE_INTEGER)); |
| hr = pStm->Seek(dlibMove,STREAM_SEEK_SET,NULL); |
| if (S_OK != hr) |
| return hr; |
| |
| V_VT(pVal) = VT_UNKNOWN; |
| V_UNKNOWN(pVal) = pStm.Detach(); |
| |
| return S_OK; |
| } |
| |
| STDMETHODIMP CXMLHttpRequest::get_readyState(long *pVal) |
| { |
| ATLTRACE(_T("CXMLHttpRequest::get_readyState\n")); |
| |
| if (NULL == pVal) |
| return E_POINTER; |
| |
| *pVal = m_lReadyState; |
| |
| return S_OK; |
| } |
| |
| STDMETHODIMP CXMLHttpRequest::put_onreadystatechange(IDispatch * pReadyStateSink) |
| { |
| ATLTRACE(_T("CXMLHttpRequest::put_onreadystatechange\n")); |
| |
| if (m_pOnReadyStateChange != NULL) { |
| m_pOnReadyStateChange->Release(); |
| m_pOnReadyStateChange = NULL; |
| } |
| m_pOnReadyStateChange = pReadyStateSink; |
| if (m_pOnReadyStateChange != NULL) |
| m_pOnReadyStateChange->AddRef(); |
| |
| return S_OK; |
| } |
| |
| _bstr_t CXMLHttpRequest::GetErrorMsg(DWORD rc) |
| { |
| _bstr_t msg(_T("")); |
| TCHAR *lpBuffer = NULL; |
| |
| if (ERROR_INTERNET_EXTENDED_ERROR == rc) { |
| DWORD dwError = 0; |
| DWORD dwLength = 0; |
| InternetGetLastResponseInfo (&dwError, NULL, &dwLength); |
| if (dwLength > 0) { |
| lpBuffer = (TCHAR *) LocalAlloc(LPTR,dwLength); |
| if (!lpBuffer) { |
| msg = _T("Unable to allocate memory to display Internet extended error: "); |
| rc = GetLastError(); |
| } |
| else { |
| if (!InternetGetLastResponseInfo(&dwError,lpBuffer,&dwLength)) { |
| msg = _T("Unable to get Internet extended error: "); |
| rc = GetLastError(); |
| LocalFree(lpBuffer); |
| } |
| else { |
| int len = lstrlen(lpBuffer); |
| for (int i=0; i < len; ++i) { |
| if (_istcntrl(lpBuffer[i])) |
| lpBuffer[i] = _T(' '); |
| } |
| msg = lpBuffer; |
| LocalFree(lpBuffer); |
| return msg; |
| } |
| } |
| } |
| } |
| |
| lpBuffer = NULL; |
| HMODULE hModule = NULL; // default to system source |
| |
| if (rc >= INTERNET_ERROR_BASE) |
| hModule = LoadLibraryEx(_T("wininet.dll"),NULL,LOAD_LIBRARY_AS_DATAFILE); |
| |
| ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | |
| FORMAT_MESSAGE_IGNORE_INSERTS | |
| FORMAT_MESSAGE_FROM_SYSTEM | |
| ((hModule != NULL) ? FORMAT_MESSAGE_FROM_HMODULE : 0), |
| hModule, |
| rc, |
| MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT), |
| (LPTSTR)&lpBuffer, 0, NULL); |
| |
| if (lpBuffer) { |
| int len = lstrlen(lpBuffer); |
| for (int i=0; i < len; ++i) { |
| if (_istcntrl(lpBuffer[i])) |
| lpBuffer[i] = _T(' '); |
| } |
| } |
| |
| msg += lpBuffer; |
| LocalFree(lpBuffer); |
| |
| if (hModule != NULL) |
| FreeLibrary(hModule); |
| |
| return msg; |
| } |
| |
| HRESULT CXMLHttpRequest::InitializeVarFromByte(VARIANT &varOut, const PBYTE pByte, long lSize) |
| { |
| ::VariantInit(&varOut); |
| V_VT(&varOut) = VT_NULL; |
| |
| HRESULT hr = S_OK; |
| SAFEARRAYBOUND rgsabound[1]; |
| rgsabound[0].cElements = lSize; |
| rgsabound[0].lLbound = 0; |
| |
| SAFEARRAY *psa = ::SafeArrayCreate( VT_VARIANT, 1, rgsabound); |
| if (psa == NULL) |
| return E_FAIL; |
| |
| if (pByte != NULL) { |
| long ix[1]; |
| for (ULONG i = 0; i < rgsabound[0].cElements; ++i) { |
| ix[0] = i; |
| VARIANT var; |
| ::VariantInit(&var); |
| V_VT(&var) = VT_UI1; |
| V_UI1(&var) = pByte[i]; |
| |
| hr = ::SafeArrayPutElement(psa, ix, &var); |
| if (S_OK != hr) { |
| ::SafeArrayDestroy(psa); |
| break; |
| } |
| } |
| } |
| |
| if (S_OK == hr) { |
| V_VT(&varOut) = VT_ARRAY | VT_VARIANT; |
| V_ARRAY(&varOut) = psa; |
| } |
| |
| return hr; |
| } |