mirror of https://github.com/apache/lucene.git
SOLR-4406: Fix RawResponseWriter to respect 'base' writer
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1622321 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
c52d04197a
commit
1eafd0fa43
|
@ -158,6 +158,9 @@ Bug Fixes
|
|||
* SOLR-5966: Admin UI Menu is fixed and doesn't respect smaller viewports.
|
||||
(Aman Tandon, steffkes via shalin)
|
||||
|
||||
* SOLR-4406: Fix RawResponseWriter to respect 'base' writer
|
||||
(Steve Davids, hossman)
|
||||
|
||||
Other Changes
|
||||
---------------------
|
||||
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.apache.solr.response;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.io.Writer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.apache.solr.common.util.ContentStreamBase;
|
||||
import org.apache.solr.request.SolrQueryRequest;
|
||||
import org.apache.solr.util.FastWriter;
|
||||
|
||||
/**
|
||||
* Static utility methods relating to {@link QueryResponseWriter}s
|
||||
*/
|
||||
public final class QueryResponseWriterUtil {
|
||||
private QueryResponseWriterUtil() { /* static helpers only */ }
|
||||
|
||||
/**
|
||||
* Writes the response writer's result to the given output stream.
|
||||
* This method inspects the specified writer to determine if it is a
|
||||
* {@link BinaryQueryResponseWriter} or not to delegate to the approprate method.
|
||||
* @see BinaryQueryResponseWriter#write(OutputStream,SolrQueryRequest,SolrQueryResponse)
|
||||
* @see BinaryQueryResponseWriter#write(Writer,SolrQueryRequest,SolrQueryResponse)
|
||||
*/
|
||||
public static void writeQueryResponse(OutputStream outputStream,
|
||||
QueryResponseWriter responseWriter, SolrQueryRequest solrRequest,
|
||||
SolrQueryResponse solrResponse, String contentType) throws IOException {
|
||||
|
||||
if (responseWriter instanceof BinaryQueryResponseWriter) {
|
||||
BinaryQueryResponseWriter binWriter = (BinaryQueryResponseWriter) responseWriter;
|
||||
binWriter.write(outputStream, solrRequest, solrResponse);
|
||||
} else {
|
||||
Writer writer = buildWriter(outputStream, ContentStreamBase.getCharsetFromContentType(contentType));
|
||||
responseWriter.write(writer, solrRequest, solrResponse);
|
||||
writer.flush();
|
||||
}
|
||||
}
|
||||
|
||||
private static Writer buildWriter(OutputStream outputStream, String charset) throws UnsupportedEncodingException {
|
||||
Writer writer = (charset == null) ? new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)
|
||||
: new OutputStreamWriter(outputStream, charset);
|
||||
|
||||
return new FastWriter(writer);
|
||||
}
|
||||
}
|
|
@ -18,6 +18,7 @@
|
|||
package org.apache.solr.response;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
|
@ -45,8 +46,7 @@ import org.apache.solr.request.SolrQueryRequest;
|
|||
*
|
||||
* @since solr 1.3
|
||||
*/
|
||||
public class RawResponseWriter implements BinaryQueryResponseWriter
|
||||
{
|
||||
public class RawResponseWriter implements BinaryQueryResponseWriter {
|
||||
/**
|
||||
* The key that should be used to add a ContentStream to the
|
||||
* SolrQueryResponse if you intend to use this Writer.
|
||||
|
@ -65,8 +65,7 @@ public class RawResponseWriter implements BinaryQueryResponseWriter
|
|||
}
|
||||
|
||||
// Even if this is null, it should be ok
|
||||
protected QueryResponseWriter getBaseWriter( SolrQueryRequest request )
|
||||
{
|
||||
protected QueryResponseWriter getBaseWriter( SolrQueryRequest request ) {
|
||||
return request.getCore().getQueryResponseWriter( _baseWriter );
|
||||
}
|
||||
|
||||
|
@ -80,42 +79,31 @@ public class RawResponseWriter implements BinaryQueryResponseWriter
|
|||
}
|
||||
|
||||
@Override
|
||||
public void write(Writer writer, SolrQueryRequest request, SolrQueryResponse response) throws IOException
|
||||
{
|
||||
public void write(Writer writer, SolrQueryRequest request, SolrQueryResponse response) throws IOException {
|
||||
Object obj = response.getValues().get( CONTENT );
|
||||
if( obj != null && (obj instanceof ContentStream ) ) {
|
||||
// copy the contents to the writer...
|
||||
ContentStream content = (ContentStream)obj;
|
||||
Reader reader = content.getReader();
|
||||
try {
|
||||
try(Reader reader = content.getReader()) {
|
||||
IOUtils.copy( reader, writer );
|
||||
} finally {
|
||||
reader.close();
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
getBaseWriter( request ).write( writer, request, response );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(OutputStream out, SolrQueryRequest request,
|
||||
SolrQueryResponse response) throws IOException {
|
||||
@Override
|
||||
public void write(OutputStream out, SolrQueryRequest request, SolrQueryResponse response) throws IOException {
|
||||
Object obj = response.getValues().get( CONTENT );
|
||||
if( obj != null && (obj instanceof ContentStream ) ) {
|
||||
// copy the contents to the writer...
|
||||
ContentStream content = (ContentStream)obj;
|
||||
java.io.InputStream in = content.getStream();
|
||||
try {
|
||||
try(InputStream in = content.getStream()) {
|
||||
IOUtils.copy( in, out );
|
||||
} finally {
|
||||
in.close();
|
||||
}
|
||||
} else {
|
||||
QueryResponseWriterUtil.writeQueryResponse(out,
|
||||
getBaseWriter(request), request, response, getContentType(request, response));
|
||||
}
|
||||
else {
|
||||
//getBaseWriter( request ).write( writer, request, response );
|
||||
throw new IOException("did not find a CONTENT object");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,12 +24,11 @@ import org.apache.solr.common.util.SimpleOrderedMap;
|
|||
import org.apache.solr.core.SolrCore;
|
||||
import org.apache.solr.request.SolrQueryRequest;
|
||||
import org.apache.solr.request.SolrRequestInfo;
|
||||
import org.apache.solr.response.BinaryQueryResponseWriter;
|
||||
import org.apache.solr.response.QueryResponseWriter;
|
||||
import org.apache.solr.response.QueryResponseWriterUtil;
|
||||
import org.apache.solr.response.SolrQueryResponse;
|
||||
import org.apache.solr.schema.IndexSchema;
|
||||
import org.apache.solr.servlet.ResponseUtils;
|
||||
import org.apache.solr.util.FastWriter;
|
||||
import org.restlet.data.MediaType;
|
||||
import org.restlet.data.Method;
|
||||
import org.restlet.data.Status;
|
||||
|
@ -40,19 +39,14 @@ import org.slf4j.Logger;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.io.Writer;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
|
||||
/**
|
||||
* Base class of all Solr Restlet server resource classes.
|
||||
*/
|
||||
public abstract class BaseSolrResource extends ServerResource {
|
||||
protected static final Charset UTF8 = StandardCharsets.UTF_8;
|
||||
protected static final String SHOW_DEFAULTS = "showDefaults";
|
||||
|
||||
private SolrCore solrCore;
|
||||
|
@ -157,18 +151,7 @@ public abstract class BaseSolrResource extends ServerResource {
|
|||
@Override
|
||||
public void write(OutputStream outputStream) throws IOException {
|
||||
if (getRequest().getMethod() != Method.HEAD) {
|
||||
if (responseWriter instanceof BinaryQueryResponseWriter) {
|
||||
BinaryQueryResponseWriter binWriter = (BinaryQueryResponseWriter)responseWriter;
|
||||
binWriter.write(outputStream, solrRequest, solrResponse);
|
||||
} else {
|
||||
String charset = ContentStreamBase.getCharsetFromContentType(contentType);
|
||||
Writer out = (charset == null)
|
||||
? new OutputStreamWriter(outputStream, UTF8)
|
||||
: new OutputStreamWriter(outputStream, charset);
|
||||
out = new FastWriter(out);
|
||||
responseWriter.write(out, solrRequest, solrResponse);
|
||||
out.flush();
|
||||
}
|
||||
QueryResponseWriterUtil.writeQueryResponse(outputStream, responseWriter, solrRequest, solrResponse, contentType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,11 +66,11 @@ import org.apache.solr.request.SolrRequestHandler;
|
|||
import org.apache.solr.request.SolrRequestInfo;
|
||||
import org.apache.solr.response.BinaryQueryResponseWriter;
|
||||
import org.apache.solr.response.QueryResponseWriter;
|
||||
import org.apache.solr.response.QueryResponseWriterUtil;
|
||||
import org.apache.solr.response.SolrQueryResponse;
|
||||
import org.apache.solr.servlet.cache.HttpCacheHeaderUtil;
|
||||
import org.apache.solr.servlet.cache.Method;
|
||||
import org.apache.solr.update.processor.DistributingUpdateProcessorFactory;
|
||||
import org.apache.solr.util.FastWriter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -86,11 +86,7 @@ import java.io.ByteArrayInputStream;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
@ -120,8 +116,6 @@ public class SolrDispatchFilter extends BaseSolrFilter {
|
|||
protected String abortErrorMessage = null;
|
||||
protected final HttpClient httpClient = HttpClientUtil.createClient(new ModifiableSolrParams());
|
||||
|
||||
private static final Charset UTF8 = StandardCharsets.UTF_8;
|
||||
|
||||
public SolrDispatchFilter() {
|
||||
}
|
||||
|
||||
|
@ -756,18 +750,7 @@ public class SolrDispatchFilter extends BaseSolrFilter {
|
|||
}
|
||||
|
||||
if (Method.HEAD != reqMethod) {
|
||||
if (responseWriter instanceof BinaryQueryResponseWriter) {
|
||||
BinaryQueryResponseWriter binWriter = (BinaryQueryResponseWriter) responseWriter;
|
||||
binWriter.write(response.getOutputStream(), solrReq, solrRsp);
|
||||
} else {
|
||||
String charset = ContentStreamBase.getCharsetFromContentType(ct);
|
||||
Writer out = (charset == null)
|
||||
? new OutputStreamWriter(response.getOutputStream(), UTF8)
|
||||
: new OutputStreamWriter(response.getOutputStream(), charset);
|
||||
out = new FastWriter(out);
|
||||
responseWriter.write(out, solrReq, solrRsp);
|
||||
out.flush();
|
||||
}
|
||||
QueryResponseWriterUtil.writeQueryResponse(response.getOutputStream(), responseWriter, solrReq, solrRsp, ct);
|
||||
}
|
||||
//else http HEAD request, nothing to write out, waited this long just to get ContentType
|
||||
}
|
||||
|
|
|
@ -0,0 +1,200 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.apache.solr.response;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.util.Collections;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.apache.lucene.util.TestUtil;
|
||||
import org.apache.solr.SolrTestCaseJ4;
|
||||
import org.apache.solr.client.solrj.impl.BinaryResponseParser;
|
||||
import org.apache.solr.common.util.ContentStreamBase.ByteArrayStream;
|
||||
import org.apache.solr.common.util.ContentStreamBase.StringStream;
|
||||
import org.apache.solr.common.SolrException;
|
||||
import org.apache.solr.common.util.NamedList;
|
||||
import org.apache.solr.request.SolrQueryRequest;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.AfterClass;
|
||||
|
||||
/**
|
||||
* Tests the {@link RawResponseWriter} behavior, in particular when dealing with "base" writer
|
||||
*/
|
||||
public class TestRawResponseWriter extends SolrTestCaseJ4 {
|
||||
|
||||
private static RawResponseWriter writerXmlBase;
|
||||
private static RawResponseWriter writerJsonBase;
|
||||
private static RawResponseWriter writerBinBase;
|
||||
private static RawResponseWriter writerNoBase;
|
||||
|
||||
private static RawResponseWriter[] allWriters;
|
||||
|
||||
@BeforeClass
|
||||
public static void setupCoreAndWriters() throws Exception {
|
||||
// we don't directly use this core or it's config, we use
|
||||
// QueryResponseWriters' constructed programaticly,
|
||||
// but we do use this core for managing the life cycle of the requests
|
||||
// we spin up.
|
||||
initCore("solrconfig.xml","schema.xml");
|
||||
|
||||
writerNoBase = newRawResponseWriter(null); /* defaults to standard writer as base */
|
||||
writerXmlBase = newRawResponseWriter("xml");
|
||||
writerJsonBase = newRawResponseWriter("json");
|
||||
writerBinBase = newRawResponseWriter("javabin");
|
||||
|
||||
allWriters = new RawResponseWriter[] {
|
||||
writerXmlBase, writerJsonBase, writerBinBase, writerNoBase
|
||||
};
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void cleanupWriters() throws Exception {
|
||||
writerXmlBase = null;
|
||||
writerJsonBase = null;
|
||||
writerBinBase = null;
|
||||
writerNoBase = null;
|
||||
|
||||
allWriters = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Regardless of base writer, the bytes in should be the same as the bytes out
|
||||
* when response is a raw ContentStream written to an OutputStream
|
||||
*/
|
||||
public void testRawBinaryContentStream() throws IOException {
|
||||
SolrQueryResponse rsp = new SolrQueryResponse();
|
||||
byte[] data = new byte[TestUtil.nextInt(random(), 10, 2048)];
|
||||
random().nextBytes(data);
|
||||
ByteArrayStream stream = new ByteArrayStream(data, TestUtil.randomUnicodeString(random()));
|
||||
|
||||
stream.setContentType(TestUtil.randomSimpleString(random()));
|
||||
rsp.add(RawResponseWriter.CONTENT, stream);
|
||||
|
||||
for (RawResponseWriter writer : allWriters) {
|
||||
assertEquals(stream.getContentType(), writer.getContentType(req(), rsp));
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
writer.write(out, req(), rsp);
|
||||
assertArrayEquals(data, out.toByteArray());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Regardless of base writer, the String in should be the same as the String out
|
||||
* when response is a raw ContentStream written to a Writer (or OutputStream)
|
||||
*/
|
||||
public void testRawStringContentStream() throws IOException {
|
||||
SolrQueryResponse rsp = new SolrQueryResponse();
|
||||
String data = TestUtil.randomUnicodeString(random());
|
||||
StringStream stream = new StringStream(data);
|
||||
|
||||
stream.setContentType(TestUtil.randomSimpleString(random()));
|
||||
rsp.add(RawResponseWriter.CONTENT, stream);
|
||||
|
||||
for (RawResponseWriter writer : allWriters) {
|
||||
assertEquals(stream.getContentType(), writer.getContentType(req(), rsp));
|
||||
|
||||
// we should have the same string if we use a Writer
|
||||
StringWriter sout = new StringWriter();
|
||||
writer.write(sout, req(), rsp);
|
||||
assertEquals(data, sout.toString());
|
||||
|
||||
// we should have UTF-8 Bytes if we use an OutputStream
|
||||
ByteArrayOutputStream bout = new ByteArrayOutputStream();
|
||||
writer.write(bout, req(), rsp);
|
||||
assertEquals(data, bout.toString(StandardCharsets.UTF_8.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When no real ContentStream is specified, each base writer should be used for formatting
|
||||
*/
|
||||
public void testStructuredDataViaBaseWriters() throws IOException {
|
||||
SolrQueryResponse rsp = new SolrQueryResponse();
|
||||
// Don't send a ContentStream back, this will fall back to the configured base writer.
|
||||
// But abuse the CONTENT key to ensure writer is also checking type
|
||||
rsp.add(RawResponseWriter.CONTENT, "test");
|
||||
rsp.add("foo", "bar");
|
||||
|
||||
// check Content-Type against each writer
|
||||
assertEquals("application/xml; charset=UTF-8", writerNoBase.getContentType(req(), rsp));
|
||||
assertEquals("application/xml; charset=UTF-8", writerXmlBase.getContentType(req(), rsp));
|
||||
assertEquals("application/json; charset=UTF-8", writerJsonBase.getContentType(req(), rsp));
|
||||
assertEquals("application/octet-stream", writerBinBase.getContentType(req(), rsp));
|
||||
|
||||
// check response against each writer
|
||||
|
||||
// xml & none (default behavior same as XML)
|
||||
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<response>\n<str name=\"content\">test</str><str name=\"foo\">bar</str>\n</response>\n";
|
||||
StringWriter xmlSout = new StringWriter();
|
||||
writerXmlBase.write(xmlSout, req(), rsp);
|
||||
assertEquals(xml, xmlSout.toString());
|
||||
ByteArrayOutputStream xmlBout = new ByteArrayOutputStream();
|
||||
writerXmlBase.write(xmlBout, req(), rsp);
|
||||
assertEquals(xml, xmlBout.toString(StandardCharsets.UTF_8.toString()));
|
||||
//
|
||||
StringWriter noneSout = new StringWriter();
|
||||
writerNoBase.write(noneSout, req(), rsp);
|
||||
assertEquals(xml, noneSout.toString());
|
||||
ByteArrayOutputStream noneBout = new ByteArrayOutputStream();
|
||||
writerNoBase.write(noneBout, req(), rsp);
|
||||
assertEquals(xml, noneBout.toString(StandardCharsets.UTF_8.toString()));
|
||||
|
||||
// json
|
||||
String json = "{\"content\":\"test\",\"foo\":\"bar\"}\n";
|
||||
StringWriter jsonSout = new StringWriter();
|
||||
writerJsonBase.write(jsonSout, req(), rsp);
|
||||
assertEquals(json, jsonSout.toString());
|
||||
ByteArrayOutputStream jsonBout = new ByteArrayOutputStream();
|
||||
writerJsonBase.write(jsonBout, req(), rsp);
|
||||
assertEquals(json, jsonBout.toString(StandardCharsets.UTF_8.toString()));
|
||||
|
||||
// javabin
|
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
writerBinBase.write(bytes, req(), rsp);
|
||||
BinaryResponseParser parser = new BinaryResponseParser();
|
||||
NamedList<Object> out = parser.processResponse
|
||||
(new ByteArrayInputStream(bytes.toByteArray()), /* encoding irelevent */ null);
|
||||
assertEquals(RawResponseWriter.CONTENT, out.getName(0));
|
||||
assertEquals("test", out.getVal(0));
|
||||
assertEquals("foo", out.getName(1));
|
||||
assertEquals("bar", out.getVal(1));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new {@link RawResponseWriter} wraping the specified baseWriter name
|
||||
* (which much either be an implicitly definied response writer, or one explicitly
|
||||
* configured in solrconfig.xml)
|
||||
*
|
||||
* @param baseWriter null or the name of a valid base writer
|
||||
*/
|
||||
private static RawResponseWriter newRawResponseWriter(String baseWriter) {
|
||||
RawResponseWriter writer = new RawResponseWriter();
|
||||
NamedList initArgs = new NamedList<Object>();
|
||||
if (null != baseWriter) {
|
||||
initArgs.add("base", baseWriter);
|
||||
}
|
||||
writer.init(initArgs);
|
||||
return writer;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue