PageRenderTime 49ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/dlls/urlmon/protocol.c

https://github.com/wesgarner/wine
C | 442 lines | 312 code | 82 blank | 48 comment | 61 complexity | a267da40cbebf826481562fbb8b8eb28 MD5 | raw file
  1. /*
  2. * Copyright 2007 Misha Koshelev
  3. * Copyright 2009 Jacek Caban for CodeWeavers
  4. *
  5. * This library is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU Lesser General Public
  7. * License as published by the Free Software Foundation; either
  8. * version 2.1 of the License, or (at your option) any later version.
  9. *
  10. * This library is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * Lesser General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Lesser General Public
  16. * License along with this library; if not, write to the Free Software
  17. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  18. */
  19. #include "urlmon_main.h"
  20. #include "wine/debug.h"
  21. WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
  22. /* Flags are needed for, among other things, return HRESULTs from the Read function
  23. * to conform to native. For example, Read returns:
  24. *
  25. * 1. E_PENDING if called before the request has completed,
  26. * (flags = 0)
  27. * 2. S_FALSE after all data has been read and S_OK has been reported,
  28. * (flags = FLAG_REQUEST_COMPLETE | FLAG_ALL_DATA_READ | FLAG_RESULT_REPORTED)
  29. * 3. INET_E_DATA_NOT_AVAILABLE if InternetQueryDataAvailable fails. The first time
  30. * this occurs, INET_E_DATA_NOT_AVAILABLE will also be reported to the sink,
  31. * (flags = FLAG_REQUEST_COMPLETE)
  32. * but upon subsequent calls to Read no reporting will take place, yet
  33. * InternetQueryDataAvailable will still be called, and, on failure,
  34. * INET_E_DATA_NOT_AVAILABLE will still be returned.
  35. * (flags = FLAG_REQUEST_COMPLETE | FLAG_RESULT_REPORTED)
  36. *
  37. * FLAG_FIRST_DATA_REPORTED and FLAG_LAST_DATA_REPORTED are needed for proper
  38. * ReportData reporting. For example, if OnResponse returns S_OK, Continue will
  39. * report BSCF_FIRSTDATANOTIFICATION, and when all data has been read Read will
  40. * report BSCF_INTERMEDIATEDATANOTIFICATION|BSCF_LASTDATANOTIFICATION. However,
  41. * if OnResponse does not return S_OK, Continue will not report data, and Read
  42. * will report BSCF_FIRSTDATANOTIFICATION|BSCF_LASTDATANOTIFICATION when all
  43. * data has been read.
  44. */
  45. #define FLAG_REQUEST_COMPLETE 0x0001
  46. #define FLAG_FIRST_CONTINUE_COMPLETE 0x0002
  47. #define FLAG_FIRST_DATA_REPORTED 0x0004
  48. #define FLAG_ALL_DATA_READ 0x0008
  49. #define FLAG_LAST_DATA_REPORTED 0x0010
  50. #define FLAG_RESULT_REPORTED 0x0020
  51. static inline HRESULT report_progress(Protocol *protocol, ULONG status_code, LPCWSTR status_text)
  52. {
  53. return IInternetProtocolSink_ReportProgress(protocol->protocol_sink, status_code, status_text);
  54. }
  55. static inline HRESULT report_result(Protocol *protocol, HRESULT hres)
  56. {
  57. if (!(protocol->flags & FLAG_RESULT_REPORTED) && protocol->protocol_sink) {
  58. protocol->flags |= FLAG_RESULT_REPORTED;
  59. IInternetProtocolSink_ReportResult(protocol->protocol_sink, hres, 0, NULL);
  60. }
  61. return hres;
  62. }
  63. static void report_data(Protocol *protocol)
  64. {
  65. DWORD bscf;
  66. if((protocol->flags & FLAG_LAST_DATA_REPORTED) || !protocol->protocol_sink)
  67. return;
  68. if(protocol->flags & FLAG_FIRST_DATA_REPORTED) {
  69. bscf = BSCF_INTERMEDIATEDATANOTIFICATION;
  70. }else {
  71. protocol->flags |= FLAG_FIRST_DATA_REPORTED;
  72. bscf = BSCF_FIRSTDATANOTIFICATION;
  73. }
  74. if(protocol->flags & FLAG_ALL_DATA_READ && !(protocol->flags & FLAG_LAST_DATA_REPORTED)) {
  75. protocol->flags |= FLAG_LAST_DATA_REPORTED;
  76. bscf |= BSCF_LASTDATANOTIFICATION;
  77. }
  78. IInternetProtocolSink_ReportData(protocol->protocol_sink, bscf,
  79. protocol->current_position+protocol->available_bytes,
  80. protocol->content_length);
  81. }
  82. static void all_data_read(Protocol *protocol)
  83. {
  84. protocol->flags |= FLAG_ALL_DATA_READ;
  85. report_data(protocol);
  86. report_result(protocol, S_OK);
  87. }
  88. static void request_complete(Protocol *protocol, INTERNET_ASYNC_RESULT *ar)
  89. {
  90. PROTOCOLDATA data;
  91. if(!ar->dwResult) {
  92. WARN("request failed: %d\n", ar->dwError);
  93. return;
  94. }
  95. protocol->flags |= FLAG_REQUEST_COMPLETE;
  96. if(!protocol->request) {
  97. TRACE("setting request handle %p\n", (HINTERNET)ar->dwResult);
  98. protocol->request = (HINTERNET)ar->dwResult;
  99. }
  100. /* PROTOCOLDATA same as native */
  101. memset(&data, 0, sizeof(data));
  102. data.dwState = 0xf1000000;
  103. if(protocol->flags & FLAG_FIRST_CONTINUE_COMPLETE)
  104. data.pData = (LPVOID)BINDSTATUS_ENDDOWNLOADCOMPONENTS;
  105. else
  106. data.pData = (LPVOID)BINDSTATUS_DOWNLOADINGDATA;
  107. if (protocol->bindf & BINDF_FROMURLMON)
  108. IInternetProtocolSink_Switch(protocol->protocol_sink, &data);
  109. else
  110. protocol_continue(protocol, &data);
  111. }
  112. static void WINAPI internet_status_callback(HINTERNET internet, DWORD_PTR context,
  113. DWORD internet_status, LPVOID status_info, DWORD status_info_len)
  114. {
  115. Protocol *protocol = (Protocol*)context;
  116. switch(internet_status) {
  117. case INTERNET_STATUS_RESOLVING_NAME:
  118. TRACE("%p INTERNET_STATUS_RESOLVING_NAME\n", protocol);
  119. report_progress(protocol, BINDSTATUS_FINDINGRESOURCE, (LPWSTR)status_info);
  120. break;
  121. case INTERNET_STATUS_CONNECTING_TO_SERVER:
  122. TRACE("%p INTERNET_STATUS_CONNECTING_TO_SERVER\n", protocol);
  123. report_progress(protocol, BINDSTATUS_CONNECTING, (LPWSTR)status_info);
  124. break;
  125. case INTERNET_STATUS_SENDING_REQUEST:
  126. TRACE("%p INTERNET_STATUS_SENDING_REQUEST\n", protocol);
  127. report_progress(protocol, BINDSTATUS_SENDINGREQUEST, (LPWSTR)status_info);
  128. break;
  129. case INTERNET_STATUS_REDIRECT:
  130. TRACE("%p INTERNET_STATUS_REDIRECT\n", protocol);
  131. report_progress(protocol, BINDSTATUS_REDIRECTING, (LPWSTR)status_info);
  132. break;
  133. case INTERNET_STATUS_REQUEST_COMPLETE:
  134. request_complete(protocol, status_info);
  135. break;
  136. case INTERNET_STATUS_HANDLE_CREATED:
  137. TRACE("%p INTERNET_STATUS_HANDLE_CREATED\n", protocol);
  138. IInternetProtocol_AddRef(protocol->protocol);
  139. break;
  140. case INTERNET_STATUS_HANDLE_CLOSING:
  141. TRACE("%p INTERNET_STATUS_HANDLE_CLOSING\n", protocol);
  142. if(*(HINTERNET *)status_info == protocol->request) {
  143. protocol->request = NULL;
  144. if(protocol->protocol_sink) {
  145. IInternetProtocolSink_Release(protocol->protocol_sink);
  146. protocol->protocol_sink = NULL;
  147. }
  148. if(protocol->bind_info.cbSize) {
  149. ReleaseBindInfo(&protocol->bind_info);
  150. memset(&protocol->bind_info, 0, sizeof(protocol->bind_info));
  151. }
  152. }else if(*(HINTERNET *)status_info == protocol->connection) {
  153. protocol->connection = NULL;
  154. }
  155. IInternetProtocol_Release(protocol->protocol);
  156. break;
  157. default:
  158. WARN("Unhandled Internet status callback %d\n", internet_status);
  159. }
  160. }
  161. static HINTERNET create_internet_session(IInternetBindInfo *bind_info)
  162. {
  163. LPWSTR global_user_agent = NULL;
  164. LPOLESTR user_agent = NULL;
  165. ULONG size = 0;
  166. HINTERNET ret;
  167. HRESULT hres;
  168. hres = IInternetBindInfo_GetBindString(bind_info, BINDSTRING_USER_AGENT, &user_agent, 1, &size);
  169. if(hres != S_OK || !size)
  170. global_user_agent = get_useragent();
  171. ret = InternetOpenW(user_agent ? user_agent : global_user_agent, 0, NULL, NULL, INTERNET_FLAG_ASYNC);
  172. heap_free(global_user_agent);
  173. CoTaskMemFree(user_agent);
  174. if(!ret) {
  175. WARN("InternetOpen failed: %d\n", GetLastError());
  176. return NULL;
  177. }
  178. InternetSetStatusCallbackW(ret, internet_status_callback);
  179. return ret;
  180. }
  181. static HINTERNET internet_session;
  182. HINTERNET get_internet_session(IInternetBindInfo *bind_info)
  183. {
  184. HINTERNET new_session;
  185. if(internet_session)
  186. return internet_session;
  187. if(!bind_info)
  188. return NULL;
  189. new_session = create_internet_session(bind_info);
  190. if(new_session && InterlockedCompareExchangePointer((void**)&internet_session, new_session, NULL))
  191. InternetCloseHandle(new_session);
  192. return internet_session;
  193. }
  194. HRESULT protocol_start(Protocol *protocol, IInternetProtocol *prot, IUri *uri,
  195. IInternetProtocolSink *protocol_sink, IInternetBindInfo *bind_info)
  196. {
  197. DWORD request_flags;
  198. HRESULT hres;
  199. protocol->protocol = prot;
  200. IInternetProtocolSink_AddRef(protocol_sink);
  201. protocol->protocol_sink = protocol_sink;
  202. memset(&protocol->bind_info, 0, sizeof(protocol->bind_info));
  203. protocol->bind_info.cbSize = sizeof(BINDINFO);
  204. hres = IInternetBindInfo_GetBindInfo(bind_info, &protocol->bindf, &protocol->bind_info);
  205. if(hres != S_OK) {
  206. WARN("GetBindInfo failed: %08x\n", hres);
  207. return report_result(protocol, hres);
  208. }
  209. if(!(protocol->bindf & BINDF_FROMURLMON))
  210. report_progress(protocol, BINDSTATUS_DIRECTBIND, NULL);
  211. if(!get_internet_session(bind_info))
  212. return report_result(protocol, INET_E_NO_SESSION);
  213. request_flags = INTERNET_FLAG_KEEP_CONNECTION;
  214. if(protocol->bindf & BINDF_NOWRITECACHE)
  215. request_flags |= INTERNET_FLAG_NO_CACHE_WRITE;
  216. if(protocol->bindf & BINDF_NEEDFILE)
  217. request_flags |= INTERNET_FLAG_NEED_FILE;
  218. hres = protocol->vtbl->open_request(protocol, uri, request_flags, internet_session, bind_info);
  219. if(FAILED(hres)) {
  220. protocol_close_connection(protocol);
  221. return report_result(protocol, hres);
  222. }
  223. return S_OK;
  224. }
  225. HRESULT protocol_continue(Protocol *protocol, PROTOCOLDATA *data)
  226. {
  227. HRESULT hres;
  228. if (!data) {
  229. WARN("Expected pProtocolData to be non-NULL\n");
  230. return S_OK;
  231. }
  232. if(!protocol->request) {
  233. WARN("Expected request to be non-NULL\n");
  234. return S_OK;
  235. }
  236. if(!protocol->protocol_sink) {
  237. WARN("Expected IInternetProtocolSink pointer to be non-NULL\n");
  238. return S_OK;
  239. }
  240. if(data->pData == (LPVOID)BINDSTATUS_DOWNLOADINGDATA) {
  241. hres = protocol->vtbl->start_downloading(protocol);
  242. if(FAILED(hres)) {
  243. protocol_close_connection(protocol);
  244. report_result(protocol, hres);
  245. return S_OK;
  246. }
  247. if(protocol->bindf & BINDF_NEEDFILE) {
  248. WCHAR cache_file[MAX_PATH];
  249. DWORD buflen = sizeof(cache_file);
  250. if(InternetQueryOptionW(protocol->request, INTERNET_OPTION_DATAFILE_NAME,
  251. cache_file, &buflen)) {
  252. report_progress(protocol, BINDSTATUS_CACHEFILENAMEAVAILABLE, cache_file);
  253. }else {
  254. FIXME("Could not get cache file\n");
  255. }
  256. }
  257. protocol->flags |= FLAG_FIRST_CONTINUE_COMPLETE;
  258. }
  259. if(data->pData >= (LPVOID)BINDSTATUS_DOWNLOADINGDATA) {
  260. BOOL res;
  261. /* InternetQueryDataAvailable may immediately fork and perform its asynchronous
  262. * read, so clear the flag _before_ calling so it does not incorrectly get cleared
  263. * after the status callback is called */
  264. protocol->flags &= ~FLAG_REQUEST_COMPLETE;
  265. res = InternetQueryDataAvailable(protocol->request, &protocol->available_bytes, 0, 0);
  266. if(res) {
  267. protocol->flags |= FLAG_REQUEST_COMPLETE;
  268. report_data(protocol);
  269. }else if(GetLastError() != ERROR_IO_PENDING) {
  270. protocol->flags |= FLAG_REQUEST_COMPLETE;
  271. WARN("InternetQueryDataAvailable failed: %d\n", GetLastError());
  272. report_result(protocol, INET_E_DATA_NOT_AVAILABLE);
  273. }
  274. }
  275. return S_OK;
  276. }
  277. HRESULT protocol_read(Protocol *protocol, void *buf, ULONG size, ULONG *read_ret)
  278. {
  279. ULONG read = 0;
  280. BOOL res;
  281. HRESULT hres = S_FALSE;
  282. if(protocol->flags & FLAG_ALL_DATA_READ) {
  283. *read_ret = 0;
  284. return S_FALSE;
  285. }
  286. if(!(protocol->flags & FLAG_REQUEST_COMPLETE)) {
  287. *read_ret = 0;
  288. return E_PENDING;
  289. }
  290. while(read < size) {
  291. if(protocol->available_bytes) {
  292. ULONG len;
  293. res = InternetReadFile(protocol->request, ((BYTE *)buf)+read,
  294. protocol->available_bytes > size-read ? size-read : protocol->available_bytes, &len);
  295. if(!res) {
  296. WARN("InternetReadFile failed: %d\n", GetLastError());
  297. hres = INET_E_DOWNLOAD_FAILURE;
  298. report_result(protocol, hres);
  299. break;
  300. }
  301. if(!len) {
  302. all_data_read(protocol);
  303. break;
  304. }
  305. read += len;
  306. protocol->current_position += len;
  307. protocol->available_bytes -= len;
  308. }else {
  309. /* InternetQueryDataAvailable may immediately fork and perform its asynchronous
  310. * read, so clear the flag _before_ calling so it does not incorrectly get cleared
  311. * after the status callback is called */
  312. protocol->flags &= ~FLAG_REQUEST_COMPLETE;
  313. res = InternetQueryDataAvailable(protocol->request, &protocol->available_bytes, 0, 0);
  314. if(!res) {
  315. if (GetLastError() == ERROR_IO_PENDING) {
  316. hres = E_PENDING;
  317. }else {
  318. WARN("InternetQueryDataAvailable failed: %d\n", GetLastError());
  319. hres = INET_E_DATA_NOT_AVAILABLE;
  320. report_result(protocol, hres);
  321. }
  322. break;
  323. }
  324. if(!protocol->available_bytes) {
  325. all_data_read(protocol);
  326. break;
  327. }
  328. }
  329. }
  330. *read_ret = read;
  331. if (hres != E_PENDING)
  332. protocol->flags |= FLAG_REQUEST_COMPLETE;
  333. if(FAILED(hres))
  334. return hres;
  335. return read ? S_OK : S_FALSE;
  336. }
  337. HRESULT protocol_lock_request(Protocol *protocol)
  338. {
  339. if (!InternetLockRequestFile(protocol->request, &protocol->lock))
  340. WARN("InternetLockRequest failed: %d\n", GetLastError());
  341. return S_OK;
  342. }
  343. HRESULT protocol_unlock_request(Protocol *protocol)
  344. {
  345. if(!protocol->lock)
  346. return S_OK;
  347. if(!InternetUnlockRequestFile(protocol->lock))
  348. WARN("InternetUnlockRequest failed: %d\n", GetLastError());
  349. protocol->lock = 0;
  350. return S_OK;
  351. }
  352. void protocol_close_connection(Protocol *protocol)
  353. {
  354. protocol->vtbl->close_connection(protocol);
  355. if(protocol->request)
  356. InternetCloseHandle(protocol->request);
  357. if(protocol->connection)
  358. InternetCloseHandle(protocol->connection);
  359. protocol->flags = 0;
  360. }