msxml3: Corrected Entity Reference Test.
[wine.git] / dlls / mshtml / navigate.c
blobcc48b9330bd91ac1a22b498ae76a3d162ff01fdd
1 /*
2 * Copyright 2006-2007 Jacek Caban for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "config.h"
21 #include <stdarg.h>
23 #define COBJMACROS
24 #define NONAMELESSUNION
25 #define NONAMELESSSTRUCT
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winuser.h"
30 #include "ole2.h"
31 #include "hlguids.h"
32 #include "shlguid.h"
34 #include "wine/debug.h"
35 #include "wine/unicode.h"
37 #include "mshtml_private.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
41 #define CONTENT_LENGTH "Content-Length"
42 #define UTF16_STR "utf-16"
44 #define NSINSTREAM(x) ((nsIInputStream*) &(x)->lpInputStreamVtbl)
46 #define NSINSTREAM_THIS(iface) DEFINE_THIS(nsProtocolStream, InputStream, iface)
48 static nsresult NSAPI nsInputStream_QueryInterface(nsIInputStream *iface, nsIIDRef riid,
49 nsQIResult result)
51 nsProtocolStream *This = NSINSTREAM_THIS(iface);
53 *result = NULL;
55 if(IsEqualGUID(&IID_nsISupports, riid)) {
56 TRACE("(%p)->(IID_nsISupports %p)\n", This, result);
57 *result = NSINSTREAM(This);
58 }else if(IsEqualGUID(&IID_nsIInputStream, riid)) {
59 TRACE("(%p)->(IID_nsIInputStream %p)\n", This, result);
60 *result = NSINSTREAM(This);
63 if(*result) {
64 nsIInputStream_AddRef(NSINSTREAM(This));
65 return NS_OK;
68 WARN("unsupported interface %s\n", debugstr_guid(riid));
69 return NS_NOINTERFACE;
72 static nsrefcnt NSAPI nsInputStream_AddRef(nsIInputStream *iface)
74 nsProtocolStream *This = NSINSTREAM_THIS(iface);
75 LONG ref = InterlockedIncrement(&This->ref);
77 TRACE("(%p) ref=%d\n", This, ref);
79 return ref;
83 static nsrefcnt NSAPI nsInputStream_Release(nsIInputStream *iface)
85 nsProtocolStream *This = NSINSTREAM_THIS(iface);
86 LONG ref = InterlockedDecrement(&This->ref);
88 TRACE("(%p) ref=%d\n", This, ref);
90 if(!ref)
91 heap_free(This);
93 return ref;
96 static nsresult NSAPI nsInputStream_Close(nsIInputStream *iface)
98 nsProtocolStream *This = NSINSTREAM_THIS(iface);
99 FIXME("(%p)\n", This);
100 return NS_ERROR_NOT_IMPLEMENTED;
103 static nsresult NSAPI nsInputStream_Available(nsIInputStream *iface, PRUint32 *_retval)
105 nsProtocolStream *This = NSINSTREAM_THIS(iface);
106 FIXME("(%p)->(%p)\n", This, _retval);
107 return NS_ERROR_NOT_IMPLEMENTED;
110 static nsresult NSAPI nsInputStream_Read(nsIInputStream *iface, char *aBuf, PRUint32 aCount,
111 PRUint32 *_retval)
113 nsProtocolStream *This = NSINSTREAM_THIS(iface);
115 TRACE("(%p)->(%p %d %p)\n", This, aBuf, aCount, _retval);
117 /* Gecko always calls Read with big enough buffer */
118 if(aCount < This->buf_size)
119 FIXME("aCount < This->buf_size\n");
121 *_retval = This->buf_size;
122 if(This->buf_size)
123 memcpy(aBuf, This->buf, This->buf_size);
124 This->buf_size = 0;
126 return NS_OK;
129 static nsresult NSAPI nsInputStream_ReadSegments(nsIInputStream *iface,
130 nsresult (WINAPI *aWriter)(nsIInputStream*,void*,const char*,PRUint32,PRUint32,PRUint32*),
131 void *aClousure, PRUint32 aCount, PRUint32 *_retval)
133 nsProtocolStream *This = NSINSTREAM_THIS(iface);
134 PRUint32 written = 0;
135 nsresult nsres;
137 TRACE("(%p)->(%p %p %d %p)\n", This, aWriter, aClousure, aCount, _retval);
139 if(!This->buf_size)
140 return S_OK;
142 if(This->buf_size > aCount)
143 FIXME("buf_size > aCount\n");
145 nsres = aWriter(NSINSTREAM(This), aClousure, This->buf, 0, This->buf_size, &written);
146 if(NS_FAILED(nsres))
147 TRACE("aWritter failed: %08x\n", nsres);
148 else if(written != This->buf_size)
149 FIXME("written %d != buf_size %d\n", written, This->buf_size);
151 This->buf_size -= written;
153 *_retval = written;
154 return nsres;
157 static nsresult NSAPI nsInputStream_IsNonBlocking(nsIInputStream *iface, PRBool *_retval)
159 nsProtocolStream *This = NSINSTREAM_THIS(iface);
160 FIXME("(%p)->(%p)\n", This, _retval);
161 return NS_ERROR_NOT_IMPLEMENTED;
164 #undef NSINSTREAM_THIS
166 static const nsIInputStreamVtbl nsInputStreamVtbl = {
167 nsInputStream_QueryInterface,
168 nsInputStream_AddRef,
169 nsInputStream_Release,
170 nsInputStream_Close,
171 nsInputStream_Available,
172 nsInputStream_Read,
173 nsInputStream_ReadSegments,
174 nsInputStream_IsNonBlocking
177 static nsProtocolStream *create_nsprotocol_stream(void)
179 nsProtocolStream *ret = heap_alloc(sizeof(nsProtocolStream));
181 ret->lpInputStreamVtbl = &nsInputStreamVtbl;
182 ret->ref = 1;
183 ret->buf_size = 0;
185 return ret;
188 static HRESULT read_stream_data(BSCallback *This, IStream *stream)
190 nsresult nsres;
191 HRESULT hres;
193 if(!This->nslistener) {
194 BYTE buf[1024];
195 DWORD read;
197 do {
198 read = 0;
199 hres = IStream_Read(stream, buf, sizeof(buf), &read);
200 }while(hres == S_OK && read);
202 return S_OK;
205 if(!This->nsstream)
206 This->nsstream = create_nsprotocol_stream();
208 do {
209 hres = IStream_Read(stream, This->nsstream->buf, sizeof(This->nsstream->buf),
210 &This->nsstream->buf_size);
211 if(!This->nsstream->buf_size)
212 break;
214 if(!This->readed && This->nsstream->buf_size >= 2 && *(WORD*)This->nsstream->buf == 0xfeff) {
215 This->nschannel->charset = heap_alloc(sizeof(UTF16_STR));
216 memcpy(This->nschannel->charset, UTF16_STR, sizeof(UTF16_STR));
219 if(!This->readed) {
220 nsres = nsIStreamListener_OnStartRequest(This->nslistener,
221 (nsIRequest*)NSCHANNEL(This->nschannel), This->nscontext);
222 if(NS_FAILED(nsres))
223 FIXME("OnStartRequest failed: %08x\n", nsres);
225 /* events are reset when a new document URI is loaded, so re-initialise them here */
226 if(This->doc && This->doc->bscallback == This && This->doc->nscontainer)
227 init_nsevents(This->doc->nscontainer);
230 This->readed += This->nsstream->buf_size;
232 nsres = nsIStreamListener_OnDataAvailable(This->nslistener,
233 (nsIRequest*)NSCHANNEL(This->nschannel), This->nscontext,
234 NSINSTREAM(This->nsstream), This->readed-This->nsstream->buf_size,
235 This->nsstream->buf_size);
236 if(NS_FAILED(nsres))
237 ERR("OnDataAvailable failed: %08x\n", nsres);
239 if(This->nsstream->buf_size)
240 FIXME("buffer is not empty!\n");
241 }while(hres == S_OK);
243 return S_OK;
246 static void add_nsrequest(BSCallback *This)
248 if(This->nschannel && This->nschannel->load_group) {
249 nsresult nsres = nsILoadGroup_AddRequest(This->nschannel->load_group,
250 (nsIRequest*)NSCHANNEL(This->nschannel), This->nscontext);
252 if(NS_FAILED(nsres))
253 ERR("AddRequest failed:%08x\n", nsres);
257 static void on_stop_nsrequest(BSCallback *This) {
258 if(This->nslistener)
259 nsIStreamListener_OnStopRequest(This->nslistener, (nsIRequest*)NSCHANNEL(This->nschannel),
260 This->nscontext, NS_OK);
263 #define STATUSCLB_THIS(iface) DEFINE_THIS(BSCallback, BindStatusCallback, iface)
265 static HRESULT WINAPI BindStatusCallback_QueryInterface(IBindStatusCallback *iface,
266 REFIID riid, void **ppv)
268 BSCallback *This = STATUSCLB_THIS(iface);
270 *ppv = NULL;
271 if(IsEqualGUID(&IID_IUnknown, riid)) {
272 TRACE("(%p)->(IID_IUnknown, %p)\n", This, ppv);
273 *ppv = STATUSCLB(This);
274 }else if(IsEqualGUID(&IID_IBindStatusCallback, riid)) {
275 TRACE("(%p)->(IID_IBindStatusCallback, %p)\n", This, ppv);
276 *ppv = STATUSCLB(This);
277 }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
278 TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
279 *ppv = SERVPROV(This);
280 }else if(IsEqualGUID(&IID_IHttpNegotiate, riid)) {
281 TRACE("(%p)->(IID_IHttpNegotiate %p)\n", This, ppv);
282 *ppv = HTTPNEG(This);
283 }else if(IsEqualGUID(&IID_IHttpNegotiate2, riid)) {
284 TRACE("(%p)->(IID_IHttpNegotiate2 %p)\n", This, ppv);
285 *ppv = HTTPNEG(This);
286 }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
287 TRACE("(%p)->(IID_IInternetBindInfo %p)\n", This, ppv);
288 *ppv = BINDINFO(This);
291 if(*ppv) {
292 IBindStatusCallback_AddRef(STATUSCLB(This));
293 return S_OK;
296 TRACE("Unsupported riid = %s\n", debugstr_guid(riid));
297 return E_NOINTERFACE;
300 static ULONG WINAPI BindStatusCallback_AddRef(IBindStatusCallback *iface)
302 BSCallback *This = STATUSCLB_THIS(iface);
303 LONG ref = InterlockedIncrement(&This->ref);
305 TRACE("(%p) ref = %d\n", This, ref);
307 return ref;
310 static ULONG WINAPI BindStatusCallback_Release(IBindStatusCallback *iface)
312 BSCallback *This = STATUSCLB_THIS(iface);
313 LONG ref = InterlockedDecrement(&This->ref);
315 TRACE("(%p) ref = %d\n", This, ref);
317 if(!ref) {
318 if(This->post_data)
319 GlobalFree(This->post_data);
320 if(This->nschannel)
321 nsIChannel_Release(NSCHANNEL(This->nschannel));
322 if(This->nslistener)
323 nsIStreamListener_Release(This->nslistener);
324 if(This->nscontext)
325 nsISupports_Release(This->nscontext);
326 if(This->nsstream)
327 nsIInputStream_Release(NSINSTREAM(This->nsstream));
328 if(This->mon)
329 IMoniker_Release(This->mon);
330 if(This->binding)
331 IBinding_Release(This->binding);
332 list_remove(&This->entry);
333 heap_free(This->headers);
334 heap_free(This);
337 return ref;
340 static HRESULT WINAPI BindStatusCallback_OnStartBinding(IBindStatusCallback *iface,
341 DWORD dwReserved, IBinding *pbind)
343 BSCallback *This = STATUSCLB_THIS(iface);
345 TRACE("(%p)->(%d %p)\n", This, dwReserved, pbind);
347 IBinding_AddRef(pbind);
348 This->binding = pbind;
350 if(This->doc)
351 list_add_head(&This->doc->bindings, &This->entry);
353 add_nsrequest(This);
355 return S_OK;
358 static HRESULT WINAPI BindStatusCallback_GetPriority(IBindStatusCallback *iface, LONG *pnPriority)
360 BSCallback *This = STATUSCLB_THIS(iface);
361 FIXME("(%p)->(%p)\n", This, pnPriority);
362 return E_NOTIMPL;
365 static HRESULT WINAPI BindStatusCallback_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
367 BSCallback *This = STATUSCLB_THIS(iface);
368 FIXME("(%p)->(%d)\n", This, reserved);
369 return E_NOTIMPL;
372 static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
373 ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
375 BSCallback *This = STATUSCLB_THIS(iface);
377 TRACE("%p)->(%u %u %u %s)\n", This, ulProgress, ulProgressMax, ulStatusCode,
378 debugstr_w(szStatusText));
380 switch(ulStatusCode) {
381 case BINDSTATUS_MIMETYPEAVAILABLE: {
382 int len;
384 if(!This->nschannel)
385 return S_OK;
386 heap_free(This->nschannel->content);
388 len = WideCharToMultiByte(CP_ACP, 0, szStatusText, -1, NULL, 0, NULL, NULL);
389 This->nschannel->content = heap_alloc(len*sizeof(WCHAR));
390 WideCharToMultiByte(CP_ACP, 0, szStatusText, -1, This->nschannel->content, -1, NULL, NULL);
394 return S_OK;
397 static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallback *iface,
398 HRESULT hresult, LPCWSTR szError)
400 BSCallback *This = STATUSCLB_THIS(iface);
402 TRACE("(%p)->(%08x %s)\n", This, hresult, debugstr_w(szError));
404 if(This->binding) {
405 IBinding_Release(This->binding);
406 This->binding = NULL;
409 on_stop_nsrequest(This);
411 if(This->nslistener) {
412 if(This->nschannel->load_group) {
413 nsresult nsres;
415 nsres = nsILoadGroup_RemoveRequest(This->nschannel->load_group,
416 (nsIRequest*)NSCHANNEL(This->nschannel), NULL, NS_OK);
417 if(NS_FAILED(nsres))
418 ERR("RemoveRequest failed: %08x\n", nsres);
422 list_remove(&This->entry);
424 if(FAILED(hresult))
425 return S_OK;
427 if(This->doc && This->doc->bscallback == This && !This->doc->nscontainer) {
428 task_t *task = heap_alloc(sizeof(task_t));
430 task->doc = This->doc;
431 task->task_id = TASK_PARSECOMPLETE;
432 task->next = NULL;
435 * This should be done in the worker thread that parses HTML,
436 * but we don't have such thread.
438 push_task(task);
441 return S_OK;
444 static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallback *iface,
445 DWORD *grfBINDF, BINDINFO *pbindinfo)
447 BSCallback *This = STATUSCLB_THIS(iface);
448 DWORD size;
450 TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
452 *grfBINDF = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA;
454 size = pbindinfo->cbSize;
455 memset(pbindinfo, 0, size);
456 pbindinfo->cbSize = size;
458 pbindinfo->cbstgmedData = This->post_data_len;
459 pbindinfo->dwCodePage = CP_UTF8;
460 pbindinfo->dwOptions = 0x80000;
462 if(This->post_data) {
463 pbindinfo->dwBindVerb = BINDVERB_POST;
465 pbindinfo->stgmedData.tymed = TYMED_HGLOBAL;
466 pbindinfo->stgmedData.u.hGlobal = This->post_data;
467 pbindinfo->stgmedData.pUnkForRelease = (IUnknown*)STATUSCLB(This);
468 IBindStatusCallback_AddRef(STATUSCLB(This));
471 return S_OK;
474 static HRESULT WINAPI BindStatusCallback_OnDataAvailable(IBindStatusCallback *iface,
475 DWORD grfBSCF, DWORD dwSize, FORMATETC *pformatetc, STGMEDIUM *pstgmed)
477 BSCallback *This = STATUSCLB_THIS(iface);
479 TRACE("(%p)->(%08x %d %p %p)\n", This, grfBSCF, dwSize, pformatetc, pstgmed);
481 return read_stream_data(This, pstgmed->u.pstm);
484 static HRESULT WINAPI BindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface,
485 REFIID riid, IUnknown *punk)
487 BSCallback *This = STATUSCLB_THIS(iface);
488 FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), punk);
489 return E_NOTIMPL;
492 #undef STATUSCLB_THIS
494 static const IBindStatusCallbackVtbl BindStatusCallbackVtbl = {
495 BindStatusCallback_QueryInterface,
496 BindStatusCallback_AddRef,
497 BindStatusCallback_Release,
498 BindStatusCallback_OnStartBinding,
499 BindStatusCallback_GetPriority,
500 BindStatusCallback_OnLowResource,
501 BindStatusCallback_OnProgress,
502 BindStatusCallback_OnStopBinding,
503 BindStatusCallback_GetBindInfo,
504 BindStatusCallback_OnDataAvailable,
505 BindStatusCallback_OnObjectAvailable
508 #define HTTPNEG_THIS(iface) DEFINE_THIS(BSCallback, HttpNegotiate2, iface)
510 static HRESULT WINAPI HttpNegotiate_QueryInterface(IHttpNegotiate2 *iface,
511 REFIID riid, void **ppv)
513 BSCallback *This = HTTPNEG_THIS(iface);
514 return IBindStatusCallback_QueryInterface(STATUSCLB(This), riid, ppv);
517 static ULONG WINAPI HttpNegotiate_AddRef(IHttpNegotiate2 *iface)
519 BSCallback *This = HTTPNEG_THIS(iface);
520 return IBindStatusCallback_AddRef(STATUSCLB(This));
523 static ULONG WINAPI HttpNegotiate_Release(IHttpNegotiate2 *iface)
525 BSCallback *This = HTTPNEG_THIS(iface);
526 return IBindStatusCallback_Release(STATUSCLB(This));
529 static HRESULT WINAPI HttpNegotiate_BeginningTransaction(IHttpNegotiate2 *iface,
530 LPCWSTR szURL, LPCWSTR szHeaders, DWORD dwReserved, LPWSTR *pszAdditionalHeaders)
532 BSCallback *This = HTTPNEG_THIS(iface);
533 DWORD size;
535 TRACE("(%p)->(%s %s %d %p)\n", This, debugstr_w(szURL), debugstr_w(szHeaders),
536 dwReserved, pszAdditionalHeaders);
538 if(!This->headers) {
539 *pszAdditionalHeaders = NULL;
540 return S_OK;
543 size = (strlenW(This->headers)+1)*sizeof(WCHAR);
544 *pszAdditionalHeaders = CoTaskMemAlloc(size);
545 memcpy(*pszAdditionalHeaders, This->headers, size);
547 return S_OK;
550 static HRESULT WINAPI HttpNegotiate_OnResponse(IHttpNegotiate2 *iface, DWORD dwResponseCode,
551 LPCWSTR szResponseHeaders, LPCWSTR szRequestHeaders, LPWSTR *pszAdditionalRequestHeaders)
553 BSCallback *This = HTTPNEG_THIS(iface);
554 FIXME("(%p)->(%d %s %s %p)\n", This, dwResponseCode, debugstr_w(szResponseHeaders),
555 debugstr_w(szRequestHeaders), pszAdditionalRequestHeaders);
556 return E_NOTIMPL;
559 static HRESULT WINAPI HttpNegotiate_GetRootSecurityId(IHttpNegotiate2 *iface,
560 BYTE *pbSecurityId, DWORD *pcbSecurityId, DWORD_PTR dwReserved)
562 BSCallback *This = HTTPNEG_THIS(iface);
563 FIXME("(%p)->(%p %p %ld)\n", This, pbSecurityId, pcbSecurityId, dwReserved);
564 return E_NOTIMPL;
567 #undef HTTPNEG
569 static const IHttpNegotiate2Vtbl HttpNegotiate2Vtbl = {
570 HttpNegotiate_QueryInterface,
571 HttpNegotiate_AddRef,
572 HttpNegotiate_Release,
573 HttpNegotiate_BeginningTransaction,
574 HttpNegotiate_OnResponse,
575 HttpNegotiate_GetRootSecurityId
578 #define BINDINFO_THIS(iface) DEFINE_THIS(BSCallback, InternetBindInfo, iface)
580 static HRESULT WINAPI InternetBindInfo_QueryInterface(IInternetBindInfo *iface,
581 REFIID riid, void **ppv)
583 BSCallback *This = BINDINFO_THIS(iface);
584 return IBindStatusCallback_QueryInterface(STATUSCLB(This), riid, ppv);
587 static ULONG WINAPI InternetBindInfo_AddRef(IInternetBindInfo *iface)
589 BSCallback *This = BINDINFO_THIS(iface);
590 return IBindStatusCallback_AddRef(STATUSCLB(This));
593 static ULONG WINAPI InternetBindInfo_Release(IInternetBindInfo *iface)
595 BSCallback *This = BINDINFO_THIS(iface);
596 return IBindStatusCallback_Release(STATUSCLB(This));
599 static HRESULT WINAPI InternetBindInfo_GetBindInfo(IInternetBindInfo *iface,
600 DWORD *grfBINDF, BINDINFO *pbindinfo)
602 BSCallback *This = BINDINFO_THIS(iface);
603 FIXME("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
604 return E_NOTIMPL;
607 static HRESULT WINAPI InternetBindInfo_GetBindString(IInternetBindInfo *iface,
608 ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
610 BSCallback *This = BINDINFO_THIS(iface);
611 FIXME("(%p)->(%u %p %u %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
612 return E_NOTIMPL;
615 #undef BINDINFO_THIS
617 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
618 InternetBindInfo_QueryInterface,
619 InternetBindInfo_AddRef,
620 InternetBindInfo_Release,
621 InternetBindInfo_GetBindInfo,
622 InternetBindInfo_GetBindString
625 #define SERVPROV_THIS(iface) DEFINE_THIS(BSCallback, ServiceProvider, iface)
627 static HRESULT WINAPI BSCServiceProvider_QueryInterface(IServiceProvider *iface,
628 REFIID riid, void **ppv)
630 BSCallback *This = SERVPROV_THIS(iface);
631 return IBindStatusCallback_QueryInterface(STATUSCLB(This), riid, ppv);
634 static ULONG WINAPI BSCServiceProvider_AddRef(IServiceProvider *iface)
636 BSCallback *This = SERVPROV_THIS(iface);
637 return IBindStatusCallback_AddRef(STATUSCLB(This));
640 static ULONG WINAPI BSCServiceProvider_Release(IServiceProvider *iface)
642 BSCallback *This = SERVPROV_THIS(iface);
643 return IBindStatusCallback_Release(STATUSCLB(This));
646 static HRESULT WINAPI BSCServiceProvider_QueryService(IServiceProvider *iface,
647 REFGUID guidService, REFIID riid, void **ppv)
649 BSCallback *This = SERVPROV_THIS(iface);
650 TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
651 return E_NOINTERFACE;
654 #undef SERVPROV_THIS
656 static const IServiceProviderVtbl ServiceProviderVtbl = {
657 BSCServiceProvider_QueryInterface,
658 BSCServiceProvider_AddRef,
659 BSCServiceProvider_Release,
660 BSCServiceProvider_QueryService
663 BSCallback *create_bscallback(IMoniker *mon)
665 BSCallback *ret = heap_alloc(sizeof(BSCallback));
667 ret->lpBindStatusCallbackVtbl = &BindStatusCallbackVtbl;
668 ret->lpServiceProviderVtbl = &ServiceProviderVtbl;
669 ret->lpHttpNegotiate2Vtbl = &HttpNegotiate2Vtbl;
670 ret->lpInternetBindInfoVtbl = &InternetBindInfoVtbl;
671 ret->ref = 1;
672 ret->post_data = NULL;
673 ret->headers = NULL;
674 ret->post_data_len = 0;
675 ret->readed = 0;
676 ret->nschannel = NULL;
677 ret->nslistener = NULL;
678 ret->nscontext = NULL;
679 ret->nsstream = NULL;
680 ret->binding = NULL;
681 ret->doc = NULL;
683 list_init(&ret->entry);
685 if(mon)
686 IMoniker_AddRef(mon);
687 ret->mon = mon;
689 return ret;
692 /* Calls undocumented 84 cmd of CGID_ShellDocView */
693 static void call_docview_84(HTMLDocument *doc)
695 IOleCommandTarget *olecmd;
696 VARIANT var;
697 HRESULT hres;
699 if(!doc->client)
700 return;
702 hres = IOleClientSite_QueryInterface(doc->client, &IID_IOleCommandTarget, (void**)&olecmd);
703 if(FAILED(hres))
704 return;
706 VariantInit(&var);
707 hres = IOleCommandTarget_Exec(olecmd, &CGID_ShellDocView, 84, 0, NULL, &var);
708 IOleCommandTarget_Release(olecmd);
709 if(SUCCEEDED(hres) && V_VT(&var) != VT_NULL)
710 FIXME("handle result\n");
713 static void parse_post_data(nsIInputStream *post_data_stream, LPWSTR *headers_ret,
714 HGLOBAL *post_data_ret, ULONG *post_data_len_ret)
716 PRUint32 post_data_len = 0, available = 0;
717 HGLOBAL post_data = NULL;
718 LPWSTR headers = NULL;
719 DWORD headers_len = 0, len;
720 const char *ptr, *ptr2, *post_data_end;
722 nsIInputStream_Available(post_data_stream, &available);
723 post_data = GlobalAlloc(0, available+1);
724 nsIInputStream_Read(post_data_stream, post_data, available, &post_data_len);
726 TRACE("post_data = %s\n", debugstr_an(post_data, post_data_len));
728 ptr = ptr2 = post_data;
729 post_data_end = (const char*)post_data+post_data_len;
731 while(ptr < post_data_end && (*ptr != '\r' || ptr[1] != '\n')) {
732 while(ptr < post_data_end && (*ptr != '\r' || ptr[1] != '\n'))
733 ptr++;
735 if(!*ptr) {
736 FIXME("*ptr = 0\n");
737 return;
740 ptr += 2;
742 if(ptr-ptr2 >= sizeof(CONTENT_LENGTH)
743 && CompareStringA(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
744 CONTENT_LENGTH, sizeof(CONTENT_LENGTH)-1,
745 ptr2, sizeof(CONTENT_LENGTH)-1) == CSTR_EQUAL) {
746 ptr2 = ptr;
747 continue;
750 len = MultiByteToWideChar(CP_ACP, 0, ptr2, ptr-ptr2, NULL, 0);
752 if(headers)
753 headers = heap_realloc(headers,(headers_len+len+1)*sizeof(WCHAR));
754 else
755 headers = heap_alloc((len+1)*sizeof(WCHAR));
757 len = MultiByteToWideChar(CP_ACP, 0, ptr2, ptr-ptr2, headers+headers_len, -1);
758 headers_len += len;
760 ptr2 = ptr;
763 headers[headers_len] = 0;
764 *headers_ret = headers;
766 if(ptr >= post_data_end-2) {
767 GlobalFree(post_data);
768 return;
771 ptr += 2;
773 if(headers_len) {
774 post_data_len -= ptr-(const char*)post_data;
775 memmove(post_data, ptr, post_data_len);
776 post_data = GlobalReAlloc(post_data, post_data_len+1, 0);
779 *post_data_ret = post_data;
780 *post_data_len_ret = post_data_len;
783 void hlink_frame_navigate(HTMLDocument *doc, IHlinkFrame *hlink_frame,
784 LPCWSTR uri, nsIInputStream *post_data_stream, DWORD hlnf)
786 BSCallback *callback;
787 IBindCtx *bindctx;
788 IMoniker *mon;
789 IHlink *hlink;
790 HRESULT hr;
792 callback = create_bscallback(NULL);
794 if(post_data_stream) {
795 parse_post_data(post_data_stream, &callback->headers, &callback->post_data,
796 &callback->post_data_len);
797 TRACE("headers = %s post_data = %s\n", debugstr_w(callback->headers),
798 debugstr_an(callback->post_data, callback->post_data_len));
801 hr = CreateAsyncBindCtx(0, STATUSCLB(callback), NULL, &bindctx);
802 if (FAILED(hr)) {
803 IBindStatusCallback_Release(STATUSCLB(callback));
804 return;
807 hr = CoCreateInstance(&CLSID_StdHlink, NULL, CLSCTX_INPROC_SERVER, &IID_IHlink, (LPVOID*)&hlink);
808 if (FAILED(hr)) {
809 IBindCtx_Release(bindctx);
810 IBindStatusCallback_Release(STATUSCLB(callback));
811 return;
814 hr = CreateURLMoniker(NULL, uri, &mon);
815 if (SUCCEEDED(hr)) {
816 IHlink_SetMonikerReference(hlink, 0, mon, NULL);
818 if(hlnf & HLNF_OPENINNEWWINDOW) {
819 static const WCHAR wszBlank[] = {'_','b','l','a','n','k',0};
820 IHlink_SetTargetFrameName(hlink, wszBlank); /* FIXME */
823 IHlinkFrame_Navigate(hlink_frame, hlnf, bindctx, STATUSCLB(callback), hlink);
825 IMoniker_Release(mon);
828 IBindCtx_Release(bindctx);
829 IBindStatusCallback_Release(STATUSCLB(callback));
832 HRESULT start_binding(HTMLDocument *doc, BSCallback *bscallback, IBindCtx *bctx)
834 IStream *str = NULL;
835 HRESULT hres;
837 bscallback->doc = doc;
838 call_docview_84(bscallback->doc);
840 if(bctx) {
841 RegisterBindStatusCallback(bctx, STATUSCLB(bscallback), NULL, 0);
842 IBindCtx_AddRef(bctx);
843 }else {
844 hres = CreateAsyncBindCtx(0, STATUSCLB(bscallback), NULL, &bctx);
845 if(FAILED(hres)) {
846 WARN("CreateAsyncBindCtx failed: %08x\n", hres);
847 on_stop_nsrequest(bscallback);
848 return hres;
852 hres = IMoniker_BindToStorage(bscallback->mon, bctx, NULL, &IID_IStream, (void**)&str);
853 IBindCtx_Release(bctx);
854 if(FAILED(hres)) {
855 WARN("BindToStorage failed: %08x\n", hres);
856 on_stop_nsrequest(bscallback);
857 return hres;
860 if(str)
861 IStream_Release(str);
863 IMoniker_Release(bscallback->mon);
864 bscallback->mon = NULL;
866 return S_OK;
869 void set_document_bscallback(HTMLDocument *doc, BSCallback *callback)
871 BSCallback *iter;
873 if(doc->bscallback) {
874 if(doc->bscallback->binding)
875 IBinding_Abort(doc->bscallback->binding);
876 doc->bscallback->doc = NULL;
877 IBindStatusCallback_Release(STATUSCLB(doc->bscallback));
880 LIST_FOR_EACH_ENTRY(iter, &doc->bindings, BSCallback, entry) {
881 iter->doc = NULL;
882 list_remove(&iter->entry);
885 doc->bscallback = callback;
887 if(callback) {
888 IBindStatusCallback_AddRef(STATUSCLB(callback));
889 callback->doc = doc;
893 HRESULT load_stream(BSCallback *bscallback, IStream *stream)
895 HRESULT hres;
897 const char text_html[] = "text/html";
899 add_nsrequest(bscallback);
901 if(bscallback->nschannel) {
902 bscallback->nschannel->content = heap_alloc(sizeof(text_html));
903 memcpy(bscallback->nschannel->content, text_html, sizeof(text_html));
906 hres = read_stream_data(bscallback, stream);
907 IBindStatusCallback_OnStopBinding(STATUSCLB(bscallback), hres, ERROR_SUCCESS);
909 return hres;