mshtml: Added noscript tag handling tests.
[wine] / dlls / mshtml / htmllocation.c
1 /*
2  * Copyright 2008 Jacek Caban for CodeWeavers
3  *
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.
8  *
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.
13  *
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
17  */
18
19 #include <stdarg.h>
20
21 #define COBJMACROS
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winuser.h"
26 #include "winreg.h"
27 #include "ole2.h"
28 #include "wininet.h"
29 #include "shlwapi.h"
30
31 #include "wine/debug.h"
32
33 #include "mshtml_private.h"
34 #include "resource.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
37
38 static HRESULT get_url(HTMLLocation *This, const WCHAR **ret)
39 {
40     if(!This->window || !This->window->base.outer_window || !This->window->base.outer_window->url) {
41         FIXME("No current URL\n");
42         return E_NOTIMPL;
43     }
44
45     *ret = This->window->base.outer_window->url;
46     return S_OK;
47 }
48
49 static IUri *get_uri(HTMLLocation *This)
50 {
51     if(!This->window || !This->window->base.outer_window)
52         return NULL;
53     return This->window->base.outer_window->uri;
54 }
55
56 static HRESULT get_url_components(HTMLLocation *This, URL_COMPONENTSW *url)
57 {
58     const WCHAR *doc_url;
59     HRESULT hres;
60
61     hres = get_url(This, &doc_url);
62     if(FAILED(hres))
63         return hres;
64
65     if(!InternetCrackUrlW(doc_url, 0, 0, url)) {
66         FIXME("InternetCrackUrlW failed: 0x%08x\n", GetLastError());
67         SetLastError(0);
68         return E_FAIL;
69     }
70
71     return S_OK;
72 }
73
74 static inline HTMLLocation *impl_from_IHTMLLocation(IHTMLLocation *iface)
75 {
76     return CONTAINING_RECORD(iface, HTMLLocation, IHTMLLocation_iface);
77 }
78
79 static HRESULT WINAPI HTMLLocation_QueryInterface(IHTMLLocation *iface, REFIID riid, void **ppv)
80 {
81     HTMLLocation *This = impl_from_IHTMLLocation(iface);
82
83     *ppv = NULL;
84
85     if(IsEqualGUID(&IID_IUnknown, riid)) {
86         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
87         *ppv = &This->IHTMLLocation_iface;
88     }else if(IsEqualGUID(&IID_IHTMLLocation, riid)) {
89         TRACE("(%p)->(IID_IHTMLLocation %p)\n", This, ppv);
90         *ppv = &This->IHTMLLocation_iface;
91     }else if(dispex_query_interface(&This->dispex, riid, ppv)) {
92         return *ppv ? S_OK : E_NOINTERFACE;
93     }
94
95     if(*ppv) {
96         IUnknown_AddRef((IUnknown*)*ppv);
97         return S_OK;
98     }
99
100     WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
101     return E_NOINTERFACE;
102 }
103
104 static ULONG WINAPI HTMLLocation_AddRef(IHTMLLocation *iface)
105 {
106     HTMLLocation *This = impl_from_IHTMLLocation(iface);
107     LONG ref = InterlockedIncrement(&This->ref);
108
109     TRACE("(%p) ref=%d\n", This, ref);
110
111     return ref;
112 }
113
114 static ULONG WINAPI HTMLLocation_Release(IHTMLLocation *iface)
115 {
116     HTMLLocation *This = impl_from_IHTMLLocation(iface);
117     LONG ref = InterlockedDecrement(&This->ref);
118
119     TRACE("(%p) ref=%d\n", This, ref);
120
121     if(!ref) {
122         if(This->window)
123             This->window->location = NULL;
124         release_dispex(&This->dispex);
125         heap_free(This);
126     }
127
128     return ref;
129 }
130
131 static HRESULT WINAPI HTMLLocation_GetTypeInfoCount(IHTMLLocation *iface, UINT *pctinfo)
132 {
133     HTMLLocation *This = impl_from_IHTMLLocation(iface);
134     return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
135 }
136
137 static HRESULT WINAPI HTMLLocation_GetTypeInfo(IHTMLLocation *iface, UINT iTInfo,
138                                               LCID lcid, ITypeInfo **ppTInfo)
139 {
140     HTMLLocation *This = impl_from_IHTMLLocation(iface);
141     return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
142 }
143
144 static HRESULT WINAPI HTMLLocation_GetIDsOfNames(IHTMLLocation *iface, REFIID riid,
145                                                 LPOLESTR *rgszNames, UINT cNames,
146                                                 LCID lcid, DISPID *rgDispId)
147 {
148     HTMLLocation *This = impl_from_IHTMLLocation(iface);
149     return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames,
150             lcid, rgDispId);
151 }
152
153 static HRESULT WINAPI HTMLLocation_Invoke(IHTMLLocation *iface, DISPID dispIdMember,
154                             REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
155                             VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
156 {
157     HTMLLocation *This = impl_from_IHTMLLocation(iface);
158     return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid,
159             wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
160 }
161
162 static HRESULT WINAPI HTMLLocation_put_href(IHTMLLocation *iface, BSTR v)
163 {
164     HTMLLocation *This = impl_from_IHTMLLocation(iface);
165
166     TRACE("(%p)->(%s)\n", This, debugstr_w(v));
167
168     if(!This->window || !This->window->base.outer_window) {
169         FIXME("No window available\n");
170         return E_FAIL;
171     }
172
173     return navigate_url(This->window->base.outer_window, v, This->window->base.outer_window->uri);
174 }
175
176 static HRESULT WINAPI HTMLLocation_get_href(IHTMLLocation *iface, BSTR *p)
177 {
178     HTMLLocation *This = impl_from_IHTMLLocation(iface);
179     URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)};
180     WCHAR *buf = NULL, *url_path = NULL;
181     HRESULT hres, ret;
182     DWORD len = 0;
183     int i;
184
185     TRACE("(%p)->(%p)\n", This, p);
186
187     if(!p)
188         return E_POINTER;
189
190     url.dwSchemeLength = 1;
191     url.dwHostNameLength = 1;
192     url.dwUrlPathLength = 1;
193     url.dwExtraInfoLength = 1;
194     hres = get_url_components(This, &url);
195     if(FAILED(hres))
196         return hres;
197
198     switch(url.nScheme) {
199     case INTERNET_SCHEME_FILE:
200         {
201             /* prepend a slash */
202             url_path = HeapAlloc(GetProcessHeap(), 0, (url.dwUrlPathLength + 1) * sizeof(WCHAR));
203             if(!url_path)
204                 return E_OUTOFMEMORY;
205             url_path[0] = '/';
206             memcpy(url_path + 1, url.lpszUrlPath, url.dwUrlPathLength * sizeof(WCHAR));
207             url.lpszUrlPath = url_path;
208             url.dwUrlPathLength = url.dwUrlPathLength + 1;
209         }
210         break;
211
212     case INTERNET_SCHEME_HTTP:
213     case INTERNET_SCHEME_HTTPS:
214     case INTERNET_SCHEME_FTP:
215         if(!url.dwUrlPathLength) {
216             /* add a slash if it's blank */
217             url_path = url.lpszUrlPath = HeapAlloc(GetProcessHeap(), 0, 1 * sizeof(WCHAR));
218             if(!url.lpszUrlPath)
219                 return E_OUTOFMEMORY;
220             url.lpszUrlPath[0] = '/';
221             url.dwUrlPathLength = 1;
222         }
223         break;
224
225     default:
226         break;
227     }
228
229     /* replace \ with / */
230     for(i = 0; i < url.dwUrlPathLength; ++i)
231         if(url.lpszUrlPath[i] == '\\')
232             url.lpszUrlPath[i] = '/';
233
234     if(InternetCreateUrlW(&url, ICU_ESCAPE, NULL, &len)) {
235         FIXME("InternetCreateUrl succeeded with NULL buffer?\n");
236         ret = E_FAIL;
237         goto cleanup;
238     }
239
240     if(GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
241         FIXME("InternetCreateUrl failed with error: %08x\n", GetLastError());
242         SetLastError(0);
243         ret = E_FAIL;
244         goto cleanup;
245     }
246     SetLastError(0);
247
248     buf = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
249     if(!buf) {
250         ret = E_OUTOFMEMORY;
251         goto cleanup;
252     }
253
254     if(!InternetCreateUrlW(&url, ICU_ESCAPE, buf, &len)) {
255         FIXME("InternetCreateUrl failed with error: %08x\n", GetLastError());
256         SetLastError(0);
257         ret = E_FAIL;
258         goto cleanup;
259     }
260
261     *p = SysAllocStringLen(buf, len);
262     if(!*p) {
263         ret = E_OUTOFMEMORY;
264         goto cleanup;
265     }
266
267     ret = S_OK;
268
269 cleanup:
270     HeapFree(GetProcessHeap(), 0, buf);
271     HeapFree(GetProcessHeap(), 0, url_path);
272
273     return ret;
274 }
275
276 static HRESULT WINAPI HTMLLocation_put_protocol(IHTMLLocation *iface, BSTR v)
277 {
278     HTMLLocation *This = impl_from_IHTMLLocation(iface);
279     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
280     return E_NOTIMPL;
281 }
282
283 static HRESULT WINAPI HTMLLocation_get_protocol(IHTMLLocation *iface, BSTR *p)
284 {
285     HTMLLocation *This = impl_from_IHTMLLocation(iface);
286     BSTR protocol, ret;
287     unsigned len;
288     IUri *uri;
289     HRESULT hres;
290
291     TRACE("(%p)->(%p)\n", This, p);
292
293     if(!p)
294         return E_POINTER;
295
296     if(!(uri = get_uri(This))) {
297         FIXME("No current URI\n");
298         return E_NOTIMPL;
299     }
300
301     hres = IUri_GetSchemeName(uri, &protocol);
302     if(FAILED(hres))
303         return hres;
304     if(hres == S_FALSE) {
305         SysFreeString(protocol);
306         *p = NULL;
307         return S_OK;
308     }
309
310     len = SysStringLen(protocol);
311     ret = SysAllocStringLen(protocol, len+1);
312     SysFreeString(protocol);
313     if(!ret)
314         return E_OUTOFMEMORY;
315
316     ret[len] = ':';
317     *p = ret;
318     return S_OK;
319 }
320
321 static HRESULT WINAPI HTMLLocation_put_host(IHTMLLocation *iface, BSTR v)
322 {
323     HTMLLocation *This = impl_from_IHTMLLocation(iface);
324     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
325     return E_NOTIMPL;
326 }
327
328 static HRESULT WINAPI HTMLLocation_get_host(IHTMLLocation *iface, BSTR *p)
329 {
330     HTMLLocation *This = impl_from_IHTMLLocation(iface);
331     URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)};
332     HRESULT hres;
333
334     TRACE("(%p)->(%p)\n", This, p);
335
336     if(!p)
337         return E_POINTER;
338
339     url.dwHostNameLength = 1;
340     hres = get_url_components(This, &url);
341     if(FAILED(hres))
342         return hres;
343
344     if(!url.dwHostNameLength){
345         *p = NULL;
346         return S_OK;
347     }
348
349     if(url.nPort) {
350         /* <hostname>:<port> */
351         const WCHAR format[] = {'%','u',0};
352         DWORD len = url.dwHostNameLength + 1 + 5;
353         WCHAR *buf;
354
355         buf = *p = SysAllocStringLen(NULL, len);
356         memcpy(buf, url.lpszHostName, url.dwHostNameLength * sizeof(WCHAR));
357         buf[url.dwHostNameLength] = ':';
358         snprintfW(buf + url.dwHostNameLength + 1, 6, format, url.nPort);
359     }else
360         *p = SysAllocStringLen(url.lpszHostName, url.dwHostNameLength);
361
362     if(!*p)
363         return E_OUTOFMEMORY;
364     return S_OK;
365 }
366
367 static HRESULT WINAPI HTMLLocation_put_hostname(IHTMLLocation *iface, BSTR v)
368 {
369     HTMLLocation *This = impl_from_IHTMLLocation(iface);
370     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
371     return E_NOTIMPL;
372 }
373
374 static HRESULT WINAPI HTMLLocation_get_hostname(IHTMLLocation *iface, BSTR *p)
375 {
376     HTMLLocation *This = impl_from_IHTMLLocation(iface);
377     BSTR hostname;
378     IUri *uri;
379     HRESULT hres;
380
381     TRACE("(%p)->(%p)\n", This, p);
382
383     if(!p)
384         return E_POINTER;
385
386     if(!(uri = get_uri(This))) {
387         FIXME("No current URI\n");
388         return E_NOTIMPL;
389     }
390
391     hres = IUri_GetHost(uri, &hostname);
392     if(hres == S_OK) {
393         *p = hostname;
394     }else if(hres == S_FALSE) {
395         SysFreeString(hostname);
396         *p = NULL;
397     }else {
398         return hres;
399     }
400
401     return S_OK;
402 }
403
404 static HRESULT WINAPI HTMLLocation_put_port(IHTMLLocation *iface, BSTR v)
405 {
406     HTMLLocation *This = impl_from_IHTMLLocation(iface);
407     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
408     return E_NOTIMPL;
409 }
410
411 static HRESULT WINAPI HTMLLocation_get_port(IHTMLLocation *iface, BSTR *p)
412 {
413     HTMLLocation *This = impl_from_IHTMLLocation(iface);
414     DWORD port;
415     IUri *uri;
416     HRESULT hres;
417
418     TRACE("(%p)->(%p)\n", This, p);
419
420     if(!p)
421         return E_POINTER;
422
423     if(!(uri = get_uri(This))) {
424         FIXME("No current URI\n");
425         return E_NOTIMPL;
426     }
427
428     hres = IUri_GetPort(uri, &port);
429     if(FAILED(hres))
430         return hres;
431
432     if(hres == S_OK) {
433         static const WCHAR formatW[] = {'%','u',0};
434         WCHAR buf[12];
435
436         sprintfW(buf, formatW, port);
437         *p = SysAllocString(buf);
438     }else {
439         *p = SysAllocStringLen(NULL, 0);
440     }
441
442     if(!*p)
443         return E_OUTOFMEMORY;
444     return S_OK;
445 }
446
447 static HRESULT WINAPI HTMLLocation_put_pathname(IHTMLLocation *iface, BSTR v)
448 {
449     HTMLLocation *This = impl_from_IHTMLLocation(iface);
450     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
451     return E_NOTIMPL;
452 }
453
454 static HRESULT WINAPI HTMLLocation_get_pathname(IHTMLLocation *iface, BSTR *p)
455 {
456     HTMLLocation *This = impl_from_IHTMLLocation(iface);
457     URL_COMPONENTSW url = {sizeof(URL_COMPONENTSW)};
458     HRESULT hres;
459
460     TRACE("(%p)->(%p)\n", This, p);
461
462     if(!p)
463         return E_POINTER;
464
465     url.dwUrlPathLength = 1;
466     url.dwExtraInfoLength = 1;
467     hres = get_url_components(This, &url);
468     if(FAILED(hres))
469         return hres;
470
471     if(url.dwUrlPathLength && url.lpszUrlPath[0] == '/')
472         *p = SysAllocStringLen(url.lpszUrlPath + 1, url.dwUrlPathLength - 1);
473     else
474         *p = SysAllocStringLen(url.lpszUrlPath, url.dwUrlPathLength);
475
476     if(!*p)
477         return E_OUTOFMEMORY;
478     return S_OK;
479 }
480
481 static HRESULT WINAPI HTMLLocation_put_search(IHTMLLocation *iface, BSTR v)
482 {
483     HTMLLocation *This = impl_from_IHTMLLocation(iface);
484     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
485     return E_NOTIMPL;
486 }
487
488 static HRESULT WINAPI HTMLLocation_get_search(IHTMLLocation *iface, BSTR *p)
489 {
490     HTMLLocation *This = impl_from_IHTMLLocation(iface);
491     BSTR query;
492     IUri *uri;
493     HRESULT hres;
494
495     TRACE("(%p)->(%p)\n", This, p);
496
497     if(!p)
498         return E_POINTER;
499
500     if(!(uri = get_uri(This))) {
501         FIXME("No current URI\n");
502         return E_NOTIMPL;
503     }
504
505     hres = IUri_GetQuery(uri, &query);
506     if(hres == S_OK) {
507         *p = query;
508     }else if(hres == S_FALSE) {
509         SysFreeString(query);
510         *p = NULL;
511     }else {
512         return hres;
513     }
514
515     return S_OK;
516 }
517
518 static HRESULT WINAPI HTMLLocation_put_hash(IHTMLLocation *iface, BSTR v)
519 {
520     HTMLLocation *This = impl_from_IHTMLLocation(iface);
521     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
522     return E_NOTIMPL;
523 }
524
525 static HRESULT WINAPI HTMLLocation_get_hash(IHTMLLocation *iface, BSTR *p)
526 {
527     HTMLLocation *This = impl_from_IHTMLLocation(iface);
528     BSTR hash;
529     IUri *uri;
530     HRESULT hres;
531
532     TRACE("(%p)->(%p)\n", This, p);
533
534     if(!p)
535         return E_POINTER;
536
537     if(!(uri = get_uri(This))) {
538         FIXME("No current URI\n");
539         return E_NOTIMPL;
540     }
541
542     hres = IUri_GetFragment(uri, &hash);
543     if(hres == S_OK) {
544         *p = hash;
545     }else if(hres == S_FALSE) {
546         SysFreeString(hash);
547         *p = NULL;
548     }else {
549         return hres;
550     }
551
552     return S_OK;
553 }
554
555 static HRESULT WINAPI HTMLLocation_reload(IHTMLLocation *iface, VARIANT_BOOL flag)
556 {
557     HTMLLocation *This = impl_from_IHTMLLocation(iface);
558     FIXME("(%p)->(%x)\n", This, flag);
559     return E_NOTIMPL;
560 }
561
562 static HRESULT WINAPI HTMLLocation_replace(IHTMLLocation *iface, BSTR bstr)
563 {
564     HTMLLocation *This = impl_from_IHTMLLocation(iface);
565
566     TRACE("(%p)->(%s)\n", This, debugstr_w(bstr));
567
568     if(!This->window || !This->window->base.outer_window) {
569         FIXME("No window available\n");
570         return E_FAIL;
571     }
572
573     return navigate_url(This->window->base.outer_window, bstr, This->window->base.outer_window->uri);
574 }
575
576 static HRESULT WINAPI HTMLLocation_assign(IHTMLLocation *iface, BSTR bstr)
577 {
578     HTMLLocation *This = impl_from_IHTMLLocation(iface);
579     FIXME("(%p)->(%s)\n", This, debugstr_w(bstr));
580     return E_NOTIMPL;
581 }
582
583 static HRESULT WINAPI HTMLLocation_toString(IHTMLLocation *iface, BSTR *String)
584 {
585     HTMLLocation *This = impl_from_IHTMLLocation(iface);
586     FIXME("(%p)->(%p)\n", This, String);
587     return E_NOTIMPL;
588 }
589
590 static const IHTMLLocationVtbl HTMLLocationVtbl = {
591     HTMLLocation_QueryInterface,
592     HTMLLocation_AddRef,
593     HTMLLocation_Release,
594     HTMLLocation_GetTypeInfoCount,
595     HTMLLocation_GetTypeInfo,
596     HTMLLocation_GetIDsOfNames,
597     HTMLLocation_Invoke,
598     HTMLLocation_put_href,
599     HTMLLocation_get_href,
600     HTMLLocation_put_protocol,
601     HTMLLocation_get_protocol,
602     HTMLLocation_put_host,
603     HTMLLocation_get_host,
604     HTMLLocation_put_hostname,
605     HTMLLocation_get_hostname,
606     HTMLLocation_put_port,
607     HTMLLocation_get_port,
608     HTMLLocation_put_pathname,
609     HTMLLocation_get_pathname,
610     HTMLLocation_put_search,
611     HTMLLocation_get_search,
612     HTMLLocation_put_hash,
613     HTMLLocation_get_hash,
614     HTMLLocation_reload,
615     HTMLLocation_replace,
616     HTMLLocation_assign,
617     HTMLLocation_toString
618 };
619
620 static const tid_t HTMLLocation_iface_tids[] = {
621     IHTMLLocation_tid,
622     0
623 };
624 static dispex_static_data_t HTMLLocation_dispex = {
625     NULL,
626     DispHTMLLocation_tid,
627     NULL,
628     HTMLLocation_iface_tids
629 };
630
631
632 HRESULT HTMLLocation_Create(HTMLInnerWindow *window, HTMLLocation **ret)
633 {
634     HTMLLocation *location;
635
636     location = heap_alloc(sizeof(*location));
637     if(!location)
638         return E_OUTOFMEMORY;
639
640     location->IHTMLLocation_iface.lpVtbl = &HTMLLocationVtbl;
641     location->ref = 1;
642     location->window = window;
643
644     init_dispex(&location->dispex, (IUnknown*)&location->IHTMLLocation_iface, &HTMLLocation_dispex);
645
646     *ret = location;
647     return S_OK;
648 }