WebDAV checkpoint (NPOTB, I feel so dirty).

- return properties for propname results, as well as properties proper.
  (Depends on 263957 to actually be useful.)
- ACString > string.
- remove vestigial ChildListener interface.
- OperationListener is also used for get and put.
- put needs a content-type.
- getToOutputStream for somewhat easier use from script.
- implement put, getToOutputStream
- much refactoring of propfind stuff for reuse and clarity
- "davshell" xpcshell test framework
- honestly, did we lose a string-API bet with someone?
This commit is contained in:
shaver%mozilla.org 2004-10-12 04:13:04 +00:00
Родитель 08eea60ca0
Коммит 1c3f4cfd9e
9 изменённых файлов: 698 добавлений и 60 удалений

Просмотреть файл

@ -44,9 +44,7 @@ interface nsIWebDAVMetadataListener : nsISupports
{ {
void onGetPropertyNamesResult(in unsigned long aStatusCode, void onGetPropertyNamesResult(in unsigned long aStatusCode,
in AUTF8String aResource, in AUTF8String aResource,
in PRUint32 nameCount, in nsIProperties aPropertyNames);
[array, size_is(nameCount)]
in string propertyNames);
void onGetPropertiesResult(in unsigned long aStatusCode, void onGetPropertiesResult(in unsigned long aStatusCode,
in AUTF8String aResource, in AUTF8String aResource,
@ -59,7 +57,7 @@ interface nsIWebDAVMetadataListener : nsISupports
void onMetadataComplete(in unsigned long aStatusCode, void onMetadataComplete(in unsigned long aStatusCode,
in nsIWebDAVResource aResource, in nsIWebDAVResource aResource,
in string method); in ACString method);
}; };
[scriptable,uuid(e198a0fd-9e62-4299-84e3-d93c0cd68881)] [scriptable,uuid(e198a0fd-9e62-4299-84e3-d93c0cd68881)]
@ -73,17 +71,8 @@ interface nsIWebDAVOperationListener : nsISupports
in nsIWebDAVResource aResource); in nsIWebDAVResource aResource);
void onCopyResult(in unsigned long aStatusCode, void onCopyResult(in unsigned long aStatusCode,
in nsIWebDAVResource aResource); in nsIWebDAVResource aResource);
}; void onPutResult(in unsigned long aStatusCode,
in nsIWebDAVResource aResource);
[scriptable,uuid(c368540a-b4c3-45d7-b20f-1474c140c0dd)] void onGetResult(in unsigned long aStatusCode,
interface nsIWebDAVChildrenListener : nsISupports in nsIWebDAVResource aResource);
{
void hasChild(in unsigned long aStatusCode,
in AUTF8String aParent,
in AUTF8String aChild);
void childListComplete(in AUTF8String aParent);
void childListFailed(in unsigned long aStatusCode,
in AUTF8String aParent);
}; };

Просмотреть файл

