Back to index

lightning-sunbird  0.9+nobinonly
nsOperationStreamListeners.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 // vim:expandtab:ts=4 sw=4:
00003 /* ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is Mozilla.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Oracle Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 2004
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Mike Shaver <shaver@off.net> (original author)
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "nsWebDAVInternal.h"
00041 
00042 #include "nsIHttpChannel.h"
00043 #include "nsIIOService.h"
00044 #include "nsNetUtil.h"
00045 #include "nsIURL.h"
00046 
00047 #include "nsIDOM3Node.h"
00048 #include "nsIDOMDocument.h"
00049 #include "nsIDOMElement.h"
00050 #include "nsIDOMNodeList.h"
00051 #include "nsIDOMRange.h"
00052 
00053 #include "nsIDocument.h"
00054 #include "nsIDocumentEncoder.h"
00055 #include "nsContentCID.h"
00056 
00057 #include "nsIWebDAVResource.h"
00058 #include "nsIWebDAVListener.h"
00059 
00060 #include "nsString.h"
00061 
00062 #include "nsISupportsPrimitives.h"
00063 
00064 class OperationStreamListener : public nsIStreamListener
00065 {
00066 public:
00067     NS_DECL_ISUPPORTS
00068     NS_DECL_NSIREQUESTOBSERVER
00069     NS_DECL_NSISTREAMLISTENER
00070     
00071     static NS_METHOD StreamReaderCallback(nsIInputStream *in, void *closure,
00072                                           const char *fromRawSegment,
00073                                           PRUint32 toOffset, PRUint32 count,
00074                                           PRUint32 *writeCount);
00075 
00076     OperationStreamListener(nsIWebDAVResource *resource,
00077                             nsIWebDAVOperationListener *listener,
00078                             nsISupports *closure,
00079                             nsIOutputStream *outstream,
00080                             PRUint32 mode) :
00081         mResource(resource), mListener(listener), mClosure(closure), 
00082         mOutputStream(outstream), mOperation(mode) { }
00083 
00084     virtual ~OperationStreamListener() { }
00085     
00086 protected:
00087     virtual nsresult SignalCompletion(PRUint32 status)
00088     {    
00089         mListener->OnOperationComplete(status, mResource, mOperation,
00090                                        mClosure);
00091         if (mOutputStream)
00092             return mOutputStream->Flush();
00093         return NS_OK;
00094     }
00095 
00096     virtual void SignalDetail(PRUint32 statusCode, const nsACString &resource,
00097                               nsISupports *detail);
00098 
00099     virtual nsresult ProcessResponse(nsIDOMElement *responseElt);
00100 
00101     nsresult StatusAndHrefFromResponse(nsIDOMElement *responseElt,
00102                                        nsACString &href,
00103                                        PRUint32 *statusCode);
00104 
00105     nsCOMPtr<nsIWebDAVResource>          mResource;
00106     nsCOMPtr<nsIWebDAVOperationListener> mListener;
00107     nsCOMPtr<nsISupports>                mClosure;
00108     nsCOMPtr<nsIOutputStream>            mOutputStream;
00109     PRUint32                             mOperation;
00110     nsCString                            mBody;
00111     nsCOMPtr<nsIDOMDocument>             mXMLDoc;
00112 };
00113 
00114 NS_IMPL_ADDREF(OperationStreamListener)
00115 NS_IMPL_RELEASE(OperationStreamListener)
00116 NS_INTERFACE_MAP_BEGIN(OperationStreamListener)
00117   NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
00118   NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
00119   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIStreamListener)
00120 NS_INTERFACE_MAP_END
00121 
00122 NS_IMETHODIMP
00123 OperationStreamListener::OnStartRequest(nsIRequest *aRequest,
00124                                         nsISupports *aContext)
00125 {
00126     LOG(("OperationStreamListener::OnStartRequest() entered"));
00127     mBody.Truncate();
00128     return NS_OK;
00129 }
00130 
00131 NS_IMETHODIMP
00132 OperationStreamListener::OnStopRequest(nsIRequest *aRequest,
00133                                        nsISupports *aContext,
00134                                        nsresult aStatusCode)
00135 {
00136     PRUint32 status, rv;
00137     nsCOMPtr<nsIHttpChannel> channel = do_QueryInterface(aContext);
00138 
00139     LOG(("OperationStreamListener::OnStopRequest() entered"));
00140 
00141     rv = channel ? channel->GetResponseStatus(&status) : NS_ERROR_UNEXPECTED;
00142 
00143     if (NS_FAILED(rv))
00144         return SignalCompletion(rv);
00145 
00146     if (status != 207)
00147         return SignalCompletion(status);
00148 
00149     // ZZZ Check content-length against mBody.Length()
00150 
00151     // Now we parse!
00152     nsCOMPtr<nsIDOMNodeList> responseList;
00153     PRUint32 length;
00154     rv = NS_WD_GetDocAndResponseListFromBuffer(mBody, getter_AddRefs(mXMLDoc),
00155                                                getter_AddRefs(responseList),
00156                                                &length);
00157     NS_ENSURE_SUCCESS(rv, SignalCompletion(rv));
00158 
00159     LOG(("found %d responses", length));
00160     
00161     for (PRUint32 i = 0; i < length; i++) {
00162         nsCOMPtr<nsIDOMNode> responseNode;
00163         rv = responseList->Item(i, getter_AddRefs(responseNode));
00164         NS_ENSURE_SUCCESS(rv, SignalCompletion(rv));
00165 
00166         nsCOMPtr<nsIDOMElement> responseElt =
00167             do_QueryInterface(responseNode, &rv);
00168         NS_ENSURE_SUCCESS(rv, SignalCompletion(rv));
00169     
00170         rv = ProcessResponse(responseElt);
00171         NS_ENSURE_SUCCESS(rv, SignalCompletion(rv));
00172     }
00173 
00174     SignalCompletion(status);
00175     return NS_OK;
00176 }
00177 
00178 NS_METHOD
00179 OperationStreamListener::StreamReaderCallback(nsIInputStream *aInputStream,
00180                                               void *aClosure,
00181                                               const char *aRawSegment,
00182                                               PRUint32 aToOffset,
00183                                               PRUint32 aCount,
00184                                               PRUint32 *aWriteCount)
00185 {
00186     OperationStreamListener *osl = NS_STATIC_CAST(OperationStreamListener *,
00187                                                   aClosure);
00188     osl->mBody.Append(aRawSegment, aCount);
00189     *aWriteCount = aCount;
00190     return NS_OK;
00191 }
00192 
00193 NS_IMETHODIMP
00194 OperationStreamListener::OnDataAvailable(nsIRequest *aRequest,
00195                                          nsISupports *aContext,
00196                                          nsIInputStream *aInputStream,
00197                                          PRUint32 offset, PRUint32 count)
00198 {
00199     LOG(("OperationStreamListener::OnDataAvailable() entered"));
00200     PRUint32 result;
00201     nsCOMPtr<nsIHttpChannel> channel = do_QueryInterface(aContext);
00202     if (!channel)
00203         result = NS_ERROR_UNEXPECTED;
00204 
00205     PRBool succeeded = PR_FALSE;
00206     channel->GetRequestSucceeded(&succeeded);
00207     if (!succeeded) {
00208         aRequest->Cancel(NS_BINDING_ABORTED);
00209         return NS_BINDING_ABORTED;
00210     }
00211 
00212     PRUint32 totalRead;
00213     return aInputStream->ReadSegments(StreamReaderCallback, this, count,
00214                                       &totalRead);
00215 }
00216 
00217 void
00218 OperationStreamListener::SignalDetail(PRUint32 statusCode,
00219                                       const nsACString &resource,
00220                                       nsISupports *detail)
00221 {
00222     nsCOMPtr<nsIURL> resourceURL, detailURL;
00223     nsCOMPtr<nsIURI> detailURI;
00224     if (NS_FAILED(mResource->GetResourceURL(getter_AddRefs(resourceURL))))
00225         return;
00226     if (resource.IsEmpty()) {
00227         detailURL = resourceURL;
00228     } else {
00229         // if this URL is relative, resolve it.
00230         nsresult rv;
00231         nsCAutoString resolvedSpec;
00232         rv = resourceURL->Resolve(resource, resolvedSpec);
00233 
00234         // XXX better error handling
00235         NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to resolve remote URL!");
00236 
00237         if (NS_FAILED(resourceURL->Clone(getter_AddRefs(detailURI))) ||
00238             !(detailURL = do_QueryInterface(detailURI)) ||
00239             NS_FAILED(detailURI->SetSpec(resolvedSpec))) {
00240             return;
00241         }
00242     }
00243     mListener->OnOperationDetail(statusCode, detailURL, mOperation, detail,
00244                                  mClosure);
00245 }
00246 
00247 nsresult
00248 OperationStreamListener::ProcessResponse(nsIDOMElement *responseElt)
00249 {
00250     nsCAutoString href;
00251     PRUint32 statusCode;
00252     nsresult rv = StatusAndHrefFromResponse(responseElt, href, &statusCode);
00253     NS_ENSURE_SUCCESS(rv, rv);
00254 
00255     SignalDetail(statusCode, href, nsnull);
00256     return NS_OK;
00257 }
00258 
00259 nsresult
00260 OperationStreamListener::StatusAndHrefFromResponse(nsIDOMElement *responseElt,
00261                                                    nsACString &href,
00262                                                    PRUint32 *statusCode)
00263 {
00264     nsAutoString hrefString;
00265     nsresult rv = NS_WD_ElementTextChildValue(responseElt,
00266                                               NS_LITERAL_STRING("href"),
00267                                               hrefString);
00268     NS_ENSURE_SUCCESS(rv, rv);
00269     href = NS_ConvertUTF16toUTF8(hrefString);
00270     
00271     nsAutoString statusString;
00272     rv = NS_WD_ElementTextChildValue(responseElt, NS_LITERAL_STRING("status"),
00273                                      statusString);
00274     // XXX if we don't find a status element (or hit any other parse error,
00275     // for that matter) we need to signal this back to the caller
00276     //
00277     NS_ENSURE_SUCCESS(rv, rv);
00278 
00279     PRInt32 res = 0;
00280     NS_ConvertUTF16toUTF8 statusUTF8(statusString);
00281     LOG(("status: %s", statusUTF8.get()));
00282     PRInt32 statusVal = nsCAutoString(Substring(statusUTF8,
00283                                                 8)).ToInteger(&res, 10);
00284     NS_ENSURE_SUCCESS(res, (nsresult)res);
00285     
00286     *statusCode = (PRUint32)statusVal;
00287     
00288     return NS_OK;
00289 }
00290 
00291 class PropfindStreamListener : public OperationStreamListener
00292 {
00293 public:
00294     NS_DECL_ISUPPORTS_INHERITED
00295 
00296     PropfindStreamListener(nsIWebDAVResource *resource,
00297                            nsIWebDAVOperationListener *listener,
00298                            nsISupports *closure,
00299                            PRBool isPropname) :
00300         OperationStreamListener(resource, listener, closure, nsnull,
00301                                 isPropname ?
00302                                 (PRUint32)nsIWebDAVOperationListener::GET_PROPERTY_NAMES :
00303                                 (PRUint32)nsIWebDAVOperationListener::GET_PROPERTIES) { }
00304     virtual ~PropfindStreamListener() { }
00305 protected:
00306 
00307     virtual nsresult ProcessResponse(nsIDOMElement *responseElt);
00308     virtual nsresult PropertiesFromPropElt(nsIDOMElement *elt,
00309                                            nsIProperties **retProps);
00310 };
00311 
00312 NS_IMPL_ISUPPORTS_INHERITED0(PropfindStreamListener, OperationStreamListener)
00313 
00314 nsresult
00315 PropfindStreamListener::PropertiesFromPropElt(nsIDOMElement *propElt,
00316                                               nsIProperties **retProps)
00317 {
00318     nsresult rv = CallCreateInstance(NS_PROPERTIES_CONTRACTID, retProps);
00319     NS_ENSURE_SUCCESS(rv, rv);
00320 
00321     nsIProperties *props = *retProps;
00322 
00323     nsCOMPtr<nsIDOMNodeList> list;
00324     rv = propElt->GetChildNodes(getter_AddRefs(list));
00325     NS_ENSURE_SUCCESS(rv, rv);
00326 
00327     PRUint32 length;
00328     rv = list->GetLength(&length);
00329     NS_ENSURE_SUCCESS(rv, rv);
00330 
00331     LOG(("%d properties found", length));
00332 
00333     PRUint32 realProps = 0;
00334 
00335     for (PRUint32 i = 0; i < length; i++) {
00336         nsCOMPtr<nsIDOMNode> node;
00337         nsCOMPtr<nsIDOM3Node> node3;
00338         rv = list->Item(i, getter_AddRefs(node));
00339         NS_ENSURE_SUCCESS(rv, rv);
00340 
00341         PRUint16 type;
00342         node->GetNodeType(&type);
00343         if (type != nsIDOMNode::ELEMENT_NODE)
00344             continue;
00345 
00346         realProps++;
00347         
00348         nsCOMPtr<nsIDOMRange> range = 
00349           do_CreateInstance("@mozilla.org/content/range;1", &rv);
00350         NS_ENSURE_SUCCESS(rv, rv);
00351 
00352         rv = range->SelectNodeContents(node);
00353         NS_ENSURE_SUCCESS(rv, rv);
00354         
00355         nsString nsStr;
00356         rv = node->GetNamespaceURI(nsStr);
00357         NS_ENSURE_SUCCESS(rv, rv);
00358 
00359         nsString propName;
00360         rv = node->GetLocalName(propName);
00361         NS_ENSURE_SUCCESS(rv, rv);
00362 
00363         NS_ConvertUTF16toUTF8 propkey(nsStr + NS_LITERAL_STRING(" ") +
00364                                       propName);
00365         if (mOperation == nsIWebDAVOperationListener::GET_PROPERTY_NAMES) {
00366             LOG(("  propname: %s", propkey.get()));
00367             rv = props->Set(propkey.get(), nsnull);
00368             NS_ENSURE_SUCCESS(rv, rv);
00369             continue;
00370         }
00371 
00372         nsCOMPtr<nsIDocumentEncoder> encoder =
00373           do_CreateInstance(NS_DOC_ENCODER_CONTRACTID_BASE "text/xml", &rv);
00374 
00375         nsCOMPtr<nsIDocument> baseDoc = do_QueryInterface(mXMLDoc, &rv);
00376         NS_ENSURE_SUCCESS(rv, rv);
00377 
00378         // This method will fail if no document
00379         rv = encoder->Init(baseDoc, NS_LITERAL_STRING("text/xml"),
00380                            nsIDocumentEncoder::OutputEncodeBasicEntities);
00381         NS_ENSURE_SUCCESS(rv, rv);
00382         
00383         rv = encoder->SetRange(range);
00384         NS_ENSURE_SUCCESS(rv, rv);
00385 
00386         nsString valueStr;
00387         encoder->EncodeToString(valueStr);
00388 
00389         nsCOMPtr<nsISupportsString>
00390             suppString(do_CreateInstance("@mozilla.org/supports-string;1",
00391                                          &rv));
00392         NS_ENSURE_SUCCESS(rv, rv);
00393         suppString->SetData(valueStr);
00394 
00395         LOG(("  %s = %s", propkey.get(),
00396              NS_ConvertUTF16toUTF8(valueStr).get()));
00397         rv = props->Set(propkey.get(), suppString);
00398         NS_ENSURE_SUCCESS(rv, rv);
00399     }
00400 
00401     LOG(("%d real properties added", realProps));
00402     
00403     return NS_OK;
00404 }
00405 
00406 nsresult
00407 PropfindStreamListener::ProcessResponse(nsIDOMElement *responseElt)
00408 {
00409     nsCAutoString href;
00410     PRUint32 statusCode;
00411     nsresult rv = StatusAndHrefFromResponse(responseElt, href, &statusCode);
00412     NS_ENSURE_SUCCESS(rv, rv);
00413 
00414     LOG(("response for %s: %d", href.get(), statusCode));
00415 
00416     nsCOMPtr<nsIDOMNodeList> proplist;
00417     rv = responseElt->GetElementsByTagNameNS(NS_LITERAL_STRING("DAV:"),
00418                                              NS_LITERAL_STRING("propstat"),
00419                                              getter_AddRefs(proplist));
00420     NS_ENSURE_SUCCESS(rv, rv);
00421 
00422     PRUint32 length;
00423     rv = proplist->GetLength(&length);
00424     NS_ENSURE_SUCCESS(rv, rv);
00425 
00426     nsCOMPtr<nsIDOMNode> node;
00427     for (PRUint32 i = 0; i < length; i++) {
00428         rv = proplist->Item(i, getter_AddRefs(node));
00429         NS_ENSURE_SUCCESS(rv, rv);
00430 
00431         nsCOMPtr<nsIDOMElement> propstatElt = do_QueryInterface(node, &rv);
00432         NS_ENSURE_SUCCESS(rv, rv);
00433 
00434         nsCOMPtr<nsIDOMElement> elt;
00435         rv = NS_WD_GetElementByTagName(propstatElt, NS_LITERAL_STRING("prop"),
00436                                        getter_AddRefs(elt));
00437         NS_ENSURE_SUCCESS(rv, rv);
00438 
00439         nsCOMPtr<nsIProperties> props;
00440         rv = PropertiesFromPropElt(elt, getter_AddRefs(props));
00441         NS_ENSURE_SUCCESS(rv, rv);
00442         
00443         SignalDetail(statusCode, href, props);
00444     }
00445     return NS_OK;
00446 }
00447 
00448 
00449 class ReportStreamListener : public OperationStreamListener
00450 {
00451 public:
00452     NS_DECL_ISUPPORTS_INHERITED
00453 
00454     ReportStreamListener(nsIWebDAVResource *resource,
00455                          nsIWebDAVOperationListener *listener,
00456                          nsISupports *closure) :
00457         OperationStreamListener(resource, listener, closure, nsnull,
00458                                 nsIWebDAVOperationListener::REPORT) { }
00459     virtual ~ReportStreamListener() { }
00460 
00461 protected:
00462     virtual nsresult ProcessResponse(nsIDOMElement *responseElt);
00463 };
00464 
00465 NS_IMPL_ISUPPORTS_INHERITED0(ReportStreamListener, OperationStreamListener)
00466 
00467 nsresult
00468 ReportStreamListener::ProcessResponse(nsIDOMElement *responseElt)
00469 {
00470     nsCAutoString href;
00471     PRUint32 statusCode;
00472     nsresult rv = StatusAndHrefFromResponse(responseElt, href, &statusCode);
00473     NS_ENSURE_SUCCESS(rv, rv);
00474 
00475     LOG(("response for %s: %d", href.get(), statusCode));
00476 
00477     SignalDetail(statusCode, href, responseElt);
00478     return NS_OK;
00479 }
00480 
00481 
00482 class GetToStringStreamListener : public OperationStreamListener
00483 {
00484 public:
00485     NS_DECL_ISUPPORTS_INHERITED
00486 
00487     GetToStringStreamListener(nsIWebDAVResource *resource,
00488                               nsIWebDAVOperationListener *listener,
00489                               nsISupports *closure) :
00490         OperationStreamListener(resource, listener, closure, nsnull,
00491                                 nsIWebDAVOperationListener::GET_TO_STRING)
00492     { }
00493 
00494     virtual ~GetToStringStreamListener() { }
00495 protected:
00496     NS_IMETHOD OnStopRequest(nsIRequest *aRequest,
00497                                    nsISupports *aContext,
00498                                    nsresult aStatusCode);
00499 };
00500 
00501 NS_IMPL_ISUPPORTS_INHERITED0(GetToStringStreamListener, OperationStreamListener)
00502 
00503 NS_IMETHODIMP
00504 GetToStringStreamListener::OnStopRequest(nsIRequest *aRequest,
00505                                          nsISupports *aContext,
00506                                          nsresult aStatusCode)
00507 {
00508     PRUint32 status, rv;
00509     nsCOMPtr<nsIHttpChannel> channel = do_QueryInterface(aContext);
00510 
00511     LOG(("OperationStreamListener::OnStopRequest() entered"));
00512 
00513     rv = channel ? channel->GetResponseStatus(&status) : NS_ERROR_UNEXPECTED;
00514 
00515     if (NS_FAILED(rv))
00516         return SignalCompletion(rv);
00517 
00518     if (status != 200)
00519         return SignalCompletion(status);
00520 
00521     nsCOMPtr<nsISupportsCString>
00522         suppString(do_CreateInstance("@mozilla.org/supports-cstring;1",
00523                                      &rv));
00524     NS_ENSURE_SUCCESS(rv, rv);
00525     suppString->SetData(mBody);
00526 
00527     SignalDetail(status, nsCAutoString(""), suppString);
00528     SignalCompletion(status);
00529     return NS_OK;
00530 }
00531 
00532 nsIStreamListener *
00533 NS_WD_NewPropfindStreamListener(nsIWebDAVResource *resource,
00534                                 nsIWebDAVOperationListener *listener,
00535                                 nsISupports *closure,
00536                                 PRBool isPropname)
00537 {
00538     return new PropfindStreamListener(resource, listener, closure, isPropname);
00539 }
00540 
00541 nsIStreamListener *
00542 NS_WD_NewReportStreamListener(nsIWebDAVResource *resource,
00543                               nsIWebDAVOperationListener *listener,
00544                               nsISupports *closure)
00545 {
00546     return new ReportStreamListener(resource, listener, closure);
00547 }
00548 
00549 nsresult
00550 NS_WD_NewOperationStreamListener(nsIWebDAVResource *resource,
00551                                  nsIWebDAVOperationListener *listener,
00552                                  nsISupports *closure,
00553                                  PRUint32 operation,
00554                                  nsIStreamListener **streamListener)
00555 {
00556     nsCOMPtr<nsIRequestObserver> osl = 
00557         new OperationStreamListener(resource, listener, closure, nsnull,
00558                                     operation);
00559     if (!osl)
00560         return NS_ERROR_OUT_OF_MEMORY;
00561     return CallQueryInterface(osl, streamListener);
00562 }
00563 
00564 nsresult
00565 NS_WD_NewGetOperationRequestObserver(nsIWebDAVResource *resource,
00566                                      nsIWebDAVOperationListener *listener,
00567                                      nsISupports *closure,
00568                                      nsIOutputStream *outstream,
00569                                      nsIRequestObserver **observer)
00570 {
00571     nsCOMPtr<nsIRequestObserver> osl = 
00572         new OperationStreamListener(resource, listener, closure, outstream,
00573                                     nsIWebDAVOperationListener::GET);
00574     if (!osl)
00575         return NS_ERROR_OUT_OF_MEMORY;
00576     return CallQueryInterface(osl, observer);
00577 }
00578 
00579 nsresult
00580 NS_WD_NewGetToStringOperationRequestObserver(nsIWebDAVResource *resource,
00581                                              nsIWebDAVOperationListener *listener,
00582                                              nsISupports *closure,
00583                                              nsIStreamListener **streamListener)
00584 {
00585     nsCOMPtr<nsIRequestObserver> osl = 
00586         new GetToStringStreamListener(resource, listener, closure);
00587     if (!osl)
00588         return NS_ERROR_OUT_OF_MEMORY;
00589     return CallQueryInterface(osl, streamListener);
00590 }
00591