ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

protocol.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.