headers = new SimpleOrderedMap<>();
// error if this is set...
protected Exception err;
@@ -245,4 +260,110 @@ public class SolrQueryResponse {
public boolean isHttpCaching() {
return this.httpCaching;
}
+
+ /**
+ *
+ * Sets a response header with the given name and value. This header
+ * will be included in the HTTP response
+ * If the header had already been set, the new value overwrites the
+ * previous ones (all of them if there are multiple for the same name).
+ *
+ * @param name the name of the header
+ * @param value the header value If it contains octet string,
+ * it should be encoded according to RFC 2047
+ * (http://www.ietf.org/rfc/rfc2047.txt)
+ *
+ * @see #addHttpHeader
+ * @see HttpServletResponse#setHeader
+ */
+ public void setHttpHeader(String name, String value) {
+ headers.removeAll(name);
+ headers.add(name, value);
+ }
+
+ /**
+ * Adds a response header with the given name and value. This header
+ * will be included in the HTTP response
+ * This method allows response headers to have multiple values.
+ *
+ * @param name the name of the header
+ * @param value the additional header value If it contains
+ * octet string, it should be encoded
+ * according to RFC 2047
+ * (http://www.ietf.org/rfc/rfc2047.txt)
+ *
+ * @see #setHttpHeader
+ * @see HttpServletResponse#addHeader
+ */
+ public void addHttpHeader(String name, String value) {
+ headers.add(name, value);
+ }
+
+ /**
+ * Gets the value of the response header with the given name.
+ *
+ * If a response header with the given name exists and contains
+ * multiple values, the value that was added first will be returned.
+ *
+ * NOTE: this runs in linear time (it scans starting at the
+ * beginning of the list until it finds the first pair with
+ * the specified name).
+ *
+ * @param name the name of the response header whose value to return
+ * @return the value of the response header with the given name,
+ * or null if no header with the given name has been set
+ * on this response
+ */
+ public String getHttpHeader(String name) {
+ return headers.get(name);
+ }
+
+ /**
+ * Gets the values of the response header with the given name.
+ *
+ * @param name the name of the response header whose values to return
+ *
+ * @return a (possibly empty) Collection
of the values
+ * of the response header with the given name
+ *
+ */
+ public Collection getHttpHeaders(String name) {
+ return headers.getAll(name);
+ }
+
+ /**
+ * Removes a previously added header with the given name (only
+ * the first one if multiple are present for the same name)
+ *
+ * NOTE: this runs in linear time (it scans starting at the
+ * beginning of the list until it finds the first pair with
+ * the specified name).
+ *
+ * @param name the name of the response header to remove
+ * @return the value of the removed entry or null if no
+ * value is found for the given header name
+ */
+ public String removeHttpHeader(String name) {
+ return headers.remove(name);
+ }
+
+ /**
+ * Removes all previously added headers with the given name.
+ *
+ * @param name the name of the response headers to remove
+ * @return a Collection
with all the values
+ * of the removed entries. It returns null
if no
+ * entries are found for the given name
+ */
+ public Collection removeHttpHeaders(String name) {
+ return headers.removeAll(name);
+ }
+
+ /**
+ * Returns a new iterator of response headers
+ * @return a new Iterator instance for the response headers
+ */
+ public Iterator> httpHeaders() {
+ return headers.iterator();
+ }
}
diff --git a/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java b/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java
index da4f9f0cb3f..c61cecc5149 100644
--- a/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java
+++ b/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java
@@ -419,16 +419,11 @@ public class SolrDispatchFilter extends BaseSolrFilter {
SolrRequestInfo.setRequestInfo(new SolrRequestInfo(solrReq, solrRsp));
this.execute( req, handler, solrReq, solrRsp );
HttpCacheHeaderUtil.checkHttpCachingVeto(solrRsp, resp, reqMethod);
- // add info to http headers
- //TODO: See SOLR-232 and SOLR-267.
- /*try {
- NamedList solrRspHeader = solrRsp.getResponseHeader();
- for (int i=0; i> headers = solrRsp.httpHeaders();
+ while (headers.hasNext()) {
+ Entry entry = headers.next();
+ resp.addHeader(entry.getKey(), entry.getValue());
+ }
QueryResponseWriter responseWriter = core.getQueryResponseWriter(solrReq);
writeResponse(solrRsp, response, responseWriter, solrReq, reqMethod);
}
diff --git a/solr/core/src/test-files/solr/collection1/conf/solrconfig-headers.xml b/solr/core/src/test-files/solr/collection1/conf/solrconfig-headers.xml
new file mode 100644
index 00000000000..e19ecfa70ba
--- /dev/null
+++ b/solr/core/src/test-files/solr/collection1/conf/solrconfig-headers.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+ ${tests.luceneMatchVersion:LUCENE_CURRENT}
+ ${solr.data.dir:}
+
+
+
+
+
+ componentThatAddsHeader
+
+
+
+
diff --git a/solr/core/src/test/org/apache/solr/servlet/ResponseHeaderTest.java b/solr/core/src/test/org/apache/solr/servlet/ResponseHeaderTest.java
new file mode 100644
index 00000000000..1f4689e1cd4
--- /dev/null
+++ b/solr/core/src/test/org/apache/solr/servlet/ResponseHeaderTest.java
@@ -0,0 +1,231 @@
+package org.apache.solr.servlet;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.Map.Entry;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.http.Header;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.solr.SolrJettyTestBase;
+import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.client.solrj.SolrServerException;
+import org.apache.solr.client.solrj.impl.HttpSolrServer;
+import org.apache.solr.handler.component.ResponseBuilder;
+import org.apache.solr.handler.component.SearchComponent;
+import org.apache.solr.response.SolrQueryResponse;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+
+public class ResponseHeaderTest extends SolrJettyTestBase {
+
+ private static File solrHomeDirectory;
+
+ @BeforeClass
+ public static void beforeTest() throws Exception {
+ solrHomeDirectory = createTempDir();
+ setupJettyTestHome(solrHomeDirectory, "collection1");
+ String top = SolrTestCaseJ4.TEST_HOME() + "/collection1/conf";
+ FileUtils.copyFile(new File(top, "solrconfig-headers.xml"), new File(solrHomeDirectory + "/collection1/conf", "solrconfig.xml"));
+ createJetty(solrHomeDirectory.getAbsolutePath(), null, null);
+ }
+
+ @AfterClass
+ public static void afterTest() throws Exception {
+ cleanUpJettyHome(solrHomeDirectory);
+ }
+
+ @Test
+ public void testHttpResponse() throws SolrServerException, IOException {
+ HttpSolrServer client = (HttpSolrServer)getSolrServer();
+ HttpClient httpClient = client.getHttpClient();
+ URI uri = URI.create(client.getBaseURL() + "/withHeaders?q=*:*");
+ HttpGet httpGet = new HttpGet(uri);
+ HttpResponse response = httpClient.execute(httpGet);
+ Header[] headers = response.getAllHeaders();
+ boolean containsWarningHeader = false;
+ for (Header header:headers) {
+ if ("Warning".equals(header.getName())) {
+ containsWarningHeader = true;
+ assertEquals("This is a test warning", header.getValue());
+ break;
+ }
+ }
+ assertTrue("Expected header not found", containsWarningHeader);
+ }
+
+ @Test
+ public void testAddHttpHeader() {
+ SolrQueryResponse response = new SolrQueryResponse();
+ Iterator> it = response.httpHeaders();
+ assertFalse(it.hasNext());
+
+ response.addHttpHeader("key1", "value1");
+ it = response.httpHeaders();
+ assertTrue(it.hasNext());
+ Entry entry = it.next();
+ assertEquals("key1", entry.getKey());
+ assertEquals("value1", entry.getValue());
+ assertFalse(it.hasNext());
+
+ response.addHttpHeader("key1", "value2");
+ it = response.httpHeaders();
+ assertTrue(it.hasNext());
+ entry = it.next();
+ assertEquals("key1", entry.getKey());
+ assertEquals("value1", entry.getValue());
+ assertTrue(it.hasNext());
+ entry = it.next();
+ assertEquals("key1", entry.getKey());
+ assertEquals("value2", entry.getValue());
+ assertFalse(it.hasNext());
+
+ response.addHttpHeader("key2", "value2");
+ it = response.httpHeaders();
+ assertTrue(it.hasNext());
+ entry = it.next();
+ assertEquals("key1", entry.getKey());
+ assertEquals("value1", entry.getValue());
+ assertTrue(it.hasNext());
+ entry = it.next();
+ assertEquals("key1", entry.getKey());
+ assertEquals("value2", entry.getValue());
+ assertTrue(it.hasNext());
+ entry = it.next();
+ assertEquals("key2", entry.getKey());
+ assertEquals("value2", entry.getValue());
+ assertFalse(it.hasNext());
+ }
+
+ @Test
+ public void testSetHttpHeader() {
+ SolrQueryResponse response = new SolrQueryResponse();
+ Iterator> it = response.httpHeaders();
+ assertFalse(it.hasNext());
+
+ response.setHttpHeader("key1", "value1");
+ it = response.httpHeaders();
+ assertTrue(it.hasNext());
+ Entry entry = it.next();
+ assertEquals("key1", entry.getKey());
+ assertEquals("value1", entry.getValue());
+ assertFalse(it.hasNext());
+
+ response.setHttpHeader("key1", "value2");
+ it = response.httpHeaders();
+ assertTrue(it.hasNext());
+ entry = it.next();
+ assertEquals("key1", entry.getKey());
+ assertEquals("value2", entry.getValue());
+ assertFalse(it.hasNext());
+
+ response.addHttpHeader("key1", "value3");
+ response.setHttpHeader("key1", "value4");
+ it = response.httpHeaders();
+ assertTrue(it.hasNext());
+ entry = it.next();
+ assertEquals("key1", entry.getKey());
+ assertEquals("value4", entry.getValue());
+ assertFalse(it.hasNext());
+
+ response.setHttpHeader("key2", "value5");
+ it = response.httpHeaders();
+ assertTrue(it.hasNext());
+ entry = it.next();
+ assertEquals("key1", entry.getKey());
+ assertEquals("value4", entry.getValue());
+ assertTrue(it.hasNext());
+ entry = it.next();
+ assertEquals("key2", entry.getKey());
+ assertEquals("value5", entry.getValue());
+ assertFalse(it.hasNext());
+ }
+
+ @Test
+ public void testRemoveHttpHeader() {
+ SolrQueryResponse response = new SolrQueryResponse();
+ Iterator> it = response.httpHeaders();
+ assertFalse(it.hasNext());
+ response.addHttpHeader("key1", "value1");
+ assertTrue(response.httpHeaders().hasNext());
+ assertEquals("value1", response.removeHttpHeader("key1"));
+ assertFalse(response.httpHeaders().hasNext());
+
+ response.addHttpHeader("key1", "value2");
+ response.addHttpHeader("key1", "value3");
+ response.addHttpHeader("key2", "value4");
+ assertTrue(response.httpHeaders().hasNext());
+ assertEquals("value2", response.removeHttpHeader("key1"));
+ assertEquals("value3", response.httpHeaders().next().getValue());
+ assertEquals("value3", response.removeHttpHeader("key1"));
+ assertNull(response.removeHttpHeader("key1"));
+ assertEquals("key2", response.httpHeaders().next().getKey());
+
+ }
+
+ @Test
+ public void testRemoveHttpHeaders() {
+ SolrQueryResponse response = new SolrQueryResponse();
+ Iterator> it = response.httpHeaders();
+ assertFalse(it.hasNext());
+ response.addHttpHeader("key1", "value1");
+ assertTrue(response.httpHeaders().hasNext());
+ assertEquals(Arrays.asList("value1"), response.removeHttpHeaders("key1"));
+ assertFalse(response.httpHeaders().hasNext());
+
+ response.addHttpHeader("key1", "value2");
+ response.addHttpHeader("key1", "value3");
+ response.addHttpHeader("key2", "value4");
+ assertTrue(response.httpHeaders().hasNext());
+ assertEquals(Arrays.asList(new String[]{"value2", "value3"}), response.removeHttpHeaders("key1"));
+ assertNull(response.removeHttpHeaders("key1"));
+ assertEquals("key2", response.httpHeaders().next().getKey());
+ }
+
+ public static class ComponentThatAddsHeader extends SearchComponent {
+
+ @Override
+ public void prepare(ResponseBuilder rb) throws IOException {
+ rb.rsp.addHttpHeader("Warning", "This is a test warning");
+ }
+
+ @Override
+ public void process(ResponseBuilder rb) throws IOException {}
+
+ @Override
+ public String getDescription() {
+ return null;
+ }
+
+ @Override
+ public String getSource() {
+ return null;
+ }
+
+ }
+
+}