mirror of
https://github.com/etesync/android
synced 2025-01-23 14:10:54 +00:00
Ensure trailing slashes are always used for collections + tests
This commit is contained in:
parent
b2bd53f36f
commit
1ec1db3045
@ -7,6 +7,8 @@
|
||||
******************************************************************************/
|
||||
package at.bitfire.davdroid;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@ -18,7 +20,32 @@ public class URIUtils {
|
||||
private static final String TAG = "davdroid.URIUtils";
|
||||
|
||||
|
||||
// handles invalid URLs/paths as good as possible
|
||||
public static String ensureTrailingSlash(String href) {
|
||||
if (!href.endsWith("/")) {
|
||||
Log.d(TAG, "Implicitly appending trailing slash to collection " + href);
|
||||
return href + "/";
|
||||
} else
|
||||
return href;
|
||||
}
|
||||
|
||||
public static URI ensureTrailingSlash(URI href) {
|
||||
if (!href.getPath().endsWith("/"))
|
||||
try {
|
||||
URI newURI = new URI(href.getScheme(), href.getAuthority(), href.getPath() + "/", href.getQuery(), null);
|
||||
|
||||
// "@" is the only character that is not encoded
|
||||
newURI = new URI(newURI.toString().replaceAll("@", "%40"));
|
||||
|
||||
Log.d(TAG, "Implicitly appending trailing slash to collection " + href + " -> " + newURI);
|
||||
return newURI;
|
||||
} catch (URISyntaxException e) {
|
||||
Log.e(TAG, "Couldn't append trailing slash to collection URI", e);
|
||||
}
|
||||
return href;
|
||||
}
|
||||
|
||||
|
||||
/** handles invalid URLs/paths as good as possible **/
|
||||
public static String sanitize(String original) {
|
||||
if (original == null)
|
||||
return null;
|
||||
@ -67,4 +94,5 @@ public class URIUtils {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -88,15 +88,17 @@ public class DavResourceFinder {
|
||||
if (homeSetCalendars.getMembers() != null)
|
||||
for (WebDavResource resource : homeSetCalendars.getMembers())
|
||||
if (resource.isCalendar()) {
|
||||
Log.i(TAG, "Found calendar: " + resource.getLocation().getRawPath());
|
||||
Log.i(TAG, "Found calendar: " + resource.getLocation().getPath());
|
||||
if (resource.getSupportedComponents() != null) {
|
||||
// CALDAV:supported-calendar-component-set available
|
||||
boolean supportsEvents = false;
|
||||
for (String supportedComponent : resource.getSupportedComponents())
|
||||
if (supportedComponent.equalsIgnoreCase("VEVENT"))
|
||||
supportsEvents = true;
|
||||
if (!supportsEvents) // ignore collections without VEVENT support
|
||||
if (!supportsEvents) { // ignore collections without VEVENT support
|
||||
Log.i(TAG, "Ignoring this calendar because of missing VEVENT support");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
ServerInfo.ResourceInfo info = new ServerInfo.ResourceInfo(
|
||||
ServerInfo.ResourceInfo.Type.CALENDAR,
|
||||
|
@ -39,13 +39,16 @@ public class DavProp {
|
||||
@Root(strict=false)
|
||||
public static class ResourceType {
|
||||
@Element(required=false)
|
||||
@Getter private Addressbook addressbook;
|
||||
@Element(required=false)
|
||||
@Getter private Calendar calendar;
|
||||
@Getter private Collection collection;
|
||||
public static class Collection { }
|
||||
|
||||
@Element(required=false)
|
||||
@Getter private Addressbook addressbook;
|
||||
@Namespace(prefix="CD",reference="urn:ietf:params:xml:ns:carddav")
|
||||
public static class Addressbook { }
|
||||
|
||||
@Element(required=false)
|
||||
@Getter private Calendar calendar;
|
||||
@Namespace(prefix="C",reference="urn:ietf:params:xml:ns:caldav")
|
||||
public static class Calendar { }
|
||||
}
|
||||
|
@ -68,7 +68,8 @@ public class WebDavResource {
|
||||
CURRENT_USER_PRINCIPAL, // resource detection
|
||||
ADDRESSBOOK_HOMESET, CALENDAR_HOMESET,
|
||||
CONTENT_TYPE, READ_ONLY, // WebDAV (common)
|
||||
DISPLAY_NAME, DESCRIPTION, CTAG, ETAG,
|
||||
DISPLAY_NAME, DESCRIPTION, ETAG,
|
||||
IS_COLLECTION, CTAG, // collections
|
||||
IS_CALENDAR, COLOR, TIMEZONE, // CalDAV
|
||||
IS_ADDRESSBOOK, VCARD_VERSION // CardDAV
|
||||
}
|
||||
@ -452,6 +453,7 @@ public class WebDavResource {
|
||||
// member list will be built from response
|
||||
List<WebDavResource> members = new LinkedList<WebDavResource>();
|
||||
|
||||
// iterate through all resources (either ourselves or member)
|
||||
for (DavResponse singleResponse : multiStatus.response) {
|
||||
URI href;
|
||||
try {
|
||||
@ -461,42 +463,19 @@ public class WebDavResource {
|
||||
continue;
|
||||
}
|
||||
Log.d(TAG, "Processing multi-status element: " + href);
|
||||
|
||||
// about which resource is this response?
|
||||
WebDavResource referenced = null;
|
||||
|
||||
// "this" resource is either at "location" …
|
||||
if (location.equals(href)) { // -> ourselves
|
||||
referenced = this;
|
||||
} else {
|
||||
// … or at location + "/" (in case of a collection where the server has implicitly appended the trailing slash)
|
||||
if (!location.getRawPath().endsWith("/")) // this is only possible if location doesn't have a trailing slash
|
||||
try {
|
||||
URI locationAsCollection = new URI(location.getScheme(), location.getAuthority(), location.getPath() + "/", location.getQuery(), null);
|
||||
if (locationAsCollection.equals(href)) {
|
||||
Log.d(TAG, "Server implicitly appended trailing slash to " + locationAsCollection);
|
||||
referenced = this;
|
||||
}
|
||||
} catch (URISyntaxException e) {
|
||||
Log.wtf(TAG, "Couldn't understand our own URI", e);
|
||||
}
|
||||
|
||||
// otherwise, the referenced resource is a member
|
||||
if (referenced == null) {
|
||||
referenced = new WebDavResource(this, href);
|
||||
members.add(referenced);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// process known properties
|
||||
HashMap<Property, String> properties = new HashMap<Property, String>();
|
||||
List<String> supportedComponents = null;
|
||||
byte[] data = null;
|
||||
|
||||
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;
|
||||
HashMap<Property, String> properties = referenced.properties;
|
||||
|
||||
if (prop.currentUserPrincipal != null && prop.currentUserPrincipal.getHref() != null)
|
||||
properties.put(Property.CURRENT_USER_PRINCIPAL, prop.currentUserPrincipal.getHref().href);
|
||||
@ -520,15 +499,20 @@ public class WebDavResource {
|
||||
}
|
||||
|
||||
if (prop.addressbookHomeSet != null && prop.addressbookHomeSet.getHref() != null)
|
||||
properties.put(Property.ADDRESSBOOK_HOMESET, prop.addressbookHomeSet.getHref().href);
|
||||
properties.put(Property.ADDRESSBOOK_HOMESET, URIUtils.ensureTrailingSlash(prop.addressbookHomeSet.getHref().href));
|
||||
|
||||
if (prop.calendarHomeSet != null && prop.calendarHomeSet.getHref() != null)
|
||||
properties.put(Property.CALENDAR_HOMESET, prop.calendarHomeSet.getHref().href);
|
||||
properties.put(Property.CALENDAR_HOMESET, URIUtils.ensureTrailingSlash(prop.calendarHomeSet.getHref().href));
|
||||
|
||||
if (prop.displayname != null)
|
||||
properties.put(Property.DISPLAY_NAME, prop.displayname.getDisplayName());
|
||||
|
||||
if (prop.resourcetype != null) {
|
||||
if (prop.resourcetype.getCollection() != null) {
|
||||
properties.put(Property.IS_COLLECTION, "1");
|
||||
// is a collection, ensure trailing slash
|
||||
href = URIUtils.ensureTrailingSlash(href);
|
||||
}
|
||||
if (prop.resourcetype.getAddressbook() != null) { // CardDAV collection properties
|
||||
properties.put(Property.IS_ADDRESSBOOK, "1");
|
||||
|
||||
@ -554,9 +538,9 @@ public class WebDavResource {
|
||||
properties.put(Property.TIMEZONE, Event.TimezoneDefToTzId(prop.calendarTimezone.getTimezone()));
|
||||
|
||||
if (prop.supportedCalendarComponentSet != null) {
|
||||
referenced.supportedComponents = new LinkedList<String>();
|
||||
supportedComponents = new LinkedList<String>();
|
||||
for (Comp component : prop.supportedCalendarComponentSet)
|
||||
referenced.supportedComponents.add(component.getName());
|
||||
supportedComponents.add(component.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -568,9 +552,26 @@ public class WebDavResource {
|
||||
properties.put(Property.ETAG, prop.getetag.getETag());
|
||||
|
||||
if (prop.calendarData != null && prop.calendarData.ical != null)
|
||||
referenced.content = prop.calendarData.ical.getBytes();
|
||||
data = prop.calendarData.ical.getBytes();
|
||||
else if (prop.addressData != null && prop.addressData.vcard != null)
|
||||
referenced.content = prop.addressData.vcard.getBytes();
|
||||
data = prop.addressData.vcard.getBytes();
|
||||
}
|
||||
|
||||
// about which resource is this response?
|
||||
// "this" resource is either at "location" …
|
||||
if (location.equals(href)) { // -> ourselves
|
||||
this.properties.putAll(properties);
|
||||
if (supportedComponents != null)
|
||||
this.supportedComponents = supportedComponents;
|
||||
this.content = data;
|
||||
|
||||
} else {
|
||||
WebDavResource member = new WebDavResource(this, href);
|
||||
member.properties = properties;
|
||||
member.supportedComponents = supportedComponents;
|
||||
member.content = data;
|
||||
|
||||
members.add(member);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ exports.getBodyParts = function(conf) {
|
||||
<CARD:addressbook/>\
|
||||
</resourcetype>\
|
||||
<CARD:addressbook-description>\
|
||||
Address Book with absolute URL\
|
||||
Address Book with absolute URL and at sign in path\
|
||||
</CARD:addressbook-description>\
|
||||
</prop>\
|
||||
<status>HTTP/1.1 200 OK</status>\
|
||||
|
@ -7,11 +7,24 @@
|
||||
******************************************************************************/
|
||||
package at.bitfire.davdroid.test;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import at.bitfire.davdroid.URIUtils;
|
||||
|
||||
public class URIUtilsTest extends TestCase {
|
||||
|
||||
public void testEnsureTrailingSlash() throws URISyntaxException {
|
||||
assertEquals("/test/", URIUtils.ensureTrailingSlash("/test"));
|
||||
assertEquals("/test/", URIUtils.ensureTrailingSlash("/test/"));
|
||||
|
||||
String withoutSlash = "http://www.test.at/dav/collection",
|
||||
withSlash = withoutSlash + "/";
|
||||
assertEquals(new URI(withSlash), URIUtils.ensureTrailingSlash(new URI(withoutSlash)));
|
||||
assertEquals(new URI(withSlash), URIUtils.ensureTrailingSlash(new URI(withSlash)));
|
||||
}
|
||||
|
||||
public void testSanitize() {
|
||||
assertNull(URIUtils.sanitize(null));
|
||||
|
||||
|
@ -103,7 +103,7 @@ public class WebDavResourceTest extends InstrumentationTestCase {
|
||||
public void testPropfindHomeSets() throws IOException, HttpException, DavException {
|
||||
WebDavResource dav = new WebDavResource(davCollection, "principals/users/test");
|
||||
dav.propfind(HttpPropfind.Mode.HOME_SETS);
|
||||
assertEquals("/dav/addressbooks/test", dav.getAddressbookHomeSet());
|
||||
assertEquals("/dav/addressbooks/test/", dav.getAddressbookHomeSet());
|
||||
assertEquals("/dav/calendars/test/", dav.getCalendarHomeSet());
|
||||
}
|
||||
|
||||
@ -221,7 +221,7 @@ public class WebDavResourceTest extends InstrumentationTestCase {
|
||||
List<WebDavResource> members = dav.getMembers();
|
||||
assertEquals(2, members.size());
|
||||
assertEquals(Constants.ROBOHYDRA_BASE + "dav/addressbooks/user%40domain/My%20Contacts%3a1.vcf/", members.get(0).getLocation().toString());
|
||||
assertEquals("HTTPS://example.com/user%40domain/absolute-url.vcf", members.get(1).getLocation().toString());
|
||||
assertEquals("HTTPS://example.com/user%40domain/absolute-url.vcf/", members.get(1).getLocation().toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user