Trying to make a CHttpFile::SendRequest, device hangs - visual-c++

I'm trying to fetch contents of an URL on a WM 6.5 not so uber gizmo, using VC++ 2008
CString http_request(CString params){
CInternetSession session(_T("My Session")); // add device identifier here?
CHttpConnection* pServer = NULL;
CHttpFile* pFile = NULL;
CString szHeaders( _T("Content-Type: application/x-www-form-urlencoded;Accept: text/xml, text/plain, text/html, text/htm\r\nHost: www.mydomain.com\r\n\r\n"));
CString strObject("");
CString out;
DWORD dwRet;
char *szBuff = new char[1023];
try
{
CString strServerName("www.mydomain.com");
INTERNET_PORT nPort(80);
pServer = session.GetHttpConnection(strServerName, nPort);
pFile = pServer->OpenRequest(CHttpConnection::HTTP_VERB_GET, strObject);
pFile->AddRequestHeaders(szHeaders);
pFile->SendRequest(LPCTSTR(params),params.GetLength());
pFile->QueryInfoStatusCode(dwRet);
if (dwRet == HTTP_STATUS_OK)
{
UINT nRead = pFile->Read(szBuff, 1023);
while (nRead > 0)
{
//read file...
out = CString(szBuff);
}
}
delete pFile;
delete pServer;
}
catch (CInternetException* pEx)
{
//catch errors from WinInet
out = CString("Something went wrong.");
}
session.Close();
return out;
}
I do see the request coming in but the URI does not get passed, the server throws a 500 or 404 because of this.
I've tried passing params as "GET /blah.txt HTTP/1.0" and also "/blah.txt", no luck, would like to keep testing various input parameters but the device hangs for some reason...
Any pointers would be greatly appreciated!
TIA
Later edit: Solution:
Here's how I got it to work, full code snippet in case anyone wants a copy paste solution (yeah these come in handy)
CString http_request(CString server, CString uri){
CInternetSession session(_T("My Session")); // add device identifier here? IMEI ftw
CHttpConnection* pServer = NULL;
CHttpFile* pFile = NULL;
CString szHeaders( _T("Content-Type: application/x-www-form-urlencoded;Accept: text/xml, text/plain, text/html, text/htm\r\nHost: www.domain.com\r\n\r\n")); // maybe pass as param?
CString strObject(uri);
CString out;
DWORD dwRet;
CString params;
char *szBuff = new char[1023];
try
{
CString strServerName(server);
INTERNET_PORT nPort(80);
pServer = session.GetHttpConnection(strServerName, nPort);
pFile = pServer->OpenRequest(CHttpConnection::HTTP_VERB_GET, strObject);
pFile->AddRequestHeaders(szHeaders);
pFile->SendRequest(szHeaders, szHeaders.GetLength(),&params, params.GetLength());
pFile->QueryInfoStatusCode(dwRet);
if (dwRet == HTTP_STATUS_OK)
{
UINT nRead = pFile->Read(szBuff, 1023);
//while (nRead > 0)
//{
//read, for more data you might want to uncomment the while and append to a var. I only needed a few bytes actually.
out = CString(szBuff);
//}
} else {
out = CString("Communication error!");
}
delete pFile;
delete pServer;
}
catch (CInternetException* pEx)
{
//catch errors from WinInet
out = CString("Network error!"); // stupid a$$ cpp the code to handle this would be longer than my ****
}
session.Close();
pServer->Close();
return out;
}

your strObject is empty. Shouldn't this be where you put "blah.txt"?
also, you should delete[] szBuf;
and you're calling pServer->Close() after you've deleted pServer which will probably cause your app to except.

Related

Waitformultipleobjects returns invalid handle

