JonDrnek
JonDrnek

Reputation: 1434

MFC File upload

How would I upload a file to a webserver using c++ and MFC. We are not using .Net. Would I need to open a socket and do everything myself? If so, where is a good reference to follow?

Upvotes: 2

Views: 8168

Answers (6)

JonDrnek
JonDrnek

Reputation: 1434

Here is the code I ended up using. I stripped out the error checking, and other notification stuff. This does a multi-part form upload.

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

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

CInternetSession session("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("www.YOURSITE.com",NULL,INTERNET_DEFAULT_HTTP_PORT);

pHTTP = connection->OpenRequest(CHttpConnection::HTTP_VERB_POST, _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, 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, 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();
}

AfxMessageBox(strResponse);

//close everything up.
pHTTP->Close();
connection->Close();
session.Close();

CString CHelpRequestUpload::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 CHelpRequestUpload::MakePreFileData(CString& strBoundary, CString& strFileName)
{
CString strFormat;
CString strData;

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

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

strFormat += _T("--%s");
strFormat += _T("\r\n");
strFormat += _T("Content-Disposition: form-data; name=\"filename\"; filename=\"%s\"");
strFormat += _T("\r\n");
strFormat += _T("Content-Type: audio/x-flac");
strFormat += _T("\r\n");
strFormat += _T("Content-Transfer-Encoding: binary");
strFormat += _T("\r\n\r\n");

strData.Format(strFormat, strBoundary, m_Name, strBoundary, m_Email,  strBoundary, strFileName);

return strData;
 }

CString CHelpRequestUpload::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=\"submitted\"");
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;

} 

Upvotes: 3

djeidot
djeidot

Reputation: 4642

If you have an ftp server, check out the CFtpConnection class.

Upvotes: 0

Serge Wautier
Serge Wautier

Reputation: 21878

WinInet as suggested. Bear in mind that there are MFC classes that wrap these APIs. If for some reason these APIs aren't flexible engouh for your requirements (e.g. you need to implement connection through a proxy including authentication), give a look at WinHTTP. It's a superset of WinInet (no MFC wrappers though for WinHTTP).

Upvotes: 1

Shog9
Shog9

Reputation: 159618

You can also use XMLHTTP. Even if you aren't sending XML. Built on WinINet, but a bit easier to use (if you're used to working with COM anyway).
See MSDN: http://msdn.microsoft.com/en-us/library/ms759148.aspx

Upvotes: 0

fryguybob
fryguybob

Reputation: 4410

You could use BITS:

http://www.codeproject.com/KB/IP/bitsman.aspx

Upvotes: 0

Tron
Tron

Reputation: 1397

You don't want to use direct socket calls. It's hard to get HTTP right this way.

The easier way is to the WinINet APIs. Check out the docs for InternetOpen, this will likely be the first call you make. Functions you will likely need:

  • InternetOpen
  • InternetConnect
  • HttpOpenRequest
  • HttpSendRequest
  • HttpQueryInfo
  • InternetCloseHandle

You can find docs for all of these on msdn

Upvotes: 5

Related Questions