wolvorinePk
wolvorinePk

Reputation: 1790

MFC C++ file upload with http post returning invalid win apis

I am trying to upload a file using MFC C++ but for some reason i am getting invalid file on the upload. I feels like maybe this is the problem due to wrong header or post information i am using but after several hours tries i cant find my error. Here is my code.. I will appreciate if you experts can elaborate some light on my mistakes so i can correct it...

void CFileUpload::UploadByPost(CString strFileName,CString  strServerUrl,CString strServerUploadFile)
{

DWORD dwTotalRequestLength;
DWORD dwChunkLength;
DWORD dwReadLength;
DWORD dwResponseLength;
CHttpFile* pHTTP = NULL;

dwChunkLength = 64 * 1024; 
void* pBuffer = malloc(dwChunkLength);
CFile file ;

if (!file.Open(strFileName.GetBuffer(),
  CFile::modeRead | CFile::shareDenyWrite))
 {
        return;
   }

CInternetSession session(L"sendFile");
CHttpConnection *connection = NULL;

try
{
    //Create the multi-part form data that goes before and after the actual file upload.

    CString strHTTPBoundary = _T("FFF3F395A90B452BB8BEDC878DDBD152");       
    CString strPreFileData = MakePreFileData(strHTTPBoundary, file.GetFileName());
    CString strPostFileData = MakePostFileData(strHTTPBoundary);
    CString strRequestHeaders = MakeRequestHeaders(strHTTPBoundary);
    dwTotalRequestLength = strPreFileData.GetLength() + strPostFileData.GetLength() + file.GetLength();

    connection = session.GetHttpConnection(/*L"www.YOURSITE.com"*/strServerUrl.GetBuffer(),NULL,INTERNET_DEFAULT_HTTP_PORT);

    pHTTP = connection->OpenRequest(CHttpConnection::HTTP_VERB_POST, strServerUploadFile.GetBuffer());//_T("/YOUURL/submit_file.pl"));
    pHTTP->AddRequestHeaders(strRequestHeaders);
    pHTTP->SendRequestEx(dwTotalRequestLength, HSR_SYNC | HSR_INITIATE);

    //Write out the headers and the form variables
    pHTTP->Write((LPSTR)(LPCSTR)strPreFileData.GetBuffer(), strPreFileData.GetLength());

    //upload the file.

    dwReadLength = -1;
    int length = file.GetLength(); //used to calculate percentage complete.
    while (0 != dwReadLength)
    {
        dwReadLength = file.Read(pBuffer, dwChunkLength);
        if (0 != dwReadLength)
        {
        pHTTP->Write(pBuffer, dwReadLength);
        }
    }

    file.Close();

    //Finish the upload.
    pHTTP->Write((LPSTR)(LPCSTR)strPostFileData.GetBuffer(), strPostFileData.GetLength());
    pHTTP->EndRequest(HSR_SYNC);


    //get the response from the server.
    LPSTR szResponse;
    CString strResponse;
    dwResponseLength = pHTTP->GetLength();
    while (0 != dwResponseLength )
    {
        szResponse = (LPSTR)malloc(dwResponseLength + 1);
        szResponse[dwResponseLength] = '\0';
        pHTTP->Read(szResponse, dwResponseLength);
        strResponse += szResponse;
        free(szResponse);
        dwResponseLength = pHTTP->GetLength();
    }

    TRACE(L"%s",strResponse.GetBuffer());

    //close everything up.
    pHTTP->Close();
    connection->Close();
    session.Close();
}
catch(CInternetException* e)
{
    TRACE(L"error: %d \n",e->m_dwError);
}
catch(CFileException* e)
{
    TRACE(L"error: %d \n",e->m_cause);
}
catch(...)
{
    TRACE(L" unexpected error");
}

}

here is my header and post function

CString CFileUpload::MakeRequestHeaders(CString& strBoundary)
{
    CString strFormat;
    CString strData;
    strFormat = _T("Content-Type: multipart/form-data; boundary=%s\r\n");
    strData.Format(strFormat, strBoundary);
    return strData;
}

