Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

957 lines
25 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Network
  4. // Copyright (C) Microsoft Corporation, 1998
  5. //
  6. // File: HttpFilePost.cpp
  7. //
  8. // Contents:
  9. // CHttpFilePoster
  10. // RFC 1867 file uploader
  11. //
  12. // Posts files to an http server using HTTP POST
  13. //
  14. // Links:
  15. // RFC 1867 - Form-based File Upload in HTML : http://www.ietf.org/rfc/rfc1867.txt
  16. // RFC 1521 - MIME (Multipurpose Internet Mail Extensions) : http://www.ietf.org/rfc/rfc1521.txt
  17. //
  18. //
  19. // Author: Noah Booth ([email protected])
  20. //
  21. // Revision History:
  22. //
  23. // 2/5/99 noahb created
  24. // 4/25/99 noahb integration with MSN communities
  25. // 3/7/2000 noahb integration with communities File Cabinet
  26. //------------------------------------------------------------------------
  27. #include "precomp.h"
  28. #pragma hdrstop
  29. #include <string>
  30. #include <list>
  31. #include <map>
  32. #include "stdstring.h"
  33. #include "HTTPFilePost.h"
  34. #include "ProgressInfo.h"
  35. using namespace std;
  36. #pragma warning(disable: 4800) //disable warning forcing int to bool
  37. static void ThrowUploaderException(DWORD dwError /* = -1 */)
  38. {
  39. if(dwError == -1)
  40. dwError = GetLastError();
  41. throw( new CUploaderException(dwError) );
  42. }
  43. #define USER_AGENT "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT 5.0) [MSN Communities Active-X Upload Control]"
  44. #define UNKNOWN_MIME "application/octet-stream" //MIME type to use when there is none other available
  45. #define REG_CONTENT_TYPE "Content Type" //name of content type value in HKCR key for a file extension
  46. #define CONTENT_TYPE "Content-Type" //HTTP header content type string
  47. #define MULTI_PART_FORM_DATA "multipart/form-data"
  48. static DWORD g_dwContentLength = 0;
  49. static const char szFileHeaderContentDisp[] = "Content-Disposition: form-data; name=\"Attachment\"; filename=\"";
  50. static const char szFileHeaderContentType[] = "\"\r\nContent-Type: ";
  51. static const char szFileHeaderEnd[] = "\r\n\r\n";
  52. static const char szFormHeaderContentDisp[] = "Content-Disposition: form-data; name=\"";
  53. static const char szFormHeaderEnd[] = "\"\r\n\r\n";
  54. static const char szTitleName[] = "Subject";
  55. static const char szDescName[] = "Message_Body";
  56. #define CHECK_ERROR(cond, err) if (!(cond)) {pszErr=(err); goto done;}
  57. #define SAFERELEASE(p) if (p) {(p)->Release(); p = NULL;} else ;
  58. CHttpFilePoster::CHttpFilePoster()
  59. {
  60. m_iStatus = HFP_UNINITIALIZED;
  61. m_dwFileCount = 0;
  62. m_dwTotalFileBytes = 0;
  63. m_bSinglePost = false;
  64. Initialize("", NULL);
  65. m_hSession = NULL;
  66. m_hConnection = NULL;
  67. m_hFile = NULL;
  68. m_dwContext = reinterpret_cast<DWORD_PTR>(this);
  69. GenBoundaryString();
  70. }
  71. CHttpFilePoster::~CHttpFilePoster()
  72. {
  73. Reset(); //free up memory allocated for the file list
  74. if(m_hFile)
  75. InternetCloseHandle(m_hFile);
  76. if(m_hConnection)
  77. InternetCloseHandle(m_hConnection);
  78. if(m_hSession)
  79. InternetCloseHandle(m_hSession);
  80. }
  81. //generate a boundary string that is statistically likely to be unique
  82. void CHttpFilePoster::GenBoundaryString()
  83. {
  84. GUID guid;
  85. char buff[128];
  86. static const char* szFormat = "-------------%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x-------------";
  87. ::CoCreateGuid(&guid);
  88. //TODO: remove sprintf
  89. sprintf(buff, szFormat,
  90. guid.Data1, guid.Data2, guid.Data3,
  91. guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
  92. guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
  93. m_strBoundary = buff;
  94. }
  95. void CHttpFilePoster::BuildFilePostHeader(CUploaderFile* pFile)
  96. {
  97. m_strFileHeader = "\r\n" + m_strBoundary + "\r\n";
  98. m_strFileHeader += szFileHeaderContentDisp;
  99. m_strFileHeader += pFile->strName;
  100. m_strFileHeader += szFileHeaderContentType;
  101. m_strFileHeader += pFile->strMime;
  102. m_strFileHeader += szFileHeaderEnd;
  103. }
  104. void CHttpFilePoster::BuildFilePost(CUploaderFile* pFile)
  105. {
  106. m_strFilePost = "\r\n" + m_strBoundary + "\r\n";
  107. m_strFilePost += szFormHeaderContentDisp;
  108. m_strFilePost += szTitleName;
  109. m_strFilePost += szFormHeaderEnd;
  110. m_strFilePost += pFile->strTitle;
  111. m_strFilePost += "\r\n" + m_strBoundary + "\r\n";
  112. m_strFilePost += szFormHeaderContentDisp;
  113. m_strFilePost += szDescName;
  114. m_strFilePost += pFile->strDescription;
  115. m_strFilePost += szFormHeaderEnd;
  116. m_strFilePost += "\r\n";
  117. }
  118. void CHttpFilePoster::BuildCommonPost()
  119. {
  120. WIA_PUSHFUNCTION(TEXT("CHttpFilePoster::BuildCommonPost"));
  121. TFormMapIterator begin = m_mapFormData.begin();
  122. TFormMapIterator end = m_mapFormData.end();
  123. TFormMapIterator it;
  124. m_strCommonPost = "";
  125. if(m_mapFormData.size())
  126. {
  127. for(it = begin; it != end; it++)
  128. {
  129. WIA_TRACE((TEXT("%hs: %hs"), it->first.c_str(), it->second.c_str()));
  130. m_strCommonPost += m_strBoundary + "\r\n";
  131. m_strCommonPost += szFormHeaderContentDisp;
  132. m_strCommonPost += it->first;
  133. m_strCommonPost += szFormHeaderEnd;
  134. m_strCommonPost += it->second;
  135. m_strCommonPost += "\r\n";
  136. }
  137. }
  138. m_strCommonPost += m_strBoundary + "--\r\n";
  139. }
  140. void CHttpFilePoster::CrackPostingURL()
  141. {
  142. BOOL bResult;
  143. char szBuff[INTERNET_MAX_URL_LENGTH];
  144. char* pBuffer = szBuff;
  145. DWORD dwBufLen = INTERNET_MAX_URL_LENGTH;
  146. m_strHttpServer = "";
  147. m_strHttpObject = "";
  148. DWORD dwFlags = ICU_NO_ENCODE | ICU_DECODE | ICU_NO_META | ICU_ENCODE_SPACES_ONLY | ICU_BROWSER_MODE;
  149. bResult = InternetCanonicalizeUrlA(m_strSitePostingURL.c_str(), pBuffer, &dwBufLen, dwFlags);
  150. if(!bResult)
  151. {
  152. pBuffer = new char[dwBufLen];
  153. if(pBuffer)
  154. {
  155. bResult = InternetCanonicalizeUrlA(m_strSitePostingURL.c_str(), pBuffer, &dwBufLen, dwFlags);
  156. }
  157. }
  158. if(bResult)
  159. {
  160. //INTERNET_PORT iPort;
  161. URL_COMPONENTSA urlComponents;
  162. char szServer[INTERNET_MAX_URL_LENGTH + 1];
  163. char szObject[INTERNET_MAX_URL_LENGTH + 1];
  164. dwFlags = 0;
  165. ZeroMemory(&urlComponents, sizeof(urlComponents));
  166. urlComponents.dwStructSize = sizeof(urlComponents);
  167. urlComponents.dwHostNameLength = INTERNET_MAX_URL_LENGTH;
  168. urlComponents.lpszHostName = szServer;
  169. urlComponents.dwUrlPathLength = INTERNET_MAX_URL_LENGTH;
  170. urlComponents.lpszUrlPath = szObject;
  171. bResult = InternetCrackUrlA(pBuffer, 0, dwFlags, &urlComponents);
  172. if(bResult)
  173. {
  174. m_strHttpServer = szServer;
  175. m_strHttpObject = szObject;
  176. }
  177. }
  178. ATLASSERT(bResult);
  179. if(pBuffer != szBuff)
  180. delete pBuffer;
  181. }
  182. bool CHttpFilePoster::Connect()
  183. {
  184. bool bResult = false;
  185. ATLASSERT(m_hSession);
  186. if(!m_hConnection)
  187. {
  188. m_hConnection = InternetConnectA(
  189. m_hSession, //session
  190. m_strHttpServer.c_str(), //server name
  191. INTERNET_INVALID_PORT_NUMBER, //server port
  192. NULL, //user name
  193. NULL, //password
  194. INTERNET_SERVICE_HTTP,
  195. 0, //flags
  196. m_dwContext);
  197. if(m_hConnection)
  198. bResult = true;
  199. }
  200. if(!bResult)
  201. ThrowUploaderException();
  202. return bResult;
  203. }
  204. ///////////////////////////////////////////////////////////////////////////////
  205. //
  206. ///////////////////////////////////////////////////////////////////////////////
  207. bool CHttpFilePoster::Disconnect()
  208. {
  209. if(NULL == m_hConnection || InternetCloseHandle(m_hConnection))
  210. {
  211. m_hConnection = NULL;
  212. return true;
  213. }
  214. else
  215. {
  216. return false;
  217. }
  218. }
  219. bool CHttpFilePoster::Startup()
  220. {
  221. ATLASSERT(m_hSession == NULL);
  222. //CWaitCursor wait;
  223. DWORD dwAccessType = INTERNET_OPEN_TYPE_PRECONFIG;
  224. m_hSession = InternetOpenA(
  225. USER_AGENT,
  226. dwAccessType,
  227. NULL, //proxy name
  228. NULL, //proxy bypass
  229. INTERNET_FLAG_DONT_CACHE
  230. );
  231. InternetSetStatusCallback(m_hSession, CHttpFilePoster::InternetStatusCallback);
  232. if(m_hSession == NULL)
  233. ThrowUploaderException();
  234. return (m_hSession != NULL);
  235. }
  236. ///////////////////////////////////////////////////////////////////////////////
  237. //
  238. ///////////////////////////////////////////////////////////////////////////////
  239. bool CHttpFilePoster::Shutdown()
  240. {
  241. if(IsConnected())
  242. {
  243. Disconnect();
  244. }
  245. InternetCloseHandle(m_hSession);
  246. m_hSession = NULL;
  247. return true;
  248. }
  249. ///////////////////////////////////////////////////////////////////////////////
  250. //
  251. ///////////////////////////////////////////////////////////////////////////////
  252. bool CHttpFilePoster::IsConnected()
  253. {
  254. return (m_hConnection != NULL);
  255. }
  256. /*
  257. RequestHead() request posting acceptor headers
  258. Note: It is necessary to call this function before posting files because of the
  259. way HTTP authentication works. When you request an object that requires authentication
  260. the server will first read the entire body of the request. It then determines if
  261. authentication is required. If no authentication is required, it will service the
  262. request and send back the response, otherwise it will send back a response with status 401
  263. (access denied) and some other headers enumerating acceptable authentication schemes.
  264. When client sees these headers, it prompts the user if necessary, and resends the request
  265. with headers containing the requested credentials.
  266. For small posts the user barely notices, but for a large POST this is insane. You
  267. have to send up your entire post just to find out that you need to be authenticated.
  268. Then you have to supply your username/password to your user agent, which will then
  269. resend the POST.
  270. The upshot is that it's necessary to make sure the user is authenticated, if
  271. necessary, BEFORE we attempt to post a bunch of files. One way to do this is to
  272. send a HEAD request to the server, using HttpSendRequest, check the headers and authenticate
  273. if necessary. Then we can continue with the file post.
  274. */
  275. bool CHttpFilePoster::RequestHead()
  276. {
  277. bool bRet = false;
  278. DWORD dwRet = 0;
  279. return true;
  280. HINTERNET hFile;
  281. hFile = HttpOpenRequestA(m_hConnection, "HEAD", m_strHttpObject.c_str(),
  282. NULL, NULL, NULL, INTERNET_FLAG_EXISTING_CONNECT, m_dwContext);
  283. if(hFile)
  284. {
  285. do
  286. {
  287. HttpSendRequest(hFile, NULL, 0, NULL, 0);
  288. #ifdef _DEBUG
  289. {
  290. //HACK: magic numbers
  291. DWORD dwLen = 1024;
  292. char buffer[1024];
  293. if(HttpQueryInfo(hFile, HTTP_QUERY_RAW_HEADERS_CRLF, buffer, &dwLen, NULL))
  294. {
  295. ATLTRACE("---- HEADERS: \n");
  296. ATLTRACE(buffer);
  297. ATLTRACE("------ DONE --\n");
  298. }
  299. }
  300. #endif
  301. dwRet = InternetErrorDlg(
  302. m_hWndParent,
  303. hFile,
  304. ERROR_INTERNET_INCORRECT_PASSWORD,
  305. FLAGS_ERROR_UI_FLAGS_GENERATE_DATA | FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS,
  306. NULL);
  307. if(dwRet== ERROR_SUCCESS)
  308. bRet = true;
  309. }
  310. while(dwRet == ERROR_INTERNET_FORCE_RETRY);
  311. InternetCloseHandle(hFile);
  312. }
  313. return bRet;
  314. }
  315. bool CHttpFilePoster::DoUpload(CProgressInfo* pProgress)
  316. {
  317. DWORD dwThreadID;
  318. CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) UploadThreadProc, (LPVOID) pProgress, 0, &dwThreadID);
  319. return TRUE;
  320. }
  321. //find the MIME type for a file based on the file extension by
  322. // looking in the registry under HKEY_CLASSES_ROOT\.<ext>\Content Type
  323. CStdString CHttpFilePoster::GetMimeType(const CHAR* pszFilename)
  324. {
  325. CHAR* pszExt, *pszRet;
  326. CHAR pszBuff[MAX_PATH];
  327. DWORD dwBuffSize = MAX_PATH;
  328. LONG lResult;
  329. //get file extension
  330. pszExt = strrchr(pszFilename, _T('.'));
  331. if(pszExt == NULL)
  332. {
  333. pszRet = UNKNOWN_MIME;
  334. }
  335. else
  336. {
  337. HKEY hkey = NULL;
  338. lResult = RegOpenKeyExA(HKEY_CLASSES_ROOT, pszExt, 0, KEY_QUERY_VALUE, &hkey);
  339. if(lResult != ERROR_SUCCESS)
  340. pszRet = UNKNOWN_MIME;
  341. lResult = RegQueryValueExA(hkey, REG_CONTENT_TYPE, 0, NULL, (LPBYTE) pszBuff, &dwBuffSize);
  342. if(lResult != ERROR_SUCCESS)
  343. pszRet = UNKNOWN_MIME;
  344. else
  345. pszRet = pszBuff;
  346. if(hkey)
  347. RegCloseKey(hkey);
  348. }
  349. return pszRet;
  350. }
  351. bool CHttpFilePoster::SendString(const CStdString& str)
  352. {
  353. bool bRet = false;
  354. DWORD dwWritten, dwLen;
  355. dwLen = str.length();
  356. if(InternetWriteFile(m_hFile, str.data(), dwLen, &dwWritten) && (dwWritten == dwLen))
  357. {
  358. g_dwContentLength -= dwLen;
  359. ATLTRACE((LPCSTR)str);
  360. bRet = true;
  361. }
  362. if(!bRet)
  363. ThrowUploaderException();
  364. return bRet;
  365. }
  366. DWORD CHttpFilePoster::CalculateContentLength(CUploaderFile* pFile)
  367. {
  368. DWORD dwContentLength = 0;
  369. dwContentLength = m_strFileHeader.length();
  370. dwContentLength += pFile->dwSize;
  371. dwContentLength += m_strFilePost.length();
  372. dwContentLength += m_strCommonPost.length();
  373. g_dwContentLength = dwContentLength;
  374. return dwContentLength;
  375. }
  376. bool CHttpFilePoster::SendHeader()
  377. {
  378. bool bResult = false;
  379. ATLASSERT(m_hFile);
  380. //HACK: magic number
  381. char szBuff[1000];
  382. // boundary string doesn't include the first two '-' characters
  383. sprintf(szBuff, "%s:%s; boundary=%s\r\n", CONTENT_TYPE, MULTI_PART_FORM_DATA, m_strBoundary.c_str() + 2);
  384. bResult = HttpAddRequestHeadersA(m_hFile, szBuff, -1, HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDREQ_FLAG_ADD);
  385. if(!bResult)
  386. ThrowUploaderException();
  387. return true;
  388. }
  389. bool CHttpFilePoster::BeginUpload(CProgressInfo* pProgressInfo)
  390. {
  391. bool bResult = false;
  392. if(RequestHead())
  393. {
  394. BuildCommonPost();
  395. BuildFilePostHeader(m_pCurrentFile);
  396. BuildFilePost(m_pCurrentFile);
  397. m_hFile = HttpOpenRequestA(
  398. m_hConnection, //connection
  399. "POST", //verb
  400. m_strHttpObject.c_str(),//object
  401. NULL, //http version, use default (1.0)
  402. NULL, //referer, none
  403. NULL, //accept types, use default
  404. INTERNET_FLAG_NO_CACHE_WRITE, //flags, don't write result to cache
  405. m_dwContext);
  406. if(m_hFile)
  407. {
  408. ZeroMemory(&m_internetBuffers, sizeof(m_internetBuffers));
  409. m_internetBuffers.dwBufferTotal = CalculateContentLength(m_pCurrentFile);
  410. m_internetBuffers.dwStructSize = sizeof(m_internetBuffers);
  411. if(SendHeader())
  412. {
  413. bResult = !!HttpSendRequestEx(m_hFile, &m_internetBuffers, NULL, HSR_INITIATE, 0);
  414. }
  415. }
  416. }
  417. if(!bResult)
  418. {
  419. ThrowUploaderException();
  420. //BUGBUG: do we really want to abort the entire upload, or just this file?
  421. //pProgressInfo->dwStatus = TRANSFER_SKIPPING_FILE;
  422. //pProgressInfo->NotifyCaller();
  423. }
  424. return bResult;
  425. }
  426. void CHttpFilePoster::DrainSocket()
  427. {
  428. WIA_PUSHFUNCTION(TEXT("CHttpFilePoster::DrainSocket"));
  429. ATLASSERT(m_hFile);
  430. CHAR buffer[401];
  431. DWORD dwRead = 0;
  432. WIA_TRACE((TEXT("--response body--")));
  433. while(InternetReadFile(m_hFile, buffer, 400, &dwRead) && dwRead > 0)
  434. {
  435. #ifdef DBG
  436. WIA_TRACE((TEXT("dwRead: %d"), dwRead ));
  437. buffer[dwRead] = '\0';
  438. WIA_TRACE((TEXT("%hs"), buffer));
  439. #endif
  440. }
  441. WIA_TRACE((TEXT("--done--")));
  442. ATLASSERT(dwRead == 0);
  443. }
  444. bool CHttpFilePoster::QueryStatusCode(DWORD& dwStatus)
  445. {
  446. ATLASSERT(m_hFile != NULL);
  447. TCHAR szBuffer[80];
  448. DWORD dwLen = 80;
  449. bool bRet;
  450. bRet = HttpQueryInfo(m_hFile, HTTP_QUERY_STATUS_CODE, szBuffer, &dwLen, NULL);
  451. if (bRet)
  452. dwStatus = (DWORD) _ttol(szBuffer);
  453. return bRet;
  454. }
  455. bool CHttpFilePoster::CleanupUpload()
  456. {
  457. BOOL bSuccess = false;
  458. if(m_hFile)
  459. {
  460. bSuccess = HttpEndRequest(m_hFile, NULL, 0, 0);
  461. //drain socket
  462. DrainSocket();
  463. InternetCloseHandle(m_hFile);
  464. m_hFile = NULL;
  465. }
  466. if(!bSuccess)
  467. ThrowUploaderException();
  468. return bSuccess;
  469. }
  470. bool CHttpFilePoster::FinishUpload()
  471. {
  472. return CleanupUpload();
  473. }
  474. bool CHttpFilePoster::CancelUpload()
  475. {
  476. return CleanupUpload();
  477. }
  478. bool CHttpFilePoster::SendFile(CProgressInfo* pProgressInfo)
  479. {
  480. HANDLE hFile = NULL;
  481. BYTE buffer[UPLOAD_BUFFSIZE];
  482. bool bRet = false; // assume failure
  483. try
  484. {
  485. hFile = CreateFileA(
  486. pProgressInfo->strFilename.c_str(),
  487. GENERIC_READ,
  488. FILE_SHARE_READ,
  489. NULL,
  490. OPEN_EXISTING,
  491. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
  492. NULL);
  493. if(INVALID_HANDLE_VALUE == hFile)
  494. {
  495. DWORD dwError = GetLastError();
  496. // file either doesn't exist, or is in use by another process, or
  497. // otherwise can't be opened, just skip the file and continue
  498. pProgressInfo->dwStatus = TRANSFER_SKIPPING_FILE;
  499. pProgressInfo->NotifyCaller();
  500. ThrowUploaderException(dwError);
  501. return bRet;
  502. }
  503. ATLASSERT(m_hFile);
  504. DWORD dwBytesTotal = GetFileSize(hFile, NULL);
  505. // this assertion should only fail if the file was modified since
  506. // the upload map was built, if this happens we just skip the file
  507. ATLASSERT(dwBytesTotal == pProgressInfo->dwCurrentBytes);
  508. if(dwBytesTotal != pProgressInfo->dwCurrentBytes)
  509. {
  510. pProgressInfo->dwStatus = TRANSFER_SKIPPING_FILE;
  511. pProgressInfo->NotifyCaller();
  512. CloseHandle(hFile);
  513. ThrowUploaderException();
  514. return bRet;
  515. }
  516. pProgressInfo->dwCurrentDone = 0;
  517. while(pProgressInfo->dwCurrentDone < pProgressInfo->dwCurrentBytes)
  518. {
  519. DWORD dwLeft = pProgressInfo->dwCurrentBytes - pProgressInfo->dwCurrentDone;
  520. DWORD dwToRead = min(UPLOAD_BUFFSIZE, dwLeft);
  521. DWORD dwRead;
  522. DWORD dwWritten;
  523. ReadFile(hFile, buffer, dwToRead, &dwRead, NULL);
  524. if(dwRead != dwToRead)
  525. {
  526. ATLTRACE("Error: enexpected end of file in SendFile\n");
  527. ThrowUploaderException();
  528. }
  529. if(!InternetWriteFile(m_hFile, &buffer, dwRead, &dwWritten))
  530. {
  531. ThrowUploaderException();
  532. }
  533. if(dwWritten != dwRead)
  534. {
  535. ATLTRACE("Error: InternetWriteFile sent less than requested!\n");
  536. ThrowUploaderException();
  537. }
  538. g_dwContentLength -= dwWritten;
  539. ATLTRACE("sent %d, %d left\n", dwWritten, g_dwContentLength);
  540. pProgressInfo->UpdateProgress(dwWritten);
  541. }
  542. if(hFile)
  543. {
  544. CloseHandle(hFile);
  545. hFile = NULL;
  546. }
  547. }
  548. catch(CUploaderException*)
  549. {
  550. if(hFile)
  551. {
  552. CloseHandle(hFile);
  553. hFile = NULL;
  554. }
  555. throw;
  556. }
  557. return bRet;
  558. }
  559. DWORD CHttpFilePoster::AddFile(const CStdString& sFileName, const CStdString& sTitle, DWORD dwFileSize, BOOL bDelete)
  560. {
  561. //getting file size not supported
  562. ATLASSERT(dwFileSize > 0);
  563. CStdString strMime = GetMimeType(sFileName.c_str());
  564. m_dwTotalFileBytes += dwFileSize;
  565. m_listFiles.push_back(new CUploaderFile(sFileName, dwFileSize, bDelete, strMime, sTitle));
  566. return ++m_dwFileCount;
  567. }
  568. void CHttpFilePoster::AddFormData(const CStdString& strName, const CStdString& strValue)
  569. {
  570. m_mapFormData[strName] = strValue;
  571. }
  572. DWORD CHttpFilePoster::RemoveFile(DWORD dwIndex)
  573. {
  574. std::list<CUploaderFile*>::iterator it;
  575. int i;
  576. for(i = 0, it = m_listFiles.begin(); it != m_listFiles.end() && i <= dwIndex; i++ , it++)
  577. ;
  578. if(it != m_listFiles.end())
  579. {
  580. m_dwTotalFileBytes -= (*it)->dwSize;
  581. m_dwFileCount--;
  582. delete (*it);
  583. m_listFiles.erase(it);
  584. return i;
  585. }
  586. return -1;
  587. }
  588. DWORD CHttpFilePoster::GetFileCount()
  589. {
  590. m_dwFileCount;
  591. return 0;
  592. }
  593. void CHttpFilePoster::Reset()
  594. {
  595. m_dwTotalFileBytes = 0;
  596. m_dwFileCount = 0;
  597. m_listFiles.clear();
  598. m_mapFormData.clear();
  599. }
  600. ///////////////////////////////////////////////////////////////////////////////
  601. // called by WinINet on various connection events
  602. // this function simply passes them to the caller though
  603. // the progress info callback.
  604. // note: this is a static member function, the dwContext parameter
  605. // contains the this pointer
  606. void CALLBACK CHttpFilePoster::InternetStatusCallback(
  607. HINTERNET hInternet,
  608. DWORD_PTR dwContext,
  609. DWORD dwInternetStatus,
  610. LPVOID lpvStatusInformation,
  611. DWORD dwStatusInformationLength
  612. )
  613. {
  614. CHttpFilePoster* pThis = (CHttpFilePoster*) dwContext;
  615. ATLTRACE("InternetStatusCallback dwContext=0x%08x ", dwContext);
  616. switch(dwInternetStatus)
  617. {
  618. case INTERNET_STATUS_RESOLVING_NAME:
  619. ATLTRACE("Looking up the IP address of %s\n", (char*)lpvStatusInformation);
  620. break;
  621. case INTERNET_STATUS_NAME_RESOLVED:
  622. ATLTRACE("IP address is: %s\n", (char*) lpvStatusInformation);
  623. break;
  624. case INTERNET_STATUS_CONNECTING_TO_SERVER:
  625. ATLTRACE("Connecting to server\n");
  626. //pSocketAddress = (SOCKADDR*) lpvStatusInformation;
  627. break;
  628. case INTERNET_STATUS_CONNECTED_TO_SERVER:
  629. ATLTRACE("Connected to the server\n");
  630. //pSocketAddress = (SOCKADDR*) lpvStatusInformation;
  631. break;
  632. case INTERNET_STATUS_SENDING_REQUEST:
  633. ATLTRACE("Sending request\n");
  634. break;
  635. case INTERNET_STATUS_REQUEST_SENT:
  636. ATLTRACE("Request sent\n");
  637. break;
  638. case INTERNET_STATUS_RECEIVING_RESPONSE:
  639. ATLTRACE("Waiting for server response\n");
  640. break;
  641. case INTERNET_STATUS_RESPONSE_RECEIVED:
  642. ATLTRACE("Response received\n");
  643. break;
  644. case INTERNET_STATUS_CLOSING_CONNECTION:
  645. ATLTRACE("Closing connection\n");
  646. break;
  647. case INTERNET_STATUS_CONNECTION_CLOSED:
  648. ATLTRACE("Connection closed\n");
  649. break;
  650. case INTERNET_STATUS_HANDLE_CREATED:
  651. ATLTRACE("Handle created\n");
  652. break;
  653. case INTERNET_STATUS_HANDLE_CLOSING:
  654. ATLTRACE("Handle closed\n");
  655. break;
  656. case INTERNET_STATUS_REQUEST_COMPLETE:
  657. ATLTRACE("Async request complete\n");
  658. break;
  659. default:
  660. ATLTRACE("Some other unknown callback\n");
  661. break;
  662. }
  663. }
  664. HRESULT CHttpFilePoster::ForegroundUpload( CProgressInfo *pProgress )
  665. {
  666. WIA_PUSHFUNCTION(TEXT("CHttpFilePoster::ForegroundUpload"));
  667. DWORD dwError = 0;
  668. try
  669. {
  670. std::list<CHttpFilePoster::CUploaderFile*>::iterator it, begin, end;
  671. Startup();
  672. Connect();
  673. pProgress->StartSession(m_dwFileCount, m_dwTotalFileBytes);
  674. begin = m_listFiles.begin();
  675. end = m_listFiles.end();
  676. for(it = begin; it != end; it++)
  677. {
  678. m_pCurrentFile = *it;
  679. BeginUpload(pProgress);
  680. WIA_TRACE((TEXT("Filename: %hs, Title: %hs, Size: %d"), (*it)->strNameMBCS.c_str(), (*it)->strTitle.c_str(), (*it)->dwSize ));
  681. WIA_TRACE((TEXT("m_strFileHeader: %hs"), m_strFileHeader.c_str()));
  682. WIA_TRACE((TEXT("m_strFilePost: %hs"), m_strFilePost.c_str()));
  683. WIA_TRACE((TEXT("m_strCommonPost: %hs"), m_strCommonPost.c_str()));
  684. SendString(m_strFileHeader);
  685. pProgress->StartFile((*it)->strNameMBCS, (*it)->strTitle, (*it)->dwSize);
  686. SendFile(pProgress);
  687. SendString(m_strFilePost);
  688. SendString(m_strCommonPost);
  689. pProgress->EndFile();
  690. FinishUpload();
  691. }
  692. pProgress->EndSession(!dwError);
  693. Disconnect();
  694. Shutdown();
  695. }
  696. catch(CUploaderException* pE)
  697. {
  698. dwError = pE->m_dwError;
  699. delete pE;
  700. }
  701. return HRESULT_FROM_WIN32(dwError);
  702. }
  703. ///////////////////////////////////////////////////////////////////////////////
  704. UINT CHttpFilePoster::UploadThreadProc(LPVOID pVoid)
  705. {
  706. #if 0
  707. CProgressInfo* pProgress = (CProgressInfo*) pVoid;
  708. CUploadProgressDialog* pDialog = (CUploadProgressDialog*) pProgress->lParam;
  709. CHttpFilePoster* pThis = (CHttpFilePoster*) pDialog->m_pHttpFilePoster;
  710. DWORD dwError = 0;
  711. try
  712. {
  713. std::list<CHttpFilePoster::CUploaderFile*>::iterator it, begin, end;
  714. pThis->Startup();
  715. pThis->Connect();
  716. pProgress->StartSession(pThis->m_dwFileCount, pThis->m_dwTotalFileBytes);
  717. begin = pThis->m_listFiles.begin();
  718. end = pThis->m_listFiles.end();
  719. for(it = begin; it != end; it++)
  720. {
  721. pThis->m_pCurrentFile = *it;
  722. pThis->BeginUpload(pProgress);
  723. pThis->SendString(pThis->m_strFileHeader);
  724. pProgress->StartFile((*it)->strNameMBCS, (*it)->strTitle, (*it)->dwSize);
  725. pThis->SendFile(pProgress);
  726. pThis->SendString(pThis->m_strFilePost);
  727. pThis->SendString(pThis->m_strCommonPost);
  728. pProgress->EndFile();
  729. pThis->FinishUpload();
  730. }
  731. pProgress->EndSession(!dwError);
  732. pThis->Disconnect();
  733. pThis->Shutdown();
  734. }
  735. catch(CUploaderException* pE)
  736. {
  737. dwError = pE->m_dwError;
  738. delete pE;
  739. }
  740. ::SendMessage(pDialog->m_hWnd, UPLOAD_WM_THREAD_DONE, dwError, 0);
  741. ::SendMessage(pThis->m_hWndParent, UPLOAD_WM_THREAD_DONE, dwError, 0);
  742. return dwError;
  743. #else
  744. return 0;
  745. #endif
  746. }