1
0
mirror of https://github.com/etesync/android synced 2024-11-26 09:58:11 +00:00

Handle HTTP redirections (fixes #83)

This commit is contained in:
rfc2822 2014-07-18 19:04:27 +02:00
parent 1678873885
commit cf40cb2ebc
12 changed files with 247 additions and 83 deletions

View File

@ -88,7 +88,7 @@
o comprar-lo.</p> o comprar-lo.</p>
<h1>Llicència</h1> <h1>Llicència</h1>
<p>Copyright (c) 2013 2014 Richard Hirner (<a href="http://www.bitfire.at">bitfire web engineering</a>). Tots els drets reservats. <p>Copyright (c) 2013 2014 Ricki Hirner (<a href="http://www.bitfire.at">bitfire web engineering</a>). Tots els drets reservats.
Aquest programa i tots els materials que l\'acompanyen estan disponibles sota els termes de la GNU Public License v3.0 que acompanya Aquest programa i tots els materials que l\'acompanyen estan disponibles sota els termes de la GNU Public License v3.0 que acompanya
aquesta distribució i està disponible a <a aquesta distribució i està disponible a <a
href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a>. Respecte al Google Play, Samsung href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a>. Respecte al Google Play, Samsung

View File

@ -82,7 +82,7 @@
<a href="http://davdroid.bitfire.at/donate?pk_campaign=davdroid-app&amp;pk_kwd=main-activity">für DAVdroid spenden</a> oder die App kaufen.</p> <a href="http://davdroid.bitfire.at/donate?pk_campaign=davdroid-app&amp;pk_kwd=main-activity">für DAVdroid spenden</a> oder die App kaufen.</p>
<h1>Lizenz</h1> <h1>Lizenz</h1>
<p>Copyright (c) 2013 2014 Richard Hirner (<a href="http://www.bitfire.at">bitfire web engineering</a>), alle Rechte <p>Copyright (c) 2013 2014 Ricki Hirner (<a href="http://www.bitfire.at">bitfire web engineering</a>), alle Rechte
vorbehalten. Dieses Programm ist freie Software. Sie können es unter den Bedingungen der <a href="http://www.gnu.org/licenses/gpl.html">GNU vorbehalten. Dieses Programm ist freie Software. Sie können es unter den Bedingungen der <a href="http://www.gnu.org/licenses/gpl.html">GNU
General Public License Version 3</a>, wie von der Free Software Foundation veröffentlicht, weitergeben und/oder modifizieren. General Public License Version 3</a>, wie von der Free Software Foundation veröffentlicht, weitergeben und/oder modifizieren.
Sofern Google Play oder Samsung Store andere Bedingungen benötigen, gelten für über den jeweiligen Markt heruntergeladene Sofern Google Play oder Samsung Store andere Bedingungen benötigen, gelten für über den jeweiligen Markt heruntergeladene

View File

@ -65,7 +65,7 @@
Si vous voulez aider ce projet <a href="http://davdroid.bitfire.at/donate?pk_campaign=davdroid-app&amp;pk_kwd=main-activity">faites un don à DAVdroid</a> ou achetez le</p> Si vous voulez aider ce projet <a href="http://davdroid.bitfire.at/donate?pk_campaign=davdroid-app&amp;pk_kwd=main-activity">faites un don à DAVdroid</a> ou achetez le</p>
<h1>License</h1> <h1>License</h1>
<p>Copyright (c) 2013 2014 Richard Hirner (<a href="http://www.bitfire.at">bitfire web engineering</a>). All rights reserved. <p>Copyright (c) 2013 2014 Ricki Hirner (<a href="http://www.bitfire.at">bitfire web engineering</a>). All rights reserved.
Ce programme et les documents qui l\'accompagnent sont mis à disposition sous les termes de la Licence Public GNU v3.0 qui Ce programme et les documents qui l\'accompagnent sont mis à disposition sous les termes de la Licence Public GNU v3.0 qui
accompagne cette distribution, et est disponible à <a accompagne cette distribution, et est disponible à <a
href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a>. En ce qui concerne Google Play ou Samsung Store, les conditions respectives s\'appliquent pour les versions qui sont téléchargées via ces services.</p> href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a>. En ce qui concerne Google Play ou Samsung Store, les conditions respectives s\'appliquent pour les versions qui sont téléchargées via ces services.</p>

View File

@ -87,7 +87,7 @@
or purchasing it.</p> or purchasing it.</p>
<h1>License</h1> <h1>License</h1>
<p>Copyright (c) 2013 2014 Richard Hirner (<a href="http://www.bitfire.at">bitfire web engineering</a>). All rights reserved. <p>Copyright (c) 2013 2014 Ricki Hirner (<a href="http://www.bitfire.at">bitfire web engineering</a>). All rights reserved.
This program and the accompanying materials are made available under the terms of the GNU Public License v3.0 which 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 <a accompanies this distribution, and is available at <a
href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a>. As far as Google Play, Samsung href="http://www.gnu.org/licenses/gpl.html">http://www.gnu.org/licenses/gpl.html</a>. As far as Google Play, Samsung

View File

@ -48,7 +48,7 @@ public abstract class RemoteCollection<T extends Resource> {
public RemoteCollection(CloseableHttpClient httpClient, String baseURL, String user, String password, boolean preemptiveAuth) throws URISyntaxException { public RemoteCollection(CloseableHttpClient httpClient, String baseURL, String user, String password, boolean preemptiveAuth) throws URISyntaxException {
this.httpClient = httpClient; this.httpClient = httpClient;
collection = new WebDavResource(httpClient, new URI(baseURL), user, password, preemptiveAuth, true); collection = new WebDavResource(httpClient, new URI(baseURL), user, password, preemptiveAuth);
} }

View File

@ -125,14 +125,15 @@ public class EnterCredentialsFragment extends Fragment implements TextWatcher {
editUserName.getText().length() > 0 && editUserName.getText().length() > 0 &&
editPassword.getText().length() > 0; editPassword.getText().length() > 0;
// check host name if (ok)
try { // check host name
URI uri = new URI(URIUtils.sanitize(protocol + editBaseURL.getText().toString())); try {
if (StringUtils.isBlank(uri.getHost())) URI uri = new URI(URIUtils.sanitize(protocol + editBaseURL.getText().toString()));
if (StringUtils.isBlank(uri.getHost()))
ok = false;
} catch (URISyntaxException e) {
ok = false; ok = false;
} catch (URISyntaxException e) { }
ok = false;
}
MenuItem item = menu.findItem(R.id.next); MenuItem item = menu.findItem(R.id.next);
item.setEnabled(ok); item.setEnabled(ok);

View File

@ -117,7 +117,7 @@ public class QueryServerDialogFragment extends DialogFragment implements LoaderC
try { try {
// (1/5) detect capabilities // (1/5) detect capabilities
WebDavResource base = new WebDavResource(httpClient, new URI(serverInfo.getProvidedURL()), serverInfo.getUserName(), WebDavResource base = new WebDavResource(httpClient, new URI(serverInfo.getProvidedURL()), serverInfo.getUserName(),
serverInfo.getPassword(), serverInfo.isAuthPreemptive(), true); serverInfo.getPassword(), serverInfo.isAuthPreemptive());
base.options(); base.options();
serverInfo.setCardDAV(base.supportsDAV("addressbook")); serverInfo.setCardDAV(base.supportsDAV("addressbook"));

View File

@ -52,6 +52,7 @@ public class DavHttpClient {
.setConnectionManager(connectionManager) .setConnectionManager(connectionManager)
.setDefaultRequestConfig(defaultRqConfig) .setDefaultRequestConfig(defaultRqConfig)
.setRetryHandler(DavHttpRequestRetryHandler.INSTANCE) .setRetryHandler(DavHttpRequestRetryHandler.INSTANCE)
.setRedirectStrategy(DavRedirectStrategy.INSTANCE)
.setUserAgent("DAVdroid/" + Constants.APP_VERSION) .setUserAgent("DAVdroid/" + Constants.APP_VERSION)
.disableCookieManagement(); .disableCookieManagement();

View File

@ -0,0 +1,94 @@
package at.bitfire.davdroid.webdav;
import java.net.URI;
import java.net.URISyntaxException;
import android.util.Log;
import ch.boye.httpclientandroidlib.Header;
import ch.boye.httpclientandroidlib.HttpRequest;
import ch.boye.httpclientandroidlib.HttpResponse;
import ch.boye.httpclientandroidlib.ProtocolException;
import ch.boye.httpclientandroidlib.RequestLine;
import ch.boye.httpclientandroidlib.client.RedirectStrategy;
import ch.boye.httpclientandroidlib.client.methods.HttpUriRequest;
import ch.boye.httpclientandroidlib.client.methods.RequestBuilder;
import ch.boye.httpclientandroidlib.client.protocol.HttpClientContext;
import ch.boye.httpclientandroidlib.protocol.HttpContext;
/**
* Custom Redirect Strategy that handles 30x for CalDAV/CardDAV-specific requests correctly
*/
public class DavRedirectStrategy implements RedirectStrategy {
private final static String TAG = "davdroid.DavRedirectStrategy";
final static DavRedirectStrategy INSTANCE = new DavRedirectStrategy();
protected final static String REDIRECTABLE_METHODS[] = {
"OPTIONS", "GET", "PUT", "DELETE"
};
@Override
public HttpUriRequest getRedirect(HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException {
RequestLine line = request.getRequestLine();
String location = getLocation(request, response, context).toString();
Log.i(TAG, "Following redirection: " + line.getMethod() + " " + line.getUri() + " -> " + location);
return RequestBuilder.copy(request)
.setUri(location)
.removeHeaders("Content-Length") // Content-Length will be set again automatically, if required;
// remove it now to avoid duplicate header
.build();
}
/**
* Determines whether a response indicates a redirection and if it does, whether to follow this redirection.
* PROPFIND and REPORT must handle redirections explicitely because multi-status processing requires knowledge of the content location.
* @return true for 3xx responses on OPTIONS, GET, PUT, DELETE requests that have a valid Location header; false otherwise
*/
@Override
public boolean isRedirected(HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException {
if (response.getStatusLine().getStatusCode()/100 == 3) {
boolean redirectable = false;
for (String method : REDIRECTABLE_METHODS)
if (method.equalsIgnoreCase(request.getRequestLine().getMethod())) {
redirectable = true;
break;
}
return redirectable && getLocation(request, response, context) != null;
}
return false;
}
/**
* Gets the destination of a redirection
* @return absolute URL of new location; null if not available
*/
static URI getLocation(HttpRequest request, HttpResponse response, HttpContext context) {
Header locationHdr = response.getFirstHeader("Location");
if (locationHdr == null) {
Log.e(TAG, "Received redirection without Location header, ignoring");
return null;
}
try {
URI location = new URI(locationHdr.getValue());
// some servers don't return absolute URLs as required by RFC 2616
if (!location.isAbsolute()) {
Log.w(TAG, "Received invalid redirection with relative URL, repairing");
// determine original URL
final HttpClientContext clientContext = HttpClientContext.adapt(context);
final URI originalURI = new URI(clientContext.getTargetHost() + request.getRequestLine().getUri());
// determine new location relative to original URL
location = originalURI.resolve(location);
}
return location;
} catch (URISyntaxException e) {
Log.e(TAG, "Received redirection from/to invalid URL, ignoring", e);
}
return null;
}
}

View File

@ -95,19 +95,16 @@ public class WebDavResource {
protected HttpClientContext context; protected HttpClientContext context;
public WebDavResource(CloseableHttpClient httpClient, URI baseURL, boolean trailingSlash) throws URISyntaxException { public WebDavResource(CloseableHttpClient httpClient, URI baseURL) throws URISyntaxException {
this.httpClient = httpClient; this.httpClient = httpClient;
location = baseURL.normalize(); location = baseURL.normalize();
if (trailingSlash && !location.getRawPath().endsWith("/"))
location = new URI(location.getScheme(), location.getSchemeSpecificPart() + "/", null);
context = HttpClientContext.create(); context = HttpClientContext.create();
context.setCredentialsProvider(new BasicCredentialsProvider()); context.setCredentialsProvider(new BasicCredentialsProvider());
} }
public WebDavResource(CloseableHttpClient httpClient, URI baseURL, String username, String password, boolean preemptive, boolean trailingSlash) throws URISyntaxException { public WebDavResource(CloseableHttpClient httpClient, URI baseURL, String username, String password, boolean preemptive) throws URISyntaxException {
this(httpClient, baseURL, trailingSlash); this(httpClient, baseURL);
HttpHost host = new HttpHost(baseURL.getHost(), baseURL.getPort(), baseURL.getScheme()); HttpHost host = new HttpHost(baseURL.getHost(), baseURL.getPort(), baseURL.getScheme());
context.getCredentialsProvider().setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password)); context.getCredentialsProvider().setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));
@ -250,67 +247,75 @@ public class WebDavResource {
/* collection operations */ /* collection operations */
public void propfind(HttpPropfind.Mode mode) throws IOException, DavException, HttpException { public void propfind(HttpPropfind.Mode mode) throws IOException, DavException, HttpException {
HttpPropfind propfind = new HttpPropfind(location, mode); CloseableHttpResponse response = null;
CloseableHttpResponse response = httpClient.execute(propfind, context);
try { // processMultiStatus() requires knowledge of the actual content location,
checkResponse(response); // so we have to handle redirections manually and create a new request for the new location
for (int i = context.getRequestConfig().getMaxRedirects(); i > 0; i--) {
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_MULTI_STATUS) HttpPropfind propfind = new HttpPropfind(location, mode);
throw new DavNoMultiStatusException(); response = httpClient.execute(propfind, context);
HttpEntity entity = response.getEntity();
if (entity == null)
throw new DavNoContentException();
@Cleanup InputStream content = entity.getContent();
DavMultistatus multistatus; if (response.getStatusLine().getStatusCode()/100 == 3) {
try { location = DavRedirectStrategy.getLocation(propfind, response, context);
Serializer serializer = new Persister(); Log.i(TAG, "Redirection on PROPFIND; trying again at new content URL: " + location);
multistatus = serializer.read(DavMultistatus.class, content, false); // don't forget to throw away the unneeded response content
} catch (Exception ex) { HttpEntity entity = response.getEntity();
throw new DavException("Couldn't parse Multi-Status response on PROPFIND", ex); if (entity != null) { @Cleanup InputStream content = entity.getContent(); }
} } else
processMultiStatus(multistatus); break; // answer was NOT a redirection, continue
}
if (response == null)
throw new DavNoContentException();
try {
checkResponse(response); // will also handle Content-Location
processMultiStatus(response);
} finally { } finally {
response.close(); response.close();
} }
} }
public void multiGet(DavMultiget.Type type, String[] names) throws IOException, DavException, HttpException { public void multiGet(DavMultiget.Type type, String[] names) throws IOException, DavException, HttpException {
List<String> hrefs = new LinkedList<String>(); CloseableHttpResponse response = null;
for (String name : names)
hrefs.add(location.resolve(name).getRawPath());
DavMultiget multiget = DavMultiget.newRequest(type, hrefs.toArray(new String[0]));
Serializer serializer = new Persister(); // processMultiStatus() requires knowledge of the actual content location,
StringWriter writer = new StringWriter(); // so we have to handle redirections manually and create a new request for the new location
try { for (int i = context.getRequestConfig().getMaxRedirects(); i > 0; i--) {
serializer.write(multiget, writer); // build multi-get XML request
} catch (Exception ex) { List<String> hrefs = new LinkedList<String>();
Log.e(TAG, "Couldn't create XML multi-get request", ex); for (String name : names)
throw new DavException("Couldn't create multi-get request"); hrefs.add(location.resolve(name).getRawPath());
} DavMultiget multiget = DavMultiget.newRequest(type, hrefs.toArray(new String[0]));
HttpReport report = new HttpReport(location, writer.toString());
CloseableHttpResponse response = httpClient.execute(report, context);
try {
checkResponse(response);
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_MULTI_STATUS) StringWriter writer = new StringWriter();
throw new DavNoMultiStatusException();
HttpEntity entity = response.getEntity();
if (entity == null)
throw new DavNoContentException();
@Cleanup InputStream content = entity.getContent();
DavMultistatus multiStatus;
try { try {
multiStatus = serializer.read(DavMultistatus.class, content, false); Serializer serializer = new Persister();
serializer.write(multiget, writer);
} catch (Exception ex) { } catch (Exception ex) {
throw new DavException("Couldn't parse Multi-Status response on REPORT multi-get", ex); Log.e(TAG, "Couldn't create XML multi-get request", ex);
throw new DavException("Couldn't create multi-get request");
} }
processMultiStatus(multiStatus);
// submit REPORT request
HttpReport report = new HttpReport(location, writer.toString());
response = httpClient.execute(report, context);
if (response.getStatusLine().getStatusCode()/100 == 3) {
location = DavRedirectStrategy.getLocation(report, response, context);
Log.i(TAG, "Redirection on REPORT multi-get; trying again at new content URL: " + location);
// don't forget to throw away the unneeded response content
HttpEntity entity = response.getEntity();
if (entity != null) { @Cleanup InputStream content = entity.getContent(); }
} else
break; // answer was NOT a redirection, continue
}
if (response == null)
throw new DavNoContentException();
try {
checkResponse(response); // will also handle Content-Location
processMultiStatus(response);
} finally { } finally {
response.close(); response.close();
} }
@ -383,8 +388,19 @@ public class WebDavResource {
/* helpers */ /* helpers */
protected static void checkResponse(HttpResponse response) throws HttpException { protected void checkResponse(HttpResponse response) throws HttpException {
checkResponse(response.getStatusLine()); checkResponse(response.getStatusLine());
// handle Content-Location header (see RFC 4918 5.2 Collection Resources)
Header contentLocationHdr = response.getFirstHeader("Content-Location");
if (contentLocationHdr != null)
try {
// Content-Location was set, update location correspondingly
location = location.resolve(new URI(contentLocationHdr.getValue()));
Log.d(TAG, "Set Content-Location to " + location);
} catch (URISyntaxException e) {
Log.w(TAG, "Ignoring invalid Content-Location", e);
}
} }
protected static void checkResponse(StatusLine statusLine) throws HttpException { protected static void checkResponse(StatusLine statusLine) throws HttpException {
@ -404,14 +420,30 @@ public class WebDavResource {
} }
} }
protected void processMultiStatus(DavMultistatus multistatus) throws HttpException, DavException { protected void processMultiStatus(HttpResponse response) throws IOException, HttpException, DavException {
if (multistatus.response == null) // empty response if (response.getStatusLine().getStatusCode() != HttpStatus.SC_MULTI_STATUS)
throw new DavNoMultiStatusException();
HttpEntity entity = response.getEntity();
if (entity == null)
throw new DavNoContentException();
@Cleanup InputStream content = entity.getContent();
DavMultistatus multiStatus;
try {
Serializer serializer = new Persister();
multiStatus = serializer.read(DavMultistatus.class, content, false);
} catch (Exception ex) {
throw new DavException("Couldn't parse Multi-Status response on REPORT multi-get", ex);
}
if (multiStatus.response == null) // empty response
throw new DavNoContentException(); throw new DavNoContentException();
// member list will be built from response // member list will be built from response
List<WebDavResource> members = new LinkedList<WebDavResource>(); List<WebDavResource> members = new LinkedList<WebDavResource>();
for (DavResponse singleResponse : multistatus.response) { for (DavResponse singleResponse : multiStatus.response) {
URI href; URI href;
try { try {
href = location.resolve(URIUtils.sanitize(singleResponse.getHref().href)); href = location.resolve(URIUtils.sanitize(singleResponse.getHref().href));
@ -423,12 +455,28 @@ public class WebDavResource {
// about which resource is this response? // about which resource is this response?
WebDavResource referenced = null; WebDavResource referenced = null;
// "this" resource is either at "location"
if (location.equals(href)) { // -> ourselves if (location.equals(href)) { // -> ourselves
referenced = this; 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);
}
} else { // -> about a member // otherwise, the referenced resource is a member
referenced = new WebDavResource(this, href); if (referenced == null) {
members.add(referenced); referenced = new WebDavResource(this, href);
members.add(referenced);
}
} }
for (DavPropstat singlePropstat : singleResponse.getPropstat()) { for (DavPropstat singlePropstat : singleResponse.getPropstat()) {

View File

@ -4,11 +4,23 @@ exports.getBodyParts = function(conf) {
return { return {
heads: [ heads: [
new RoboHydraHead({ new RoboHydraHead({
path: "/redirect", path: "/redirect/301",
handler: function(req,res,next) {
res.statusCode = 301;
var location = req.queryParams['to'] || '/assets/test.random';
res.headers = {
Location: location
}
res.end();
}
}),
new RoboHydraHead({
path: "/redirect/302",
handler: function(req,res,next) { handler: function(req,res,next) {
res.statusCode = 302; res.statusCode = 302;
var location = req.queryParams['to'] || '/assets/test.random';
res.headers = { res.headers = {
location: 'http://www.example.com' Location: location
} }
res.end(); res.end();
} }

View File

@ -27,6 +27,7 @@ import at.bitfire.davdroid.webdav.DavHttpClient;
import at.bitfire.davdroid.webdav.DavMultiget; import at.bitfire.davdroid.webdav.DavMultiget;
import at.bitfire.davdroid.webdav.HttpException; import at.bitfire.davdroid.webdav.HttpException;
import at.bitfire.davdroid.webdav.HttpPropfind; import at.bitfire.davdroid.webdav.HttpPropfind;
import at.bitfire.davdroid.webdav.HttpPropfind.Mode;
import at.bitfire.davdroid.webdav.NotFoundException; import at.bitfire.davdroid.webdav.NotFoundException;
import at.bitfire.davdroid.webdav.PreconditionFailedException; import at.bitfire.davdroid.webdav.PreconditionFailedException;
import at.bitfire.davdroid.webdav.WebDavResource; import at.bitfire.davdroid.webdav.WebDavResource;
@ -52,13 +53,13 @@ public class WebDavResourceTest extends InstrumentationTestCase {
assetMgr = getInstrumentation().getContext().getResources().getAssets(); assetMgr = getInstrumentation().getContext().getResources().getAssets();
simpleFile = new WebDavResource(httpClient, new URI(ROBOHYDRA_BASE + "assets/test.random"), false); simpleFile = new WebDavResource(httpClient, new URI(ROBOHYDRA_BASE + "assets/test.random"));
davCollection = new WebDavResource(httpClient, new URI(ROBOHYDRA_BASE + "dav"), true); davCollection = new WebDavResource(httpClient, new URI(ROBOHYDRA_BASE + "dav/"));
davNonExistingFile = new WebDavResource(davCollection, "collection/new.file"); davNonExistingFile = new WebDavResource(davCollection, "collection/new.file");
davExistingFile = new WebDavResource(davCollection, "collection/existing.file"); davExistingFile = new WebDavResource(davCollection, "collection/existing.file");
davInvalid = new WebDavResource(httpClient, new URI(ROBOHYDRA_BASE + "dav-invalid"), true); davInvalid = new WebDavResource(httpClient, new URI(ROBOHYDRA_BASE + "dav-invalid/"));
} }
@Override @Override
@ -112,6 +113,7 @@ public class WebDavResourceTest extends InstrumentationTestCase {
try { try {
simpleFile.propfind(HttpPropfind.Mode.CURRENT_USER_PRINCIPAL); simpleFile.propfind(HttpPropfind.Mode.CURRENT_USER_PRINCIPAL);
fail(); fail();
} catch(DavException ex) { } catch(DavException ex) {
} }
assertNull(simpleFile.getCurrentUserPrincipal()); assertNull(simpleFile.getCurrentUserPrincipal());
@ -154,8 +156,14 @@ public class WebDavResourceTest extends InstrumentationTestCase {
/* test normal HTTP/WebDAV */ /* test normal HTTP/WebDAV */
public void testFollowGetRedirections() throws URISyntaxException, IOException, DavException, HttpException { public void testRedirections() throws URISyntaxException, IOException, DavException, HttpException {
WebDavResource redirection = new WebDavResource(httpClient, new URI(ROBOHYDRA_BASE + "redirect"), false); // PROPFIND redirection
WebDavResource redirection = new WebDavResource(httpClient, new URI(ROBOHYDRA_BASE + "redirect/301?to=/dav/"));
redirection.propfind(Mode.CURRENT_USER_PRINCIPAL);
assertEquals("/dav/", redirection.getLocation().getPath());
// normal GET redirection
redirection = new WebDavResource(httpClient, new URI(ROBOHYDRA_BASE + "redirect/301"));
redirection.get(); redirection.get();
} }
@ -167,7 +175,7 @@ public class WebDavResourceTest extends InstrumentationTestCase {
} }
public void testGetHttpsWithSni() throws URISyntaxException, HttpException, IOException, DavException { public void testGetHttpsWithSni() throws URISyntaxException, HttpException, IOException, DavException {
WebDavResource file = new WebDavResource(httpClient, new URI("https://sni.velox.ch"), false); WebDavResource file = new WebDavResource(httpClient, new URI("https://sni.velox.ch"));
boolean sniWorking = false; boolean sniWorking = false;
try { try {