The code is below and it is part of a thread. pFileChange->m_hDirectory is of type HANDLE and pFileChange->m_eventFileChange if of type CEvent. CreateFile and ReadDirectoryChangesW return with a success. I am not able to figure out why i am getting an invalid handle status, please help!
UINT CFileChange::FileMontiorThread(LPVOID pArgs)
{
CFileChange* pFileChange = NULL;
pFileChange = (CFileChange*)pArgs;
pFileChange = (CFileChange*)pArgs;
CString str = pFileChange->m_strDirectory;
LPSTR strDirectory;
strDirectory = str.GetBuffer(str.GetLength());
PathRemoveFileSpec(strDirectory);
DWORD dwBytes = 0;
vector<BYTE> m_Buffer;
BOOL m_bChildren;
OVERLAPPED m_Overlapped;
HANDLE arrHandles[2] = { pFileChange->m_hDirectory, pFileChange->m_eventFileChange };
::ZeroMemory(&m_Overlapped, sizeof(OVERLAPPED));
DWORD dwBufferSize = 16384;
m_Buffer.resize(dwBufferSize);
m_bChildren = false;
pFileChange->m_hDirectory = ::CreateFile(
(LPCSTR)(LPCTSTR)strDirectory,
FILE_LIST_DIRECTORY,
FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS
| FILE_FLAG_OVERLAPPED,
NULL);
if (pFileChange->m_hDirectory == INVALID_HANDLE_VALUE)
{
return false;
}
BOOL success = ::ReadDirectoryChangesW(
pFileChange->m_hDirectory, // handle to directory
&m_Buffer[0], // read results buffer
m_Buffer.size(), // length of buffer
m_bChildren, // monitoring option
FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_FILE_NAME, // filter conditions
&dwBytes, // bytes returned
&m_Overlapped, // overlapped buffer
NULL); // no completion routine
DWORD dwWaitStatus;
while (!pFileChange->m_bKillThread)
{
dwWaitStatus = WaitForMultipleObjects(2, arrHandles, FALSE, INFINITE);
Switch(dwWaitStatus)
{
case WAIT_FAILED:
{
ULONG rc = 0;
rc = ::GetLastError();
LPVOID lpMsgBuf = NULL;
::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
rc,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR)&lpMsgBuf,
0,
NULL);
CString strErrMsg;
strErrMsg.Format(_T("%s, %s, Reason:%s"), "", "", (LPTSTR)lpMsgBuf);
break;
}
}
}
return 0;
}
Note that, as it specifies in the documentation, you can't wait on any type of handle.
Waiting on a directory handle isn't going to do what you think it should. Read this related question and its answers for more information and background reading.
As it seems you're trying to create a folder monitor, perhaps read this blog post for the correct way to use ReadDirectoryChangesW.
The answer was provided by Hans Passant in a comment:
You copy the handles into arrHandles too soon, before they are created. That cannot work of course.

Resources getting deleted when trying to add at run time

