Improve attachment handling using redirect on list root folder
Code Review : https://codereview.appspot.com/72720043/
diff --git a/src/com/google/enterprise/adaptor/sharepoint/SharePointAdaptor.java b/src/com/google/enterprise/adaptor/sharepoint/SharePointAdaptor.java
index 7f9955e..c71092e 100644
--- a/src/com/google/enterprise/adaptor/sharepoint/SharePointAdaptor.java
+++ b/src/com/google/enterprise/adaptor/sharepoint/SharePointAdaptor.java
@@ -2135,11 +2135,33 @@
log.exiting("SiteAdaptor", "getAttachmentDocContent", false);
return false;
}
- Holder<String> listIdHolder = new Holder<String>();
- // TODO(ejona): Find a more reliable way to determine the list's id.
- // Hope the list's default view is AllItems.aspx.
- boolean result = siteDataClient.getUrlSegments(
- listBase + "/AllItems.aspx", listIdHolder, null);
+ String listRedirectLocation = httpClient.getRedirectLocation(
+ spUrlToUri(listBase).toURL(),
+ authenticationHandler.getAuthenticationCookies());
+ // if listRedirectLocation is null, use listBase as list url. This is
+ // possible if list has no views defined.
+ // if listRedirectLocation is not null, it should begin with listBase
+ // to be considered as valid list location else use listBase as listUrl.
+ String listUrl
+ = listRedirectLocation == null ? listBase
+ : listRedirectLocation.startsWith(listBase)
+ ? listRedirectLocation : listBase;
+
+ log.log(Level.FINER, "List url {0}", listUrl);
+ Holder<String> listIdHolder = new Holder<String>();
+ boolean result = siteDataClient.getUrlSegments(listUrl,
+ listIdHolder, null);
+ // There is a possiblity that default view url for a list is empty but
+ // list contains additional non default view.
+ // In this case, SharePoint will redirect to non default view url.
+ // getUrlSegments call fails for a non default view url.
+ // So lets try with listBase for getUrlSegments.
+ if (!result && !listUrl.equals(listBase)) {
+ result = siteDataClient.getUrlSegments(listBase, listIdHolder, null);
+ }
+ // For valid lists, one of the getUrlSegments calls above should work on
+ // SP2010 and SP2013. It can still fail for SP2007. So lets try with
+ // ItemId url. This will fail if parent item is inside a folder.
if (!result) {
log.fine("Could not get list id from list url");
// AllItems.aspx may not be the default view, so hope that list items
@@ -2498,6 +2520,9 @@
*/
public FileInfo issueGetRequest(URL url, List<String> authenticationCookies)
throws IOException;
+
+ public String getRedirectLocation(URL url,
+ List<String> authenticationCookies) throws IOException;
}
static class HttpClientImpl implements HttpClient {
@@ -2511,7 +2536,7 @@
throw new IOException(ex);
}
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
-
+ // TODO :Close connection for non 200 responses.
if (authenticationCookies.isEmpty()) {
conn.addRequestProperty("X-FORMS_BASED_AUTH_ACCEPTED", "f");
} else {
@@ -2560,6 +2585,42 @@
return new FileInfo.Builder(conn.getInputStream()).setHeaders(headers)
.build();
}
+
+ @Override
+ public String getRedirectLocation(URL url,
+ List<String> authenticationCookies) throws IOException {
+
+ // Handle Unicode. Java does not properly encode the GET.
+ try {
+ url = new URL(url.toURI().toASCIIString());
+ } catch (URISyntaxException ex) {
+ throw new IOException(ex);
+ }
+ HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+ try {
+ if (authenticationCookies.isEmpty()) {
+ conn.addRequestProperty("X-FORMS_BASED_AUTH_ACCEPTED", "f");
+ } else {
+ for (String cookie : authenticationCookies) {
+ conn.addRequestProperty("Cookie", cookie);
+ }
+ }
+ conn.setDoInput(true);
+ conn.setDoOutput(false);
+ conn.setInstanceFollowRedirects(false);
+ if (conn.getResponseCode() != HttpURLConnection.HTTP_MOVED_TEMP) {
+ log.log(Level.WARNING,
+ "Received response code {0} instead of 302 for URL {1}",
+ new Object[]{conn.getResponseCode(), url});
+ return null;
+ }
+ return conn.getHeaderField("Location");
+ } finally {
+ InputStream inputStream = conn.getResponseCode() >= 400
+ ? conn.getErrorStream() : conn.getInputStream();
+ inputStream.close();
+ }
+ }
}
@VisibleForTesting
diff --git a/test/com/google/enterprise/adaptor/sharepoint/SharePointAdaptorTest.java b/test/com/google/enterprise/adaptor/sharepoint/SharePointAdaptorTest.java
index f786d17..586134b 100644
--- a/test/com/google/enterprise/adaptor/sharepoint/SharePointAdaptorTest.java
+++ b/test/com/google/enterprise/adaptor/sharepoint/SharePointAdaptorTest.java
@@ -911,6 +911,17 @@
"Last-Modified", "Tue, 01 May 2012 22:14:41 GMT");
return new FileInfo.Builder(contents).setHeaders(headers).build();
}
+
+ @Override
+ public String getRedirectLocation(URL url,
+ List<String> authenticationCookies) throws IOException {
+ assertEquals(
+ "http://localhost:1/sites/SiteCollection/Lists/Custom%20List",
+ url.toString());
+
+ return "http://localhost:1/sites/SiteCollection/Lists/Custom List"
+ + "/AllItems.aspx";
+ }
}, executorFactory);
adaptor.init(new MockAdaptorContext(config, pusher));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -960,6 +971,17 @@
"Content-Type", "application/vnd.ms-excel.12");
return new FileInfo.Builder(contents).setHeaders(headers).build();
}
+
+ @Override
+ public String getRedirectLocation(URL url,
+ List<String> authenticationCookies) throws IOException {
+ assertEquals(
+ "http://localhost:1/sites/SiteCollection/Lists/Custom%20List",
+ url.toString());
+
+ return "http://localhost:1/sites/SiteCollection/Lists/Custom List"
+ + "/AllItems.aspx";
+ }
}, executorFactory);
adaptor.init(new MockAdaptorContext(config, pusher));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -1837,6 +1859,12 @@
List<String> authenticationCookies) {
throw new UnsupportedOperationException();
}
+
+ @Override
+ public String getRedirectLocation(URL url,
+ List<String> authenticationCookies) throws IOException {
+ throw new UnsupportedOperationException();
+ }
}
private abstract static class DelegatingPeopleSoap implements PeopleSoap {