fajir moin
fajir moin

Reputation: 109

Failed to send Http request based on MFC

I'm new to HTTP and MFC. I suppose to upload a binary file to a given URL, by sending PUT request. I'm sure the requesting URL and the header are well formed and the file works well, because I tried them by Postman then get a SUCCESS returned.

But when I try to do this by the following MFC code, it always returns a 403 error. Please help me.

bool UploadFile(LPCTSTR strUrl, LPCTSTR filenameFullpath, CString header)
{
    BOOL bResult = FALSE;
    DWORD dwType = 0;
    CString strServer;
    CString strObject;
    INTERNET_PORT wPort = 0;
    DWORD dwFileLength = 0;
    BYTE * pFileBuff = NULL;
    CHttpConnection * pHC = NULL;
    CHttpFile * pHF = NULL;
    CInternetSession cis;

    bResult = AfxParseURL(strUrl, dwType, strServer, strObject, wPort);
    if (!bResult)
        return FALSE;
    CFile file;
    try
    {
        // Read the file
        if (!file.Open(filenameFullpath, CFile::shareDenyNone | CFile::modeRead))
            return FALSE;
        dwFileLength = file.GetLength();
        if (dwFileLength <= 0)
            return FALSE;
        pFileBuff = new BYTE[dwFileLength];
        memset(pFileBuff, 0, sizeof(BYTE) * dwFileLength);
        file.Read(pFileBuff, dwFileLength);

        // Set up internet connection
        const int nTimeOut = 5000;
        cis.SetOption(INTERNET_OPTION_CONNECT_TIMEOUT, nTimeOut);
        cis.SetOption(INTERNET_OPTION_CONNECT_RETRIES, 2);  // Retry once if failed
        pHC = cis.GetHttpConnection(strServer, dwType == AFX_INET_SERVICE_HTTP ? NORMAL_CONNECT : SECURE_CONNECT, wPort);  // Get a HTTP connection

        pHF = pHC->OpenRequest(CHttpConnection::HTTP_VERB_PUT, strObject);//strObject

        pHF->AddRequestHeaders(header , HTTP_ADDREQ_FLAG_ADD_IF_NEW);
        // I set the header separately instead of passing it as the first parameter of the next call.
        // If I don't do so, another error occurs
        if (!pHF->SendRequest(NULL, 0, pFileBuff, dwFileLength))
        {
            delete[]pFileBuff;
            pFileBuff = NULL;
            pHF->Close();
            pHC->Close();
            cis.Close();
            return FALSE;
        }

        DWORD dwStateCode = 0;
        pHF->QueryInfoStatusCode(dwStateCode);

        if (dwStateCode == HTTP_STATUS_OK)
            bResult = TRUE;
    }

    catch (CInternetException * pEx)
    {
        char sz[256] = "";
        pEx->GetErrorMessage(sz, 25);
        CString str;
        str.Format("InternetException occur!\r\n%s", sz);
        AfxMessageBox(str);
    }

    delete[]pFileBuff;
    pFileBuff = NULL;
    file.Close();
    pHF->Close();
    pHC->Close();
    cis.Close();
    return bResult;
}

And the calling of this function is just something like this:

CHttpClient hc;
hc.UploadFile(csUrl, "E:\\blah blah blah\\blah.tma", csUploadHeader);

while csUrl and csUploadHeader are well formed CString;

Upvotes: 1

Views: 332

Answers (1)

fajir moin
fajir moin

Reputation: 109

I got it! I should give pHF the header items (the key-value pairs) one by one, by calling the AddRequestHeaders() method several times, instead of wrapping and passing them together to pHF.

Then the following codes works very well:

CString sHeader1, sHeader2, sHeader3;
sHeader1.Format(_T("%s : %s"), sKey1, sValue1); // sKey_, sValue_ are strings
sHeader2.Format(_T("%s : %s"), sKey2, sValue2);
sHeader3.Format(_T("%s : %s"), sKey3, sValue3);

pHF->AddRequestHeaders(sHeader1, HTTP_ADDREQ_FLAG_ADD_IF_NEW); // Keep the second paeramter as these
pHF->AddRequestHeaders(sHeader2, HTTP_ADDREQ_FLAG_COALESCE);
pHF->AddRequestHeaders(sHeader3, HTTP_ADDREQ_FLAG_COALESCE);

And a very important notification: the string we pass to AddRequestHeaders() should not have the quotation("") around either the key or the value. In other words, string like "MyKey":"MyValue" have to be modified as MyKey:MyValue before giving to AddRequestHeaders();

Upvotes: 1

Related Questions