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();
     }
   }