@ -39,6 +39,7 @@
#include "nsIWebDAVResource.idl" #include "nsIWebDAVResource.idl"
interface nsIStreamListener; interface nsIStreamListener;
interface nsIOutputStream;
[scriptable,uuid(173ef52e-2a2f-45ca-8f9f-abc7429163c2)] [scriptable,uuid(173ef52e-2a2f-45ca-8f9f-abc7429163c2)]
interface nsIWebDAVService : nsISupports interface nsIWebDAVService : nsISupports
@ -67,13 +68,15 @@ interface nsIWebDAVService : nsISupports
void getResourceOptions(in nsIWebDAVResource resource, void getResourceOptions(in nsIWebDAVResource resource,
in nsIWebDAVMetadataListener listener); in nsIWebDAVMetadataListener listener);
void getChildren(in nsIWebDAVResource resource,
in PRUint32 depth, in nsIWebDAVChildrenListener listener);
void get(in nsIWebDAVResource resource, void get(in nsIWebDAVResource resource,
in nsIStreamListener listener); in nsIStreamListener listener);
void getToOutputStream(in nsIWebDAVResource resource,
in nsIOutputStream stream,
in nsIWebDAVOperationListener listener);
void put(in nsIWebDAVResourceWithData resource, void put(in nsIWebDAVResourceWithData resource,
in ACString contentType,
in nsIWebDAVOperationListener listener); in nsIWebDAVOperationListener listener);
void remove(in nsIWebDAVResource resource, void remove(in nsIWebDAVResource resource,

Просмотреть файл

@ -58,9 +58,10 @@ REQUIRES = xpcom \
xmlextras \ xmlextras \
$(NULL) $(NULL)
CPPSRCS = nsWebDAVService.cpp \ CPPSRCS = nsWebDAVService.cpp \
nsPropfindStreamListener.cpp \ nsPropfindStreamListener.cpp \
nsWebDAVUtils.cpp \ nsOperationStreamListeners.cpp \
nsWebDAVUtils.cpp \
$(NULL) $(NULL)
include $(topsrcdir)/config/rules.mk include $(topsrcdir)/config/rules.mk

Просмотреть файл

@ -0,0 +1,123 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
// vim:expandtab:ts=4 sw=4:
/*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla.
*
* The Initial Developer of the Original Code is Oracle Corporation.
* Portions created by Oracle Corporation are Copyright (C) 2004
* by Oracle Corporation. All Rights Reserved.
*
* Contributor(s):
* Mike Shaver <shaver@off.net> (original author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsIHttpChannel.h"
#include "nsIIOService.h"
#include "nsNetUtil.h"
#include "nsIWebDAVResource.h"
#include "nsIWebDAVListener.h"
#include "nsWebDAVInternal.h"
class OperationStreamListener : public nsIStreamListener
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
enum OperationMode {
PUT, GET
};
OperationStreamListener(nsIWebDAVResource *resource,
nsIWebDAVOperationListener *listener,
OperationMode mode) :
mResource(resource), mListener(listener), mMode(mode) { }
virtual ~OperationStreamListener() { }
protected:
nsCOMPtr<nsIWebDAVResource> mResource;
nsCOMPtr<nsIWebDAVOperationListener> mListener;
OperationMode mMode;
};
NS_IMPL_ISUPPORTS1(OperationStreamListener, nsIStreamListener);
NS_IMETHODIMP
OperationStreamListener::OnStartRequest(nsIRequest *aRequest,
nsISupports *aContext)
{
return NS_OK;
}
NS_IMETHODIMP
OperationStreamListener::OnStopRequest(nsIRequest *aRequest,
nsISupports *aContext,
nsresult aStatusCode)
{
switch (mMode) {
case PUT:
mListener->OnPutResult(aStatusCode, mResource);
break;
case GET:
mListener->OnGetResult(aStatusCode, mResource);
break;
}
return NS_OK;
}
NS_IMETHODIMP
OperationStreamListener::OnDataAvailable(nsIRequest *aRequest,
nsISupports *aContext,
nsIInputStream *aInputStream,
PRUint32 offset, PRUint32 count)
{
aRequest->Cancel(NS_BINDING_ABORTED);
return NS_BINDING_ABORTED;
}
nsIStreamListener *
NS_WD_NewPutOperationStreamListener(nsIWebDAVResource *resource,
nsIWebDAVOperationListener *listener)
{
nsCOMPtr<nsIStreamListener> osl =
return new OperationStreamListener(resource, listener,
OperationStreamListener::PUT);
}
nsIRequestObserver *
NS_WD_NewGetOperationRequestObserver(nsIWebDAVResource *resource,
nsIWebDAVOperationListener *listener)
{
nsCOMPtr<nsIRequestObserver> osl =
do_QueryInterface(new OperationStreamListener(resource, listener,
OperationStreamListener::GET));
return osl.get();
}

Просмотреть файл

@ -19,6 +19,7 @@
* *
* Contributor(s): * Contributor(s):
* Mike Shaver <shaver@off.net> (original author) * Mike Shaver <shaver@off.net> (original author)
*
* Alternatively, the contents of this file may be used under the terms of * Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or * either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
@ -62,8 +63,9 @@ public:
NS_DECL_NSISTREAMLISTENER NS_DECL_NSISTREAMLISTENER
PropfindStreamListener(nsIWebDAVResource *resource, PropfindStreamListener(nsIWebDAVResource *resource,
nsIWebDAVMetadataListener *listener) : nsIWebDAVMetadataListener *listener,
mResource(resource), mListener(listener) { } PRBool isPropname) :
mResource(resource), mListener(listener), mNameOnly(isPropname) { }
virtual ~PropfindStreamListener() { } virtual ~PropfindStreamListener() { }
protected: protected:
@ -79,7 +81,8 @@ protected:
mResource->GetUrlSpec(spec); mResource->GetUrlSpec(spec);
LOG(("PROPFIND completed for %s: %d", spec.get(), aStatusCode)); LOG(("PROPFIND completed for %s: %d", spec.get(), aStatusCode));
} }
mListener->OnMetadataComplete(aStatusCode, mResource, "PROPFIND"); mListener->OnMetadataComplete(aStatusCode, mResource,
NS_LITERAL_CSTRING("PROPFIND"));
return NS_OK; return NS_OK;
} }
@ -91,6 +94,7 @@ protected:
nsCOMPtr<nsIWebDAVMetadataListener> mListener; nsCOMPtr<nsIWebDAVMetadataListener> mListener;
nsCOMPtr<nsIDOMDocument> mXMLDoc; nsCOMPtr<nsIDOMDocument> mXMLDoc;
nsCString mBody; nsCString mBody;
PRBool mNameOnly;
}; };
NS_IMPL_ISUPPORTS1(PropfindStreamListener, nsIStreamListener) NS_IMPL_ISUPPORTS1(PropfindStreamListener, nsIStreamListener)
@ -152,6 +156,15 @@ PropfindStreamListener::PropertiesFromPropElt(nsIDOMElement *propElt,
rv = node->GetLocalName(propName); rv = node->GetLocalName(propName);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
NS_ConvertUTF16toUTF8 propkey(nsStr + NS_LITERAL_STRING(" ") +
propName);
if (mNameOnly) {
LOG((" propname: %s", propkey.get()));
rv = props->Set(propkey.get(), nsnull);
NS_ENSURE_SUCCESS(rv, rv);
continue;
}
nsCOMPtr<nsIDocumentEncoder> encoder = nsCOMPtr<nsIDocumentEncoder> encoder =
do_CreateInstance(NS_DOC_ENCODER_CONTRACTID_BASE "text/xml", &rv); do_CreateInstance(NS_DOC_ENCODER_CONTRACTID_BASE "text/xml", &rv);
@ -175,8 +188,6 @@ PropfindStreamListener::PropertiesFromPropElt(nsIDOMElement *propElt,
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
suppString->SetData(valueStr); suppString->SetData(valueStr);
NS_ConvertUTF16toUTF8 propkey(nsStr + NS_LITERAL_STRING(" ") +
propName);
LOG((" %s = %s", propkey.get(), LOG((" %s = %s", propkey.get(),
NS_ConvertUTF16toUTF8(valueStr).get())); NS_ConvertUTF16toUTF8(valueStr).get()));
rv = props->Set(propkey.get(), suppString); rv = props->Set(propkey.get(), suppString);
@ -240,7 +251,14 @@ PropfindStreamListener::ProcessResponse(nsIDOMElement *responseElt)
PRInt32 statusVal = nsCAutoString(Substring(statusUTF8, 8)).ToInteger(&res, 10); PRInt32 statusVal = nsCAutoString(Substring(statusUTF8, 8)).ToInteger(&res, 10);
NS_ENSURE_SUCCESS(res, (nsresult)res); NS_ENSURE_SUCCESS(res, (nsresult)res);
mListener->OnGetPropertiesResult((PRUint32)statusVal, hrefUTF8, props);
if (mNameOnly) {
mListener->OnGetPropertyNamesResult((PRUint32)statusVal, hrefUTF8,
props);
} else {
mListener->OnGetPropertiesResult((PRUint32)statusVal, hrefUTF8,
props);
}
} }
return NS_OK; return NS_OK;
} }
@ -346,8 +364,9 @@ PropfindStreamListener::OnDataAvailable(nsIRequest *aRequest,
} }
nsIStreamListener * nsIStreamListener *
NS_NewPropfindStreamListener(nsIWebDAVResource *resource, NS_WD_NewPropfindStreamListener(nsIWebDAVResource *resource,
nsIWebDAVMetadataListener *listener) nsIWebDAVMetadataListener *listener,
PRBool isPropname)
{ {
return new PropfindStreamListener(resource, listener); return new PropfindStreamListener(resource, listener, isPropname);
} }

Просмотреть файл

@ -42,6 +42,7 @@
#include "nsString.h" #include "nsString.h"
class nsIStreamListener; class nsIStreamListener;
class nsIRequestObserver;
#include "nsIDOMElement.h" #include "nsIDOMElement.h"
#include "nsIWebDAVListener.h" #include "nsIWebDAVListener.h"
@ -53,8 +54,17 @@ class nsIStreamListener;
extern PRLogModuleInfo *gDAVLog; extern PRLogModuleInfo *gDAVLog;
nsIStreamListener * nsIStreamListener *
NS_NewPropfindStreamListener(nsIWebDAVResource *resource, NS_WD_NewPropfindStreamListener(nsIWebDAVResource *resource,
nsIWebDAVMetadataListener *listener); nsIWebDAVMetadataListener *listener,
PRBool isPropname);
nsIStreamListener *
NS_WD_NewPutOperationStreamListener(nsIWebDAVResource *resource,
nsIWebDAVOperationListener *listener);
nsIRequestObserver *
NS_WD_NewGetOperationRequestObserver(nsIWebDAVResource *resource,
nsIWebDAVOperationListener *listener);
nsresult nsresult
NS_WD_GetElementByTagName(nsIDOMElement *parentElt, const nsAString &tagName, NS_WD_GetElementByTagName(nsIDOMElement *parentElt, const nsAString &tagName,
@ -64,4 +74,9 @@ nsresult
NS_WD_ElementTextChildValue(nsIDOMElement *elt, const nsAString &tagName, NS_WD_ElementTextChildValue(nsIDOMElement *elt, const nsAString &tagName,
nsAString &value); nsAString &value);
nsresult
NS_WD_AppendElementWithNS(nsIDOMDocument *doc, nsIDOMNode *parent,
const nsAString& ns, const nsAString& tagName,
nsIDOMElement **child);
#endif /* nsWebDAVInternal_h__ */ #endif /* nsWebDAVInternal_h__ */

Просмотреть файл

@ -48,10 +48,20 @@
#include "nsIHttpChannel.h" #include "nsIHttpChannel.h"
#include "nsIIOService.h" #include "nsIIOService.h"
#include "nsNetUtil.h" #include "nsNetUtil.h"
#include "nsIStorageStream.h"
#include "nsIUploadChannel.h"
#include "nsContentCID.h"
#include "nsIDOMXMLDocument.h"
#include "nsIDOMElement.h" #include "nsIDOMElement.h"
#include "nsIDOMNodeList.h" #include "nsIDOMNodeList.h"
#include "nsIDOM3Node.h" #include "nsIDOM3Node.h"
#include "nsIPrivateDOMImplementation.h" // I don't even pretend any more
#include "nsIDOMDOMImplementation.h"
#include "nsIDocument.h"
#include "nsIDocumentEncoder.h"
#include "nsIDOMParser.h" #include "nsIDOMParser.h"
@ -68,8 +78,28 @@ public:
protected: protected:
nsresult EnsureIOService(); nsresult EnsureIOService();
nsresult ChannelFromResource(nsIWebDAVResource *resource, nsresult ChannelFromResource(nsIWebDAVResource *resource,
nsIHttpChannel** channel); nsIHttpChannel** channel,
nsIURI ** resourceURI = 0);
nsresult ChannelWithStreamFromResource(nsIWebDAVResource *resource,
nsIHttpChannel **channel,
nsIInputStream **stream);
nsresult CreatePropfindDocument(nsIURI *resourceURI,
nsIDOMDocument **requestDoc,
nsIDOMElement **propfindElt);
nsresult PropfindInternal(nsIWebDAVResource *resource, PRUint32 propCount,
const char **properties, PRBool withDepth,
nsIWebDAVMetadataListener *listener,
PRBool namesOnly);
nsresult SendPropfindDocumentToChannel(nsIDocument *doc,
nsIHttpChannel *channel,
nsIStreamListener *listener,
PRBool withDepth);
nsCOMPtr<nsIIOService> mIOService; // XXX weak? nsCOMPtr<nsIIOService> mIOService; // XXX weak?
nsAutoString mDAVNSString; // "DAV:"
}; };
NS_IMPL_ISUPPORTS1_CI(nsWebDAVService, nsIWebDAVService) NS_IMPL_ISUPPORTS1_CI(nsWebDAVService, nsIWebDAVService)
@ -93,13 +123,149 @@ nsWebDAVService::EnsureIOService()
return NS_OK; return NS_OK;
} }
nsresult
nsWebDAVService::SendPropfindDocumentToChannel(nsIDocument *doc,
nsIHttpChannel *channel,
nsIStreamListener *listener,
PRBool withDepth)
{
nsCOMPtr<nsIStorageStream> storageStream;
// Why do I have to pick values for these? I just want to store some data
// for stream access! (And how would script set these?)
nsresult rv = NS_NewStorageStream(4 * 1024, 256 * 1024,
getter_AddRefs(storageStream));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIOutputStream> storageOutputStream;
rv = storageStream->GetOutputStream(0,
getter_AddRefs(storageOutputStream));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDocumentEncoder> encoder =
do_CreateInstance(NS_DOC_ENCODER_CONTRACTID_BASE "text/xml", &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = encoder->Init(doc, NS_LITERAL_STRING("text/xml"),
nsIDocumentEncoder::OutputEncodeBasicEntities);
NS_ENSURE_SUCCESS(rv, rv);
encoder->SetCharset(NS_LITERAL_CSTRING("UTF-8"));
rv = encoder->EncodeToStream(storageOutputStream);
NS_ENSURE_SUCCESS(rv, rv);
storageOutputStream->Close();
// You gotta really want it.
if (PR_LOG_TEST(gDAVLog, 5)) {
nsCOMPtr<nsIInputStream> logInputStream;
rv = storageStream->NewInputStream(0, getter_AddRefs(logInputStream));
NS_ENSURE_SUCCESS(rv, rv);
PRUint32 len, read;
logInputStream->Available(&len);
char *buf = new char[len+1];
memset(buf, 0, len+1);
logInputStream->Read(buf, len, &read);
NS_ASSERTION(len == read, "short read on closed storage stream?");
LOG(("XML:\n\n%*s\n\n", len, buf));
delete [] buf;
}
nsCOMPtr<nsIInputStream> inputStream;
rv = storageStream->NewInputStream(0, getter_AddRefs(inputStream));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIUploadChannel> uploadChannel = do_QueryInterface(channel, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = uploadChannel->SetUploadStream(inputStream,
NS_LITERAL_CSTRING("text/xml"), -1);
NS_ENSURE_SUCCESS(rv, rv);
channel->SetRequestMethod(NS_LITERAL_CSTRING("PROPFIND"));
// XXX I wonder how many compilers this will break...
const nsACString &depthValue = withDepth ? NS_LITERAL_CSTRING("1") :
NS_LITERAL_CSTRING("0");
channel->SetRequestHeader(NS_LITERAL_CSTRING("Depth"), depthValue, false);
if (LOG_ENABLED()) {
nsCOMPtr<nsIURI> uri;
channel->GetURI(getter_AddRefs(uri));
nsCAutoString spec;
uri->GetSpec(spec);
LOG(("PROPFIND starting for %s", spec.get()));
}
return channel->AsyncOpen(listener, channel);
}
nsresult
nsWebDAVService::CreatePropfindDocument(nsIURI *resourceURI,
nsIDOMDocument **requestDoc,
nsIDOMElement **propfindElt)
{
nsresult rv;
static NS_DEFINE_CID(kDOMDOMDOMDOMImplementationCID,
NS_DOM_IMPLEMENTATION_CID);
nsCOMPtr<nsIDOMDOMImplementation>
implementation(do_CreateInstance(kDOMDOMDOMDOMImplementationCID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIPrivateDOMImplementation>
privImpl(do_QueryInterface(implementation));
privImpl->Init(resourceURI);
nsCOMPtr<nsIDOMDocument> doc;
nsAutoString emptyString;
rv = implementation->CreateDocument(mDAVNSString, emptyString, nsnull,
getter_AddRefs(doc));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDocument> baseDoc = do_QueryInterface(doc);
baseDoc->SetXMLDeclaration(NS_LITERAL_STRING("1.0"), emptyString,
emptyString);
baseDoc->SetDocumentURI(resourceURI);
nsCOMPtr<nsIDOMElement> elt;
rv = NS_WD_AppendElementWithNS(doc, doc, mDAVNSString, NS_LITERAL_STRING("propfind"),
getter_AddRefs(elt));
elt->SetPrefix(NS_LITERAL_STRING("D"));
NS_ENSURE_SUCCESS(rv, rv);
*requestDoc = doc.get();
NS_ADDREF(*requestDoc);
*propfindElt = elt.get();
NS_ADDREF(*propfindElt);
return NS_OK;
}
nsresult
nsWebDAVService::ChannelWithStreamFromResource(nsIWebDAVResource *resource,
nsIHttpChannel **channel,
nsIInputStream **stream)
{
nsresult rv = ChannelFromResource(resource, channel);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIWebDAVResourceWithData> resWithData =
do_QueryInterface(resource, &rv);
NS_ENSURE_SUCCESS(rv, rv);
return resWithData->GetData(stream);
}
nsresult nsresult
nsWebDAVService::ChannelFromResource(nsIWebDAVResource *resource, nsWebDAVService::ChannelFromResource(nsIWebDAVResource *resource,
nsIHttpChannel **channel) nsIHttpChannel **channel,
nsIURI **resourceURI)
{ {
ENSURE_IO_SERVICE(); ENSURE_IO_SERVICE();
nsCAutoString spec; nsCAutoString spec;
nsresult rv = resource->GetUrlSpec(spec); nsresult rv = resource->GetUrlSpec(spec);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
if (spec.IsEmpty()) { if (spec.IsEmpty()) {
@ -115,10 +281,17 @@ nsWebDAVService::ChannelFromResource(nsIWebDAVResource *resource,
rv = mIOService->NewChannelFromURI(uri, getter_AddRefs(baseChannel)); rv = mIOService->NewChannelFromURI(uri, getter_AddRefs(baseChannel));
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
if (resourceURI) {
*resourceURI = uri.get();
NS_ADDREF(*resourceURI);
}
return CallQueryInterface(baseChannel, channel); return CallQueryInterface(baseChannel, channel);
} }
nsWebDAVService::nsWebDAVService() nsWebDAVService::nsWebDAVService() :
mDAVNSString(NS_LITERAL_STRING("DAV:"))
{ {
gDAVLog = PR_NewLogModule("webdav"); gDAVLog = PR_NewLogModule("webdav");
} }
@ -147,46 +320,114 @@ nsWebDAVService::GetResourcePropertyNames(nsIWebDAVResource *resource,
PRBool withDepth, PRBool withDepth,
nsIWebDAVMetadataListener *listener) nsIWebDAVMetadataListener *listener)
{ {
return NS_ERROR_NOT_IMPLEMENTED; return PropfindInternal(resource, 0, nsnull, withDepth,
listener, PR_TRUE);
} }
NS_IMETHODIMP NS_IMETHODIMP
nsWebDAVService::GetResourceProperties(nsIWebDAVResource *resource, nsWebDAVService::GetResourceProperties(nsIWebDAVResource *resource,
PRUint32 propCount, PRUint32 propCount,
const char **properties, const char **properties,
PRBool withDepth, PRBool withDepth,
nsIWebDAVMetadataListener *listener) nsIWebDAVMetadataListener *listener)
{
return PropfindInternal(resource, propCount, properties, withDepth,
listener, PR_FALSE);
}
nsresult
nsWebDAVService::PropfindInternal(nsIWebDAVResource *resource,
PRUint32 propCount,
const char **properties,
PRBool withDepth,
nsIWebDAVMetadataListener *listener,
PRBool namesOnly)
{ {
nsresult rv; nsresult rv;
NS_ENSURE_ARG(resource); NS_ENSURE_ARG(resource);
NS_ENSURE_ARG(listener); NS_ENSURE_ARG(listener);
nsCOMPtr<nsIURI> resourceURI;
nsCOMPtr<nsIHttpChannel> channel; nsCOMPtr<nsIHttpChannel> channel;
rv = ChannelFromResource(resource, getter_AddRefs(channel)); rv = ChannelFromResource(resource, getter_AddRefs(channel),
getter_AddRefs(resourceURI));
if (NS_FAILED(rv)) if (NS_FAILED(rv))
return rv; return rv;
// XXX I wonder how many compilers this will break... nsCOMPtr<nsIDOMDocument> requestDoc;
const nsACString &depthValue = withDepth ? NS_LITERAL_CSTRING("1") : nsCOMPtr<nsIDOMElement> propfindElt;
NS_LITERAL_CSTRING("0"); rv = CreatePropfindDocument(resourceURI, getter_AddRefs(requestDoc),
channel->SetRequestMethod(NS_LITERAL_CSTRING("PROPFIND")); getter_AddRefs(propfindElt));
channel->SetRequestHeader(NS_LITERAL_CSTRING("Depth"), depthValue, false); NS_ENSURE_SUCCESS(rv, rv);
if (LOG_ENABLED()) { if (namesOnly) {
nsCAutoString spec; nsCOMPtr<nsIDOMElement> allpropElt;
resource->GetUrlSpec(spec); rv = NS_WD_AppendElementWithNS(requestDoc, propfindElt,
LOG(("PROPFIND starting for %s", spec.get())); mDAVNSString, NS_LITERAL_STRING("propname"),
getter_AddRefs(allpropElt));
NS_ENSURE_SUCCESS(rv, rv);
} else if (propCount == 0) {
nsCOMPtr<nsIDOMElement> allpropElt;
rv = NS_WD_AppendElementWithNS(requestDoc, propfindElt,
mDAVNSString, NS_LITERAL_STRING("allprop"),
getter_AddRefs(allpropElt));
NS_ENSURE_SUCCESS(rv, rv);
} else {
nsCOMPtr<nsIDOMElement> propElt;
rv = NS_WD_AppendElementWithNS(requestDoc, propfindElt,
mDAVNSString, NS_LITERAL_STRING("prop"),
getter_AddRefs(propElt));
NS_ENSURE_SUCCESS(rv, rv);
for (PRUint32 i = 0; i < propCount; i++) {
nsDependentCString fullpropName(properties[i]);
// This string math is _ridiculous_. It better compile to a total of
// 5 instructions, or I'm ripping it all out and doing my own looping.
nsACString::const_iterator start, saveStart, end, saveEnd;
fullpropName.BeginReading(start);
fullpropName.BeginReading(saveStart);
fullpropName.EndReading(end);
fullpropName.EndReading(saveEnd);
RFindInReadable(NS_LITERAL_CSTRING(" "), start, end);
if (start == end) {
nsCAutoString msg(NS_LITERAL_CSTRING("Illegal property name ") +
fullpropName);
NS_WARNING(msg.get());
return NS_ERROR_INVALID_ARG;
}
if (LOG_ENABLED()) {
nsACString::const_iterator s = start;
nsCAutoString propNamespace(nsDependentCSubstring(saveStart, s));
nsCAutoString propName(nsDependentCSubstring(++s, saveEnd));
LOG(("prop ns: '%s', name: '%s'", propNamespace.get(), propName.get()));
}
NS_ConvertASCIItoUTF16 propNamespace(nsDependentCSubstring(saveStart, start)),
propName(nsDependentCSubstring(++start, saveEnd));
nsCOMPtr<nsIDOMElement> junk;
rv = NS_WD_AppendElementWithNS(requestDoc, propElt, propNamespace,
propName, getter_AddRefs(junk));
NS_ENSURE_SUCCESS(rv, rv);
}
} }
nsCOMPtr<nsIStreamListener> streamListener = nsCOMPtr<nsIStreamListener> streamListener =
NS_NewPropfindStreamListener(resource, listener); NS_WD_NewPropfindStreamListener(resource, listener, namesOnly);
if (!streamListener) if (!streamListener)
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
return channel->AsyncOpen(streamListener, channel); nsCOMPtr<nsIDocument> requestBaseDoc = do_QueryInterface(requestDoc);
return SendPropfindDocumentToChannel(requestBaseDoc, channel,
streamListener, withDepth);
} }
NS_IMETHODIMP NS_IMETHODIMP
@ -196,13 +437,6 @@ nsWebDAVService::GetResourceOptions(nsIWebDAVResource *resource,
return NS_ERROR_NOT_IMPLEMENTED; return NS_ERROR_NOT_IMPLEMENTED;
} }
NS_IMETHODIMP
nsWebDAVService::GetChildren(nsIWebDAVResource *resource, PRUint32 depth,
nsIWebDAVChildrenListener *listener)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP NS_IMETHODIMP
nsWebDAVService::Get(nsIWebDAVResource *resource, nsIStreamListener *listener) nsWebDAVService::Get(nsIWebDAVResource *resource, nsIStreamListener *listener)
{ {
@ -215,11 +449,61 @@ nsWebDAVService::Get(nsIWebDAVResource *resource, nsIStreamListener *listener)
return channel->AsyncOpen(listener, nsnull); return channel->AsyncOpen(listener, nsnull);
} }
NS_IMETHODIMP
nsWebDAVService::GetToOutputStream(nsIWebDAVResource *resource,
nsIOutputStream *stream,
nsIWebDAVOperationListener *listener)
{
nsresult rv;
nsCOMPtr<nsIRequestObserver> getObserver =
NS_WD_NewGetOperationRequestObserver(resource, listener);
if (!getObserver)
return NS_ERROR_OUT_OF_MEMORY;
nsCOMPtr<nsIStreamListener> streamListener;
rv = NS_NewSimpleStreamListener(getter_AddRefs(streamListener),
stream, getObserver);
NS_ENSURE_SUCCESS(rv, rv);
return Get(resource, streamListener);
}
NS_IMETHODIMP NS_IMETHODIMP
nsWebDAVService::Put(nsIWebDAVResourceWithData *resource, nsWebDAVService::Put(nsIWebDAVResourceWithData *resource,
const nsACString& contentType,
nsIWebDAVOperationListener *listener) nsIWebDAVOperationListener *listener)
{ {
return NS_ERROR_NOT_IMPLEMENTED; nsCOMPtr<nsIHttpChannel> channel;
nsCOMPtr<nsIInputStream> stream;
nsresult rv = ChannelWithStreamFromResource(resource,
getter_AddRefs(channel),
getter_AddRefs(stream));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIUploadChannel> uploadChannel = do_QueryInterface(channel, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = uploadChannel->SetUploadStream(stream, contentType, -1);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIStreamListener> streamListener =
NS_WD_NewPutOperationStreamListener(resource, listener);
if (!streamListener)
return NS_ERROR_OUT_OF_MEMORY;
channel->SetRequestMethod(NS_LITERAL_CSTRING("PUT"));
if (LOG_ENABLED()) {
nsCOMPtr<nsIURI> uri;
channel->GetURI(getter_AddRefs(uri));
nsCAutoString spec;
uri->GetSpec(spec);
LOG(("PUT starting for %s", spec.get()));
}
return channel->AsyncOpen(streamListener, channel);
} }
NS_IMETHODIMP NS_IMETHODIMP

Просмотреть файл

@ -40,6 +40,7 @@
#include "nsIDOMNode.h" #include "nsIDOMNode.h"
#include "nsIDOM3Node.h" #include "nsIDOM3Node.h"
#include "nsIDOMNodeList.h" #include "nsIDOMNodeList.h"
#include "nsIDOMDocument.h"
#if defined(PR_LOGGING) #if defined(PR_LOGGING)
PRLogModuleInfo *gDAVLog = nsnull; PRLogModuleInfo *gDAVLog = nsnull;
@ -77,3 +78,24 @@ NS_WD_ElementTextChildValue(nsIDOMElement *elt, const nsAString &tagName,
return node3->GetTextContent(value); return node3->GetTextContent(value);
} }
nsresult
NS_WD_AppendElementWithNS(nsIDOMDocument *doc, nsIDOMNode *parent,
const nsAString& ns, const nsAString& tagName,
nsIDOMElement **child)
{
nsresult rv;
nsCOMPtr<nsIDOMElement> childElt;
nsCOMPtr<nsIDOMNode> junk;
rv = doc->CreateElementNS(ns, tagName, getter_AddRefs(childElt));
NS_ENSURE_SUCCESS(rv, rv);
rv = parent->AppendChild(childElt, getter_AddRefs(junk));
NS_ENSURE_SUCCESS(rv, rv);
*child = childElt.get();
NS_ADDREF(*child);
return NS_OK;
}

Просмотреть файл

@ -0,0 +1,182 @@
const C = Components;
const CI = C.interfaces;
function getService(contract, iface)
{
return C.classes[contract].getService(CI[iface]);
}
function createInstance(contract, iface)
{
return C.classes[contract].createInstance(CI[iface]);
}
const davSvc = getService("@mozilla.org/webdav/service;1",
"nsIWebDAVService");
function Resource(url)
{
this.urlSpec = url;
}
Resource.prototype = {
QueryInterface: function(outer, iid) {
if (iid.equals(CI.nsIWebDAVResource) ||
iid.equals(CI.nsISupports)) {
return this;
}
throw Components.interfaces.NS_NO_INTERFACE;
}
};
function ResourceWithFileData(url, filename)
{
this.urlSpec = url;
this.mFilename = filename;
}
ResourceWithFileData.prototype = {
QueryInterface: function(outer, iid) {
if (iid.equals(CI.nsIWebDAVResourceWithData))
return this;
return Resource.prototype.QueryInterface.call(this, outer, iid);
},
__proto__: Resource.prototype
};
function propertiesToKeyArray(props)
{
return props.getKeys({ });
}
function propertiesToObject(props)
{
var count = { };
var keys = props.getKeys({ });
var propObj = { };
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
var val = props.get(keys[i], CI.nsISupportsString);
val = val.data;
propObj[key] = val;
}
return propObj;
}
function OperationListener()
{
}
OperationListener.prototype =
{
onPutResult: function (status, resource)
{
dump("PUT " + resource.urlSpec + " complete: " + status + "\n");
stopEventPump();
},
onGetResult: function (status, resource)
{
dump("GET " + resource.urlSpec + " complete: " + status + "\n");
stopEventPump();
}
}
function PropfindListener()
{
}
PropfindListener.prototype =
{
onGetPropertyNamesResult: function (status, URL, props)
{
var keys = propertiesToKeyArray(props);
dump(URL + " (" + status + "):\n");
for (var i = 0; i < keys.length; i++ )
dump(" " + keys[i] + "\n");
},
onGetPropertiesResult: function (status, URL, props)
{
var propObj = propertiesToObject(props);
dump(URL + " (" + status + "):\n");
for (var i in propObj) {
dump(" " + i + " = " + propObj[i] + "\n");
}
},
onMetadataComplete: function (status, resource, method)
{
dump(method + " on " + resource.urlSpec + " completed: " + status +
"\n");
stopEventPump();
}
}
const evQSvc = getService("@mozilla.org/event-queue-service;1",
"nsIEventQueueService");
const ioSvc = getService("@mozilla.org/network/io-service;1",
"nsIIOService");
const evQ = evQSvc.getSpecialEventQueue(CI.nsIEventQueueService.CURRENT_THREAD_EVENT_QUEUE);
function runEventPump()
{
pumpRunning = true;
while (pumpRunning) {
evQ.processPendingEvents();
}
}
function stopEventPump()
{
pumpRunning = false;
}
function PROPFIND(url, depth, props)
{
var listener = new PropfindListener();
if (props) {
var length = props.length;
} else {
var length = 0;
props = null;
}
davSvc.getResourceProperties(new Resource(url), length, props, depth,
listener);
runEventPump();
}
function PROPFIND_names(url, depth)
{
var listener = new PropfindListener();
davSvc.getResourcePropertyNames(new Resource(url), depth, listener);
runEventPump();
}
function makeFile(path)
{
var file = createInstance("@mozilla.org/file/local;1", "nsILocalFile");
file.initWithPath(path);
return file;
}
function GET(url, filename)
{
var file = makeFile(filename);
var outstream = createInstance("@mozilla.org/network/file-output-stream;1",
"nsIFileOutputStream");
outstream.init(file, 0x02 | 0x08, 0644, 0);
davSvc.getToOutputStream(new Resource(url), outstream,
new OperationListener());
runEventPump();
}