Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenprotocol.c
Go to the documentation of this file.
00001 /* 00002 * Copyright 2007 Misha Koshelev 00003 * Copyright 2009 Jacek Caban for CodeWeavers 00004 * 00005 * This library is free software; you can redistribute it and/or 00006 * modify it under the terms of the GNU Lesser General Public 00007 * License as published by the Free Software Foundation; either 00008 * version 2.1 of the License, or (at your option) any later version. 00009 * 00010 * This library is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 * Lesser General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU Lesser General Public 00016 * License along with this library; if not, write to the Free Software 00017 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00018 */ 00019 00020 #include "urlmon_main.h" 00021 00022 #include "wine/debug.h" 00023 00024 WINE_DEFAULT_DEBUG_CHANNEL(urlmon); 00025 00026 static inline HRESULT report_progress(Protocol *protocol, ULONG status_code, LPCWSTR status_text) 00027 { 00028 return IInternetProtocolSink_ReportProgress(protocol->protocol_sink, status_code, status_text); 00029 } 00030 00031 static inline HRESULT report_result(Protocol *protocol, HRESULT hres) 00032 { 00033 if (!(protocol->flags & FLAG_RESULT_REPORTED) && protocol->protocol_sink) { 00034 protocol->flags |= FLAG_RESULT_REPORTED; 00035 IInternetProtocolSink_ReportResult(protocol->protocol_sink, hres, 0, NULL); 00036 } 00037 00038 return hres; 00039 } 00040 00041 static void report_data(Protocol *protocol) 00042 { 00043 DWORD bscf; 00044 00045 if((protocol->flags & FLAG_LAST_DATA_REPORTED) || !protocol->protocol_sink) 00046 return; 00047 00048 if(protocol->flags & FLAG_FIRST_DATA_REPORTED) { 00049 bscf = BSCF_INTERMEDIATEDATANOTIFICATION; 00050 }else { 00051 protocol->flags |= FLAG_FIRST_DATA_REPORTED; 00052 bscf = BSCF_FIRSTDATANOTIFICATION; 00053 } 00054 00055 if(protocol->flags & FLAG_ALL_DATA_READ && !(protocol->flags & FLAG_LAST_DATA_REPORTED)) { 00056 protocol->flags |= FLAG_LAST_DATA_REPORTED; 00057 bscf |= BSCF_LASTDATANOTIFICATION; 00058 } 00059 00060 IInternetProtocolSink_ReportData(protocol->protocol_sink, bscf, 00061 protocol->current_position+protocol->available_bytes, 00062 protocol->content_length); 00063 } 00064 00065 static void all_data_read(Protocol *protocol) 00066 { 00067 protocol->flags |= FLAG_ALL_DATA_READ; 00068 00069 report_data(protocol); 00070 report_result(protocol, S_OK); 00071 } 00072 00073 static void request_complete(Protocol *protocol, INTERNET_ASYNC_RESULT *ar) 00074 { 00075 PROTOCOLDATA data; 00076 00077 TRACE("(%p)->(%p)\n", protocol, ar); 00078 00079 /* PROTOCOLDATA same as native */ 00080 memset(&data, 0, sizeof(data)); 00081 data.dwState = 0xf1000000; 00082 00083 if(ar->dwResult) { 00084 protocol->flags |= FLAG_REQUEST_COMPLETE; 00085 00086 if(!protocol->request) { 00087 TRACE("setting request handle %p\n", (HINTERNET)ar->dwResult); 00088 protocol->request = (HINTERNET)ar->dwResult; 00089 } 00090 00091 if(protocol->flags & FLAG_FIRST_CONTINUE_COMPLETE) 00092 data.pData = (LPVOID)BINDSTATUS_ENDDOWNLOADCOMPONENTS; 00093 else 00094 data.pData = (LPVOID)BINDSTATUS_DOWNLOADINGDATA; 00095 00096 }else { 00097 protocol->flags |= FLAG_ERROR; 00098 data.pData = (LPVOID)ar->dwError; 00099 } 00100 00101 if (protocol->bindf & BINDF_FROMURLMON) 00102 IInternetProtocolSink_Switch(protocol->protocol_sink, &data); 00103 else 00104 protocol_continue(protocol, &data); 00105 } 00106 00107 static void WINAPI internet_status_callback(HINTERNET internet, DWORD_PTR context, 00108 DWORD internet_status, LPVOID status_info, DWORD status_info_len) 00109 { 00110 Protocol *protocol = (Protocol*)context; 00111 00112 switch(internet_status) { 00113 case INTERNET_STATUS_RESOLVING_NAME: 00114 TRACE("%p INTERNET_STATUS_RESOLVING_NAME\n", protocol); 00115 report_progress(protocol, BINDSTATUS_FINDINGRESOURCE, (LPWSTR)status_info); 00116 break; 00117 00118 case INTERNET_STATUS_CONNECTING_TO_SERVER: 00119 TRACE("%p INTERNET_STATUS_CONNECTING_TO_SERVER\n", protocol); 00120 report_progress(protocol, BINDSTATUS_CONNECTING, (LPWSTR)status_info); 00121 break; 00122 00123 case INTERNET_STATUS_SENDING_REQUEST: 00124 TRACE("%p INTERNET_STATUS_SENDING_REQUEST\n", protocol); 00125 report_progress(protocol, BINDSTATUS_SENDINGREQUEST, (LPWSTR)status_info); 00126 break; 00127 00128 case INTERNET_STATUS_REDIRECT: 00129 TRACE("%p INTERNET_STATUS_REDIRECT\n", protocol); 00130 report_progress(protocol, BINDSTATUS_REDIRECTING, (LPWSTR)status_info); 00131 break; 00132 00133 case INTERNET_STATUS_REQUEST_COMPLETE: 00134 request_complete(protocol, status_info); 00135 break; 00136 00137 case INTERNET_STATUS_HANDLE_CREATED: 00138 TRACE("%p INTERNET_STATUS_HANDLE_CREATED\n", protocol); 00139 IInternetProtocol_AddRef(protocol->protocol); 00140 break; 00141 00142 case INTERNET_STATUS_HANDLE_CLOSING: 00143 TRACE("%p INTERNET_STATUS_HANDLE_CLOSING\n", protocol); 00144 00145 if(*(HINTERNET *)status_info == protocol->request) { 00146 protocol->request = NULL; 00147 if(protocol->protocol_sink) { 00148 IInternetProtocolSink_Release(protocol->protocol_sink); 00149 protocol->protocol_sink = NULL; 00150 } 00151 00152 if(protocol->bind_info.cbSize) { 00153 ReleaseBindInfo(&protocol->bind_info); 00154 memset(&protocol->bind_info, 0, sizeof(protocol->bind_info)); 00155 } 00156 }else if(*(HINTERNET *)status_info == protocol->connection) { 00157 protocol->connection = NULL; 00158 } 00159 00160 IInternetProtocol_Release(protocol->protocol); 00161 break; 00162 00163 default: 00164 WARN("Unhandled Internet status callback %d\n", internet_status); 00165 } 00166 } 00167 00168 static HRESULT write_post_stream(Protocol *protocol) 00169 { 00170 BYTE buf[0x20000]; 00171 DWORD written; 00172 ULONG size; 00173 BOOL res; 00174 HRESULT hres; 00175 00176 protocol->flags &= ~FLAG_REQUEST_COMPLETE; 00177 00178 while(1) { 00179 size = 0; 00180 hres = IStream_Read(protocol->post_stream, buf, sizeof(buf), &size); 00181 if(FAILED(hres) || !size) 00182 break; 00183 res = InternetWriteFile(protocol->request, buf, size, &written); 00184 if(!res) { 00185 FIXME("InternetWriteFile failed: %u\n", GetLastError()); 00186 hres = E_FAIL; 00187 break; 00188 } 00189 } 00190 00191 if(SUCCEEDED(hres)) { 00192 IStream_Release(protocol->post_stream); 00193 protocol->post_stream = NULL; 00194 00195 hres = protocol->vtbl->end_request(protocol); 00196 } 00197 00198 if(FAILED(hres)) 00199 return report_result(protocol, hres); 00200 00201 return S_OK; 00202 } 00203 00204 static HINTERNET create_internet_session(IInternetBindInfo *bind_info) 00205 { 00206 LPWSTR global_user_agent = NULL; 00207 LPOLESTR user_agent = NULL; 00208 ULONG size = 0; 00209 HINTERNET ret; 00210 HRESULT hres; 00211 00212 hres = IInternetBindInfo_GetBindString(bind_info, BINDSTRING_USER_AGENT, &user_agent, 1, &size); 00213 if(hres != S_OK || !size) 00214 global_user_agent = get_useragent(); 00215 00216 ret = InternetOpenW(user_agent ? user_agent : global_user_agent, 0, NULL, NULL, INTERNET_FLAG_ASYNC); 00217 heap_free(global_user_agent); 00218 CoTaskMemFree(user_agent); 00219 if(!ret) { 00220 WARN("InternetOpen failed: %d\n", GetLastError()); 00221 return NULL; 00222 } 00223 00224 InternetSetStatusCallbackW(ret, internet_status_callback); 00225 return ret; 00226 } 00227 00228 static HINTERNET internet_session; 00229 00230 HINTERNET get_internet_session(IInternetBindInfo *bind_info) 00231 { 00232 HINTERNET new_session; 00233 00234 if(internet_session) 00235 return internet_session; 00236 00237 if(!bind_info) 00238 return NULL; 00239 00240 new_session = create_internet_session(bind_info); 00241 if(new_session && InterlockedCompareExchangePointer((void**)&internet_session, new_session, NULL)) 00242 InternetCloseHandle(new_session); 00243 00244 return internet_session; 00245 } 00246 00247 HRESULT protocol_start(Protocol *protocol, IInternetProtocol *prot, IUri *uri, 00248 IInternetProtocolSink *protocol_sink, IInternetBindInfo *bind_info) 00249 { 00250 DWORD request_flags; 00251 HRESULT hres; 00252 00253 protocol->protocol = prot; 00254 00255 IInternetProtocolSink_AddRef(protocol_sink); 00256 protocol->protocol_sink = protocol_sink; 00257 00258 memset(&protocol->bind_info, 0, sizeof(protocol->bind_info)); 00259 protocol->bind_info.cbSize = sizeof(BINDINFO); 00260 hres = IInternetBindInfo_GetBindInfo(bind_info, &protocol->bindf, &protocol->bind_info); 00261 if(hres != S_OK) { 00262 WARN("GetBindInfo failed: %08x\n", hres); 00263 return report_result(protocol, hres); 00264 } 00265 00266 if(!(protocol->bindf & BINDF_FROMURLMON)) 00267 report_progress(protocol, BINDSTATUS_DIRECTBIND, NULL); 00268 00269 if(!get_internet_session(bind_info)) 00270 return report_result(protocol, INET_E_NO_SESSION); 00271 00272 request_flags = INTERNET_FLAG_KEEP_CONNECTION; 00273 if(protocol->bindf & BINDF_NOWRITECACHE) 00274 request_flags |= INTERNET_FLAG_NO_CACHE_WRITE; 00275 if(protocol->bindf & BINDF_NEEDFILE) 00276 request_flags |= INTERNET_FLAG_NEED_FILE; 00277 00278 hres = protocol->vtbl->open_request(protocol, uri, request_flags, internet_session, bind_info); 00279 if(FAILED(hres)) { 00280 protocol_close_connection(protocol); 00281 return report_result(protocol, hres); 00282 } 00283 00284 return S_OK; 00285 } 00286 00287 HRESULT protocol_continue(Protocol *protocol, PROTOCOLDATA *data) 00288 { 00289 HRESULT hres; 00290 00291 if (!data) { 00292 WARN("Expected pProtocolData to be non-NULL\n"); 00293 return S_OK; 00294 } 00295 00296 if(!protocol->request) { 00297 WARN("Expected request to be non-NULL\n"); 00298 return S_OK; 00299 } 00300 00301 if(!protocol->protocol_sink) { 00302 WARN("Expected IInternetProtocolSink pointer to be non-NULL\n"); 00303 return S_OK; 00304 } 00305 00306 if(protocol->flags & FLAG_ERROR) { 00307 protocol->flags &= ~FLAG_ERROR; 00308 protocol->vtbl->on_error(protocol, (DWORD)data->pData); 00309 return S_OK; 00310 } 00311 00312 if(protocol->post_stream) 00313 return write_post_stream(protocol); 00314 00315 if(data->pData == (LPVOID)BINDSTATUS_DOWNLOADINGDATA) { 00316 hres = protocol->vtbl->start_downloading(protocol); 00317 if(FAILED(hres)) { 00318 protocol_close_connection(protocol); 00319 report_result(protocol, hres); 00320 return S_OK; 00321 } 00322 00323 if(protocol->bindf & BINDF_NEEDFILE) { 00324 WCHAR cache_file[MAX_PATH]; 00325 DWORD buflen = sizeof(cache_file); 00326 00327 if(InternetQueryOptionW(protocol->request, INTERNET_OPTION_DATAFILE_NAME, 00328 cache_file, &buflen)) { 00329 report_progress(protocol, BINDSTATUS_CACHEFILENAMEAVAILABLE, cache_file); 00330 }else { 00331 FIXME("Could not get cache file\n"); 00332 } 00333 } 00334 00335 protocol->flags |= FLAG_FIRST_CONTINUE_COMPLETE; 00336 } 00337 00338 if(data->pData >= (LPVOID)BINDSTATUS_DOWNLOADINGDATA && !protocol->available_bytes) { 00339 BOOL res; 00340 00341 /* InternetQueryDataAvailable may immediately fork and perform its asynchronous 00342 * read, so clear the flag _before_ calling so it does not incorrectly get cleared 00343 * after the status callback is called */ 00344 protocol->flags &= ~FLAG_REQUEST_COMPLETE; 00345 res = InternetQueryDataAvailable(protocol->request, &protocol->available_bytes, 0, 0); 00346 if(res) { 00347 protocol->flags |= FLAG_REQUEST_COMPLETE; 00348 report_data(protocol); 00349 }else if(GetLastError() != ERROR_IO_PENDING) { 00350 protocol->flags |= FLAG_REQUEST_COMPLETE; 00351 WARN("InternetQueryDataAvailable failed: %d\n", GetLastError()); 00352 report_result(protocol, INET_E_DATA_NOT_AVAILABLE); 00353 } 00354 } 00355 00356 return S_OK; 00357 } 00358 00359 HRESULT protocol_read(Protocol *protocol, void *buf, ULONG size, ULONG *read_ret) 00360 { 00361 ULONG read = 0; 00362 BOOL res; 00363 HRESULT hres = S_FALSE; 00364 00365 if(protocol->flags & FLAG_ALL_DATA_READ) { 00366 *read_ret = 0; 00367 return S_FALSE; 00368 } 00369 00370 if(!(protocol->flags & FLAG_REQUEST_COMPLETE) || !protocol->available_bytes) { 00371 *read_ret = 0; 00372 return E_PENDING; 00373 } 00374 00375 while(read < size && protocol->available_bytes) { 00376 ULONG len; 00377 00378 res = InternetReadFile(protocol->request, ((BYTE *)buf)+read, 00379 protocol->available_bytes > size-read ? size-read : protocol->available_bytes, &len); 00380 if(!res) { 00381 WARN("InternetReadFile failed: %d\n", GetLastError()); 00382 hres = INET_E_DOWNLOAD_FAILURE; 00383 report_result(protocol, hres); 00384 break; 00385 } 00386 00387 if(!len) { 00388 all_data_read(protocol); 00389 break; 00390 } 00391 00392 read += len; 00393 protocol->current_position += len; 00394 protocol->available_bytes -= len; 00395 00396 if(!protocol->available_bytes) { 00397 /* InternetQueryDataAvailable may immediately fork and perform its asynchronous 00398 * read, so clear the flag _before_ calling so it does not incorrectly get cleared 00399 * after the status callback is called */ 00400 protocol->flags &= ~FLAG_REQUEST_COMPLETE; 00401 res = InternetQueryDataAvailable(protocol->request, &protocol->available_bytes, 0, 0); 00402 if(!res) { 00403 if (GetLastError() == ERROR_IO_PENDING) { 00404 hres = E_PENDING; 00405 }else { 00406 WARN("InternetQueryDataAvailable failed: %d\n", GetLastError()); 00407 hres = INET_E_DATA_NOT_AVAILABLE; 00408 report_result(protocol, hres); 00409 } 00410 break; 00411 } 00412 00413 if(!protocol->available_bytes) { 00414 all_data_read(protocol); 00415 break; 00416 } 00417 } 00418 } 00419 00420 *read_ret = read; 00421 00422 if (hres != E_PENDING) 00423 protocol->flags |= FLAG_REQUEST_COMPLETE; 00424 if(FAILED(hres)) 00425 return hres; 00426 00427 return read ? S_OK : S_FALSE; 00428 } 00429 00430 HRESULT protocol_lock_request(Protocol *protocol) 00431 { 00432 if (!InternetLockRequestFile(protocol->request, &protocol->lock)) 00433 WARN("InternetLockRequest failed: %d\n", GetLastError()); 00434 00435 return S_OK; 00436 } 00437 00438 HRESULT protocol_unlock_request(Protocol *protocol) 00439 { 00440 if(!protocol->lock) 00441 return S_OK; 00442 00443 if(!InternetUnlockRequestFile(protocol->lock)) 00444 WARN("InternetUnlockRequest failed: %d\n", GetLastError()); 00445 protocol->lock = 0; 00446 00447 return S_OK; 00448 } 00449 00450 HRESULT protocol_abort(Protocol *protocol, HRESULT reason) 00451 { 00452 if(!protocol->protocol_sink) 00453 return S_OK; 00454 00455 if(protocol->flags & FLAG_RESULT_REPORTED) 00456 return INET_E_RESULT_DISPATCHED; 00457 00458 report_result(protocol, reason); 00459 return S_OK; 00460 } 00461 00462 void protocol_close_connection(Protocol *protocol) 00463 { 00464 protocol->vtbl->close_connection(protocol); 00465 00466 if(protocol->request) 00467 InternetCloseHandle(protocol->request); 00468 00469 if(protocol->connection) 00470 InternetCloseHandle(protocol->connection); 00471 00472 if(protocol->post_stream) { 00473 IStream_Release(protocol->post_stream); 00474 protocol->post_stream = NULL; 00475 } 00476 00477 protocol->flags = 0; 00478 } Generated on Mon May 28 2012 04:23:54 for ReactOS by
1.7.6.1
|