Reputation: 1434
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
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
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
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
Reputation: 4410
You could use BITS:
http://www.codeproject.com/KB/IP/bitsman.aspx
Upvotes: 0
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:
You can find docs for all of these on msdn
Upvotes: 5