Provide Content-Type of files
diff --git a/src/com/google/enterprise/adaptor/sharepoint/SharePointAdaptor.java b/src/com/google/enterprise/adaptor/sharepoint/SharePointAdaptor.java
index 98fbc98..e5012b2 100644
--- a/src/com/google/enterprise/adaptor/sharepoint/SharePointAdaptor.java
+++ b/src/com/google/enterprise/adaptor/sharepoint/SharePointAdaptor.java
@@ -693,9 +693,16 @@
throw new IOException(ex);
}
URL finalUrl = hostUri.resolve(pathUri).toURL();
- InputStream is = httpClient.issueGetRequest(finalUrl);
- IOHelper.copyStream(is, response.getOutputStream());
- is.close();
+ FileInfo fi = httpClient.issueGetRequest(finalUrl);
+ try {
+ String contentType = fi.getFirstHeaderWithName("Content-Type");
+ if (contentType != null) {
+ response.setContentType(contentType);
+ }
+ IOHelper.copyStream(fi.getContents(), response.getOutputStream());
+ } finally {
+ fi.getContents().close();
+ }
log.exiting("SiteDataClient", "getFileDocContent");
}
@@ -1159,21 +1166,114 @@
}
@VisibleForTesting
+ static class FileInfo {
+ /** Non-null contents. */
+ private final InputStream contents;
+ /** Non-null headers. */
+ private final List<String> headers;
+
+ private FileInfo(InputStream contents, List<String> headers) {
+ this.contents = contents;
+ this.headers = headers;
+ }
+
+ public InputStream getContents() {
+ return contents;
+ }
+
+ public int getHeaderCount() {
+ return headers.size() / 2;
+ }
+
+ public String getHeaderName(int i) {
+ return headers.get(2 * i);
+ }
+
+ public String getHeaderValue(int i) {
+ return headers.get(2 * i + 1);
+ }
+
+ /**
+ * Find the first header with {@code name}, ignoring case.
+ */
+ public String getFirstHeaderWithName(String name) {
+ String nameLowerCase = name.toLowerCase(Locale.ENGLISH);
+ for (int i = 0; i < getHeaderCount(); i++) {
+ String headerNameLowerCase
+ = getHeaderName(i).toLowerCase(Locale.ENGLISH);
+ if (headerNameLowerCase.equals(nameLowerCase)) {
+ return getHeaderValue(i);
+ }
+ }
+ return null;
+ }
+
+ public static class Builder {
+ private InputStream contents;
+ private List<String> headers = Collections.emptyList();
+
+ public Builder(InputStream contents) {
+ setContents(contents);
+ }
+
+ public Builder setContents(InputStream contents) {
+ if (contents == null) {
+ throw new NullPointerException();
+ }
+ this.contents = contents;
+ return this;
+ }
+
+ public Builder setHeaders(List<String> headers) {
+ if (headers == null) {
+ throw new NullPointerException();
+ }
+ if (headers.size() % 2 != 0) {
+ throw new IllegalArgumentException(
+ "headers must have an even number of elements");
+ }
+ this.headers = Collections.unmodifiableList(
+ new ArrayList<String>(headers));
+ return this;
+ }
+
+ public FileInfo build() {
+ return new FileInfo(contents, headers);
+ }
+ }
+ }
+
+ @VisibleForTesting
interface HttpClient {
- /** The caller must close() the InputStream after use. */
- public InputStream issueGetRequest(URL url) throws IOException;
+ /**
+ * The caller must call {@code fileInfo.getContents().close()} after use.
+ */
+ public FileInfo issueGetRequest(URL url) throws IOException;
}
private static class HttpClientImpl implements HttpClient {
@Override
- public InputStream issueGetRequest(URL url) throws IOException {
+ public FileInfo issueGetRequest(URL url) throws IOException {
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true);
conn.setDoOutput(false);
if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
throw new IOException("Got status code: " + conn.getResponseCode());
}
- return conn.getInputStream();
+ List<String> headers = new LinkedList<String>();
+ // Start at 1 since index 0 is special.
+ for (int i = 1;; i++) {
+ String key = conn.getHeaderFieldKey(i);
+ if (key == null) {
+ break;
+ }
+ String value = conn.getHeaderField(i);
+ headers.add(key);
+ headers.add(value);
+ }
+ log.log(Level.FINER, "Response HTTP headers: {0}", headers);
+ return new FileInfo.Builder(conn.getInputStream()).setHeaders(headers)
+ .build();
}
}
diff --git a/test/com/google/enterprise/adaptor/sharepoint/SharePointAdaptorTest.java b/test/com/google/enterprise/adaptor/sharepoint/SharePointAdaptorTest.java
index 29a4ed9..19d51ae 100644
--- a/test/com/google/enterprise/adaptor/sharepoint/SharePointAdaptorTest.java
+++ b/test/com/google/enterprise/adaptor/sharepoint/SharePointAdaptorTest.java
@@ -14,6 +14,7 @@
package com.google.enterprise.adaptor.sharepoint;
+import static com.google.enterprise.adaptor.sharepoint.SharePointAdaptor.FileInfo;
import static com.google.enterprise.adaptor.sharepoint.SharePointAdaptor.HttpClient;
import static com.google.enterprise.adaptor.sharepoint.SharePointAdaptor.SiteDataFactory;
import static org.junit.Assert.*;
@@ -42,6 +43,7 @@
import java.io.*;
import java.net.URL;
import java.nio.charset.Charset;
+import java.util.*;
import java.util.concurrent.atomic.AtomicLong;
import javax.xml.ws.Holder;
@@ -437,17 +439,22 @@
setValue(getContentResult, getContentListItemAttachments);
}
}
+ final String goldenContents = "attachment contents";
+ final String goldenContentType = "fake/type";
adaptor = new SharePointAdaptor(
new SingleSiteDataFactory(new ListItemAttachmentsSiteData(),
"http://localhost:1/_vti_bin/SiteData.asmx"),
new HttpClient() {
@Override
- public InputStream issueGetRequest(URL url) {
+ public FileInfo issueGetRequest(URL url) {
assertEquals(
"http://localhost:1/Lists/Custom%20List/Attachments/2/1046000.pdf",
url.toString());
- return new ByteArrayInputStream(
- "attachment contents".getBytes(charset));
+ InputStream contents = new ByteArrayInputStream(
+ goldenContents.getBytes(charset));
+ List<String> headers = Arrays.asList("not-the-Content-Type", "early",
+ "conTent-TypE", goldenContentType, "Content-Type", "late");
+ return new FileInfo.Builder(contents).setHeaders(headers).build();
}
});
adaptor.init(new MockAdaptorContext(config, null));
@@ -457,8 +464,8 @@
GetContentsResponse response = new GetContentsResponse(baos);
adaptor.getDocContent(request, response);
String responseString = new String(baos.toByteArray(), charset);
- final String golden = "attachment contents";
- assertEquals(golden, responseString);
+ assertEquals(goldenContents, responseString);
+ assertEquals(goldenContentType, response.getContentType());
}
@Test
@@ -1906,6 +1913,36 @@
client.jaxbParse(xml, SPContentDatabase.class);
}
+ @Test
+ public void testFileInfoGetFirstHeaderWithNameMissing() {
+ FileInfo fi = new FileInfo.Builder(new ByteArrayInputStream(new byte[0]))
+ .setHeaders(Arrays.asList("Some-Header", "somevalue")).build();
+ assertEquals("somevalue", fi.getFirstHeaderWithName("some-heaDer"));
+ assertNull(fi.getFirstHeaderWithName("Missing-Header"));
+ }
+
+ @Test
+ public void testFileInfoNullContents() {
+ thrown.expect(NullPointerException.class);
+ new FileInfo.Builder(null);
+ }
+
+ @Test
+ public void testFileInfoNullHeaders() {
+ FileInfo.Builder builder
+ = new FileInfo.Builder(new ByteArrayInputStream(new byte[0]));
+ thrown.expect(NullPointerException.class);
+ builder.setHeaders(null);
+ }
+
+ @Test
+ public void testFileInfoOddHeadersLength() {
+ FileInfo.Builder builder
+ = new FileInfo.Builder(new ByteArrayInputStream(new byte[0]));
+ thrown.expect(IllegalArgumentException.class);
+ builder.setHeaders(Arrays.asList("odd-length"));
+ }
+
private <T> void setValue(Holder<T> holder, T value) {
if (holder != null) {
holder.value = value;
@@ -1946,7 +1983,7 @@
private static class UnsupportedHttpClient implements HttpClient {
@Override
- public InputStream issueGetRequest(URL url) {
+ public FileInfo issueGetRequest(URL url) {
throw new UnsupportedOperationException();
}
}