CString CFileUpload::MakePreFileData(CString& strBoundary, CString& strFileName)
{
CString strFormat;
CString strData;

strFormat += _T("--%s");
strFormat += _T("\r\n");
strFormat += _T("Content-Disposition: form-data; name=\"file\"; filename=\"%s\"");
strFormat += _T("\r\n");
strFormat += _T("Content-Type: text/plain");
strFormat += _T("\r\n");
strFormat += _T(" XXXXX ");
strFormat += _T("\r\n\r\n");

strData.Format(strFormat, strBoundary,/* m_Name, strBoundary,*/ strFileName);

return strData;
}

CString CFileUpload::MakePostFileData(CString& strBoundary)
{

    CString strFormat;
CString strData;

strFormat = _T("\r\n");
strFormat += _T("--%s");
strFormat += _T("\r\n");
strFormat += _T("Content-Disposition: form-data; name=\"submit\"");
strFormat += _T("\r\n\r\n");
strFormat += _T("");
strFormat += _T("\r\n");
strFormat += _T("--%s--");
strFormat += _T("\r\n");

strData.Format(strFormat, strBoundary, strBoundary);

return strData;

}

It always return invalid file, the file server code i am using is the following

<?php
$allowedExts = array("log", "txt");
$extension = end(explode(".", $_FILES["file"]["name"]));
if ((($_FILES["file"]["type"] == "text/plain")
)
&& ($_FILES["file"]["size"] < 20000)
&& in_array($extension, $allowedExts))
  {
  if ($_FILES["file"]["error"] > 0)
    {
    echo "Error: " . $_FILES["file"]["error"] . "<br>";
    }
  else
    {
    echo "Upload: " . $_FILES["file"]["name"] . "<br>";
    echo "Type: " . $_FILES["file"]["type"] . "<br>";
    echo "Size: " . ($_FILES["file"]["size"] / 1024) . " kB<br>";
    echo "Stored in: " . $_FILES["file"]["tmp_name"];
    }
  }
else
  {
  echo "Invalid file";
  }
?> 

and here is the form

<html>
<body>

<form action="upload_file.php" method="post"
enctype="multipart/form-data">
<label for="file">Filename:</label>
<input type="file" name="file" id="file"><br>
<input type="submit" name="submit" value="Submit">
</form>

</body>
</html> 

Note:- i cant use boost or poco, curl or any third party library.. just only win32 or mfc.

here are the pre make and post make data :

header

"Content-Type: multipart/form-data; boundary=FFF3F395A90B452BB8BEDC878DDBD152
"

Pre File

"--FFF3F395A90B452BB8BEDC878DDBD152
Content-Disposition: form-data; name="Filename"; filename="ddd.txt"
Content-Type: text/plain
Content-Transfer-Encoding: binary

"

Post File

"
--FFF3F395A90B452BB8BEDC878DDBD152
Content-Disposition: form-data; name="submit" value="submit"


--FFF3F395A90B452BB8BEDC878DDBD152--
"

Upvotes: 1

Views: 2639

Answers (2)

wolvorinePk
wolvorinePk

Reputation: 1790

Finally i got the error.... this is not because of the post or pre file data or headeror server script but because the way i was calling write function from http object and converting the unicode to ansi without any proper conversion....I dont know how come i didn't realize this silly mistake by me lol...but for the sake of others i would like to share this information as well.....

pHTTP->Write((LPSTR)(LPCSTR)strPreFileData.GetBuffer(), strPreFileData.GetLength());

must be change to

pHTTP->Write((LPSTR)(LPCSTR)CW2A(strPreFileData.GetBuffer()), strPreFileData.GetLength());

Also the post file version

 pHTTP->Write((LPSTR)(LPCSTR)strPostFileData.GetBuffer(), strPostFileData.GetLength());

to

 pHTTP->Write((LPSTR)(LPCSTR)CW2A(strPostFileData.GetBuffer()), strPostFileData.GetLength());

Upvotes: 1

Roel
Roel

Reputation: 19632

Well there are three cases in your server-side code that could have gone wrong:

if ((($_FILES["file"]["type"] == "text/plain")
)
&& ($_FILES["file"]["size"] < 20000)
&& in_array($extension, $allowedExts))

Apart from the hideous indentation and brace placement, have you tried testing for each condition separately so that you know what exactly the php parts thinks is wrong?

[mistake has been removed]

Upvotes: 0

Related Questions