When i am trying to add resources to another file at run time, some of the earlier resources are getting deleted. Please find the source code below:
void CResourceIncludeSampleDlg::OnBnClickedButton1()
{
CString strInputFile = _T("C:\\SampleData\\FileToInsert.zip"); // This File is 100 MB
HANDLE hFile = CreateFile(strInputFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD FileSize = GetFileSize(hFile, NULL);
BYTE *pBuffer = new BYTE[FileSize];
DWORD dwBytesRead;
ReadFile(hFile, pBuffer, FileSize, &dwBytesRead, NULL);
for (int iIndex = 1; iIndex <= 4; iIndex++)
{
InsertResource(FileSize, iIndex, pBuffer);
}
CloseHandle(hFile);
}
void CResourceIncludeSampleDlg::InsertResource(DWORD FileSize, int iIndex, BYTE *pBuffer)
{
CString strOutputFile = _T("C:\\SampleData\\ResourceIncludeSample_Source.exe");
int iResourceID = 300 + iIndex;
HANDLE hResource = BeginUpdateResource(strOutputFile, FALSE);
if (INVALID_HANDLE_VALUE != hResource)
{
if (UpdateResource(hResource, _T("VIDEOBIN"), MAKEINTRESOURCE(iResourceID), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
(LPVOID)pBuffer, FileSize) == TRUE)
{
EndUpdateResource(hResource, FALSE);
}
}
}
After completion of the execution, i am expecting output as 301, 302, 303 and 304 added under "VIDEOBIN" category. But only 2 (sometimes 3) resources are present. One resource is always deleted.
Could you please let me know what could be wrong or any fix for the same ?
Any help or sample source code is greatly appreciated.
Thanks and Regards,
YKK Reddy
You need delete[] pBuffer after closing the file. It should be RT_RCDATA instead of _T("VIDEOBIN") although custom resource name may not be the cause of this particular problem.

CInternetSession::WriteString writes the file and removes directly

I wrote a dll for an application which wil upload some information from the application via ftp to a server. The upload works fine for most of the files I upload.
There is one file which will upload completely but after the upload it is directly removed from the server (this happens not alway, sometimes the file exists on the server after upload). The file is arround 400 kb, all the other files are smaller.
date and type are two CStrings. Data contains the file content and type the first part of the filename.
CInternetSession session(_T("whtsnXt_dll"));
CFtpConnection* pServer = NULL;
CInternetFile* pFile = NULL;
LPCTSTR pszServerName = _T("servername");
CString fileName = type + L".txt";
int curPos = 0;
CString postData = data;
try
{
CString strServerName;
INTERNET_PORT nPort = 21;
pServer = session.GetFtpConnection(pszServerName, _T("username"), _T("password"), nPort, TRUE);
if (pServer->SetCurrentDirectory(L"goes") == 0) {
// MessageBox::Show("De map bestaat niet", "whtsnXt error", MessageBoxButtons::OK, MessageBoxIcon::Error);
}
pFile = pServer->OpenFile((LPCTSTR)fileName, GENERIC_WRITE);
pFile->WriteString(postData);
pFile->Close();
pServer->Close();
delete pFile;
delete pServer;
}
catch (CInternetException* pEx)
{
//catch errors from WinInet
TCHAR pszError[64];
pEx->GetErrorMessage(pszError, 64);
MessageBox::Show(gcnew String(pszError), "whtsnXt error", MessageBoxButtons::OK, MessageBoxIcon::Error);
}
session.Close();
Does someone know a way to upload that file withoud directly removing?
Try to upload the file in smaller pieces:
int i;
for (i = 0; i < postData.Getlength(); i += 1024)
{
pFile->WriteString(postData.Mid(i, min(1024, postData.Getlength() - i));
}
Just to be sure: data is actually a multi-byte or unicode string and holds no binary data? WriteString will only write till it finds a '\0' character. To upload binary data, use pFile->Write.

QNetworkReply readAll response is empty when there is an error code

Response of QNetworkReply::readAll is empty when QNetworkReply::error() != NoError.
Is this normal?
I've a Node+Express server that always send a detailed description in case of http status different of 200; I cant get this description from my Qt client base on QNAM. Qt version is 5.3, OS Win 7 64b.
This is my code, really I don't think this can help.
PendingRequest *Foo::sendMsg(QStandardItem *requestItem, HTTP_METHOD_ID method, QString path)
{
PendingRequest *pReq = new PendingRequest(method);
QString url = QString("https://%1:%2%3").arg(host, QString::number(port), path);
QNetworkRequest qNetReq = QNetworkRequest(QUrl(url));
//set headears
qNetReq.setHeader(QNetworkRequest::KnownHeaders::UserAgentHeader, HttpUserAgent);
qNetReq.setRawHeader("Connection", "Keep-Alive");
if(!credentials.isEmpty())
{
qNetReq.setRawHeader("Authorization", QByteArray("Basic ")+credentials);
}
if(!sessionId.isEmpty())
{
qNetReq.setRawHeader("Session-Id", sessionId);
}
//send request
QNetworkReply *reply;
if(method == HTTP_METHOD_ID::POST)
{
qNetReq.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
QByteArray data = outHandlerList[outHandlerIndex](requestItem);
reply = netManager.post(qNetReq, data);
}
else
{
reply = netManager.get(qNetReq);
}
connect(reply, SIGNAL(finished()), this, SLOT(handleResponse()));
connect(reply, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(handleSslErrors(QList<QSslError>)));
return pReq;
}
and this where I handle response:
void Foo::handleResponse()
{
QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
if(reply->hasRawHeader("Session-Id"))
sessionId = reply->rawHeader("Session-Id");
PendingRequest *pReq = pendingRequestMap.contains(reply) ? pendingRequestMap.take(reply) : 0;
Q_ASSERT(pReq);
QStandardItem *responseItem = 0;
QString error;
if(reply->error() != QNetworkReply::NoError)
{
qDebug() << "readAll: ", reply->readAll(), "error: ", reply->errorString();
error = reply->errorString();
}
else
{
responseItem = inHandlerList[pReq->inHandlerIndex](reply, error, pReq);
}
reply->deleteLater();
}
Thanks a lot for your help.
From the documentation:
QByteArray QIODevice::readAll()
This is an overloaded function.
Reads all available data from the device, and returns it as a
QByteArray.
This function has no way of reporting errors; returning an empty
QByteArray() can mean either that no data was currently available for
reading, or that an error occurred.
I had the same problem, spent hours debugging and searching online for solutions...
The resolution is to connect QIODevice::readyRead to as per the documentation:
connect(reply, &QIODevice::readyRead, this, [=]() {
QByteArray response = reply->readAll();
qDebug() << response;
});
You now have the server reply regardless of the HTTP error code.

Use iXMLHttpRequest2 to download zip file

I am trying to port cocos2dx application for Windows phone 8. I am trying to use iXMLHTTPRequest class to perform Network calls in C++.
I am trying to download zip file using this but dont know what and where I am doing wrong. Here is my code which I am using, Please help me to figure out the issue and what I should do to make it working.
void HTTPRequest::sendRequest(){
m_cancelHttpRequestSource = cancellation_token_source();
// Set up the GET request parameters.
std::string s_str = std::string(urlString);
std::wstring wid_str = std::wstring(s_str.begin(), s_str.end());
const wchar_t* w_char = wid_str.c_str();
auto uri = ref new Uri( ref new String(w_char));
String ^temp = uri->AbsoluteUri;
auto token = m_cancelHttpRequestSource.get_token();
// Send the request and then update the UI.
onHttpRequestCompleted(m_httpRequest.GetAsync(uri, token));
}
void HTTPRequest::onHttpRequestCompleted(concurrency::task httpRequest)
{
httpRequest.then([this](task previousTask)
{
try
{
wstring response = previousTask.get();
if (m_httpRequest.GetStatusCode() == 200)
{
size_t strSize;
FILE* fileHandle;
auto local = Windows::Storage::ApplicationData::Current->LocalFolder;
auto localFileNamePlatformString = local->Path + "\\test1.zip";
// Create an the xml file in text and Unicode encoding mode.
if ((fileHandle = _wfopen(localFileNamePlatformString->Data(), L"wb")) == NULL) // C4996
// Note: _wfopen is deprecated; consider using _wfopen_s instead
{
wprintf(L"_wfopen failed!\n");
return(0);
}
// Write a string into the file.
strSize = wcslen(response.c_str());
if (fwrite(response.c_str(), sizeof(wchar_t), strSize, fileHandle) != strSize)
{
wprintf(L"fwrite failed!\n");
}
// Close the file.
if (fclose(fileHandle))
{
wprintf(L"fclose failed!\n");
}
}
else
{
// The request failed. Show the status code and reason.
wstringstream ss;
ss << L"The server returned "
<< m_httpRequest.GetStatusCode()
<< L" ("
<< m_httpRequest.GetReasonPhrase()
<< L')';
//String ^responseText = ref new String(ss.str().c_str());
m_delegate->parserError(requestType->getCString(), "Print Status Code later");
}
}
catch (const task_canceled&)
{
// Indicate that the operation was canceled.
//String ^responseText = "The operation was canceled";
m_delegate->parserError(requestType->getCString(), "Operation has canceled");
}
catch (Exception^ e)
{
// Indicate that the operation failed.
//String ^responseText = "The operation failed";
m_delegate->parserError(requestType->getCString(), "The operation failed");
// TODO: Handle the error further.
(void)e;
}
}, task_continuation_context::use_current());
}

Resources