mirror of https://github.com/etesync/android
parent
0626f1ecdc
commit
362f0036be
@ -1,232 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013 Richard Hirner (bitfire web engineering).
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the GNU Public License v3.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.gnu.org/licenses/gpl.html
|
||||
******************************************************************************/
|
||||
package at.bitfire.davdroid.webdav;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringWriter;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import org.apache.commons.io.input.TeeInputStream;
|
||||
import org.apache.http.HttpException;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.StatusLine;
|
||||
import org.apache.http.message.BasicLineParser;
|
||||
import org.simpleframework.xml.Serializer;
|
||||
import org.simpleframework.xml.core.Persister;
|
||||
|
||||
import android.util.Log;
|
||||
import at.bitfire.davdroid.Utils;
|
||||
|
||||
public class WebDavCollection extends WebDavResource {
|
||||
private static final String TAG = "davdroid.WebDavCollection";
|
||||
|
||||
public enum MultigetType {
|
||||
ADDRESS_BOOK,
|
||||
CALENDAR
|
||||
}
|
||||
|
||||
/* list of resource members, empty until filled by propfind() or multiGet() */
|
||||
@Getter protected List<WebDavResource> members = new LinkedList<WebDavResource>();
|
||||
|
||||
|
||||
public WebDavCollection(URI baseURL, String username, String password, boolean preemptiveAuth) throws URISyntaxException {
|
||||
super(baseURL, username, password, preemptiveAuth, true);
|
||||
}
|
||||
|
||||
public WebDavCollection(WebDavCollection parent, URI member) {
|
||||
super(parent, member);
|
||||
}
|
||||
|
||||
public WebDavCollection(WebDavCollection parent, String member) {
|
||||
super(parent, member);
|
||||
}
|
||||
|
||||
|
||||
/* collection operations */
|
||||
|
||||
public boolean propfind(HttpPropfind.Mode mode) throws IOException, InvalidDavResponseException, HttpException {
|
||||
HttpPropfind propfind = new HttpPropfind(location, mode);
|
||||
HttpResponse response = client.execute(propfind);
|
||||
checkResponse(response);
|
||||
|
||||
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_MULTI_STATUS) {
|
||||
DavMultistatus multistatus;
|
||||
try {
|
||||
Serializer serializer = new Persister();
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
InputStream is = new TeeInputStream(response.getEntity().getContent(), baos);
|
||||
multistatus = serializer.read(DavMultistatus.class, is, false);
|
||||
|
||||
Log.d(TAG, "Received multistatus response: " + baos.toString("UTF-8"));
|
||||
} catch (Exception ex) {
|
||||
Log.w(TAG, "Invalid PROPFIND XML response", ex);
|
||||
throw new InvalidDavResponseException();
|
||||
}
|
||||
processMultiStatus(multistatus);
|
||||
return true;
|
||||
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean multiGet(String[] names, MultigetType type) throws IOException, InvalidDavResponseException, HttpException {
|
||||
DavMultiget multiget = (type == MultigetType.ADDRESS_BOOK) ? new DavAddressbookMultiget() : new DavCalendarMultiget();
|
||||
|
||||
multiget.prop = new DavProp();
|
||||
multiget.prop.getetag = new DavProp.DavPropGetETag();
|
||||
|
||||
if (type == MultigetType.ADDRESS_BOOK)
|
||||
multiget.prop.addressData = new DavProp.DavPropAddressData();
|
||||
else if (type == MultigetType.CALENDAR)
|
||||
multiget.prop.calendarData = new DavProp.DavPropCalendarData();
|
||||
|
||||
multiget.hrefs = new ArrayList<DavHref>(names.length);
|
||||
for (String name : names) {
|
||||
if (!name.startsWith("/")) name = "./" + name; // allow colons in relative URLs (see issue #45)
|
||||
multiget.hrefs.add(new DavHref(Utils.resolveURI(location, name).getPath()));
|
||||
}
|
||||
|
||||
Serializer serializer = new Persister();
|
||||
StringWriter writer = new StringWriter();
|
||||
try {
|
||||
serializer.write(multiget, writer);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, e.getLocalizedMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
HttpReport report = new HttpReport(location, writer.toString());
|
||||
HttpResponse response = client.execute(report);
|
||||
checkResponse(response);
|
||||
|
||||
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_MULTI_STATUS) {
|
||||
DavMultistatus multistatus;
|
||||
try {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
InputStream is = new TeeInputStream(response.getEntity().getContent(), baos);
|
||||
multistatus = serializer.read(DavMultistatus.class, is, false);
|
||||
|
||||
Log.d(TAG, "Received multistatus response: " + baos.toString("UTF-8"));
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, e.getLocalizedMessage());
|
||||
return false;
|
||||
}
|
||||
processMultiStatus(multistatus);
|
||||
|
||||
} else
|
||||
throw new InvalidDavResponseException();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* member operations */
|
||||
|
||||
@Override
|
||||
public void put(byte[] data, PutMode mode) throws IOException, HttpException {
|
||||
properties.remove(Property.CTAG);
|
||||
super.put(data, mode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() throws IOException, HttpException {
|
||||
properties.remove(Property.CTAG);
|
||||
super.delete();
|
||||
}
|
||||
|
||||
|
||||
/* HTTP support */
|
||||
|
||||
protected void processMultiStatus(DavMultistatus multistatus) throws HttpException {
|
||||
if (multistatus.response == null) // empty response
|
||||
return;
|
||||
|
||||
// member list will be built from response
|
||||
members.clear();
|
||||
|
||||
for (DavResponse singleResponse : multistatus.response) {
|
||||
URI href;
|
||||
try {
|
||||
href = Utils.resolveURI(location, singleResponse.getHref().href);
|
||||
} catch(IllegalArgumentException ex) {
|
||||
Log.w(TAG, "Ignoring illegal member URI in multi-status response", ex);
|
||||
continue;
|
||||
}
|
||||
|
||||
// about which resource is this response?
|
||||
WebDavResource referenced = null;
|
||||
if (Utils.isSameURL(location, href)) { // -> ourselves
|
||||
referenced = this;
|
||||
|
||||
} else { // -> about a member
|
||||
referenced = new WebDavResource(this, href);
|
||||
members.add(referenced);
|
||||
}
|
||||
|
||||
for (DavPropstat singlePropstat : singleResponse.getPropstat()) {
|
||||
StatusLine status = BasicLineParser.parseStatusLine(singlePropstat.status, new BasicLineParser());
|
||||
|
||||
// ignore information about missing properties etc.
|
||||
if (status.getStatusCode()/100 != 1 && status.getStatusCode()/100 != 2)
|
||||
continue;
|
||||
|
||||
DavProp prop = singlePropstat.prop;
|
||||
|
||||
if (prop.currentUserPrincipal != null)
|
||||
referenced.properties.put(Property.CURRENT_USER_PRINCIPAL, prop.currentUserPrincipal.getHref().href);
|
||||
|
||||
if (prop.addressbookHomeSet != null)
|
||||
referenced.properties.put(Property.ADDRESSBOOK_HOMESET, prop.addressbookHomeSet.getHref().href);
|
||||
|
||||
if (singlePropstat.prop.calendarHomeSet != null)
|
||||
referenced.properties.put(Property.CALENDAR_HOMESET, prop.calendarHomeSet.getHref().href);
|
||||
|
||||
if (prop.displayname != null)
|
||||
referenced.properties.put(Property.DISPLAY_NAME, prop.displayname.getDisplayName());
|
||||
|
||||
if (prop.resourcetype != null) {
|
||||
if (prop.resourcetype.getAddressbook() != null) {
|
||||
referenced.properties.put(Property.IS_ADDRESSBOOK, "1");
|
||||
|
||||
if (prop.addressbookDescription != null)
|
||||
referenced.properties.put(Property.DESCRIPTION, prop.addressbookDescription.getDescription());
|
||||
} else
|
||||
referenced.properties.remove(Property.IS_ADDRESSBOOK);
|
||||
|
||||
if (prop.resourcetype.getCalendar() != null) {
|
||||
referenced.properties.put(Property.IS_CALENDAR, "1");
|
||||
|
||||
if (prop.calendarDescription != null)
|
||||
referenced.properties.put(Property.DESCRIPTION, prop.calendarDescription.getDescription());
|
||||
} else
|
||||
referenced.properties.remove(Property.IS_CALENDAR);
|
||||
}
|
||||
|
||||
if (prop.getctag != null)
|
||||
referenced.properties.put(Property.CTAG, prop.getctag.getCTag());
|
||||
|
||||
if (prop.getetag != null)
|
||||
referenced.properties.put(Property.ETAG, prop.getetag.getETag());
|
||||
|
||||
if (prop.calendarData != null)
|
||||
referenced.content = new ByteArrayInputStream(prop.calendarData.ical.getBytes());
|
||||
else if (prop.addressData != null)
|
||||
referenced.content = new ByteArrayInputStream(prop.addressData.vcard.getBytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
@ -0,0 +1 @@
|
||||
node_modules
|
@ -0,0 +1,5 @@
|
||||
{"plugins":[
|
||||
"assets",
|
||||
"redirect",
|
||||
"dav-default"
|
||||
]}
|
@ -0,0 +1,12 @@
|
||||
var RoboHydraHeadFilesystem = require("robohydra").heads.RoboHydraHeadFilesystem;
|
||||
|
||||
exports.getBodyParts = function(conf) {
|
||||
return {
|
||||
heads: [
|
||||
new RoboHydraHeadFilesystem({
|
||||
mountPath: '/assets/',
|
||||
documentRoot: '../assets'
|
||||
})
|
||||
]
|
||||
};
|
||||
};
|
@ -0,0 +1,156 @@
|
||||
var roboHydraHeadDAV = require("../headdav");
|
||||
|
||||
exports.getBodyParts = function(conf) {
|
||||
return {
|
||||
heads: [
|
||||
/* base URL */
|
||||
new RoboHydraHeadDAV({
|
||||
path: "/dav/",
|
||||
handler: function(req,res,next) { }
|
||||
}),
|
||||
|
||||
/* principal URL */
|
||||
new RoboHydraHeadDAV({
|
||||
path: "/dav/principals/users/test",
|
||||
handler: function(req,res,next) {
|
||||
if (req.method == "PROPFIND" && req.rawBody.toString().match(/home-set/)) {
|
||||
res.statusCode = 207;
|
||||
res.write('\<?xml version="1.0" encoding="utf-8" ?>\
|
||||
<multistatus xmlns="DAV:">\
|
||||
<response>\
|
||||
<href>' + req.url + '</href> \
|
||||
<propstat>\
|
||||
<prop>\
|
||||
<CARD:addressbook-home-set xmlns:CARD="urn:ietf:params:xml:ns:carddav">\
|
||||
<href>/dav/addressbooks/test/</href>\
|
||||
</CARD:addressbook-home-set>\
|
||||
<CAL:calendar-home-set xmlns:CAL="urn:ietf:params:xml:ns:caldav">\
|
||||
<href>/dav/calendars/test/</href>\
|
||||
</CAL:calendar-home-set>\
|
||||
</prop>\
|
||||
<status>HTTP/1.1 200 OK</status>\
|
||||
</propstat>\
|
||||
</response>\
|
||||
</multistatus>\
|
||||
');
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
/* address-book home set */
|
||||
new RoboHydraHeadDAV({
|
||||
path: "/dav/addressbooks/test",
|
||||
handler: function(req,res,next) {
|
||||
if (req.method == "PROPFIND" && req.rawBody.toString().match(/addressbook-description/)) {
|
||||
res.statusCode = 207;
|
||||
res.write('\<?xml version="1.0" encoding="utf-8" ?>\
|
||||
<multistatus xmlns="DAV:">\
|
||||
<response>\
|
||||
<href>/dav/addressbooks/test/useless-member</href>\
|
||||
<propstat>\
|
||||
<prop>\
|
||||
<resourcetype/>\
|
||||
</prop>\
|
||||
<status>HTTP/1.1 200 OK</status>\
|
||||
</propstat>\
|
||||
</response>\
|
||||
<response>\
|
||||
<href>/dav/addressbooks/test/default.vcf/</href>\
|
||||
<propstat>\
|
||||
<prop xmlns:CARD="urn:ietf:params:xml:ns:carddav">\
|
||||
<resourcetype>\
|
||||
<collection/>\
|
||||
<CARD:addressbook/>\
|
||||
</resourcetype>\
|
||||
<CARD:addressbook-description>\
|
||||
Default Address Book\
|
||||
</CARD:addressbook-description>\
|
||||
</prop>\
|
||||
<status>HTTP/1.1 200 OK</status>\
|
||||
</propstat>\
|
||||
</response>\
|
||||
</multistatus>\
|
||||
');
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
/* calendar home set */
|
||||
new RoboHydraHeadDAV({
|
||||
path: "/dav/calendars/test",
|
||||
handler: function(req,res,next) {
|
||||
if (req.method == "PROPFIND" && req.rawBody.toString().match(/addressbook-description/)) {
|
||||
res.statusCode = 207;
|
||||
res.write('\<?xml version="1.0" encoding="utf-8" ?>\
|
||||
<multistatus xmlns="DAV:" xmlns:CAL="urn:ietf:params:xml:ns:caldav">\
|
||||
<response>\
|
||||
<href>/dav/calendars/test/shared.forbidden</href>\
|
||||
<propstat>\
|
||||
<prop>\
|
||||
<resourcetype/>\
|
||||
</prop>\
|
||||
<status>HTTP/1.1 403 Forbidden</status>\
|
||||
</propstat>\
|
||||
</response>\
|
||||
<response>\
|
||||
<href>/dav/calendars/test/private.ics</href>\
|
||||
<propstat>\
|
||||
<prop>\
|
||||
<resourcetype>\
|
||||
<collection/>\
|
||||
<CAL:calendar/>\
|
||||
</resourcetype>\
|
||||
</prop>\
|
||||
<status>HTTP/1.1 200 OK</status>\
|
||||
</propstat>\
|
||||
</response>\
|
||||
<response>\
|
||||
<href>/dav/calendars/test/work.ics</href>\
|
||||
<propstat>\
|
||||
<prop>\
|
||||
<resourcetype>\
|
||||
<collection/>\
|
||||
<CAL:calendar/>\
|
||||
</resourcetype>\
|
||||
</prop>\
|
||||
<status>HTTP/1.1 200 OK</status>\
|
||||
</propstat>\
|
||||
</response>\
|
||||
</multistatus>\
|
||||
');
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
/* non-existing file */
|
||||
new RoboHydraHeadDAV({
|
||||
path: "/dav/collection/new.file",
|
||||
handler: function(req,res,next) {
|
||||
if (req.method == "PUT") {
|
||||
if (req.headers['if-match']) /* can't overwrite new file */
|
||||
res.statusCode = 412;
|
||||
else
|
||||
res.statusCode = 201;
|
||||
|
||||
} else if (req.method == "DELETE")
|
||||
res.statusCode = 404;
|
||||
}
|
||||
}),
|
||||
|
||||
/* existing file */
|
||||
new RoboHydraHeadDAV({
|
||||
path: "/dav/collection/existing.file",
|
||||
handler: function(req,res,next) {
|
||||
if (req.method == "PUT") {
|
||||
if (req.headers['if-none-match']) /* requested "don't overwrite", but this file exists */
|
||||
res.statusCode = 412;
|
||||
else
|
||||
res.statusCode = 204;
|
||||
|
||||
} else if (req.method == "DELETE")
|
||||
res.statusCode = 204;
|
||||
}
|
||||
})
|
||||
]
|
||||
};
|
||||
};
|
@ -0,0 +1,36 @@
|
||||
var roboHydraHeadDAV = require("../headdav");
|
||||
|
||||
exports.getBodyParts = function(conf) {
|
||||
return {
|
||||
heads: [
|
||||
/* address-book home set */
|
||||
new RoboHydraHeadDAV({
|
||||
path: "/dav-invalid/addressbooks/user%40domain/",
|
||||
handler: function(req,res,next) {
|
||||
if (req.method == "PROPFIND" && req.rawBody.toString().match(/addressbook-description/)) {
|
||||
res.statusCode = 207;
|
||||
res.write('\<?xml version="1.0" encoding="utf-8" ?>\
|
||||
<multistatus xmlns="DAV:">\
|
||||
<response>\
|
||||
<href>/dav/addressbooks/user@domain/My Contacts.vcf/</href>\
|
||||
<propstat>\
|
||||
<prop xmlns:CARD="urn:ietf:params:xml:ns:carddav">\
|
||||
<resourcetype>\
|
||||
<collection/>\
|
||||
<CARD:addressbook/>\
|
||||
</resourcetype>\
|
||||
<CARD:addressbook-description>\
|
||||
Address Book with @ and space in URL\
|
||||
</CARD:addressbook-description>\
|
||||
</prop>\
|
||||
<status>HTTP/1.1 200 OK</status>\
|
||||
</propstat>\
|
||||
</response>\
|
||||
</multistatus>\
|
||||
');
|
||||
}
|
||||
}
|
||||
})
|
||||
]
|
||||
};
|
||||
};
|
@ -0,0 +1,50 @@
|
||||
var roboHydra = require("robohydra"),
|
||||
roboHydraHeads = roboHydra.heads,
|
||||
roboHydraHead = roboHydraHeads.RoboHydraHead;
|
||||
|
||||
RoboHydraHeadDAV = roboHydraHeads.roboHydraHeadType({
|
||||
name: 'WebDAV Server',
|
||||
mandatoryProperties: [ 'path', 'handler' ],
|
||||
|
||||
parentPropBuilder: function() {
|
||||
var myHandler = this.handler;
|
||||
return {
|
||||
path: this.path,
|
||||
handler: function(req,res,next) {
|
||||
// default DAV behavior
|
||||
res.headers['DAV'] = 'addressbook, calendar-access';
|
||||
res.statusCode = 500;
|
||||
|
||||
// DAV operations that work on all URLs
|
||||
if (req.method == "OPTIONS") {
|
||||
res.statusCode = 204;
|
||||
res.headers['Allow'] = 'OPTIONS, PROPFIND, GET, PUT, DELETE';
|
||||
|
||||
} else if (req.method == "PROPFIND" && req.rawBody.toString().match(/current-user-principal/)) {
|
||||
res.statusCode = 207;
|
||||
res.write('\<?xml version="1.0" encoding="utf-8" ?>\
|
||||
<multistatus xmlns="DAV:">\
|
||||
<response>\
|
||||
<href>' + req.url + '</href> \
|
||||
<propstat>\
|
||||
<prop>\
|
||||
<current-user-principal>\
|
||||
<href>/dav/principals/users/test</href>\
|
||||
</current-user-principal>\
|
||||
</prop>\
|
||||
<status>HTTP/1.1 200 OK</status>\
|
||||
</propstat>\
|
||||
</response>\
|
||||
</multistatus>\
|
||||
');
|
||||
|
||||
} else
|
||||
myHandler(req,res,next);
|
||||
|
||||
res.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = RoboHydraHeadDAV;
|
@ -0,0 +1,18 @@
|
||||
var RoboHydraHead = require("robohydra").heads.RoboHydraHead;
|
||||
|
||||
exports.getBodyParts = function(conf) {
|
||||
return {
|
||||
heads: [
|
||||
new RoboHydraHead({
|
||||
path: "/redirect",
|
||||
handler: function(req,res,next) {
|
||||
res.statusCode = 302;
|
||||
res.headers = {
|
||||
location: 'http://www.example.com'
|
||||
}
|
||||
res.end();
|
||||
}
|
||||
})
|
||||
]
|
||||
};
|
||||
};
|
@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
node_modules/robohydra/bin/robohydra.js davdroid.conf -I plugins
|
@ -0,0 +1,39 @@
|
||||
package at.bitfire.davdroid.test;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import android.test.InstrumentationTestCase;
|
||||
import at.bitfire.davdroid.URIUtils;
|
||||
|
||||
public class URIUtilsTest extends InstrumentationTestCase {
|
||||
final static String
|
||||
ROOT_URI = "http://server/",
|
||||
BASE_URI = ROOT_URI + "dir/";
|
||||
URI baseURI;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
baseURI = new URI(BASE_URI);
|
||||
}
|
||||
|
||||
|
||||
public void testIsSame() throws URISyntaxException {
|
||||
assertTrue(URIUtils.isSame(new URI(ROOT_URI + "my@email/"), new URI(ROOT_URI + "my%40email/")));
|
||||
}
|
||||
|
||||
public void testResolve() {
|
||||
// resolve absolute URL
|
||||
assertEquals(ROOT_URI + "file", URIUtils.resolve(baseURI, "/file").toString());
|
||||
|
||||
// resolve relative URL (default case)
|
||||
assertEquals(BASE_URI + "file", URIUtils.resolve(baseURI, "file").toString());
|
||||
|
||||
// resolve relative URL with special characters
|
||||
assertEquals(BASE_URI + "fi:le", URIUtils.resolve(baseURI, "fi:le").toString());
|
||||
assertEquals(BASE_URI + "fi@le", URIUtils.resolve(baseURI, "fi@le").toString());
|
||||
|
||||
// resolve URL with other schema
|
||||
assertEquals("https://server", URIUtils.resolve(baseURI, "https://server").toString());
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
package at.bitfire.davdroid.webdav.test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
import org.apache.http.HttpException;
|
||||
|
||||
import android.test.InstrumentationTestCase;
|
||||
import at.bitfire.davdroid.webdav.HttpPropfind;
|
||||
import at.bitfire.davdroid.webdav.InvalidDavResponseException;
|
||||
import at.bitfire.davdroid.webdav.WebDavCollection;
|
||||
import at.bitfire.davdroid.webdav.WebDavResource;
|
||||
|
||||
public class WebDavCollectionTest extends InstrumentationTestCase {
|
||||
WebDavCollection dav;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
dav = new WebDavCollection(new URI("https://wurd.dev001.net/radicale/test/"), "test", "test", true);
|
||||
}
|
||||
|
||||
|
||||
public void testAutoDetection() throws InvalidDavResponseException, IOException, HttpException {
|
||||
WebDavCollection myDav = dav;
|
||||
|
||||
myDav.propfind(HttpPropfind.Mode.CURRENT_USER_PRINCIPAL);
|
||||
String currentUserPrincipal = myDav.getCurrentUserPrincipal();
|
||||
assertEquals("/radicale/test/", currentUserPrincipal);
|
||||
|
||||
myDav = new WebDavCollection(dav, currentUserPrincipal);
|
||||
myDav.propfind(HttpPropfind.Mode.HOME_SETS);
|
||||
String homeSet = myDav.getAddressbookHomeSet();
|
||||
assertEquals("/radicale/test/", homeSet);
|
||||
assertEquals("/radicale/test/", myDav.getCalendarHomeSet());
|
||||
|
||||
myDav = new WebDavCollection(dav, homeSet);
|
||||
myDav.propfind(HttpPropfind.Mode.MEMBERS_COLLECTIONS);
|
||||
assertEquals(3, myDav.getMembers().size());
|
||||
for (WebDavResource member : myDav.getMembers())
|
||||
assertTrue(member.isAddressBook() || member.isCalendar());
|
||||
}
|
||||
|
||||
}
|
@ -1,66 +1,178 @@
|
||||
package at.bitfire.davdroid.webdav.test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.HttpException;
|
||||
|
||||
import android.content.res.AssetManager;
|
||||
import android.test.InstrumentationTestCase;
|
||||
import at.bitfire.davdroid.webdav.HttpPropfind;
|
||||
import at.bitfire.davdroid.webdav.NotFoundException;
|
||||
import at.bitfire.davdroid.webdav.PreconditionFailedException;
|
||||
import at.bitfire.davdroid.webdav.WebDavResource;
|
||||
import at.bitfire.davdroid.webdav.WebDavResource.PutMode;
|
||||
|
||||
// tests require running robohydra!
|
||||
|
||||
public class WebDavResourceTest extends InstrumentationTestCase {
|
||||
URI davBaseURI, uriWithoutDAV, uriWithRedirection;
|
||||
final static String davUsername = "test", davPassword = "test";
|
||||
static final String ROBOHYDRA_BASE = "http://10.0.0.119:3000/";
|
||||
static byte[] SAMPLE_CONTENT = new byte[] { 1, 2, 3, 4, 5 };
|
||||
|
||||
AssetManager assetMgr;
|
||||
WebDavResource simpleFile,
|
||||
davCollection, davNonExistingFile, davExistingFile;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
davBaseURI = new URI("https://wurd.dev001.net/radicale/test/");
|
||||
uriWithoutDAV = new URI("http://www.apache.org");
|
||||
uriWithRedirection = new URI("http://wurd.dev001.net/public/");
|
||||
assetMgr = getInstrumentation().getContext().getResources().getAssets();
|
||||
|
||||
simpleFile = new WebDavResource(new URI(ROBOHYDRA_BASE + "assets/test.random"), false);
|
||||
|
||||
davCollection = new WebDavResource(new URI(ROBOHYDRA_BASE + "dav"), true);
|
||||
davNonExistingFile = new WebDavResource(davCollection, "collection/new.file");
|
||||
davExistingFile = new WebDavResource(davCollection, "collection/existing.file");
|
||||
}
|
||||
|
||||
|
||||
public void testGet() throws URISyntaxException, IOException, HttpException {
|
||||
WebDavResource dav = new WebDavResource(uriWithoutDAV, "", "", false, true);
|
||||
dav.get();
|
||||
InputStream is = dav.getContent();
|
||||
assertNotNull(is);
|
||||
/* test resource name handling */
|
||||
|
||||
public void testGetName() {
|
||||
// collection names should have a trailing slash
|
||||
assertEquals("dav", davCollection.getName());
|
||||
// but non-collection names shouldn't
|
||||
assertEquals("test.random", simpleFile.getName());
|
||||
}
|
||||
|
||||
public void testTrailingSlash() throws URISyntaxException {
|
||||
WebDavResource dav = new WebDavResource(new URI("http://server/path"), "", "", false, true);
|
||||
assertEquals("/path/", dav.getLocation().getPath());
|
||||
// collections should have a trailing slash
|
||||
assertEquals("/dav/", davCollection.getLocation().getPath());
|
||||
// but non-collection members shouldn't
|
||||
assertEquals("/assets/test.random", simpleFile.getLocation().getPath());
|
||||
}
|
||||
|
||||
|
||||
/* test feature detection */
|
||||
|
||||
public void testOptions() throws URISyntaxException, IOException, HttpException {
|
||||
String[] davMethods = new String[] { "PROPFIND", "PUT", "DELETE" },
|
||||
String[] davMethods = new String[] { "PROPFIND", "GET", "PUT", "DELETE" },
|
||||
davCapabilities = new String[] { "addressbook", "calendar-access" };
|
||||
|
||||
// server without DAV
|
||||
WebDavResource dav = new WebDavResource(uriWithoutDAV, "", "", false, true);
|
||||
dav.options();
|
||||
simpleFile.options();
|
||||
for (String method : davMethods)
|
||||
assertFalse(dav.supportsMethod(method));
|
||||
assertFalse(simpleFile.supportsMethod(method));
|
||||
for (String capability : davCapabilities)
|
||||
assertFalse(dav.supportsDAV(capability));
|
||||
assertFalse(simpleFile.supportsDAV(capability));
|
||||
|
||||
// server with DAV
|
||||
dav = new WebDavResource(davBaseURI, davUsername, davPassword, false, true);
|
||||
dav.options();
|
||||
davCollection.options();
|
||||
for (String davMethod : davMethods)
|
||||
assert(dav.supportsMethod(davMethod));
|
||||
assert(davCollection.supportsMethod(davMethod));
|
||||
for (String capability : davCapabilities)
|
||||
assert(dav.supportsDAV(capability));
|
||||
assert(davCollection.supportsDAV(capability));
|
||||
}
|
||||
|
||||
public void testPropfindCurrentUserPrincipal() throws IOException, HttpException {
|
||||
assertTrue(davCollection.propfind(HttpPropfind.Mode.CURRENT_USER_PRINCIPAL));
|
||||
assertEquals("/dav/principals/users/test", davCollection.getCurrentUserPrincipal());
|
||||
|
||||
assertFalse(simpleFile.propfind(HttpPropfind.Mode.CURRENT_USER_PRINCIPAL));
|
||||
assertNull(simpleFile.getCurrentUserPrincipal());
|
||||
}
|
||||
|
||||
public void testRedirections() throws URISyntaxException, IOException {
|
||||
WebDavResource dav = new WebDavResource(uriWithRedirection, "", "", false, true);
|
||||
public void testPropfindHomeSets() throws IOException, HttpException {
|
||||
WebDavResource dav = new WebDavResource(davCollection, "principals/users/test");
|
||||
dav.propfind(HttpPropfind.Mode.HOME_SETS);
|
||||
assertEquals("/dav/addressbooks/test/", dav.getAddressbookHomeSet());
|
||||
assertEquals("/dav/calendars/test/", dav.getCalendarHomeSet());
|
||||
}
|
||||
|
||||
public void testPropfindAddressBooks() throws IOException, HttpException {
|
||||
WebDavResource dav = new WebDavResource(davCollection, "addressbooks/test");
|
||||
dav.propfind(HttpPropfind.Mode.MEMBERS_COLLECTIONS);
|
||||
assertEquals(2, dav.getMembers().size());
|
||||
for (WebDavResource member : dav.getMembers()) {
|
||||
if (member.getName().equals("default.vcf"))
|
||||
assertTrue(member.isAddressBook());
|
||||
else
|
||||
assertFalse(member.isAddressBook());
|
||||
assertFalse(member.isCalendar());
|
||||
}
|
||||
}
|
||||
|
||||
public void testPropfindCalendars() throws IOException, HttpException {
|
||||
WebDavResource dav = new WebDavResource(davCollection, "calendars/test");
|
||||
dav.propfind(HttpPropfind.Mode.MEMBERS_COLLECTIONS);
|
||||
assertEquals(3, dav.getMembers().size());
|
||||
for (WebDavResource member : dav.getMembers()) {
|
||||
if (member.getName().contains(".ics"))
|
||||
assertTrue(member.isCalendar());
|
||||
else
|
||||
assertFalse(member.isCalendar());
|
||||
assertFalse(member.isAddressBook());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* test normal HTTP */
|
||||
|
||||
public void testDontFollowRedirections() throws URISyntaxException, IOException {
|
||||
WebDavResource redirection = new WebDavResource(new URI(ROBOHYDRA_BASE + "redirect"), false);
|
||||
try {
|
||||
dav.options();
|
||||
redirection.get();
|
||||
} catch (HttpException e) {
|
||||
return;
|
||||
}
|
||||
fail();
|
||||
}
|
||||
|
||||
public void testGet() throws URISyntaxException, IOException, HttpException {
|
||||
simpleFile.get();
|
||||
assertTrue(IOUtils.contentEquals(
|
||||
assetMgr.open("test.random", AssetManager.ACCESS_STREAMING),
|
||||
simpleFile.getContent()
|
||||
));
|
||||
}
|
||||
|
||||
public void testPutAddDontOverwrite() throws IOException, HttpException {
|
||||
// should succeed on a non-existing file
|
||||
davNonExistingFile.put(SAMPLE_CONTENT, PutMode.ADD_DONT_OVERWRITE);
|
||||
|
||||
// should fail on an existing file
|
||||
try {
|
||||
davExistingFile.put(SAMPLE_CONTENT, PutMode.ADD_DONT_OVERWRITE);
|
||||
} catch(PreconditionFailedException ex) {
|
||||
return;
|
||||
}
|
||||
fail();
|
||||
}
|
||||
|
||||
public void testPutUpdateDontOverwrite() throws IOException, HttpException {
|
||||
// should succeed on an existing file
|
||||
davExistingFile.put(SAMPLE_CONTENT, PutMode.UPDATE_DONT_OVERWRITE);
|
||||
|
||||
// should fail on a non-existing file
|
||||
try {
|
||||
davNonExistingFile.put(SAMPLE_CONTENT, PutMode.UPDATE_DONT_OVERWRITE);
|
||||
} catch(PreconditionFailedException ex) {
|
||||
return;
|
||||
}
|
||||
fail();
|
||||
}
|
||||
|
||||
public void testDelete() throws IOException, HttpException {
|
||||
// should succeed on an existing file
|
||||
davExistingFile.delete();
|
||||
|
||||
// should fail on a non-existing file
|
||||
try {
|
||||
davNonExistingFile.delete();
|
||||
} catch (NotFoundException e) {
|
||||
return;
|
||||
}
|
||||
fail();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in new issue