1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
22 * Adam Lock <adamlock@eircom.net>
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
41 #include "Pluginhostctrl.h"
42 #include "nsPluginHostWnd.h"
43 #include "nsURLDataCallback.h"
46 /////////////////////////////////////////////////////////////////////////////
49 nsURLDataCallback::nsURLDataCallback() :
52 m_szContentType(NULL
),
57 m_bSaveToTempFile(FALSE
),
58 m_bNotifyOnWrite(TRUE
),
59 m_szTempFileName(NULL
),
62 memset(&m_NPStream
, 0, sizeof(m_NPStream
));
63 m_NPStream
.ndata
= this;
66 nsURLDataCallback::~nsURLDataCallback()
74 remove(m_szTempFileName
);
78 free(m_szTempFileName
);
82 void nsURLDataCallback::SetPostData(const void *pData
, unsigned long nSize
)
84 // Copy the post data into an HGLOBAL so it can be given to the
85 // bind object during the call to GetBindInfo
88 GlobalFree(m_hPostData
);
93 m_hPostData
= GlobalAlloc(GHND
, nSize
);
96 void *pPostData
= GlobalLock(m_hPostData
);
98 memcpy(pPostData
, pData
, nSize
);
99 GlobalUnlock(m_hPostData
);
104 HRESULT
nsURLDataCallback::OpenURL(nsPluginHostWnd
*pOwner
, const TCHAR
*szURL
, void *pNotifyData
, const void *pPostData
, unsigned long nPostDataSize
)
106 // Create the callback object
107 CComObject
<nsURLDataCallback
> *pCallback
= NULL
;
108 CComObject
<nsURLDataCallback
>::CreateInstance(&pCallback
);
111 return E_OUTOFMEMORY
;
116 pCallback
->SetOwner(pOwner
);
117 pCallback
->SetNotifyData(pNotifyData
);
118 if (pPostData
&& nPostDataSize
> 0)
120 pCallback
->SetPostData(pPostData
, nPostDataSize
);
124 pCallback
->SetURL(T2CA(szURL
));
126 // Create an object window on this thread that will be sent messages when
127 // something happens on the worker thread.
128 RECT rcPos
= {0, 0, 10, 10};
129 pCallback
->Create(HWND_DESKTOP
, rcPos
);
131 // Start the worker thread
132 _beginthread(StreamThread
, 0, pCallback
);
137 void __cdecl
nsURLDataCallback::StreamThread(void *pData
)
139 HRESULT hr
= CoInitialize(NULL
);
140 ATLASSERT(SUCCEEDED(hr
));
142 CComObject
<nsURLDataCallback
> *pThis
= (CComObject
<nsURLDataCallback
> *) pData
;
145 hr
= URLOpenStream(NULL
, pThis
->m_szURL
, 0, static_cast<IBindStatusCallback
*>(pThis
));
146 ATLASSERT(SUCCEEDED(hr
));
148 // Pump messages until WM_QUIT arrives
153 if (PeekMessage(&msg
, NULL
, 0, 0, PM_NOREMOVE
))
155 if (GetMessage(&msg
, NULL
, 0, 0))
157 DispatchMessage(&msg
);
170 ///////////////////////////////////////////////////////////////////////////////
171 // Windows message handlers
173 LRESULT
nsURLDataCallback::OnNPPNewStream(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
175 _NewStreamData
*pNewStreamData
= (_NewStreamData
*) lParam
;
177 // Notify the plugin that a new stream has been created
178 if (m_pOwner
->m_NPPFuncs
.newstream
)
180 NPError npres
= m_pOwner
->m_NPPFuncs
.newstream(
182 pNewStreamData
->contenttype
,
183 pNewStreamData
->stream
,
184 pNewStreamData
->seekable
,
185 pNewStreamData
->stype
);
187 // How does the plugin want its data?
188 switch (*(pNewStreamData
->stype
))
191 m_bSaveToTempFile
= FALSE
;
192 m_bNotifyOnWrite
= TRUE
;
195 m_bNotifyOnWrite
= FALSE
;
196 m_bSaveToTempFile
= TRUE
;
199 m_bNotifyOnWrite
= TRUE
;
200 m_bSaveToTempFile
= TRUE
;
211 LRESULT
nsURLDataCallback::OnNPPDestroyStream(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
213 _DestroyStreamData
*pDestroyStreamData
= (_DestroyStreamData
*) lParam
;
215 // Tell the plugin the name of the temporary file containing the data
216 if (m_bSaveToTempFile
)
224 // Determine whether the plugin should be told the name of the temp
225 // file depending on whether it completed properly or not.
226 char *szTempFileName
= NULL
;
227 if (pDestroyStreamData
->reason
== NPRES_DONE
&&
230 szTempFileName
= m_szTempFileName
;
234 if (m_pOwner
->m_NPPFuncs
.asfile
)
236 m_pOwner
->m_NPPFuncs
.asfile(
237 pDestroyStreamData
->npp
,
238 pDestroyStreamData
->stream
,
242 // Remove the file if it wasn't passed into the plugin
243 if (!szTempFileName
||
244 !m_pOwner
->m_NPPFuncs
.asfile
)
246 remove(szTempFileName
);
249 // Cleanup strings & pointers
250 if (m_szTempFileName
)
252 free(m_szTempFileName
);
253 m_szTempFileName
= NULL
;
258 // Notify the plugin that the stream has been closed
259 if (m_pOwner
->m_NPPFuncs
.destroystream
)
261 m_pOwner
->m_NPPFuncs
.destroystream(
262 pDestroyStreamData
->npp
,
263 pDestroyStreamData
->stream
,
264 pDestroyStreamData
->reason
);
270 LRESULT
nsURLDataCallback::OnNPPURLNotify(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
272 _UrlNotifyData
*pUrlNotifyData
= (_UrlNotifyData
*) lParam
;
274 // Notify the plugin that the url has loaded
275 if (m_pNotifyData
&& m_pOwner
->m_NPPFuncs
.urlnotify
)
277 m_pOwner
->m_NPPFuncs
.urlnotify(
280 pUrlNotifyData
->reason
,
281 pUrlNotifyData
->notifydata
);
286 LRESULT
nsURLDataCallback::OnNPPWriteReady(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
288 _WriteReadyData
*pWriteReadyData
= (_WriteReadyData
*) lParam
;
289 if (m_pOwner
->m_NPPFuncs
.writeready
&&
292 pWriteReadyData
->result
= m_pOwner
->m_NPPFuncs
.writeready(
293 pWriteReadyData
->npp
,
294 pWriteReadyData
->stream
);
300 LRESULT
nsURLDataCallback::OnNPPWrite(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
302 _WriteData
*pWriteData
= (_WriteData
*) lParam
;
304 #ifdef DUMP_STREAM_DATA_AS_HEX
305 // Dumps out the data to the display so you can see it's correct as its
306 // fed into the plugin.
307 const int kLineBreakAfter
= 16;
308 const int kSpaceBreakAfter
= 8;
309 ATLTRACE(_T("nsURLDataCallback::OnNPPWrite()\n"));
310 for (int i
= 0; i
< pWriteData
->len
; i
++)
314 if (i
% kLineBreakAfter
== 0)
316 _stprintf(szLine
, _T("%04x "), i
);
318 unsigned char b
= ((unsigned char *) pWriteData
->buffer
)[i
];
319 _stprintf(szTmp
, _T("%02X "), (unsigned int) b
);
320 _tcscat(szLine
, szTmp
);
322 if (i
== pWriteData
->len
- 1 ||
323 i
% kLineBreakAfter
== kLineBreakAfter
- 1)
325 _tcscat(szLine
, _T("\n"));
328 else if (i
% kSpaceBreakAfter
== kSpaceBreakAfter
- 1)
330 _tcscat(szLine
, _T(" "));
333 ATLTRACE(_T("--\n"));
336 if (m_bSaveToTempFile
)
338 if (!m_szTempFileName
)
340 m_szTempFileName
= strdup(_tempnam(NULL
, "moz"));
344 m_pTempFile
= fopen(m_szTempFileName
, "wb");
346 ATLASSERT(m_pTempFile
);
349 fwrite(pWriteData
->buffer
, 1, pWriteData
->len
, m_pTempFile
);
353 if (m_pOwner
->m_NPPFuncs
.write
&&
356 int32 nConsumed
= m_pOwner
->m_NPPFuncs
.write(
364 // TODO destroy the stream!
366 ATLASSERT(nConsumed
== pWriteData
->len
);
371 LRESULT
nsURLDataCallback::OnClassCreatePluginInstance(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
373 // Test whether the plugin for this content type exists or not and if not,
374 // create it right now.
375 if (!m_pOwner
->m_bPluginIsAlive
&&
376 m_pOwner
->m_bCreatePluginFromStreamData
)
378 if (FAILED(m_pOwner
->LoadPluginByContentType(A2CT(m_szContentType
))) ||
379 FAILED(m_pOwner
->CreatePluginInstance()))
387 LRESULT
nsURLDataCallback::OnClassCleanup(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
394 ///////////////////////////////////////////////////////////////////////////////
395 // IBindStatusCallback implementation
397 HRESULT STDMETHODCALLTYPE
nsURLDataCallback::OnStartBinding(
398 /* [in] */ DWORD dwReserved
,
399 /* [in] */ IBinding __RPC_FAR
*pib
)
401 ATLTRACE(_T("nsURLDataCallback::OnStartBinding()\n"));
406 HRESULT STDMETHODCALLTYPE
nsURLDataCallback::GetPriority(
407 /* [out] */ LONG __RPC_FAR
*pnPriority
)
412 HRESULT STDMETHODCALLTYPE
nsURLDataCallback::OnLowResource(
413 /* [in] */ DWORD reserved
)
418 HRESULT STDMETHODCALLTYPE
nsURLDataCallback::OnProgress(
419 /* [in] */ ULONG ulProgress
,
420 /* [in] */ ULONG ulProgressMax
,
421 /* [in] */ ULONG ulStatusCode
,
422 /* [in] */ LPCWSTR szStatusText
)
424 switch (ulStatusCode
)
426 case BINDSTATUS_BEGINDOWNLOADDATA
:
427 case BINDSTATUS_REDIRECTING
:
430 SetURL(W2A(szStatusText
));
434 case BINDSTATUS_MIMETYPEAVAILABLE
:
437 SetContentType(W2A(szStatusText
));
442 m_nDataMax
= ulProgressMax
;
446 HRESULT STDMETHODCALLTYPE
nsURLDataCallback::OnStopBinding(
447 /* [in] */ HRESULT hresult
,
448 /* [unique][in] */ LPCWSTR szError
)
450 ATLTRACE(_T("nsURLDataCallback::OnStopBinding()\n"));
451 if (m_pOwner
&& m_pOwner
->m_bPluginIsAlive
)
453 // TODO check for aborted ops and send NPRES_USER_BREAK
454 NPReason reason
= SUCCEEDED(hresult
) ? NPRES_DONE
: NPRES_NETWORK_ERR
;
456 // Notify the plugin that the stream has been closed
457 _DestroyStreamData destroyStreamData
;
458 destroyStreamData
.npp
= &m_pOwner
->m_NPP
;
459 destroyStreamData
.stream
= &m_NPStream
;
460 destroyStreamData
.reason
= reason
;
461 SendMessage(WM_NPP_DESTROYSTREAM
, 0, (LPARAM
) &destroyStreamData
);
463 // Notify the plugin that the url has loaded
464 _UrlNotifyData urlNotifyData
;
465 urlNotifyData
.npp
= &m_pOwner
->m_NPP
;
466 urlNotifyData
.url
= m_szURL
;
467 urlNotifyData
.reason
= reason
;
468 urlNotifyData
.notifydata
= m_pNotifyData
;
469 SendMessage(WM_NPP_URLNOTIFY
, 0, (LPARAM
) &urlNotifyData
);
472 m_cpBinding
.Release();
474 SendMessage(WM_CLASS_CLEANUP
);
480 /* [local] */ HRESULT STDMETHODCALLTYPE
nsURLDataCallback::GetBindInfo(
481 /* [out] */ DWORD __RPC_FAR
*grfBINDF
,
482 /* [unique][out][in] */ BINDINFO __RPC_FAR
*pbindinfo
)
484 *grfBINDF
= BINDF_ASYNCHRONOUS
| BINDF_ASYNCSTORAGE
|
485 BINDF_GETNEWESTVERSION
;
487 ULONG cbSize
= pbindinfo
->cbSize
;
488 memset(pbindinfo
, 0, cbSize
); // zero out structure
489 pbindinfo
->cbSize
= cbSize
;
492 pbindinfo
->dwBindVerb
= BINDVERB_POST
;
493 pbindinfo
->stgmedData
.tymed
= TYMED_HGLOBAL
;
494 pbindinfo
->stgmedData
.hGlobal
= m_hPostData
;
498 pbindinfo
->dwBindVerb
= BINDVERB_GET
;
504 /* [local] */ HRESULT STDMETHODCALLTYPE
nsURLDataCallback::OnDataAvailable(
505 /* [in] */ DWORD grfBSCF
,
506 /* [in] */ DWORD dwSize
,
507 /* [in] */ FORMATETC __RPC_FAR
*pformatetc
,
508 /* [in] */ STGMEDIUM __RPC_FAR
*pstgmed
)
510 ATLTRACE(_T("nsURLDataCallback::OnDataAvailable()\n"));
511 if (pstgmed
->tymed
!= TYMED_ISTREAM
||
521 // Notify the plugin that a stream has been opened
522 if (grfBSCF
& BSCF_FIRSTDATANOTIFICATION
)
526 // Test if there is a plugin yet. If not try and create one for this
528 if (SendMessage(WM_CLASS_CREATEPLUGININSTANCE
))
530 m_cpBinding
->Abort();
534 // Tell the plugin that there is a new stream of data
535 m_NPStream
.url
= m_szURL
;
537 m_NPStream
.lastmodified
= 0;
538 m_NPStream
.notifyData
= m_pNotifyData
;
540 uint16 stype
= NP_NORMAL
;
541 _NewStreamData newStreamData
;
542 newStreamData
.npp
= &m_pOwner
->m_NPP
;
543 newStreamData
.contenttype
= m_szContentType
;
544 newStreamData
.stream
= &m_NPStream
;
545 newStreamData
.seekable
= FALSE
;
546 newStreamData
.stype
= &stype
;
547 SendMessage(WM_NPP_NEWSTREAM
, 0, (LPARAM
) &newStreamData
);
549 if (!m_pOwner
->m_bPluginIsAlive
)
554 m_NPStream
.end
= m_nDataMax
;
556 ATLTRACE(_T("Data for stream %s (%d of %d bytes are available)\n"), m_szURL
, dwSize
, m_NPStream
.end
);
558 // Feed the stream data into the plugin
561 while (m_nDataPos
< dwSize
)
563 ULONG nBytesToRead
= dwSize
- m_nDataPos
;
564 ULONG nBytesRead
= 0;
566 if (nBytesToRead
> sizeof(bData
))
568 nBytesToRead
= sizeof(bData
);
571 // How many bytes can the plugin cope with?
572 _WriteReadyData writeReadyData
;
573 writeReadyData
.npp
= &m_pOwner
->m_NPP
;
574 writeReadyData
.stream
= &m_NPStream
;
575 writeReadyData
.result
= nBytesToRead
;
576 SendMessage(WM_NPP_WRITEREADY
, 0, (LPARAM
) &writeReadyData
);
577 if (nBytesToRead
> writeReadyData
.result
)
579 nBytesToRead
= writeReadyData
.result
;
583 ATLTRACE(_T(" Reading %d bytes\n"), (int) nBytesToRead
);
584 hr
= pstgmed
->pstm
->Read(&bData
, nBytesToRead
, &nBytesRead
);
586 _WriteData writeData
;
587 writeData
.npp
= &m_pOwner
->m_NPP
;
588 writeData
.stream
= &m_NPStream
;
589 writeData
.offset
= m_nDataPos
;
590 writeData
.len
= nBytesRead
;
591 writeData
.buffer
= bData
;
592 SendMessage(WM_NPP_WRITE
, 0, (LPARAM
) &writeData
);
594 m_nDataPos
+= nBytesRead
;
600 HRESULT STDMETHODCALLTYPE
nsURLDataCallback::OnObjectAvailable(
601 /* [in] */ REFIID riid
,
602 /* [iid_is][in] */ IUnknown __RPC_FAR
*punk
)
607 ///////////////////////////////////////////////////////////////////////////////
608 // IAuthenticate implementation
610 HRESULT STDMETHODCALLTYPE
nsURLDataCallback::Authenticate(
611 /* [out] */ HWND __RPC_FAR
*phwnd
,
612 /* [out] */ LPWSTR __RPC_FAR
*pszUsername
,
613 /* [out] */ LPWSTR __RPC_FAR
*pszPassword
)
615 ATLTRACE(_T("nsURLDataCallback::Authenticate()\n"));
617 // Caller wants to pose a password dialog so get a parent HWND for it.
618 *phwnd
= HWND_DESKTOP
;
621 *phwnd
= m_pOwner
->m_hWnd
;
622 CComPtr
<IWebBrowserApp
> cpBrowser
;
623 m_pOwner
->GetWebBrowserApp(&cpBrowser
);
627 cpBrowser
->get_HWND(&hwnd
);
630 *phwnd
= (HWND
) hwnd
;
635 // Caller will figure these out for itself