19 #include "axstream_impl.h"
24 #include "utf8_tools.h"
25 #include <boost\smart_ptr\scoped_array.hpp>
26 #include <boost\smart_ptr\shared_array.hpp>
27 #include "precompiled_headers.h"
30 using namespace FB::ActiveX;
41 ActiveXBindStatusCallback::ActiveXBindStatusCallback() :
42 m_pbinding(0), m_pstm(0), m_cRef(1), m_cbOld(0), m_dwAction( BINDVERB_GET ), m_fRedirect( FALSE ), m_transactionStarted( false ),
43 m_hDataToPost(NULL), m_cbDataToPost(0)
47 ActiveXBindStatusCallback::~ActiveXBindStatusCallback()
51 ::GlobalFree(m_hDataToPost);
59 HRESULT ActiveXBindStatusCallback::Create(ActiveXBindStatusCallback** ppBindStatusCallback, ActiveXStreamRequestPtr request)
62 ActiveXBindStatusCallback* pBindStatusCallback;
64 if (!ppBindStatusCallback)
69 *ppBindStatusCallback = NULL;
71 pBindStatusCallback =
new ActiveXBindStatusCallback();
72 if (!pBindStatusCallback)
77 hr = pBindStatusCallback->Init(request);
80 delete pBindStatusCallback;
84 *ppBindStatusCallback = pBindStatusCallback;
91 HRESULT ActiveXBindStatusCallback::Init(ActiveXStreamRequestPtr request)
97 && !m_request->stream->getVerbData().empty() )
100 m_dwAction = BINDVERB_POST;
101 hr = InitPostData(m_request->stream->getVerbData().c_str());
104 m_dwAction = m_request->stream->getVerbData().empty()? BINDVERB_GET : BINDVERB_POST;
108 HRESULT ActiveXBindStatusCallback::InitPostData(
const char* szData)
122 m_cbDataToPost = ::lstrlenA(szData);
123 m_hDataToPost = ::GlobalAlloc(GPTR, m_cbDataToPost+1);
126 return E_OUTOFMEMORY;
130 ::lstrcpyA((
char*)m_hDataToPost, szData);
140 ActiveXBindStatusCallback::QueryInterface(REFIID riid,
void** ppv)
144 if (riid==IID_IUnknown || riid==IID_IBindStatusCallback)
146 *ppv = (IBindStatusCallback*)
this;
150 else if (riid==IID_IHttpNegotiate)
152 *ppv = (IHttpNegotiate*)
this;
158 return E_NOINTERFACE;
167 ActiveXBindStatusCallback::OnStartBinding(DWORD dwReserved, IBinding* pbinding)
169 if (NULL != m_pbinding)
171 m_pbinding->Release();
175 m_pbinding = pbinding;
177 if (m_pbinding != NULL)
179 m_pbinding->AddRef();
190 ActiveXBindStatusCallback::GetPriority(LONG* pnPriority)
199 ActiveXBindStatusCallback::OnLowResource(DWORD dwReserved)
207 STDMETHODIMP ActiveXBindStatusCallback::OnProgress(ULONG ulProgress, ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
212 switch (ulStatusCode)
214 case BINDSTATUS_REDIRECTING:
215 ODS(
"Server redirecting client\n");
218 case BINDSTATUS_FINDINGRESOURCE:
219 ODS(
"Finding resource\n");
221 case BINDSTATUS_CONNECTING:
222 ODS(
"Connecting...\n");
224 case BINDSTATUS_BEGINDOWNLOADDATA:
225 ODS(
"Beginning to download data...\n");
227 case BINDSTATUS_DOWNLOADINGDATA:
228 ODS(
"Downloading data...\n");
230 case BINDSTATUS_ENDDOWNLOADDATA:
231 ODS(
"Ending data download...\n");
233 case BINDSTATUS_BEGINDOWNLOADCOMPONENTS:
234 ODS(
"Beginning to download components...\n");
236 case BINDSTATUS_INSTALLINGCOMPONENTS:
237 ODS(
"Installing components...\n");
239 case BINDSTATUS_ENDDOWNLOADCOMPONENTS:
240 ODS(
"Ending component download...\n");
242 case BINDSTATUS_USINGCACHEDCOPY:
243 ODS(
"Using cached copy...\n");
245 case BINDSTATUS_SENDINGREQUEST:
246 ODS(
"Sending request...\n");
248 case BINDSTATUS_CLASSIDAVAILABLE:
249 ODS(
"CLSID available...\n");
251 case BINDSTATUS_MIMETYPEAVAILABLE:
252 ODS(
"MIME type available...\n");
254 case BINDSTATUS_CACHEFILENAMEAVAILABLE:
255 ODS(
"Cache file name available...\n");
256 if ( m_request->stream ) m_request->stream->signalCacheFilename( szStatusText );
259 case BINDSTATUS_RAWMIMETYPE:
263 case BINDSTATUS_ACCEPTRANGES:
268 ODS(
"Unknown binding status code!\n");
284 ActiveXBindStatusCallback::OnStopBinding(HRESULT hrStatus, LPCWSTR pszError)
286 if ( m_request->stream ) m_request->stream->signalRequestCompleted( m_request, !FAILED(hrStatus) );
290 m_pbinding->Release();
294 ODS(
"OnStopBinding\n");
303 ActiveXBindStatusCallback::GetBindInfo(DWORD* pgrfBINDF, BINDINFO* pbindInfo)
305 *pgrfBINDF = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA;
306 if ( m_request->stream && m_request->stream->isCached() ) *pgrfBINDF |= BINDF_NEEDFILE;
307 else *pgrfBINDF |= BINDF_NOWRITECACHE | BINDF_PRAGMA_NO_CACHE | BINDF_GETNEWESTVERSION;
310 pbindInfo->cbSize =
sizeof(BINDINFO);
311 pbindInfo->dwBindVerb = m_dwAction;
312 pbindInfo->szExtraInfo = NULL;
315 memset(&pbindInfo->stgmedData, 0,
sizeof(STGMEDIUM));
316 pbindInfo->grfBindInfoF = 0;
317 pbindInfo->szCustomVerb = NULL;
326 pbindInfo->stgmedData.tymed = TYMED_HGLOBAL;
327 pbindInfo->stgmedData.hGlobal = m_hDataToPost;
328 pbindInfo->stgmedData.pUnkForRelease = (LPUNKNOWN)(LPBINDSTATUSCALLBACK)
this;
330 pbindInfo->cbstgmedData =
348 ActiveXBindStatusCallback::OnDataAvailable(DWORD grfBSCF, DWORD dwSize, FORMATETC* pfmtetc, STGMEDIUM* pstgmed)
352 if (BSCF_FIRSTDATANOTIFICATION & grfBSCF)
355 if (!m_pstm && pstgmed->tymed == TYMED_ISTREAM)
357 m_pstm = pstgmed->pstm;
362 if (m_pstm && dwSize > m_cbOld)
364 DWORD dwRead = dwSize - m_cbOld;
365 DWORD dwActuallyRead = 0;
369 if ( GetInfo( HTTP_QUERY_CONTENT_RANGE, data ) )
371 size_t endPos = data.find(
"-" );
372 if ( endPos != std::string::npos )
375 offset = atol( data.substr(startPos, endPos - startPos).c_str() );
382 boost::shared_array<char> cur(
new char[dwRead]);
384 hr = m_pstm->Read( cur.get(), dwRead, &dwActuallyRead);
387 if (dwActuallyRead > 0)
389 if ( m_request->stream ) m_request->stream->signalDataArrived( cur.get(), dwActuallyRead, offset + m_cbOld );
390 m_cbOld += dwActuallyRead;
393 }
while (!(hr == E_PENDING || hr == S_FALSE) && SUCCEEDED(hr));
397 if (BSCF_LASTDATANOTIFICATION & grfBSCF)
408 ODS(
"OnProgress: Last notification\n");
418 ActiveXBindStatusCallback::OnObjectAvailable(REFIID riid, IUnknown* punk)
426 STDMETHODIMP ActiveXBindStatusCallback::BeginningTransaction(LPCWSTR szURL,
429 LPWSTR __RPC_FAR *pszAdditionalHeaders)
432 if (!pszAdditionalHeaders)
437 *pszAdditionalHeaders = NULL;
439 std::wstringstream extraHeaders;
441 extraHeaders << L
"Accept-Encoding: identity\r\n";
443 if ( m_request->ranges.size() )
445 extraHeaders << L
"Range: bytes=";
446 for ( std::vector<BrowserStream::Range>::const_iterator it = m_request->ranges.begin(); it != m_request->ranges.end(); ++it )
448 extraHeaders << it->start << L
"-" << (it->end - 1);
449 if ( (it+1) != m_request->ranges.end() ) extraHeaders << L
",";
451 extraHeaders << L
"\r\n";
455 if (BINDVERB_POST == m_dwAction && m_hDataToPost)
457 extraHeaders << L
"Content-Type: application/x-www-form-urlencoded\r\n";
460 LPWSTR wszAdditionalHeaders =
461 (LPWSTR)CoTaskMemAlloc((extraHeaders.str().size()+1) *
sizeof(WCHAR));
462 if (!wszAdditionalHeaders)
464 return E_OUTOFMEMORY;
467 wcscpy(wszAdditionalHeaders, extraHeaders.str().c_str());
468 *pszAdditionalHeaders = wszAdditionalHeaders;
470 m_transactionStarted =
true;
478 STDMETHODIMP ActiveXBindStatusCallback::OnResponse( DWORD dwResponseCode,
479 LPCWSTR szResponseHeaders,
480 LPCWSTR szRequestHeaders,
481 LPWSTR __RPC_FAR *pszAdditionalRequestHeaders)
483 if (!pszAdditionalRequestHeaders)
488 *pszAdditionalRequestHeaders = NULL;
490 if ( m_request->stream )
494 bool requestedSeekable = m_request->stream->isSeekableRequested();
497 if ( GetInfo( HTTP_QUERY_CONTENT_LENGTH, data ) ) m_request->stream->setLength( atol( data.c_str() ) );
498 if ( GetInfo( HTTP_QUERY_CONTENT_TYPE, data ) ) m_request->stream->setMimeType( data );
499 if ( GetInfo( HTTP_QUERY_ACCEPT_RANGES, data ) ) m_request->stream->setSeekableByServer( data ==
"bytes" );
501 bool ok = ( dwResponseCode >= 200 && dwResponseCode < 300 );
502 if ( requestedSeekable && !m_request->stream->isSeekableByServer() ) ok =
false;
506 if ( !m_request->stream->isOpen() ) m_request->stream->signalOpened();
511 m_request->stream->signalFailedOpen();
520 bool ActiveXBindStatusCallback::GetInfo(DWORD which, std::string& result)
524 DWORD bufferSize = 2048;
525 boost::scoped_array<char> buffer(
new char[bufferSize]);
528 CComPtr<IWinInetHttpInfo> httpInfo;
529 if ( !FAILED(m_pbinding->QueryInterface( &httpInfo ) ) )
531 ok = ( S_OK == httpInfo->QueryInfo( which, &buffer[0], &bufferSize, &flags, 0 ) );
533 result = std::string( buffer.get(), bufferSize );
539 bool ActiveXBindStatusCallback::close()
541 HRESULT hr = m_pbinding->Abort();
542 return (!FAILED( hr )) || ( hr == S_FALSE ) || ( hr == INET_E_RESULT_DISPATCHED );
546 ActiveXStreamRequest::ActiveXStreamRequest( ActiveXStreamPtr Stream ) : stream(Stream)
550 ActiveXStreamRequest::ActiveXStreamRequest( ActiveXStreamPtr Stream,
const std::vector<BrowserStream::Range>& Ranges ) : stream(Stream), ranges(Ranges)
554 bool ActiveXStreamRequest::start()
556 std::string url = stream->getUrl();
557 std::wstring wideUrl( url.begin(), url.end() );
559 if ( FAILED( ActiveXBindStatusCallback::Create( &bindStatusCallback, shared_from_this() )) )
return false;
560 if ( FAILED( CreateURLMonikerEx(0, wideUrl.c_str(), &FMoniker, URL_MK_UNIFORM) ) )
return false;
561 if ( FAILED( CreateAsyncBindCtx(0, bindStatusCallback, 0, &FBindCtx) ) )
return false;
562 if ( FAILED( IsValidURL(FBindCtx, wideUrl.c_str(), 0) ) )
return false;
563 HRESULT hr = FMoniker->BindToStorage(FBindCtx, 0, IID_IStream, (
void**)&fstream);
565 if ( FAILED(hr) && (hr != MK_S_ASYNCHRONOUS) )
return false;
570 bool ActiveXStreamRequest::stop()
572 if ( !bindStatusCallback )
return true;
573 bool retVal = bindStatusCallback->close();
574 bindStatusCallback.Release();
std::string wstring_to_utf8(const std::wstring &src)
Accepts a std::wstring and returns a UTF8-encoded std::string.