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 {