mirror of
https://github.com/etesync/android
synced 2024-11-22 16:08:13 +00:00
refactoring, RoboHydra tests
This commit is contained in:
parent
0626f1ecdc
commit
362f0036be
@ -9,7 +9,7 @@ package at.bitfire.davdroid;
|
|||||||
|
|
||||||
public class Constants {
|
public class Constants {
|
||||||
public static final String
|
public static final String
|
||||||
APP_VERSION = "0.3.6-alpha",
|
APP_VERSION = "0.3.7-alpha",
|
||||||
|
|
||||||
ACCOUNT_TYPE = "bitfire.at.davdroid",
|
ACCOUNT_TYPE = "bitfire.at.davdroid",
|
||||||
|
|
||||||
|
@ -3,8 +3,8 @@ package at.bitfire.davdroid;
|
|||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
|
|
||||||
public class Utils {
|
public class URIUtils {
|
||||||
public static boolean isSameURL(URI a, URI b) {
|
public static boolean isSame(URI a, URI b) {
|
||||||
try {
|
try {
|
||||||
a = new URI(a.getScheme(), null, a.getHost(), a.getPort(), a.getPath(), a.getQuery(), a.getFragment());
|
a = new URI(a.getScheme(), null, a.getHost(), a.getPort(), a.getPath(), a.getQuery(), a.getFragment());
|
||||||
b = new URI(b.getScheme(), null, b.getHost(), b.getPort(), b.getPath(), b.getQuery(), b.getFragment());
|
b = new URI(b.getScheme(), null, b.getHost(), b.getPort(), b.getPath(), b.getQuery(), b.getFragment());
|
||||||
@ -14,8 +14,8 @@ public class Utils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static URI resolveURI(URI parent, String member) {
|
public static URI resolve(URI parent, String member) {
|
||||||
if (!member.startsWith("/") && !member.startsWith("http:") && !member.startsWith("https://"))
|
if (!member.startsWith("/") && !member.startsWith("http:") && !member.startsWith("https:"))
|
||||||
member = "./" + member;
|
member = "./" + member;
|
||||||
|
|
||||||
return parent.resolve(member);
|
return parent.resolve(member);
|
@ -7,10 +7,9 @@
|
|||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package at.bitfire.davdroid.resource;
|
package at.bitfire.davdroid.resource;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
|
|
||||||
import at.bitfire.davdroid.webdav.WebDavCollection.MultigetType;
|
import at.bitfire.davdroid.webdav.WebDavResource.MultigetType;
|
||||||
|
|
||||||
public class CalDavCalendar extends RemoteCollection<Event> {
|
public class CalDavCalendar extends RemoteCollection<Event> {
|
||||||
//private final static String TAG = "davdroid.CalDavCalendar";
|
//private final static String TAG = "davdroid.CalDavCalendar";
|
||||||
|
@ -9,7 +9,7 @@ package at.bitfire.davdroid.resource;
|
|||||||
|
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
|
|
||||||
import at.bitfire.davdroid.webdav.WebDavCollection.MultigetType;
|
import at.bitfire.davdroid.webdav.WebDavResource.MultigetType;
|
||||||
|
|
||||||
public class CardDavAddressBook extends RemoteCollection<Contact> {
|
public class CardDavAddressBook extends RemoteCollection<Contact> {
|
||||||
//private final static String TAG = "davdroid.CardDavAddressBook";
|
//private final static String TAG = "davdroid.CardDavAddressBook";
|
||||||
|
@ -23,22 +23,21 @@ import org.apache.http.HttpException;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import at.bitfire.davdroid.webdav.HttpPropfind;
|
import at.bitfire.davdroid.webdav.HttpPropfind;
|
||||||
import at.bitfire.davdroid.webdav.InvalidDavResponseException;
|
import at.bitfire.davdroid.webdav.InvalidDavResponseException;
|
||||||
import at.bitfire.davdroid.webdav.WebDavCollection;
|
|
||||||
import at.bitfire.davdroid.webdav.WebDavCollection.MultigetType;
|
|
||||||
import at.bitfire.davdroid.webdav.WebDavResource;
|
import at.bitfire.davdroid.webdav.WebDavResource;
|
||||||
|
import at.bitfire.davdroid.webdav.WebDavResource.MultigetType;
|
||||||
import at.bitfire.davdroid.webdav.WebDavResource.PutMode;
|
import at.bitfire.davdroid.webdav.WebDavResource.PutMode;
|
||||||
|
|
||||||
public abstract class RemoteCollection<ResourceType extends Resource> {
|
public abstract class RemoteCollection<ResourceType extends Resource> {
|
||||||
private static final String TAG = "davdroid.RemoteCollection";
|
private static final String TAG = "davdroid.RemoteCollection";
|
||||||
|
|
||||||
@Getter WebDavCollection collection;
|
@Getter WebDavResource collection;
|
||||||
|
|
||||||
abstract protected String memberContentType();
|
abstract protected String memberContentType();
|
||||||
abstract protected MultigetType multiGetType();
|
abstract protected MultigetType multiGetType();
|
||||||
abstract protected ResourceType newResourceSkeleton(String name, String ETag);
|
abstract protected ResourceType newResourceSkeleton(String name, String ETag);
|
||||||
|
|
||||||
public RemoteCollection(String baseURL, String user, String password, boolean preemptiveAuth) throws URISyntaxException {
|
public RemoteCollection(String baseURL, String user, String password, boolean preemptiveAuth) throws URISyntaxException {
|
||||||
collection = new WebDavCollection(new URI(baseURL), user, password, preemptiveAuth);
|
collection = new WebDavResource(new URI(baseURL), user, password, preemptiveAuth, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -58,9 +57,12 @@ public abstract class RemoteCollection<ResourceType extends Resource> {
|
|||||||
collection.propfind(HttpPropfind.Mode.MEMBERS_ETAG);
|
collection.propfind(HttpPropfind.Mode.MEMBERS_ETAG);
|
||||||
|
|
||||||
List<ResourceType> resources = new LinkedList<ResourceType>();
|
List<ResourceType> resources = new LinkedList<ResourceType>();
|
||||||
for (WebDavResource member : collection.getMembers())
|
if (collection.getMembers() != null) {
|
||||||
resources.add(newResourceSkeleton(member.getName(), member.getETag()));
|
for (WebDavResource member : collection.getMembers())
|
||||||
return resources.toArray(new Resource[0]);
|
resources.add(newResourceSkeleton(member.getName(), member.getETag()));
|
||||||
|
return resources.toArray(new Resource[0]);
|
||||||
|
} else
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@ -78,19 +80,23 @@ public abstract class RemoteCollection<ResourceType extends Resource> {
|
|||||||
collection.multiGet(names.toArray(new String[0]), multiGetType());
|
collection.multiGet(names.toArray(new String[0]), multiGetType());
|
||||||
|
|
||||||
LinkedList<ResourceType> foundResources = new LinkedList<ResourceType>();
|
LinkedList<ResourceType> foundResources = new LinkedList<ResourceType>();
|
||||||
for (WebDavResource member : collection.getMembers()) {
|
if (collection.getMembers() != null)
|
||||||
ResourceType resource = newResourceSkeleton(member.getName(), member.getETag());
|
for (WebDavResource member : collection.getMembers()) {
|
||||||
try {
|
ResourceType resource = newResourceSkeleton(member.getName(), member.getETag());
|
||||||
InputStream is = member.getContent();
|
try {
|
||||||
if (is != null) {
|
InputStream is = member.getContent();
|
||||||
resource.parseEntity(is);
|
if (is != null) {
|
||||||
foundResources.add(resource);
|
resource.parseEntity(is);
|
||||||
} else
|
foundResources.add(resource);
|
||||||
Log.e(TAG, "Ignoring entity without content");
|
} else
|
||||||
} catch (ParserException ex) {
|
Log.e(TAG, "Ignoring entity without content");
|
||||||
Log.e(TAG, "Ignoring unparseable entity in multi-response", ex);
|
} catch (ParserException ex) {
|
||||||
|
Log.e(TAG, "Ignoring unparseable entity in multi-response", ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
|
return null;
|
||||||
|
|
||||||
return foundResources.toArray(new Resource[0]);
|
return foundResources.toArray(new Resource[0]);
|
||||||
} catch (ParserException ex) {
|
} catch (ParserException ex) {
|
||||||
Log.w(TAG, "Couldn't parse single multi-get entity", ex);
|
Log.w(TAG, "Couldn't parse single multi-get entity", ex);
|
||||||
@ -113,16 +119,22 @@ public abstract class RemoteCollection<ResourceType extends Resource> {
|
|||||||
WebDavResource member = new WebDavResource(collection, res.getName(), res.getETag());
|
WebDavResource member = new WebDavResource(collection, res.getName(), res.getETag());
|
||||||
member.setContentType(memberContentType());
|
member.setContentType(memberContentType());
|
||||||
member.put(res.toEntity().getBytes("UTF-8"), PutMode.ADD_DONT_OVERWRITE);
|
member.put(res.toEntity().getBytes("UTF-8"), PutMode.ADD_DONT_OVERWRITE);
|
||||||
|
|
||||||
|
collection.invalidateCTag();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void delete(Resource res) throws IOException, HttpException {
|
public void delete(Resource res) throws IOException, HttpException {
|
||||||
WebDavResource member = new WebDavResource(collection, res.getName(), res.getETag());
|
WebDavResource member = new WebDavResource(collection, res.getName(), res.getETag());
|
||||||
member.delete();
|
member.delete();
|
||||||
|
|
||||||
|
collection.invalidateCTag();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(Resource res) throws IOException, HttpException, ValidationException {
|
public void update(Resource res) throws IOException, HttpException, ValidationException {
|
||||||
WebDavResource member = new WebDavResource(collection, res.getName(), res.getETag());
|
WebDavResource member = new WebDavResource(collection, res.getName(), res.getETag());
|
||||||
member.setContentType(memberContentType());
|
member.setContentType(memberContentType());
|
||||||
member.put(res.toEntity().getBytes("UTF-8"), PutMode.UPDATE_DONT_OVERWRITE);
|
member.put(res.toEntity().getBytes("UTF-8"), PutMode.UPDATE_DONT_OVERWRITE);
|
||||||
|
|
||||||
|
collection.invalidateCTag();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,6 @@ import android.widget.Toast;
|
|||||||
import at.bitfire.davdroid.R;
|
import at.bitfire.davdroid.R;
|
||||||
import at.bitfire.davdroid.resource.IncapableResourceException;
|
import at.bitfire.davdroid.resource.IncapableResourceException;
|
||||||
import at.bitfire.davdroid.webdav.HttpPropfind.Mode;
|
import at.bitfire.davdroid.webdav.HttpPropfind.Mode;
|
||||||
import at.bitfire.davdroid.webdav.WebDavCollection;
|
|
||||||
import at.bitfire.davdroid.webdav.WebDavResource;
|
import at.bitfire.davdroid.webdav.WebDavResource;
|
||||||
|
|
||||||
public class QueryServerDialogFragment extends DialogFragment implements LoaderCallbacks<ServerInfo> {
|
public class QueryServerDialogFragment extends DialogFragment implements LoaderCallbacks<ServerInfo> {
|
||||||
@ -110,13 +109,15 @@ public class QueryServerDialogFragment extends DialogFragment implements LoaderC
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// (1/5) detect capabilities
|
// (1/5) detect capabilities
|
||||||
WebDavCollection base = new WebDavCollection(new URI(serverInfo.getBaseURL()), serverInfo.getUserName(),
|
WebDavResource base = new WebDavResource(new URI(serverInfo.getBaseURL()), serverInfo.getUserName(),
|
||||||
serverInfo.getPassword(), serverInfo.isAuthPreemptive());
|
serverInfo.getPassword(), serverInfo.isAuthPreemptive(), true);
|
||||||
base.options();
|
base.options();
|
||||||
|
|
||||||
serverInfo.setCardDAV(base.supportsDAV("addressbook"));
|
serverInfo.setCardDAV(base.supportsDAV("addressbook"));
|
||||||
serverInfo.setCalDAV(base.supportsDAV("calendar-access"));
|
serverInfo.setCalDAV(base.supportsDAV("calendar-access"));
|
||||||
if (!base.supportsMethod("PROPFIND") || (!serverInfo.isCalDAV() && !serverInfo.isCardDAV()))
|
if (!base.supportsMethod("PROPFIND") || !base.supportsMethod("GET") ||
|
||||||
|
!base.supportsMethod("PUT") || !base.supportsMethod("DELETE") ||
|
||||||
|
(!serverInfo.isCalDAV() && !serverInfo.isCardDAV()))
|
||||||
throw new IncapableResourceException(getContext().getString(R.string.neither_caldav_nor_carddav));
|
throw new IncapableResourceException(getContext().getString(R.string.neither_caldav_nor_carddav));
|
||||||
|
|
||||||
// (2/5) get principal URL
|
// (2/5) get principal URL
|
||||||
@ -129,7 +130,7 @@ public class QueryServerDialogFragment extends DialogFragment implements LoaderC
|
|||||||
throw new IncapableResourceException(getContext().getString(R.string.error_principal_path));
|
throw new IncapableResourceException(getContext().getString(R.string.error_principal_path));
|
||||||
|
|
||||||
// (3/5) get home sets
|
// (3/5) get home sets
|
||||||
WebDavCollection principal = new WebDavCollection(base, principalPath);
|
WebDavResource principal = new WebDavResource(base, principalPath);
|
||||||
principal.propfind(Mode.HOME_SETS);
|
principal.propfind(Mode.HOME_SETS);
|
||||||
|
|
||||||
String pathAddressBooks = null;
|
String pathAddressBooks = null;
|
||||||
@ -152,42 +153,44 @@ public class QueryServerDialogFragment extends DialogFragment implements LoaderC
|
|||||||
|
|
||||||
// (4/5) get address books
|
// (4/5) get address books
|
||||||
if (serverInfo.isCardDAV()) {
|
if (serverInfo.isCardDAV()) {
|
||||||
WebDavCollection homeSetAddressBooks = new WebDavCollection(principal, pathAddressBooks);
|
WebDavResource homeSetAddressBooks = new WebDavResource(principal, pathAddressBooks);
|
||||||
homeSetAddressBooks.propfind(Mode.MEMBERS_COLLECTIONS);
|
homeSetAddressBooks.propfind(Mode.MEMBERS_COLLECTIONS);
|
||||||
|
|
||||||
List<ServerInfo.ResourceInfo> addressBooks = new LinkedList<ServerInfo.ResourceInfo>();
|
List<ServerInfo.ResourceInfo> addressBooks = new LinkedList<ServerInfo.ResourceInfo>();
|
||||||
for (WebDavResource resource : homeSetAddressBooks.getMembers())
|
if (homeSetAddressBooks.getMembers() != null)
|
||||||
if (resource.isAddressBook()) {
|
for (WebDavResource resource : homeSetAddressBooks.getMembers())
|
||||||
Log.i(TAG, "Found address book: " + resource.getLocation().getPath());
|
if (resource.isAddressBook()) {
|
||||||
ServerInfo.ResourceInfo info = new ServerInfo.ResourceInfo(
|
Log.i(TAG, "Found address book: " + resource.getLocation().getPath());
|
||||||
ServerInfo.ResourceInfo.Type.ADDRESS_BOOK,
|
ServerInfo.ResourceInfo info = new ServerInfo.ResourceInfo(
|
||||||
resource.getLocation().getPath(),
|
ServerInfo.ResourceInfo.Type.ADDRESS_BOOK,
|
||||||
resource.getDisplayName(),
|
resource.getLocation().getPath(),
|
||||||
resource.getDescription()
|
resource.getDisplayName(),
|
||||||
);
|
resource.getDescription()
|
||||||
addressBooks.add(info);
|
);
|
||||||
}
|
addressBooks.add(info);
|
||||||
|
}
|
||||||
|
|
||||||
serverInfo.setAddressBooks(addressBooks);
|
serverInfo.setAddressBooks(addressBooks);
|
||||||
}
|
}
|
||||||
|
|
||||||
// (5/5) get calendars
|
// (5/5) get calendars
|
||||||
if (serverInfo.isCalDAV()) {
|
if (serverInfo.isCalDAV()) {
|
||||||
WebDavCollection homeSetCalendars = new WebDavCollection(principal, pathCalendars);
|
WebDavResource homeSetCalendars = new WebDavResource(principal, pathCalendars);
|
||||||
homeSetCalendars.propfind(Mode.MEMBERS_COLLECTIONS);
|
homeSetCalendars.propfind(Mode.MEMBERS_COLLECTIONS);
|
||||||
|
|
||||||
List<ServerInfo.ResourceInfo> calendars = new LinkedList<ServerInfo.ResourceInfo>();
|
List<ServerInfo.ResourceInfo> calendars = new LinkedList<ServerInfo.ResourceInfo>();
|
||||||
for (WebDavResource resource : homeSetCalendars.getMembers())
|
if (homeSetCalendars.getMembers() != null)
|
||||||
if (resource.isCalendar()) {
|
for (WebDavResource resource : homeSetCalendars.getMembers())
|
||||||
Log.i(TAG, "Found calendar: " + resource.getLocation().getPath());
|
if (resource.isCalendar()) {
|
||||||
ServerInfo.ResourceInfo info = new ServerInfo.ResourceInfo(
|
Log.i(TAG, "Found calendar: " + resource.getLocation().getPath());
|
||||||
ServerInfo.ResourceInfo.Type.CALENDAR,
|
ServerInfo.ResourceInfo info = new ServerInfo.ResourceInfo(
|
||||||
resource.getLocation().getPath(),
|
ServerInfo.ResourceInfo.Type.CALENDAR,
|
||||||
resource.getDisplayName(),
|
resource.getLocation().getPath(),
|
||||||
resource.getDescription()
|
resource.getDisplayName(),
|
||||||
);
|
resource.getDescription()
|
||||||
calendars.add(info);
|
);
|
||||||
}
|
calendars.add(info);
|
||||||
|
}
|
||||||
|
|
||||||
serverInfo.setCalendars(calendars);
|
serverInfo.setCalendars(calendars);
|
||||||
}
|
}
|
||||||
|
@ -74,8 +74,8 @@ public class HttpPropfind extends HttpEntityEnclosingRequestBase {
|
|||||||
setEntity(new StringEntity(writer.toString(), "UTF-8"));
|
setEntity(new StringEntity(writer.toString(), "UTF-8"));
|
||||||
|
|
||||||
Log.d(TAG, "Prepared PROPFIND request: " + writer.toString());
|
Log.d(TAG, "Prepared PROPFIND request: " + writer.toString());
|
||||||
} catch(Exception e) {
|
} catch(Exception ex) {
|
||||||
Log.w(TAG, e.getMessage());
|
Log.e(TAG, "Couldn't prepare PROPFIND request", ex);
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -7,18 +7,25 @@
|
|||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package at.bitfire.davdroid.webdav;
|
package at.bitfire.davdroid.webdav;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.io.StringWriter;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
|
import org.apache.commons.io.input.TeeInputStream;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.apache.http.Header;
|
import org.apache.http.Header;
|
||||||
import org.apache.http.HttpException;
|
import org.apache.http.HttpException;
|
||||||
@ -35,11 +42,14 @@ import org.apache.http.client.methods.HttpPut;
|
|||||||
import org.apache.http.client.params.ClientPNames;
|
import org.apache.http.client.params.ClientPNames;
|
||||||
import org.apache.http.entity.ByteArrayEntity;
|
import org.apache.http.entity.ByteArrayEntity;
|
||||||
import org.apache.http.impl.client.DefaultHttpClient;
|
import org.apache.http.impl.client.DefaultHttpClient;
|
||||||
|
import org.apache.http.message.BasicLineParser;
|
||||||
import org.apache.http.params.CoreProtocolPNames;
|
import org.apache.http.params.CoreProtocolPNames;
|
||||||
|
import org.simpleframework.xml.Serializer;
|
||||||
|
import org.simpleframework.xml.core.Persister;
|
||||||
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import at.bitfire.davdroid.Constants;
|
import at.bitfire.davdroid.Constants;
|
||||||
import at.bitfire.davdroid.Utils;
|
import at.bitfire.davdroid.URIUtils;
|
||||||
|
|
||||||
|
|
||||||
@ToString
|
@ToString
|
||||||
@ -54,29 +64,54 @@ public class WebDavResource {
|
|||||||
CTAG, ETAG,
|
CTAG, ETAG,
|
||||||
CONTENT_TYPE
|
CONTENT_TYPE
|
||||||
}
|
}
|
||||||
|
public enum MultigetType {
|
||||||
|
ADDRESS_BOOK,
|
||||||
|
CALENDAR
|
||||||
|
}
|
||||||
public enum PutMode {
|
public enum PutMode {
|
||||||
ADD_DONT_OVERWRITE,
|
ADD_DONT_OVERWRITE,
|
||||||
UPDATE_DONT_OVERWRITE
|
UPDATE_DONT_OVERWRITE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// location of this resource
|
||||||
@Getter protected URI location;
|
@Getter protected URI location;
|
||||||
protected Set<String> capabilities = new HashSet<String>(), methods = new HashSet<String>();
|
|
||||||
|
// DAV capabilities (DAV: header) and allowed DAV methods (set for OPTIONS request)
|
||||||
|
protected Set<String> capabilities = new HashSet<String>(),
|
||||||
|
methods = new HashSet<String>();
|
||||||
|
|
||||||
|
// DAV properties
|
||||||
protected HashMap<Property, String> properties = new HashMap<Property, String>();
|
protected HashMap<Property, String> properties = new HashMap<Property, String>();
|
||||||
|
|
||||||
|
// list of members (only for collections)
|
||||||
|
@Getter protected List<WebDavResource> members;
|
||||||
|
|
||||||
|
// content (available after GET)
|
||||||
@Getter protected InputStream content;
|
@Getter protected InputStream content;
|
||||||
|
|
||||||
protected DefaultHttpClient client;
|
protected DefaultHttpClient client;
|
||||||
|
|
||||||
|
|
||||||
public WebDavResource(URI baseURL, String username, String password, boolean preemptive, boolean isCollection) throws URISyntaxException {
|
public WebDavResource(URI baseURL, boolean trailingSlash) throws URISyntaxException {
|
||||||
location = baseURL.normalize();
|
location = baseURL.normalize();
|
||||||
|
|
||||||
if (isCollection && !location.getPath().endsWith("/"))
|
if (trailingSlash && !location.getPath().endsWith("/"))
|
||||||
location = new URI(location.getScheme(), location.getSchemeSpecificPart() + "/", null);
|
location = new URI(location.getScheme(), location.getSchemeSpecificPart() + "/", null);
|
||||||
|
|
||||||
// create new HTTP client
|
// create new HTTP client
|
||||||
client = new DefaultHttpClient();
|
client = new DefaultHttpClient();
|
||||||
client.getParams().setParameter(CoreProtocolPNames.USER_AGENT, "DAVdroid/" + Constants.APP_VERSION);
|
client.getParams().setParameter(CoreProtocolPNames.USER_AGENT, "DAVdroid/" + Constants.APP_VERSION);
|
||||||
|
|
||||||
|
// allow gzip compression
|
||||||
|
GzipDecompressingEntity.enable(client);
|
||||||
|
|
||||||
|
// redirections
|
||||||
|
client.getParams().setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public WebDavResource(URI baseURL, String username, String password, boolean preemptive, boolean trailingSlash) throws URISyntaxException {
|
||||||
|
this(baseURL, trailingSlash);
|
||||||
|
|
||||||
// authenticate
|
// authenticate
|
||||||
client.getCredentialsProvider().setCredentials(new AuthScope(location.getHost(), location.getPort()),
|
client.getCredentialsProvider().setCredentials(new AuthScope(location.getHost(), location.getPort()),
|
||||||
new UsernamePasswordCredentials(username, password));
|
new UsernamePasswordCredentials(username, password));
|
||||||
@ -85,29 +120,24 @@ public class WebDavResource {
|
|||||||
Log.i(TAG, "Using preemptive Basic Authentication");
|
Log.i(TAG, "Using preemptive Basic Authentication");
|
||||||
client.addRequestInterceptor(new PreemptiveAuthInterceptor(), 0);
|
client.addRequestInterceptor(new PreemptiveAuthInterceptor(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// allow gzip compression
|
|
||||||
GzipDecompressingEntity.enable(client);
|
|
||||||
|
|
||||||
// redirections
|
|
||||||
client.getParams().setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected WebDavResource(WebDavCollection parent, URI uri) {
|
protected WebDavResource(WebDavResource parent, URI uri) {
|
||||||
location = uri;
|
location = uri;
|
||||||
client = parent.client;
|
client = parent.client;
|
||||||
}
|
}
|
||||||
|
|
||||||
public WebDavResource(WebDavCollection parent, String member) {
|
public WebDavResource(WebDavResource parent, String member) {
|
||||||
location = Utils.resolveURI(parent.location, member);
|
location = URIUtils.resolve(parent.location, member);
|
||||||
client = parent.client;
|
client = parent.client;
|
||||||
}
|
}
|
||||||
|
|
||||||
public WebDavResource(WebDavCollection parent, String member, String ETag) {
|
public WebDavResource(WebDavResource parent, String member, String ETag) {
|
||||||
this(parent, member);
|
this(parent, member);
|
||||||
properties.put(Property.ETAG, ETag);
|
properties.put(Property.ETAG, ETag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected void checkResponse(HttpResponse response) throws HttpException {
|
protected void checkResponse(HttpResponse response) throws HttpException {
|
||||||
checkResponse(response.getStatusLine());
|
checkResponse(response.getStatusLine());
|
||||||
}
|
}
|
||||||
@ -140,14 +170,12 @@ public class WebDavResource {
|
|||||||
checkResponse(response);
|
checkResponse(response);
|
||||||
|
|
||||||
Header[] allowHeaders = response.getHeaders("Allow");
|
Header[] allowHeaders = response.getHeaders("Allow");
|
||||||
if (allowHeaders != null)
|
for (Header allowHeader : allowHeaders)
|
||||||
for (Header allowHeader : allowHeaders)
|
methods.addAll(Arrays.asList(allowHeader.getValue().split(", ?")));
|
||||||
methods.addAll(Arrays.asList(allowHeader.getValue().split(", ?")));
|
|
||||||
|
|
||||||
Header[] capHeaders = response.getHeaders("DAV");
|
Header[] capHeaders = response.getHeaders("DAV");
|
||||||
if (capHeaders != null)
|
for (Header capHeader : capHeaders)
|
||||||
for (Header capHeader : capHeaders)
|
capabilities.addAll(Arrays.asList(capHeader.getValue().split(", ?")));
|
||||||
capabilities.addAll(Arrays.asList(capHeader.getValue().split(", ?")));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean supportsDAV(String capability) {
|
public boolean supportsDAV(String capability) {
|
||||||
@ -192,6 +220,9 @@ public class WebDavResource {
|
|||||||
public String getCTag() {
|
public String getCTag() {
|
||||||
return properties.get(Property.CTAG);
|
return properties.get(Property.CTAG);
|
||||||
}
|
}
|
||||||
|
public void invalidateCTag() {
|
||||||
|
properties.remove(Property.CTAG);
|
||||||
|
}
|
||||||
|
|
||||||
public String getETag() {
|
public String getETag() {
|
||||||
return properties.get(Property.ETAG);
|
return properties.get(Property.ETAG);
|
||||||
@ -214,6 +245,81 @@ public class WebDavResource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
multiget.hrefs.add(new DavHref(URIUtils.resolve(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* resource operations */
|
/* resource operations */
|
||||||
|
|
||||||
public void get() throws IOException, HttpException {
|
public void get() throws IOException, HttpException {
|
||||||
@ -233,13 +339,13 @@ public class WebDavResource {
|
|||||||
put.addHeader("If-None-Match", "*");
|
put.addHeader("If-None-Match", "*");
|
||||||
break;
|
break;
|
||||||
case UPDATE_DONT_OVERWRITE:
|
case UPDATE_DONT_OVERWRITE:
|
||||||
put.addHeader("If-Match", getETag());
|
put.addHeader("If-Match", (getETag() != null) ? getETag() : "*");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getContentType() != null)
|
if (getContentType() != null)
|
||||||
put.addHeader("Content-Type", getContentType());
|
put.addHeader("Content-Type", getContentType());
|
||||||
|
|
||||||
checkResponse(client.execute(put));
|
checkResponse(client.execute(put));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -252,4 +358,87 @@ public class WebDavResource {
|
|||||||
checkResponse(client.execute(delete));
|
checkResponse(client.execute(delete));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* helpers */
|
||||||
|
|
||||||
|
protected void processMultiStatus(DavMultistatus multistatus) throws HttpException {
|
||||||
|
if (multistatus.response == null) // empty response
|
||||||
|
return;
|
||||||
|
|
||||||
|
// member list will be built from response
|
||||||
|
List<WebDavResource> members = new LinkedList<WebDavResource>();
|
||||||
|
|
||||||
|
for (DavResponse singleResponse : multistatus.response) {
|
||||||
|
URI href;
|
||||||
|
try {
|
||||||
|
href = URIUtils.resolve(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 (URIUtils.isSame(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 && prop.currentUserPrincipal.getHref() != null)
|
||||||
|
referenced.properties.put(Property.CURRENT_USER_PRINCIPAL, prop.currentUserPrincipal.getHref().href);
|
||||||
|
|
||||||
|
if (prop.addressbookHomeSet != null && prop.addressbookHomeSet.getHref() != null)
|
||||||
|
referenced.properties.put(Property.ADDRESSBOOK_HOMESET, prop.addressbookHomeSet.getHref().href);
|
||||||
|
|
||||||
|
if (singlePropstat.prop.calendarHomeSet != null && prop.calendarHomeSet.getHref() != 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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.members = members;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
BIN
test/assets/test.random
Normal file
BIN
test/assets/test.random
Normal file
Binary file not shown.
1
test/robohydra/.gitignore
vendored
Normal file
1
test/robohydra/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
node_modules
|
5
test/robohydra/davdroid.conf
Normal file
5
test/robohydra/davdroid.conf
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{"plugins":[
|
||||||
|
"assets",
|
||||||
|
"redirect",
|
||||||
|
"dav-default"
|
||||||
|
]}
|
12
test/robohydra/plugins/assets/index.js
Normal file
12
test/robohydra/plugins/assets/index.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
var RoboHydraHeadFilesystem = require("robohydra").heads.RoboHydraHeadFilesystem;
|
||||||
|
|
||||||
|
exports.getBodyParts = function(conf) {
|
||||||
|
return {
|
||||||
|
heads: [
|
||||||
|
new RoboHydraHeadFilesystem({
|
||||||
|
mountPath: '/assets/',
|
||||||
|
documentRoot: '../assets'
|
||||||
|
})
|
||||||
|
]
|
||||||
|
};
|
||||||
|
};
|
156
test/robohydra/plugins/dav-default/index.js
Normal file
156
test/robohydra/plugins/dav-default/index.js
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
]
|
||||||
|
};
|
||||||
|
};
|
36
test/robohydra/plugins/dav-invalid/index.js
Normal file
36
test/robohydra/plugins/dav-invalid/index.js
Normal file
@ -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>\
|
||||||
|
');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
]
|
||||||
|
};
|
||||||
|
};
|
50
test/robohydra/plugins/headdav.js
Normal file
50
test/robohydra/plugins/headdav.js
Normal file
@ -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;
|
18
test/robohydra/plugins/redirect/index.js
Normal file
18
test/robohydra/plugins/redirect/index.js
Normal file
@ -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();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
]
|
||||||
|
};
|
||||||
|
};
|
2
test/robohydra/run.sh
Executable file
2
test/robohydra/run.sh
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
node_modules/robohydra/bin/robohydra.js davdroid.conf -I plugins
|
39
test/src/at/bitfire/davdroid/test/URIUtilsTest.java
Normal file
39
test/src/at/bitfire/davdroid/test/URIUtilsTest.java
Normal file
@ -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;
|
package at.bitfire.davdroid.webdav.test;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
|
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.apache.http.HttpException;
|
import org.apache.http.HttpException;
|
||||||
|
|
||||||
|
import android.content.res.AssetManager;
|
||||||
import android.test.InstrumentationTestCase;
|
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;
|
||||||
|
import at.bitfire.davdroid.webdav.WebDavResource.PutMode;
|
||||||
|
|
||||||
|
// tests require running robohydra!
|
||||||
|
|
||||||
public class WebDavResourceTest extends InstrumentationTestCase {
|
public class WebDavResourceTest extends InstrumentationTestCase {
|
||||||
URI davBaseURI, uriWithoutDAV, uriWithRedirection;
|
static final String ROBOHYDRA_BASE = "http://10.0.0.119:3000/";
|
||||||
final static String davUsername = "test", davPassword = "test";
|
static byte[] SAMPLE_CONTENT = new byte[] { 1, 2, 3, 4, 5 };
|
||||||
|
|
||||||
|
AssetManager assetMgr;
|
||||||
|
WebDavResource simpleFile,
|
||||||
|
davCollection, davNonExistingFile, davExistingFile;
|
||||||
|
|
||||||
|
@Override
|
||||||
protected void setUp() throws Exception {
|
protected void setUp() throws Exception {
|
||||||
davBaseURI = new URI("https://wurd.dev001.net/radicale/test/");
|
assetMgr = getInstrumentation().getContext().getResources().getAssets();
|
||||||
uriWithoutDAV = new URI("http://www.apache.org");
|
|
||||||
uriWithRedirection = new URI("http://wurd.dev001.net/public/");
|
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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* test resource name handling */
|
||||||
|
|
||||||
public void testGet() throws URISyntaxException, IOException, HttpException {
|
public void testGetName() {
|
||||||
WebDavResource dav = new WebDavResource(uriWithoutDAV, "", "", false, true);
|
// collection names should have a trailing slash
|
||||||
dav.get();
|
assertEquals("dav", davCollection.getName());
|
||||||
InputStream is = dav.getContent();
|
// but non-collection names shouldn't
|
||||||
assertNotNull(is);
|
assertEquals("test.random", simpleFile.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testTrailingSlash() throws URISyntaxException {
|
public void testTrailingSlash() throws URISyntaxException {
|
||||||
WebDavResource dav = new WebDavResource(new URI("http://server/path"), "", "", false, true);
|
// collections should have a trailing slash
|
||||||
assertEquals("/path/", dav.getLocation().getPath());
|
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 {
|
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" };
|
davCapabilities = new String[] { "addressbook", "calendar-access" };
|
||||||
|
|
||||||
// server without DAV
|
// server without DAV
|
||||||
WebDavResource dav = new WebDavResource(uriWithoutDAV, "", "", false, true);
|
simpleFile.options();
|
||||||
dav.options();
|
|
||||||
for (String method : davMethods)
|
for (String method : davMethods)
|
||||||
assertFalse(dav.supportsMethod(method));
|
assertFalse(simpleFile.supportsMethod(method));
|
||||||
for (String capability : davCapabilities)
|
for (String capability : davCapabilities)
|
||||||
assertFalse(dav.supportsDAV(capability));
|
assertFalse(simpleFile.supportsDAV(capability));
|
||||||
|
|
||||||
// server with DAV
|
// server with DAV
|
||||||
dav = new WebDavResource(davBaseURI, davUsername, davPassword, false, true);
|
davCollection.options();
|
||||||
dav.options();
|
|
||||||
for (String davMethod : davMethods)
|
for (String davMethod : davMethods)
|
||||||
assert(dav.supportsMethod(davMethod));
|
assert(davCollection.supportsMethod(davMethod));
|
||||||
for (String capability : davCapabilities)
|
for (String capability : davCapabilities)
|
||||||
assert(dav.supportsDAV(capability));
|
assert(davCollection.supportsDAV(capability));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testRedirections() throws URISyntaxException, IOException {
|
public void testPropfindCurrentUserPrincipal() throws IOException, HttpException {
|
||||||
WebDavResource dav = new WebDavResource(uriWithRedirection, "", "", false, true);
|
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 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 {
|
try {
|
||||||
dav.options();
|
redirection.get();
|
||||||
} catch (HttpException e) {
|
} catch (HttpException e) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fail();
|
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
Block a user