利用winInet实现文件上传到HTTP服务器
最近两个星期主要搞这个东东,到今天总算比较圆满的搞定了. 用http协议上传主要有两种形式: 第一是用http的put协议,第二是用http的post协议.
先说说put协议, 所谓put,顾名思义,就是把文件"放"到server端. 这个过程不涉及文件的http和mime封装(post协议需要做), 因而比较简单.但是考虑到安全问题,一般服务器不会开发put权限,因此这种方法的用途并不广泛
废话不多说,来看看代码:
CInternetSession internetSession("my session"); //定义session
CHttpConnection* httpConnection = internetSession.GetHttpConnection(strServerIP,intServerPort); //获得链接
CHttpFile* httpFile = httpConnection->OpenRequest(CHttpConnection::HTTP_VERB_PUT,strRemoteFile,NULL,0,NULL,NULL,INTERNET_FLAG_DONT_CACHE); //发送请求
...
httpFile->SendRequestEx(&BufferIn,NULL,HSR_INITIATE,0);
注意倒数第二句的CHttpConnection::HTTP_VERB_PUT, 表示程序将采用http的put协议上传文件.
再看post协议,这个东东如果只涉及文本还是比较简单的,可以直接post过去,不用构造表单. 但是一旦需要上传文件, 就需要用http和mime的两层封装了. 封装需要对http头和mime标识做一些了解,很恶心=,=. 最需要注意的一点, 在最后SendRequestEx的时候, 传递的参数是文件的字节数,这个字节数应该是所要上传的文件和http头以及mime头的字节总数! 否则即使CLIENT端不出错, server也得不到正确结果的!
也来看看代码吧:
CInternetSession internetSession("my session"); //定义session
CHttpConnection* httpConnection=internetSession.GetHttpConnection(strServerIP,intServerPort); //获得链接
CHttpFile* httpFile = httpConnection->OpenRequest(CHttpConnection::HTTP_VERB_POST,strRemoteFile,NULL,0,NULL,NULL,INTERNET_FLAG_DONT_CACHE); //发送请求
...
httpFile->SendRequestEx(dwTotalRequestLength, HSR_SYNC | HSR_INITIATE);
随便说说,post协议俺用baidu搜了许久,找到了一个类似的程序,研究了许久搞不定.. 后来目有办法, google一个外文论坛, 拜读了某牛人的大作后,终于弄清楚了~ 看来以后还是要多啃鸟文啊..
附上源代码:
put协议:
UpLoadFile::UpLoadFile(void){}UpLoadFile::~UpLoadFile(void){}BOOL UpLoadFile::UseHttpSendReqEx(CHttpFile* httpFile, DWORD dwPostSize,CString strLocalFile){try{DWORD dwRead,dwRet;BYTE* buffer;TRACE("Local file:%s/n",strLocalFile);FILE* fLocal;if((fLocal=fopen(strLocalFile,"rb"))==NULL){TRACE("Can't open the file:%s,maybe it doesn't exist!/n",strLocalFile);return false;}fseek(fLocal,0L,SEEK_END);dwRead=ftell(fLocal);rewind(fLocal);buffer=(BYTE *)malloc(dwRead);if(!buffer){TRACE("not enough memory!/n");return false;}TRACE("length of file:%d/n",dwRead);dwRead=fread(buffer,1,dwRead,fLocal);dwPostSize=dwRead;INTERNET_BUFFERS BufferIn;DWORD dwBytesWritten;BOOL bRet;BufferIn.dwStructSize = sizeof( INTERNET_BUFFERS ); // Must be set or error will occurBufferIn.Next = NULL;BufferIn.lpcszHeader = NULL;BufferIn.dwHeadersLength = 0;BufferIn.dwHeadersTotal = 0;BufferIn.lpvBuffer = NULL;BufferIn.dwBufferLength = 0;BufferIn.dwBufferTotal = dwPostSize; // This is the only member used other than dwStructSizeBufferIn.dwOffsetLow = 0;BufferIn.dwOffsetHigh = 0;httpFile->SendRequestEx(&BufferIn,NULL,HSR_INITIATE,0);//httpFile->SendRequestEx(dwPostSize);httpFile->Write( buffer, dwPostSize);if(!httpFile->EndRequest(0,0,0)){TRACE( "Error on HttpEndRequest %lu /n", GetLastError());return FALSE;}fclose(fLocal);free(buffer);return TRUE;}catch (CInternetException* pEx){//catch errors from WinInet}return FALSE;}BOOL UpLoadFile::Upload(CString strLocalFile,CString strServerIP,CString strServerPort,CString strRemoteFile){try{DWORD dwPostSize=0;INTERNET_PORT intServerPort=atoi(strServerPort);CInternetSession internetSession("my session");CHttpConnection* httpConnection = internetSession.GetHttpConnection(strServerIP,intServerPort);if(httpConnection == NULL){TRACE( "Failed to connect/n" );return FALSE;}CHttpFile* httpFile = httpConnection->OpenRequest(CHttpConnection::HTTP_VERB_PUT,strRemoteFile,NULL,0,NULL,NULL,INTERNET_FLAG_DONT_CACHE);//CHttpFile* httpFile = httpConnection->OpenRequest(CHttpConnection::HTTP_VERB_PUT,strRemoteFile);if(httpFile == NULL){TRACE( "Failed to open request handle/n" );return FALSE;}if(UseHttpSendReqEx(httpFile, dwPostSize,strLocalFile)){TRACE( "/nSend Finished./n" );httpFile->Close();httpConnection->Close();internetSession.Close();return TRUE;}httpFile->Close();httpConnection->Close();internetSession.Close();}catch (CInternetException* pEx){//catch errors from WinInet}return FALSE;}
post协议:
bool CVoiceXCtrl::UploadPCM(){ TCHAR tempFilePath[MAX_PATH]; tempFilePath[0] = 0; GetEnvironmentVariable(_T("ProgramFiles"), tempFilePath, MAX_PATH); if (tempFilePath[0] == 0) { strcpy(tempFilePath, "C://Program Files"); } strncat(tempFilePath, "//VoiceX//upload.pcm", MAX_PATH); monWave.Save(tempFilePath); int startp = m_StandardWavURL.ReverseFind('/'); int namelen = m_StandardWavURL.GetLength()-startp-1; CString pcmname = m_StandardWavURL.Mid(startp+1,namelen); CString defServerName ="www.bingoenglish.com"; CString defObjectName ="/upload/upload.jsp";
// USES_CONVERSION; CInternetSession Session; CHttpConnection *pHttpConnection = NULL;
INTERNET_PORT nPort = 8090;
CFile fTrack; CHttpFile* pHTTP; CString strHTTPBoundary; CString strPreFileData; CString strPostFileData; DWORD dwTotalRequestLength; DWORD dwChunkLength; DWORD dwReadLength; DWORD dwResponseLength; TCHAR szError[MAX_PATH]; void* pBuffer; LPSTR szResponse; CString strResponse; BOOL bSuccess = TRUE; CString strDebugMessage;
if (FALSE == fTrack.Open(tempFilePath, CFile::modeRead | CFile::shareDenyWrite)) { AfxMessageBox(_T("Unable to open the file.")); return FALSE; } CString strFileName = "upload.pcm"; int iRecordID = 1;
strHTTPBoundary = _T("IllBeVerySurprisedIfThisTurnsUp"); strPreFileData = MakePreFileData(strHTTPBoundary, pcmname, iRecordID); strPostFileData = MakePostFileData(strHTTPBoundary); AfxMessageBox(strPreFileData); AfxMessageBox(strPostFileData); dwTotalRequestLength = strPreFileData.GetLength() + strPostFileData.GetLength() + fTrack.GetLength(); dwChunkLength = 64 * 1024; pBuffer = malloc(dwChunkLength); if (NULL == pBuffer) { return FALSE; } try { pHttpConnection = Session.GetHttpConnection(defServerName,nPort);
pHTTP = pHttpConnection->OpenRequest(CHttpConnection::HTTP_VERB_POST, _T("/upload/upload.jsp")); pHTTP->AddRequestHeaders(MakeRequestHeaders(strHTTPBoundary)); pHTTP->SendRequestEx(dwTotalRequestLength, HSR_SYNC | HSR_INITIATE); #ifdef _UNICODE pHTTP->Write(W2A(strPreFileData), strPreFileData.GetLength());#else pHTTP->Write((LPSTR)(LPCSTR)strPreFileData, strPreFileData.GetLength());#endif dwReadLength = -1; while (0 != dwReadLength) { strDebugMessage.Format(_T("%u / %u/n"), fTrack.GetPosition(), fTrack.GetLength()); TRACE(strDebugMessage); dwReadLength = fTrack.Read(pBuffer, dwChunkLength); if (0 != dwReadLength) { pHTTP->Write(pBuffer, dwReadLength); } } #ifdef _UNICODE pHTTP->Write(W2A(strPostFileData), strPostFileData.GetLength());#else pHTTP->Write((LPSTR)(LPCSTR)strPostFileData, strPostFileData.GetLength());#endif pHTTP->EndRequest(HSR_SYNC); 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); } catch (CException* e) { e->GetErrorMessage(szError, MAX_PATH); e->Delete(); AfxMessageBox(szError); bSuccess = FALSE; } pHTTP->Close(); delete pHTTP; fTrack.Close(); if (NULL != pBuffer) { free(pBuffer); }
return bSuccess;
}
CString CVoiceXCtrl::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 CVoiceXCtrl::MakePreFileData(CString& strBoundary, CString& strFileName, int iRecordID){
CString strFormat;CString strData;
strFormat += _T("--%s");strFormat += _T("/r/n");strFormat += _T("Content-Disposition: form-data; name=/"recordid/"");strFormat += _T("/r/n/r/n");strFormat += _T("%i");strFormat += _T("/r/n");strFormat += _T("--%s");strFormat += _T("/r/n");strFormat += _T("Content-Disposition: form-data; name=/"trackdata/"; filename=/"%s/"");strFormat += _T("/r/n");strFormat += _T("Content-Type: audio/wav");strFormat += _T("/r/n");strFormat += _T("Content-Transfer-Encoding: binary");strFormat += _T("/r/n/r/n");
strData.Format(strFormat, strBoundary, iRecordID, strBoundary, strFileName);
return strData;
}
CString CVoiceXCtrl::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("hello");strFormat += _T("/r/n");strFormat += _T("--%s--");strFormat += _T("/r/n");
strData.Format(strFormat, strBoundary, strBoundary);
return strData;
}