urlmon: Recognize <head> start tag as text/html MIME type.
[wine] / dlls / urlmon / umstream.c
1 /*
2  * Based on ../shell32/memorystream.c
3  *
4  * Copyright 1999 Juergen Schmied
5  * Copyright 2003 Mike McCormack for CodeWeavers
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "urlmon_main.h"
23
24 #include "winreg.h"
25 #include "winternl.h"
26 #include "wininet.h"
27 #include "shlwapi.h"
28
29 #include "wine/debug.h"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
32
33 typedef struct ProxyBindStatusCallback
34 {
35     IBindStatusCallback IBindStatusCallback_iface;
36
37     IBindStatusCallback *pBSC;
38 } ProxyBindStatusCallback;
39
40 static inline ProxyBindStatusCallback *impl_from_IBindStatusCallback(IBindStatusCallback *iface)
41 {
42     return CONTAINING_RECORD(iface, ProxyBindStatusCallback, IBindStatusCallback_iface);
43 }
44
45 static HRESULT WINAPI ProxyBindStatusCallback_QueryInterface(IBindStatusCallback *iface, REFIID riid, void **ppv)
46 {
47     if (IsEqualGUID(&IID_IBindStatusCallback, riid) ||
48         IsEqualGUID(&IID_IUnknown, riid))
49     {
50         *ppv = iface;
51         IUnknown_AddRef(iface);
52         return S_OK;
53     }
54
55     *ppv = NULL;
56     return E_NOINTERFACE;
57 }
58
59 static ULONG WINAPI ProxyBindStatusCallback_AddRef(IBindStatusCallback *iface)
60 {
61     return 2;
62 }
63
64 static ULONG WINAPI ProxyBindStatusCallback_Release(IBindStatusCallback *iface)
65 {
66     return 1;
67 }
68
69 static HRESULT WINAPI ProxyBindStatusCallback_OnStartBinding(IBindStatusCallback *iface, DWORD dwReserved,
70                                                IBinding *pib)
71 {
72     ProxyBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
73
74     if(This->pBSC)
75         return IBindStatusCallback_OnStartBinding(This->pBSC, dwReserved, pib);
76
77     return S_OK;
78 }
79
80 static HRESULT WINAPI ProxyBindStatusCallback_GetPriority(IBindStatusCallback *iface, LONG *pnPriority)
81 {
82     ProxyBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
83
84     if(This->pBSC)
85         return IBindStatusCallback_GetPriority(This->pBSC, pnPriority);
86
87     return S_OK;
88 }
89
90 static HRESULT WINAPI ProxyBindStatusCallback_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
91 {
92     ProxyBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
93
94     if(This->pBSC)
95         return IBindStatusCallback_OnLowResource(This->pBSC, reserved);
96
97     return S_OK;
98 }
99
100 static HRESULT WINAPI ProxyBindStatusCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
101                                            ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
102 {
103     ProxyBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
104
105     if(This->pBSC)
106         return IBindStatusCallback_OnProgress(This->pBSC, ulProgress,
107                                           ulProgressMax, ulStatusCode,
108                                           szStatusText);
109
110     return S_OK;
111 }
112
113 static HRESULT WINAPI ProxyBindStatusCallback_OnStopBinding(IBindStatusCallback *iface, HRESULT hresult, LPCWSTR szError)
114 {
115     ProxyBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
116
117     if(This->pBSC)
118         return IBindStatusCallback_OnStopBinding(This->pBSC, hresult, szError);
119
120     return S_OK;
121 }
122
123 static HRESULT WINAPI ProxyBindStatusCallback_GetBindInfo(IBindStatusCallback *iface, DWORD *grfBINDF, BINDINFO *pbindinfo)
124 {
125     ProxyBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
126
127     if(This->pBSC)
128         return IBindStatusCallback_GetBindInfo(This->pBSC, grfBINDF, pbindinfo);
129
130     return E_INVALIDARG;
131 }
132
133 static HRESULT WINAPI ProxyBindStatusCallback_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF,
134                                                               DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed)
135 {
136     ProxyBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
137
138     if(This->pBSC)
139         return IBindStatusCallback_OnDataAvailable(This->pBSC, grfBSCF, dwSize,
140                                                pformatetc, pstgmed);
141
142     return S_OK;
143 }
144
145 static HRESULT WINAPI ProxyBindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface, REFIID riid, IUnknown *punk)
146 {
147     ProxyBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
148
149     if(This->pBSC)
150         return IBindStatusCallback_OnObjectAvailable(This->pBSC, riid, punk);
151
152     return S_OK;
153 }
154
155 static HRESULT WINAPI BlockingBindStatusCallback_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF,
156                                                                  DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed)
157 {
158     return S_OK;
159 }
160
161 static const IBindStatusCallbackVtbl BlockingBindStatusCallbackVtbl =
162 {
163     ProxyBindStatusCallback_QueryInterface,
164     ProxyBindStatusCallback_AddRef,
165     ProxyBindStatusCallback_Release,
166     ProxyBindStatusCallback_OnStartBinding,
167     ProxyBindStatusCallback_GetPriority,
168     ProxyBindStatusCallback_OnLowResource,
169     ProxyBindStatusCallback_OnProgress,
170     ProxyBindStatusCallback_OnStopBinding,
171     ProxyBindStatusCallback_GetBindInfo,
172     BlockingBindStatusCallback_OnDataAvailable,
173     ProxyBindStatusCallback_OnObjectAvailable
174 };
175
176 static HRESULT WINAPI AsyncBindStatusCallback_GetBindInfo(IBindStatusCallback *iface, DWORD *grfBINDF, BINDINFO *pbindinfo)
177 {
178     ProxyBindStatusCallback *This = impl_from_IBindStatusCallback(iface);
179     HRESULT hr = IBindStatusCallback_GetBindInfo(This->pBSC, grfBINDF, pbindinfo);
180     *grfBINDF |= BINDF_PULLDATA | BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE;
181     return hr;
182 }
183
184 static const IBindStatusCallbackVtbl AsyncBindStatusCallbackVtbl =
185 {
186     ProxyBindStatusCallback_QueryInterface,
187     ProxyBindStatusCallback_AddRef,
188     ProxyBindStatusCallback_Release,
189     ProxyBindStatusCallback_OnStartBinding,
190     ProxyBindStatusCallback_GetPriority,
191     ProxyBindStatusCallback_OnLowResource,
192     ProxyBindStatusCallback_OnProgress,
193     ProxyBindStatusCallback_OnStopBinding,
194     AsyncBindStatusCallback_GetBindInfo,
195     ProxyBindStatusCallback_OnDataAvailable,
196     ProxyBindStatusCallback_OnObjectAvailable
197 };
198
199 static HRESULT URLStartDownload(LPCWSTR szURL, LPSTREAM *ppStream, IBindStatusCallback *pBSC)
200 {
201     HRESULT hr;
202     IMoniker *pMoniker;
203     IBindCtx *pbc;
204
205     *ppStream = NULL;
206
207     hr = CreateURLMoniker(NULL, szURL, &pMoniker);
208     if (FAILED(hr))
209         return hr;
210
211     hr = CreateBindCtx(0, &pbc);
212     if (FAILED(hr))
213     {
214         IMoniker_Release(pMoniker);
215         return hr;
216     }
217
218     hr = RegisterBindStatusCallback(pbc, pBSC, NULL, 0);
219     if (FAILED(hr))
220     {
221         IBindCtx_Release(pbc);
222         IMoniker_Release(pMoniker);
223         return hr;
224     }
225
226     hr = IMoniker_BindToStorage(pMoniker, pbc, NULL, &IID_IStream, (void **)ppStream);
227
228     /* BindToStorage returning E_PENDING because it's asynchronous is not an error */
229     if (hr == E_PENDING) hr = S_OK;
230
231     IBindCtx_Release(pbc);
232     IMoniker_Release(pMoniker);
233
234     return hr;
235 }
236
237 /***********************************************************************
238  *              URLOpenBlockingStreamA (URLMON.@)
239  */
240 HRESULT WINAPI URLOpenBlockingStreamA(LPUNKNOWN pCaller, LPCSTR szURL,
241                                       LPSTREAM *ppStream, DWORD dwReserved,
242                                       LPBINDSTATUSCALLBACK lpfnCB)
243 {
244     LPWSTR szURLW;
245     int len;
246     HRESULT hr;
247
248     TRACE("(%p, %s, %p, 0x%x, %p)\n", pCaller, szURL, ppStream, dwReserved, lpfnCB);
249
250     if (!szURL || !ppStream)
251         return E_INVALIDARG;
252
253     len = MultiByteToWideChar(CP_ACP, 0, szURL, -1, NULL, 0);
254     szURLW = heap_alloc(len * sizeof(WCHAR));
255     if (!szURLW)
256     {
257         *ppStream = NULL;
258         return E_OUTOFMEMORY;
259     }
260     MultiByteToWideChar(CP_ACP, 0, szURL, -1, szURLW, len);
261
262     hr = URLOpenBlockingStreamW(pCaller, szURLW, ppStream, dwReserved, lpfnCB);
263
264     heap_free(szURLW);
265
266     return hr;
267 }
268
269 /***********************************************************************
270  *              URLOpenBlockingStreamW (URLMON.@)
271  */
272 HRESULT WINAPI URLOpenBlockingStreamW(LPUNKNOWN pCaller, LPCWSTR szURL,
273                                       LPSTREAM *ppStream, DWORD dwReserved,
274                                       LPBINDSTATUSCALLBACK lpfnCB)
275 {
276     ProxyBindStatusCallback blocking_bsc;
277
278     TRACE("(%p, %s, %p, 0x%x, %p)\n", pCaller, debugstr_w(szURL), ppStream,
279           dwReserved, lpfnCB);
280
281     if (!szURL || !ppStream)
282         return E_INVALIDARG;
283
284     blocking_bsc.IBindStatusCallback_iface.lpVtbl = &BlockingBindStatusCallbackVtbl;
285     blocking_bsc.pBSC = lpfnCB;
286
287     return URLStartDownload(szURL, ppStream, &blocking_bsc.IBindStatusCallback_iface);
288 }
289
290 /***********************************************************************
291  *              URLOpenStreamA (URLMON.@)
292  */
293 HRESULT WINAPI URLOpenStreamA(LPUNKNOWN pCaller, LPCSTR szURL, DWORD dwReserved,
294                               LPBINDSTATUSCALLBACK lpfnCB)
295 {
296     LPWSTR szURLW;
297     int len;
298     HRESULT hr;
299
300     TRACE("(%p, %s, 0x%x, %p)\n", pCaller, szURL, dwReserved, lpfnCB);
301
302     if (!szURL)
303         return E_INVALIDARG;
304
305     len = MultiByteToWideChar(CP_ACP, 0, szURL, -1, NULL, 0);
306     szURLW = heap_alloc(len * sizeof(WCHAR));
307     if (!szURLW)
308         return E_OUTOFMEMORY;
309     MultiByteToWideChar(CP_ACP, 0, szURL, -1, szURLW, len);
310
311     hr = URLOpenStreamW(pCaller, szURLW, dwReserved, lpfnCB);
312
313     heap_free(szURLW);
314
315     return hr;
316 }
317
318 /***********************************************************************
319  *              URLOpenStreamW (URLMON.@)
320  */
321 HRESULT WINAPI URLOpenStreamW(LPUNKNOWN pCaller, LPCWSTR szURL, DWORD dwReserved,
322                               LPBINDSTATUSCALLBACK lpfnCB)
323 {
324     HRESULT hr;
325     ProxyBindStatusCallback async_bsc;
326     IStream *pStream;
327
328     TRACE("(%p, %s, 0x%x, %p)\n", pCaller, debugstr_w(szURL), dwReserved,
329           lpfnCB);
330
331     if (!szURL)
332         return E_INVALIDARG;
333
334     async_bsc.IBindStatusCallback_iface.lpVtbl = &AsyncBindStatusCallbackVtbl;
335     async_bsc.pBSC = lpfnCB;
336
337     hr = URLStartDownload(szURL, &pStream, &async_bsc.IBindStatusCallback_iface);
338     if (SUCCEEDED(hr) && pStream)
339         IStream_Release(pStream);
340
341     return hr;
342 }