Follow-on fix for bug 457825. Use sheet principal for agent and user sheets. r=dbaron...
[wine-gecko.git] / embedding / tests / wxEmbed / GeckoProtocolHandler.cpp
blobc410f008608a0936c7099186456743d66d250b5d
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: Mozilla-sample-code 1.0
4 * Copyright (c) 2002 Netscape Communications Corporation and
5 * other contributors
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this Mozilla sample software and associated documentation files
9 * (the "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sublicense, and/or sell copies of the Software, and to permit
12 * persons to whom the Software is furnished to do so, subject to the
13 * following conditions:
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 * DEALINGS IN THE SOFTWARE.
26 * Contributor(s):
27 * Adam Lock <adamlock@netscape.com>
29 * ***** END LICENSE BLOCK ***** */
31 #include "GeckoProtocolHandler.h"
33 #include "nsNetCID.h"
34 #include "nsNetUtil.h"
35 #include "nsIGenericFactory.h"
36 #include "nsIComponentManager.h"
37 #include "nsIComponentRegistrar.h"
38 #include "nsIProgressEventSink.h"
39 #include "nsILoadGroup.h"
40 #include "nsIInterfaceRequestor.h"
41 #include "nsIInterfaceRequestorUtils.h"
42 #include "nsIStringStream.h"
43 #include "nsIStreamListener.h"
44 #include "nsIInputStreamPump.h"
45 #include "nsEmbedString.h"
47 // Everytime register handler is called, it picks the next available CID in the
48 // list.
49 // TODO - is there a cross-platform way to generate UUIDs and obviate this?
50 static const nsCID kProtocolCIDs[] =
52 { 0xfc8b2366, 0x0d07, 0x45ef, { 0x9f, 0xab, 0x22, 0x31, 0x9d, 0xbc, 0xfa, 0x77 } },
53 { 0x6b5db250, 0xcf4b, 0x4ab1, { 0xb3, 0xaa, 0x1a, 0x9a, 0xd6, 0xdf, 0x7f, 0x95 } },
54 { 0x677c6eaf, 0x3c3d, 0x4e0d, { 0xad, 0x30, 0x5a, 0xb8, 0x69, 0x1d, 0x1f, 0xfc } },
55 { 0xbe383b01, 0x58d3, 0x4e65, { 0x9d, 0x50, 0x05, 0xb4, 0xc3, 0x92, 0x43, 0x2e } },
56 { 0x81290231, 0xedf0, 0x4876, { 0x94, 0xa2, 0xdb, 0x96, 0xca, 0xa3, 0xc1, 0xfc } },
57 { 0xf9c466b0, 0x0da8, 0x48a7, { 0xbb, 0xe4, 0x2f, 0x63, 0xb0, 0x71, 0x41, 0x6f } },
58 { 0x9cbaef5e, 0xdf94, 0x4cb0, { 0xb4, 0xc3, 0x89, 0x66, 0x89, 0xd0, 0x2d, 0x56 } },
59 { 0xce79440d, 0xdafc, 0x4908, { 0xb8, 0x94, 0xb2, 0x74, 0xa3, 0x51, 0x2f, 0x45 } }
61 static const int kProtocolCIDsSize = sizeof(kProtocolCIDs) / sizeof(kProtocolCIDs[0]);
62 static PRUint32 gUsedCIDs = 0;
63 struct GeckoChannelCallbacks
65 nsCString mScheme;
66 GeckoChannelCallback *mCallback;
67 // SUCKS, component registry should properly copy this variable or take ownership of
68 // it so it doesn't have to be made a static or global like this.
69 // I also wonder if having component info memory dotted all over the place doesn't
70 // impact component registry performance in some way.
71 nsModuleComponentInfo mComponentInfo;
73 static GeckoChannelCallbacks gCallbacks[kProtocolCIDsSize];
75 class GeckoProtocolHandlerImpl :
76 public nsIProtocolHandler
78 public:
79 NS_DECL_ISUPPORTS
80 NS_DECL_NSIPROTOCOLHANDLER
81 static NS_METHOD Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
85 class GeckoProtocolChannel :
86 public nsIChannel,
87 public nsIStreamListener
89 public:
90 NS_DECL_ISUPPORTS
91 NS_DECL_NSIREQUEST
92 NS_DECL_NSICHANNEL
93 NS_DECL_NSIREQUESTOBSERVER
94 NS_DECL_NSISTREAMLISTENER
96 GeckoProtocolChannel();
97 nsresult Init(nsIURI *aURI);
99 protected:
100 nsCOMPtr<nsIURI> mURI;
101 nsCOMPtr<nsIURI> mOriginalURI;
102 nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
103 nsCOMPtr<nsIProgressEventSink> mProgressSink;
104 nsCOMPtr<nsISupports> mOwner;
105 nsCOMPtr<nsILoadGroup> mLoadGroup;
106 nsCOMPtr<nsIStreamListener> mListener;
107 nsCOMPtr<nsISupports> mListenerContext;
108 nsCOMPtr<nsIInputStream> mContentStream;
109 nsCString mContentType;
110 nsCString mContentCharset;
111 PRUint32 mLoadFlags;
112 nsresult mStatus;
113 PRUint32 mContentLength;
114 void * mData;
115 nsCOMPtr<nsIInputStreamPump> mPump;
117 virtual ~GeckoProtocolChannel();
120 nsresult GeckoProtocolHandler::RegisterHandler(const char *aScheme, const char *aDescription, GeckoChannelCallback *aCallback)
122 if (!aScheme || !aCallback)
124 return NS_ERROR_INVALID_ARG;
127 if (gUsedCIDs >= kProtocolCIDsSize)
129 // We've run out of CIDs. Perhaps this code should be generating them
130 // on the fly somehow instead?
131 return NS_ERROR_FAILURE;
133 for (PRUint32 i = 0; i < gUsedCIDs; i++)
135 if (gCallbacks[i].mScheme.EqualsIgnoreCase(aScheme))
136 return NS_ERROR_FAILURE;
139 nsCAutoString contractID(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX);
140 contractID.Append(aScheme);
141 nsCID cid = kProtocolCIDs[gUsedCIDs];
142 gCallbacks[gUsedCIDs].mScheme = aScheme;
143 gCallbacks[gUsedCIDs].mCallback = aCallback;
144 gUsedCIDs++;
146 nsModuleComponentInfo &ci = gCallbacks[gUsedCIDs].mComponentInfo;
147 memset(&ci, 0, sizeof(ci));
148 ci.mDescription = strdup(aDescription);
149 ci.mCID = cid;
150 ci.mContractID = strdup(contractID.get());
151 ci.mConstructor = GeckoProtocolHandlerImpl::Create;
153 // Create a factory object which will create the protocol handler on demand
154 nsCOMPtr<nsIGenericFactory> factory;
155 NS_NewGenericFactory(getter_AddRefs(factory), &ci);
157 nsCOMPtr<nsIComponentRegistrar> registrar;
158 NS_GetComponentRegistrar(getter_AddRefs(registrar));
159 if (registrar)
160 registrar->RegisterFactory(cid, aDescription, contractID.get(), factory);
162 return NS_OK;
166 ///////////////////////////////////////////////////////////////////////////////
167 ///////////////////////////////////////////////////////////////////////////////
170 GeckoProtocolChannel::GeckoProtocolChannel() :
171 mContentLength(0),
172 mData(nsnull),
173 mStatus(NS_OK),
174 mLoadFlags(LOAD_NORMAL)
178 GeckoProtocolChannel::~GeckoProtocolChannel()
180 // if (mData)
181 // nsMemory::Free(mData);
184 NS_METHOD GeckoProtocolHandlerImpl::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
186 GeckoProtocolHandlerImpl *impl = new GeckoProtocolHandlerImpl();
187 if (!impl)
189 return NS_ERROR_OUT_OF_MEMORY;
191 *aResult = nsnull;
192 nsresult rv = impl->QueryInterface(aIID, aResult);
193 if (NS_FAILED(rv))
195 impl->Release();
197 return rv;
200 NS_IMPL_ISUPPORTS1(GeckoProtocolHandlerImpl, nsIProtocolHandler)
202 /* readonly attribute ACString scheme; */
203 NS_IMETHODIMP GeckoProtocolHandlerImpl::GetScheme(nsACString & aScheme)
205 // Since we have no clue what scheme we're an implementation of,
206 // just return the first one that was registered.
207 aScheme = gCallbacks[0].mScheme;
208 return NS_OK;
211 /* readonly attribute long defaultPort; */
212 NS_IMETHODIMP GeckoProtocolHandlerImpl::GetDefaultPort(PRInt32 *aDefaultPort)
214 *aDefaultPort = -1;
215 return NS_OK;
218 /* readonly attribute unsigned long protocolFlags; */
219 NS_IMETHODIMP GeckoProtocolHandlerImpl::GetProtocolFlags(PRUint32 *aProtocolFlags)
221 // XXXbz Not setting any of the protocol security flags for now, because I
222 // have no idea what this is used for. Whoever uses it should set the
223 // flags.
224 *aProtocolFlags = URI_NORELATIVE | URI_NOAUTH;
225 return NS_OK;
228 /* nsIURI newURI (in AUTF8String aSpec, in string aOriginCharset, in nsIURI aBaseURI); */
229 NS_IMETHODIMP GeckoProtocolHandlerImpl::NewURI(const nsACString & aSpec, const char *aOriginCharset, nsIURI *aBaseURI, nsIURI **_retval)
231 nsresult rv;
232 nsIURI* url;
233 rv = CallCreateInstance(NS_SIMPLEURI_CONTRACTID, &url);
234 if (NS_FAILED(rv))
235 return rv;
236 rv = url->SetSpec(aSpec);
237 if (NS_FAILED(rv))
239 NS_RELEASE(url);
240 return rv;
242 *_retval = url;
243 return rv;
246 /* nsIChannel newChannel (in nsIURI aURI); */
247 NS_IMETHODIMP GeckoProtocolHandlerImpl::NewChannel(nsIURI *aURI, nsIChannel **_retval)
249 NS_ENSURE_ARG_POINTER(aURI);
250 GeckoProtocolChannel *channel = new GeckoProtocolChannel;
251 if (!channel)
253 return NS_ERROR_OUT_OF_MEMORY;
255 channel->Init(aURI);
256 channel->QueryInterface(NS_GET_IID(nsIChannel), (void **) _retval);
257 return NS_OK;
260 /* boolean allowPort (in long port, in string scheme); */
261 NS_IMETHODIMP GeckoProtocolHandlerImpl::AllowPort(PRInt32 port, const char *scheme, PRBool *_retval)
263 return NS_ERROR_NOT_IMPLEMENTED;
267 ///////////////////////////////////////////////////////////////////////////////
268 ///////////////////////////////////////////////////////////////////////////////
270 NS_IMPL_ISUPPORTS4(GeckoProtocolChannel, nsIRequest, nsIChannel, nsIRequestObserver, nsIStreamListener)
272 nsresult GeckoProtocolChannel::Init(nsIURI *aURI)
274 mURI = aURI;
275 mOriginalURI = aURI;
276 return NS_OK;
280 ///////////////////////////////////////////////////////////////////////////////
281 // nsIRequest methods
284 NS_IMETHODIMP
285 GeckoProtocolChannel::GetName(nsACString &result)
287 return mURI->GetSpec(result);
290 NS_IMETHODIMP
291 GeckoProtocolChannel::IsPending(PRBool *result)
293 *result = PR_FALSE;
294 return NS_OK;
297 NS_IMETHODIMP
298 GeckoProtocolChannel::GetStatus(nsresult *status)
300 *status = mStatus;
301 return NS_OK;
304 NS_IMETHODIMP
305 GeckoProtocolChannel::Cancel(nsresult status)
307 NS_ASSERTION(NS_FAILED(status), "shouldn't cancel with a success code");
309 mStatus = status;
310 return NS_ERROR_UNEXPECTED;
313 NS_IMETHODIMP
314 GeckoProtocolChannel::Suspend()
316 return NS_ERROR_UNEXPECTED;
319 NS_IMETHODIMP
320 GeckoProtocolChannel::Resume()
322 return NS_ERROR_UNEXPECTED;
326 ////////////////////////////////////////////////////////////////////////////////
327 // nsIChannel methods:
329 NS_IMETHODIMP
330 GeckoProtocolChannel::GetOriginalURI(nsIURI* *aURI)
332 *aURI = mOriginalURI;
333 NS_ADDREF(*aURI);
334 return NS_OK;
337 NS_IMETHODIMP
338 GeckoProtocolChannel::SetOriginalURI(nsIURI* aURI)
340 NS_ENSURE_ARG_POINTER(aURI);
341 mOriginalURI = aURI;
342 return NS_OK;
345 NS_IMETHODIMP
346 GeckoProtocolChannel::GetURI(nsIURI* *aURI)
348 *aURI = mURI;
349 NS_IF_ADDREF(*aURI);
350 return NS_OK;
353 NS_IMETHODIMP
354 GeckoProtocolChannel::Open(nsIInputStream **_retval)
356 NS_NOTREACHED("GeckoProtocolChannel::Open");
357 return NS_ERROR_NOT_IMPLEMENTED;
360 NS_IMETHODIMP
361 GeckoProtocolChannel::AsyncOpen(nsIStreamListener *aListener, nsISupports *aContext)
363 nsresult rv = NS_OK;
365 nsCAutoString scheme;
366 mURI->GetScheme(scheme);
367 for (PRUint32 i = 0; i < gUsedCIDs; i++)
369 if (stricmp(scheme.get(), gCallbacks[i].mScheme.get()) == 0)
371 rv = gCallbacks[i].mCallback->GetData(
372 mURI, static_cast<nsIChannel *>(this), mContentType, &mData, &mContentLength);
373 if (NS_FAILED(rv)) return rv;
375 rv = NS_NewByteInputStream(getter_AddRefs(mContentStream),
376 (char *) mData, mContentLength,
377 NS_ASSIGNMENT_ADOPT);
378 if (NS_FAILED(rv)) {
379 nsMemory::Free(mData);
380 mData = nsnull;
381 return rv;
384 mListenerContext = aContext;
385 mListener = aListener;
387 // XXX should this use 64-bit content lengths?
388 nsresult rv = NS_NewInputStreamPump(
389 getter_AddRefs(mPump), mContentStream, nsInt64(-1),
390 nsInt64(mContentLength), 0, 0, PR_TRUE);
391 if (NS_FAILED(rv)) return rv;
393 if (mLoadGroup)
395 mLoadGroup->AddRequest(this, nsnull);
398 rv = mPump->AsyncRead(this, nsnull);
399 if (NS_FAILED(rv)) return rv;
401 return rv;
405 return NS_ERROR_FAILURE;
408 NS_IMETHODIMP
409 GeckoProtocolChannel::GetLoadFlags(PRUint32 *aLoadFlags)
411 *aLoadFlags = mLoadFlags;
412 return NS_OK;
415 NS_IMETHODIMP
416 GeckoProtocolChannel::SetLoadFlags(PRUint32 aLoadFlags)
418 mLoadFlags = aLoadFlags;
419 return NS_OK;
422 NS_IMETHODIMP
423 GeckoProtocolChannel::GetContentType(nsACString &aContentType)
425 aContentType = mContentType;
426 return NS_OK;
429 NS_IMETHODIMP
430 GeckoProtocolChannel::SetContentType(const nsACString &aContentType)
432 mContentType = aContentType;
433 return NS_OK;
436 NS_IMETHODIMP
437 GeckoProtocolChannel::GetContentCharset(nsACString &aContentCharset)
439 aContentCharset = mContentCharset;
440 return NS_OK;
443 NS_IMETHODIMP
444 GeckoProtocolChannel::SetContentCharset(const nsACString &aContentCharset)
446 mContentCharset = aContentCharset;
447 return NS_OK;
450 NS_IMETHODIMP
451 GeckoProtocolChannel::GetContentLength(PRInt32 *aContentLength)
453 *aContentLength = mContentLength;
454 return NS_OK;
457 NS_IMETHODIMP
458 GeckoProtocolChannel::SetContentLength(PRInt32 aContentLength)
460 // silently ignore this...
461 return NS_OK;
464 NS_IMETHODIMP
465 GeckoProtocolChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup)
467 *aLoadGroup = mLoadGroup;
468 NS_IF_ADDREF(*aLoadGroup);
469 return NS_OK;
472 NS_IMETHODIMP
473 GeckoProtocolChannel::SetLoadGroup(nsILoadGroup* aLoadGroup)
475 mLoadGroup = aLoadGroup;
476 return NS_OK;
479 NS_IMETHODIMP
480 GeckoProtocolChannel::GetOwner(nsISupports* *aOwner)
482 *aOwner = mOwner.get();
483 NS_IF_ADDREF(*aOwner);
484 return NS_OK;
487 NS_IMETHODIMP
488 GeckoProtocolChannel::SetOwner(nsISupports* aOwner)
490 mOwner = aOwner;
491 return NS_OK;
494 NS_IMETHODIMP
495 GeckoProtocolChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aNotificationCallbacks)
497 *aNotificationCallbacks = mCallbacks.get();
498 NS_IF_ADDREF(*aNotificationCallbacks);
499 return NS_OK;
502 NS_IMETHODIMP
503 GeckoProtocolChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks)
505 mCallbacks = aNotificationCallbacks;
506 mProgressSink = do_GetInterface(mCallbacks);
507 return NS_OK;
510 NS_IMETHODIMP
511 GeckoProtocolChannel::GetSecurityInfo(nsISupports **aSecurityInfo)
513 *aSecurityInfo = nsnull;
514 return NS_OK;
518 ///////////////////////////////////////////////////////////////////////////////
519 // nsIStreamListener methods
522 NS_IMETHODIMP
523 GeckoProtocolChannel::OnStartRequest(nsIRequest *req, nsISupports *ctx)
525 return mListener->OnStartRequest(this, mListenerContext);
528 NS_IMETHODIMP
529 GeckoProtocolChannel::OnStopRequest(nsIRequest *req, nsISupports *ctx, nsresult status)
531 if (NS_SUCCEEDED(mStatus))
532 mStatus = status;
534 mListener->OnStopRequest(this, mListenerContext, mStatus);
535 mListener = 0;
536 mListenerContext = 0;
538 if (mLoadGroup)
539 mLoadGroup->RemoveRequest(this, nsnull, mStatus);
541 mPump = 0;
542 mContentStream = 0;
544 // Drop notification callbacks to prevent cycles.
545 mCallbacks = 0;
546 mProgressSink = 0;
548 return NS_OK;
551 NS_IMETHODIMP
552 GeckoProtocolChannel::OnDataAvailable(nsIRequest *req, nsISupports *ctx,
553 nsIInputStream *stream,
554 PRUint32 offset, PRUint32 count)
556 nsresult rv;
558 rv = mListener->OnDataAvailable(this, mListenerContext, stream, offset, count);
560 // XXX can this use real 64-bit ints?
561 if (mProgressSink && NS_SUCCEEDED(rv) && !(mLoadFlags & LOAD_BACKGROUND))
562 mProgressSink->OnProgress(this, nsnull, nsUint64(offset + count),
563 nsUint64(mContentLength));
565 return rv; // let the pump cancel on failure