mirror of https://github.com/apache/lucene.git
SOLR-10748: Make stream.body configurable and disabled by default
This commit is contained in:
parent
112bdda47e
commit
80b1430a3e
|
@ -77,6 +77,8 @@ Other Changes
|
||||||
* SOLR-10957: Changed SolrCoreParser.init to use the resource loader from getSchema()
|
* SOLR-10957: Changed SolrCoreParser.init to use the resource loader from getSchema()
|
||||||
instead of the resource loader from getCore(). (Christine Poerschke)
|
instead of the resource loader from getCore(). (Christine Poerschke)
|
||||||
|
|
||||||
|
* SOLR-10748: Make stream.body configurable and disabled by default (janhoy)
|
||||||
|
|
||||||
================== 7.0.0 ==================
|
================== 7.0.0 ==================
|
||||||
|
|
||||||
Versions of Major Components
|
Versions of Major Components
|
||||||
|
|
|
@ -18,6 +18,9 @@
|
||||||
|
|
||||||
<schemaFactory class="ClassicIndexSchemaFactory" />
|
<schemaFactory class="ClassicIndexSchemaFactory" />
|
||||||
|
|
||||||
|
<requestDispatcher>
|
||||||
|
<requestParsers enableStreamBody="true" />
|
||||||
|
</requestDispatcher>
|
||||||
|
|
||||||
<!-- Query parser used to rerank top docs with a provided model -->
|
<!-- Query parser used to rerank top docs with a provided model -->
|
||||||
<queryParser name="ltr"
|
<queryParser name="ltr"
|
||||||
|
|
|
@ -18,7 +18,10 @@
|
||||||
|
|
||||||
<schemaFactory class="ClassicIndexSchemaFactory" />
|
<schemaFactory class="ClassicIndexSchemaFactory" />
|
||||||
|
|
||||||
|
<requestDispatcher>
|
||||||
|
<requestParsers enableStreamBody="true" />
|
||||||
|
</requestDispatcher>
|
||||||
|
|
||||||
<!-- Query parser used to rerank top docs with a provided model -->
|
<!-- Query parser used to rerank top docs with a provided model -->
|
||||||
<queryParser name="ltr" class="org.apache.solr.ltr.search.LTRQParserPlugin" >
|
<queryParser name="ltr" class="org.apache.solr.ltr.search.LTRQParserPlugin" >
|
||||||
<int name="threadModule.totalPoolThreads">10</int> <!-- Maximum threads to use for all queries -->
|
<int name="threadModule.totalPoolThreads">10</int> <!-- Maximum threads to use for all queries -->
|
||||||
|
|
|
@ -18,7 +18,10 @@
|
||||||
|
|
||||||
<schemaFactory class="ClassicIndexSchemaFactory" />
|
<schemaFactory class="ClassicIndexSchemaFactory" />
|
||||||
|
|
||||||
|
<requestDispatcher>
|
||||||
|
<requestParsers enableStreamBody="true" />
|
||||||
|
</requestDispatcher>
|
||||||
|
|
||||||
<!-- Query parser used to rerank top docs with a provided model -->
|
<!-- Query parser used to rerank top docs with a provided model -->
|
||||||
<queryParser name="ltr" class="org.apache.solr.ltr.search.LTRQParserPlugin" />
|
<queryParser name="ltr" class="org.apache.solr.ltr.search.LTRQParserPlugin" />
|
||||||
|
|
||||||
|
|
|
@ -123,6 +123,7 @@ public class SolrConfig extends Config implements MapSerializable {
|
||||||
private int formUploadLimitKB;
|
private int formUploadLimitKB;
|
||||||
|
|
||||||
private boolean enableRemoteStreams;
|
private boolean enableRemoteStreams;
|
||||||
|
private boolean enableStreamBody;
|
||||||
|
|
||||||
private boolean handleSelect;
|
private boolean handleSelect;
|
||||||
|
|
||||||
|
@ -308,6 +309,9 @@ public class SolrConfig extends Config implements MapSerializable {
|
||||||
enableRemoteStreams = getBool(
|
enableRemoteStreams = getBool(
|
||||||
"requestDispatcher/requestParsers/@enableRemoteStreaming", false);
|
"requestDispatcher/requestParsers/@enableRemoteStreaming", false);
|
||||||
|
|
||||||
|
enableStreamBody = getBool(
|
||||||
|
"requestDispatcher/requestParsers/@enableStreamBody", false);
|
||||||
|
|
||||||
handleSelect = getBool(
|
handleSelect = getBool(
|
||||||
"requestDispatcher/@handleSelect", !luceneMatchVersion.onOrAfter(Version.LUCENE_7_0_0));
|
"requestDispatcher/@handleSelect", !luceneMatchVersion.onOrAfter(Version.LUCENE_7_0_0));
|
||||||
|
|
||||||
|
@ -784,6 +788,10 @@ public class SolrConfig extends Config implements MapSerializable {
|
||||||
return enableRemoteStreams;
|
return enableRemoteStreams;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isEnableStreamBody() {
|
||||||
|
return enableStreamBody;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getInt(String path) {
|
public int getInt(String path) {
|
||||||
return getInt(path, 0);
|
return getInt(path, 0);
|
||||||
|
|
|
@ -84,6 +84,7 @@ public class SolrRequestParsers
|
||||||
private final HashMap<String, SolrRequestParser> parsers =
|
private final HashMap<String, SolrRequestParser> parsers =
|
||||||
new HashMap<>();
|
new HashMap<>();
|
||||||
private final boolean enableRemoteStreams;
|
private final boolean enableRemoteStreams;
|
||||||
|
private final boolean enableStreamBody;
|
||||||
private StandardRequestParser standard;
|
private StandardRequestParser standard;
|
||||||
private boolean handleSelect = true;
|
private boolean handleSelect = true;
|
||||||
private boolean addHttpRequestToContext;
|
private boolean addHttpRequestToContext;
|
||||||
|
@ -101,8 +102,9 @@ public class SolrRequestParsers
|
||||||
final int multipartUploadLimitKB, formUploadLimitKB;
|
final int multipartUploadLimitKB, formUploadLimitKB;
|
||||||
if( globalConfig == null ) {
|
if( globalConfig == null ) {
|
||||||
multipartUploadLimitKB = formUploadLimitKB = Integer.MAX_VALUE;
|
multipartUploadLimitKB = formUploadLimitKB = Integer.MAX_VALUE;
|
||||||
enableRemoteStreams = true;
|
enableRemoteStreams = false;
|
||||||
handleSelect = true;
|
enableStreamBody = false;
|
||||||
|
handleSelect = false;
|
||||||
addHttpRequestToContext = false;
|
addHttpRequestToContext = false;
|
||||||
} else {
|
} else {
|
||||||
multipartUploadLimitKB = globalConfig.getMultipartUploadLimitKB();
|
multipartUploadLimitKB = globalConfig.getMultipartUploadLimitKB();
|
||||||
|
@ -110,6 +112,7 @@ public class SolrRequestParsers
|
||||||
formUploadLimitKB = globalConfig.getFormUploadLimitKB();
|
formUploadLimitKB = globalConfig.getFormUploadLimitKB();
|
||||||
|
|
||||||
enableRemoteStreams = globalConfig.isEnableRemoteStreams();
|
enableRemoteStreams = globalConfig.isEnableRemoteStreams();
|
||||||
|
enableStreamBody = globalConfig.isEnableStreamBody();
|
||||||
|
|
||||||
// Let this filter take care of /select?xxx format
|
// Let this filter take care of /select?xxx format
|
||||||
handleSelect = globalConfig.isHandleSelect();
|
handleSelect = globalConfig.isHandleSelect();
|
||||||
|
@ -121,9 +124,10 @@ public class SolrRequestParsers
|
||||||
|
|
||||||
private SolrRequestParsers() {
|
private SolrRequestParsers() {
|
||||||
enableRemoteStreams = false;
|
enableRemoteStreams = false;
|
||||||
|
enableStreamBody = false;
|
||||||
handleSelect = false;
|
handleSelect = false;
|
||||||
addHttpRequestToContext = false;
|
addHttpRequestToContext = false;
|
||||||
init(2048, 2048);
|
init(Integer.MAX_VALUE, Integer.MAX_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void init( int multipartUploadLimitKB, int formUploadLimitKB) {
|
private void init( int multipartUploadLimitKB, int formUploadLimitKB) {
|
||||||
|
@ -202,7 +206,7 @@ public class SolrRequestParsers
|
||||||
strs = params.getParams( CommonParams.STREAM_FILE );
|
strs = params.getParams( CommonParams.STREAM_FILE );
|
||||||
if( strs != null ) {
|
if( strs != null ) {
|
||||||
if( !enableRemoteStreams ) {
|
if( !enableRemoteStreams ) {
|
||||||
throw new SolrException( ErrorCode.BAD_REQUEST, "Remote Streaming is disabled." );
|
throw new SolrException( ErrorCode.BAD_REQUEST, "Remote Streaming is disabled. See http://lucene.apache.org/solr/guide/requestdispatcher-in-solrconfig.html for help" );
|
||||||
}
|
}
|
||||||
for( final String file : strs ) {
|
for( final String file : strs ) {
|
||||||
ContentStreamBase stream = new ContentStreamBase.FileStream( new File(file) );
|
ContentStreamBase stream = new ContentStreamBase.FileStream( new File(file) );
|
||||||
|
@ -216,6 +220,9 @@ public class SolrRequestParsers
|
||||||
// Check for streams in the request parameters
|
// Check for streams in the request parameters
|
||||||
strs = params.getParams( CommonParams.STREAM_BODY );
|
strs = params.getParams( CommonParams.STREAM_BODY );
|
||||||
if( strs != null ) {
|
if( strs != null ) {
|
||||||
|
if( !enableStreamBody ) {
|
||||||
|
throw new SolrException( ErrorCode.BAD_REQUEST, "Stream Body is disabled. See http://lucene.apache.org/solr/guide/requestdispatcher-in-solrconfig.html for help" );
|
||||||
|
}
|
||||||
for( final String body : strs ) {
|
for( final String body : strs ) {
|
||||||
ContentStreamBase stream = new ContentStreamBase.StringStream( body );
|
ContentStreamBase stream = new ContentStreamBase.StringStream( body );
|
||||||
if( contentType != null ) {
|
if( contentType != null ) {
|
||||||
|
|
|
@ -65,7 +65,8 @@
|
||||||
"requestParsers":{
|
"requestParsers":{
|
||||||
"multipartUploadLimitInKB":0,
|
"multipartUploadLimitInKB":0,
|
||||||
"formdataUploadLimitInKB":0,
|
"formdataUploadLimitInKB":0,
|
||||||
"enableRemoteStreaming":0,
|
"enableRemoteStreaming":10,
|
||||||
|
"enableStreamBody":10,
|
||||||
"addHttpRequestToContext":0}},
|
"addHttpRequestToContext":0}},
|
||||||
"peerSync":{
|
"peerSync":{
|
||||||
"useRangeVersions":11
|
"useRangeVersions":11
|
||||||
|
|
|
@ -29,6 +29,11 @@
|
||||||
|
|
||||||
<codecFactory class="solr.SchemaCodecFactory"/>
|
<codecFactory class="solr.SchemaCodecFactory"/>
|
||||||
|
|
||||||
|
<requestDispatcher>
|
||||||
|
<!-- Tests rely on stream.body -->
|
||||||
|
<requestParsers enableStreamBody="true" />
|
||||||
|
</requestDispatcher>
|
||||||
|
|
||||||
<query>
|
<query>
|
||||||
<filterCache
|
<filterCache
|
||||||
enabled="${filterCache.enabled:false}"
|
enabled="${filterCache.enabled:false}"
|
||||||
|
|
|
@ -35,6 +35,10 @@
|
||||||
</updateLog>
|
</updateLog>
|
||||||
</updateHandler>
|
</updateHandler>
|
||||||
|
|
||||||
|
<requestDispatcher>
|
||||||
|
<requestParsers enableStreamBody="true" />
|
||||||
|
</requestDispatcher>
|
||||||
|
|
||||||
<requestHandler name="/select" class="solr.SearchHandler">
|
<requestHandler name="/select" class="solr.SearchHandler">
|
||||||
<bool name="httpCaching">true</bool>
|
<bool name="httpCaching">true</bool>
|
||||||
</requestHandler>
|
</requestHandler>
|
||||||
|
|
|
@ -31,6 +31,9 @@
|
||||||
<str name="solr.hdfs.blockcache.global">${solr.hdfs.blockcache.global:true}</str>
|
<str name="solr.hdfs.blockcache.global">${solr.hdfs.blockcache.global:true}</str>
|
||||||
</directoryFactory>
|
</directoryFactory>
|
||||||
<schemaFactory class="ClassicIndexSchemaFactory"/>
|
<schemaFactory class="ClassicIndexSchemaFactory"/>
|
||||||
|
<requestDispatcher>
|
||||||
|
<requestParsers enableStreamBody="true" />
|
||||||
|
</requestDispatcher>
|
||||||
|
|
||||||
<dataDir>${solr.data.dir:}</dataDir>
|
<dataDir>${solr.data.dir:}</dataDir>
|
||||||
|
|
||||||
|
|
|
@ -457,7 +457,7 @@
|
||||||
</searchComponent>
|
</searchComponent>
|
||||||
|
|
||||||
<requestDispatcher>
|
<requestDispatcher>
|
||||||
<requestParsers enableRemoteStreaming="true" multipartUploadLimitInKB="-1" />
|
<requestParsers enableRemoteStreaming="true" enableStreamBody="true" multipartUploadLimitInKB="-1" />
|
||||||
<httpCaching lastModifiedFrom="openTime" etagSeed="Solr" never304="false">
|
<httpCaching lastModifiedFrom="openTime" etagSeed="Solr" never304="false">
|
||||||
<cacheControl>max-age=30, public</cacheControl>
|
<cacheControl>max-age=30, public</cacheControl>
|
||||||
</httpCaching>
|
</httpCaching>
|
||||||
|
|
|
@ -38,7 +38,9 @@
|
||||||
<boolTofilterOptimizer enabled="true" cacheSize="32" threshold=".05"/>
|
<boolTofilterOptimizer enabled="true" cacheSize="32" threshold=".05"/>
|
||||||
</query>
|
</query>
|
||||||
|
|
||||||
<requestDispatcher/>
|
<requestDispatcher>
|
||||||
|
<requestParsers enableStreamBody="true" />
|
||||||
|
</requestDispatcher>
|
||||||
|
|
||||||
<requestHandler name="/select" class="solr.SearchHandler" />
|
<requestHandler name="/select" class="solr.SearchHandler" />
|
||||||
<requestHandler name="/crazy_custom_qt" class="solr.SearchHandler">
|
<requestHandler name="/crazy_custom_qt" class="solr.SearchHandler">
|
||||||
|
|
|
@ -37,6 +37,7 @@ import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.FileVisitResult;
|
import java.nio.file.FileVisitResult;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.SimpleFileVisitor;
|
||||||
import java.nio.file.attribute.BasicFileAttributes;
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
@ -47,10 +48,10 @@ import java.util.LinkedList;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.nio.file.SimpleFileVisitor;
|
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipOutputStream;
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
import org.apache.http.HttpEntity;
|
import org.apache.http.HttpEntity;
|
||||||
import org.apache.http.client.HttpClient;
|
import org.apache.http.client.HttpClient;
|
||||||
|
@ -61,27 +62,22 @@ import org.apache.http.util.EntityUtils;
|
||||||
import org.apache.lucene.util.TestUtil;
|
import org.apache.lucene.util.TestUtil;
|
||||||
import org.apache.solr.SolrTestCaseJ4;
|
import org.apache.solr.SolrTestCaseJ4;
|
||||||
import org.apache.solr.client.solrj.SolrClient;
|
import org.apache.solr.client.solrj.SolrClient;
|
||||||
import org.apache.solr.client.solrj.SolrQuery;
|
|
||||||
import org.apache.solr.client.solrj.SolrRequest;
|
import org.apache.solr.client.solrj.SolrRequest;
|
||||||
import org.apache.solr.client.solrj.SolrServerException;
|
import org.apache.solr.client.solrj.SolrServerException;
|
||||||
import org.apache.solr.client.solrj.embedded.JettySolrRunner;
|
import org.apache.solr.client.solrj.embedded.JettySolrRunner;
|
||||||
import org.apache.solr.client.solrj.impl.CloudSolrClient;
|
import org.apache.solr.client.solrj.impl.CloudSolrClient;
|
||||||
import org.apache.solr.client.solrj.impl.HttpClientUtil;
|
import org.apache.solr.client.solrj.impl.HttpClientUtil;
|
||||||
import org.apache.solr.client.solrj.impl.HttpSolrClient;
|
|
||||||
import org.apache.solr.client.solrj.request.ConfigSetAdminRequest;
|
import org.apache.solr.client.solrj.request.ConfigSetAdminRequest;
|
||||||
import org.apache.solr.client.solrj.request.ConfigSetAdminRequest.Create;
|
import org.apache.solr.client.solrj.request.ConfigSetAdminRequest.Create;
|
||||||
import org.apache.solr.client.solrj.request.ConfigSetAdminRequest.Delete;
|
import org.apache.solr.client.solrj.request.ConfigSetAdminRequest.Delete;
|
||||||
import org.apache.solr.client.solrj.request.QueryRequest;
|
import org.apache.solr.client.solrj.request.QueryRequest;
|
||||||
import org.apache.solr.client.solrj.response.CollectionAdminResponse;
|
import org.apache.solr.client.solrj.response.CollectionAdminResponse;
|
||||||
import org.apache.solr.client.solrj.response.ConfigSetAdminResponse;
|
import org.apache.solr.client.solrj.response.ConfigSetAdminResponse;
|
||||||
import org.apache.solr.common.SolrException;
|
|
||||||
import org.apache.solr.common.SolrException.ErrorCode;
|
|
||||||
import org.apache.solr.common.SolrInputDocument;
|
import org.apache.solr.common.SolrInputDocument;
|
||||||
import org.apache.solr.common.cloud.SolrZkClient;
|
import org.apache.solr.common.cloud.SolrZkClient;
|
||||||
import org.apache.solr.common.cloud.ZkConfigManager;
|
import org.apache.solr.common.cloud.ZkConfigManager;
|
||||||
import org.apache.solr.common.cloud.ZkStateReader;
|
import org.apache.solr.common.cloud.ZkStateReader;
|
||||||
import org.apache.solr.common.params.CollectionParams.CollectionAction;
|
import org.apache.solr.common.params.CollectionParams.CollectionAction;
|
||||||
import org.apache.solr.common.params.CommonParams;
|
|
||||||
import org.apache.solr.common.params.ConfigSetParams;
|
import org.apache.solr.common.params.ConfigSetParams;
|
||||||
import org.apache.solr.common.params.ConfigSetParams.ConfigSetAction;
|
import org.apache.solr.common.params.ConfigSetParams.ConfigSetAction;
|
||||||
import org.apache.solr.common.params.ModifiableSolrParams;
|
import org.apache.solr.common.params.ModifiableSolrParams;
|
||||||
|
@ -104,8 +100,6 @@ import org.noggit.ObjectBuilder;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple ConfigSets API tests on user errors and simple success cases.
|
* Simple ConfigSets API tests on user errors and simple success cases.
|
||||||
*/
|
*/
|
||||||
|
@ -331,7 +325,6 @@ public class TestConfigSetsAPI extends SolrTestCaseJ4 {
|
||||||
uploadConfigSet("regular", suffix, null, null);
|
uploadConfigSet("regular", suffix, null, null);
|
||||||
// try to create a collection with the uploaded configset
|
// try to create a collection with the uploaded configset
|
||||||
createCollection("newcollection", "regular" + suffix, 1, 1, solrCluster.getSolrClient());
|
createCollection("newcollection", "regular" + suffix, 1, 1, solrCluster.getSolrClient());
|
||||||
xsltRequest("newcollection");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -506,35 +499,6 @@ public class TestConfigSetsAPI extends SolrTestCaseJ4 {
|
||||||
zout.close();
|
zout.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void xsltRequest(String collection) throws SolrServerException, IOException {
|
|
||||||
String baseUrl = solrCluster.getJettySolrRunners().get(0).getBaseUrl().toString();
|
|
||||||
try (HttpSolrClient client = getHttpSolrClient(baseUrl + "/" + collection)) {
|
|
||||||
String xml =
|
|
||||||
"<random>" +
|
|
||||||
" <document>" +
|
|
||||||
" <node name=\"id\" value=\"12345\"/>" +
|
|
||||||
" <node name=\"name\" value=\"kitten\"/>" +
|
|
||||||
" <node name=\"text\" enhance=\"3\" value=\"some other day\"/>" +
|
|
||||||
" <node name=\"title\" enhance=\"4\" value=\"A story\"/>" +
|
|
||||||
" <node name=\"timestamp\" enhance=\"5\" value=\"2011-07-01T10:31:57.140Z\"/>" +
|
|
||||||
" </document>" +
|
|
||||||
"</random>";
|
|
||||||
|
|
||||||
SolrQuery query = new SolrQuery();
|
|
||||||
query.setQuery( "*:*" );//for anything
|
|
||||||
query.add("qt","/update");
|
|
||||||
query.add(CommonParams.TR, "xsl-update-handler-test.xsl");
|
|
||||||
query.add("stream.body", xml);
|
|
||||||
query.add("commit", "true");
|
|
||||||
try {
|
|
||||||
client.query(query);
|
|
||||||
fail("This should've returned a 401.");
|
|
||||||
} catch (SolrException ex) {
|
|
||||||
assertEquals(ErrorCode.UNAUTHORIZED.code, ex.code());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void scriptRequest(String collection) throws SolrServerException, IOException {
|
public void scriptRequest(String collection) throws SolrServerException, IOException {
|
||||||
SolrClient client = solrCluster.getSolrClient();
|
SolrClient client = solrCluster.getSolrClient();
|
||||||
|
|
|
@ -53,6 +53,7 @@ public class TestConfigOverlay extends LuceneTestCase {
|
||||||
assertTrue(isEditableProp("requestDispatcher.requestParsers.multipartUploadLimitInKB", false, null));
|
assertTrue(isEditableProp("requestDispatcher.requestParsers.multipartUploadLimitInKB", false, null));
|
||||||
assertTrue(isEditableProp("requestDispatcher.requestParsers.formdataUploadLimitInKB", false, null));
|
assertTrue(isEditableProp("requestDispatcher.requestParsers.formdataUploadLimitInKB", false, null));
|
||||||
assertTrue(isEditableProp("requestDispatcher.requestParsers.enableRemoteStreaming", false, null));
|
assertTrue(isEditableProp("requestDispatcher.requestParsers.enableRemoteStreaming", false, null));
|
||||||
|
assertTrue(isEditableProp("requestDispatcher.requestParsers.enableStreamBody", false, null));
|
||||||
assertTrue(isEditableProp("requestDispatcher.requestParsers.addHttpRequestToContext", false, null));
|
assertTrue(isEditableProp("requestDispatcher.requestParsers.addHttpRequestToContext", false, null));
|
||||||
|
|
||||||
assertTrue(isEditableProp("requestDispatcher.handleSelect", false, null));
|
assertTrue(isEditableProp("requestDispatcher.handleSelect", false, null));
|
||||||
|
|
|
@ -182,7 +182,8 @@ public class TestSolrConfigHandler extends RestTestBase {
|
||||||
log.info("going to send config command. path {} , payload: {}", uri, payload);
|
log.info("going to send config command. path {} , payload: {}", uri, payload);
|
||||||
String response = harness.post(uri, json);
|
String response = harness.post(uri, json);
|
||||||
Map map = (Map) ObjectBuilder.getVal(new JSONParser(new StringReader(response)));
|
Map map = (Map) ObjectBuilder.getVal(new JSONParser(new StringReader(response)));
|
||||||
assertNull(response, map.get("errors"));
|
assertNull(response, map.get("errorMessages"));
|
||||||
|
assertNull(response, map.get("errors")); // Will this ever be returned?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -20,15 +20,14 @@ import org.apache.commons.io.IOUtils;
|
||||||
import org.apache.lucene.util.LuceneTestCase;
|
import org.apache.lucene.util.LuceneTestCase;
|
||||||
import org.apache.solr.SolrJettyTestBase;
|
import org.apache.solr.SolrJettyTestBase;
|
||||||
import org.apache.solr.SolrTestCaseJ4.SuppressSSL;
|
import org.apache.solr.SolrTestCaseJ4.SuppressSSL;
|
||||||
import org.apache.solr.client.solrj.SolrQuery;
|
|
||||||
import org.apache.solr.client.solrj.SolrClient;
|
import org.apache.solr.client.solrj.SolrClient;
|
||||||
|
import org.apache.solr.client.solrj.SolrQuery;
|
||||||
import org.apache.solr.client.solrj.SolrServerException;
|
import org.apache.solr.client.solrj.SolrServerException;
|
||||||
import org.apache.solr.client.solrj.impl.HttpSolrClient;
|
import org.apache.solr.client.solrj.impl.HttpSolrClient;
|
||||||
import org.apache.solr.client.solrj.request.QueryRequest;
|
|
||||||
import org.apache.solr.client.solrj.response.QueryResponse;
|
import org.apache.solr.client.solrj.response.QueryResponse;
|
||||||
import org.apache.solr.common.SolrException;
|
import org.apache.solr.common.SolrException;
|
||||||
import org.apache.solr.common.SolrInputDocument;
|
|
||||||
import org.apache.solr.common.SolrException.ErrorCode;
|
import org.apache.solr.common.SolrException.ErrorCode;
|
||||||
|
import org.apache.solr.common.SolrInputDocument;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
|
@ -120,30 +119,7 @@ public class TestRemoteStreaming extends SolrJettyTestBase {
|
||||||
assertSame(ErrorCode.BAD_REQUEST, ErrorCode.getErrorCode(se.code()));
|
assertSame(ErrorCode.BAD_REQUEST, ErrorCode.getErrorCode(se.code()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** SOLR-3161
|
|
||||||
* Technically stream.body isn't remote streaming, but there wasn't a better place for this test method. */
|
|
||||||
@Test(expected = SolrException.class)
|
|
||||||
public void testQtUpdateFails() throws SolrServerException, IOException {
|
|
||||||
SolrQuery query = new SolrQuery();
|
|
||||||
query.setQuery( "*:*" );//for anything
|
|
||||||
query.add("echoHandler","true");
|
|
||||||
//sneaky sneaky
|
|
||||||
query.add("qt","/update");
|
|
||||||
query.add("stream.body","<delete><query>*:*</query></delete>");
|
|
||||||
|
|
||||||
QueryRequest queryRequest = new QueryRequest(query) {
|
|
||||||
@Override
|
|
||||||
public String getPath() { //don't let superclass substitute qt for the path
|
|
||||||
return "/select";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
QueryResponse rsp = queryRequest.process(getSolrClient());
|
|
||||||
//!! should *fail* above for security purposes
|
|
||||||
String handler = (String) rsp.getHeader().get("handler");
|
|
||||||
System.out.println(handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Compose a url that if you get it, it will delete all the data. */
|
/** Compose a url that if you get it, it will delete all the data. */
|
||||||
private String makeDeleteAllUrl() throws UnsupportedEncodingException {
|
private String makeDeleteAllUrl() throws UnsupportedEncodingException {
|
||||||
HttpSolrClient client = (HttpSolrClient) getSolrClient();
|
HttpSolrClient client = (HttpSolrClient) getSolrClient();
|
||||||
|
|
|
@ -0,0 +1,138 @@
|
||||||
|
/*
|
||||||
|
* 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.request;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.util.SortedMap;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import org.apache.solr.client.solrj.SolrQuery;
|
||||||
|
import org.apache.solr.client.solrj.request.QueryRequest;
|
||||||
|
import org.apache.solr.common.SolrException;
|
||||||
|
import org.apache.solr.common.params.CommonParams;
|
||||||
|
import org.apache.solr.util.RestTestBase;
|
||||||
|
import org.apache.solr.util.RestTestHarness;
|
||||||
|
import org.eclipse.jetty.servlet.ServletHolder;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.restlet.ext.servlet.ServerServlet;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import static org.apache.solr.core.TestSolrConfigHandler.runConfigCommand;
|
||||||
|
|
||||||
|
public class TestStreamBody extends RestTestBase {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||||
|
|
||||||
|
private static final String collection = "collection1";
|
||||||
|
private static final String confDir = collection + "/conf";
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before() throws Exception {
|
||||||
|
File tmpSolrHome = createTempDir().toFile();
|
||||||
|
FileUtils.copyDirectory(new File(TEST_HOME()), tmpSolrHome.getAbsoluteFile());
|
||||||
|
|
||||||
|
final SortedMap<ServletHolder, String> extraServlets = new TreeMap<>();
|
||||||
|
final ServletHolder solrRestApi = new ServletHolder("SolrSchemaRestApi", ServerServlet.class);
|
||||||
|
solrRestApi.setInitParameter("org.restlet.application", "org.apache.solr.rest.SolrSchemaRestApi");
|
||||||
|
extraServlets.put(solrRestApi, "/schema/*"); // '/schema/*' matches '/schema', '/schema/', and '/schema/whatever...'
|
||||||
|
|
||||||
|
System.setProperty("managed.schema.mutable", "true");
|
||||||
|
System.setProperty("enable.update.log", "false");
|
||||||
|
|
||||||
|
createJettyAndHarness(tmpSolrHome.getAbsolutePath(), "solrconfig-minimal.xml", "schema-rest.xml",
|
||||||
|
"/solr", true, extraServlets);
|
||||||
|
if (random().nextBoolean()) {
|
||||||
|
log.info("These tests are run with V2 API");
|
||||||
|
restTestHarness.setServerProvider(() -> jetty.getBaseUrl().toString() + "/____v2/cores/" + DEFAULT_TEST_CORENAME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void after() throws Exception {
|
||||||
|
if (jetty != null) {
|
||||||
|
jetty.stop();
|
||||||
|
jetty = null;
|
||||||
|
}
|
||||||
|
if (client != null) {
|
||||||
|
client.close();
|
||||||
|
client = null;
|
||||||
|
}
|
||||||
|
if (restTestHarness != null) {
|
||||||
|
restTestHarness.close();
|
||||||
|
restTestHarness = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SOLR-3161
|
||||||
|
@Test
|
||||||
|
public void testQtUpdateFails() throws Exception {
|
||||||
|
enableStreamBody(true);
|
||||||
|
SolrQuery query = new SolrQuery();
|
||||||
|
query.setQuery( "*:*" );//for anything
|
||||||
|
query.add("echoHandler","true");
|
||||||
|
//sneaky sneaky
|
||||||
|
query.add("qt","/update");
|
||||||
|
query.add(CommonParams.STREAM_BODY,"<delete><query>*:*</query></delete>");
|
||||||
|
|
||||||
|
QueryRequest queryRequest = new QueryRequest(query) {
|
||||||
|
@Override
|
||||||
|
public String getPath() { //don't let superclass substitute qt for the path
|
||||||
|
return "/select";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
queryRequest.process(getSolrClient());
|
||||||
|
fail();
|
||||||
|
} catch (SolrException se) {
|
||||||
|
assertTrue(se.getMessage(), se.getMessage().contains("Bad contentType for search handler :text/xml"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests that stream.body is disabled by default, and can be edited through Config API
|
||||||
|
@Test
|
||||||
|
public void testStreamBodyDefaultAndConfigApi() throws Exception {
|
||||||
|
SolrQuery query = new SolrQuery();
|
||||||
|
query.add(CommonParams.STREAM_BODY,"<delete><query>*:*</query></delete>");
|
||||||
|
query.add("commit","true");
|
||||||
|
|
||||||
|
QueryRequest queryRequest = new QueryRequest(query) {
|
||||||
|
@Override
|
||||||
|
public String getPath() { //don't let superclass substitute qt for the path
|
||||||
|
return "/update";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
queryRequest.process(getSolrClient());
|
||||||
|
fail();
|
||||||
|
} catch (SolrException se) {
|
||||||
|
assertTrue(se.getMessage(), se.getMessage().contains("Stream Body is disabled"));
|
||||||
|
}
|
||||||
|
enableStreamBody(true);
|
||||||
|
queryRequest.process(getSolrClient());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enables/disables stream.body through Config API
|
||||||
|
private void enableStreamBody(boolean enable) throws Exception {
|
||||||
|
RestTestHarness harness = restTestHarness;
|
||||||
|
String payload = "{ 'set-property' : { 'requestDispatcher.requestParsers.enableStreamBody':" + enable + "} }";
|
||||||
|
runConfigCommand(harness, "/config?wt=json", payload);
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,6 +20,7 @@ import org.apache.lucene.util.LuceneTestCase;
|
||||||
import org.apache.solr.JSONTestUtil;
|
import org.apache.solr.JSONTestUtil;
|
||||||
import org.apache.solr.SolrTestCaseHS;
|
import org.apache.solr.SolrTestCaseHS;
|
||||||
|
|
||||||
|
import org.apache.solr.common.params.CommonParams;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
@ -181,33 +182,33 @@ public class TestJsonRequest extends SolrTestCaseHS {
|
||||||
//
|
//
|
||||||
// with body
|
// with body
|
||||||
//
|
//
|
||||||
client.testJQ(params("stream.body", "{query:'cat_s:A'}", "stream.contentType", "application/json")
|
client.testJQ(params(CommonParams.STREAM_BODY, "{query:'cat_s:A'}", "stream.contentType", "application/json")
|
||||||
, "response/numFound==2"
|
, "response/numFound==2"
|
||||||
);
|
);
|
||||||
|
|
||||||
// test body in conjunction with query params
|
// test body in conjunction with query params
|
||||||
client.testJQ(params("stream.body", "{query:'cat_s:A'}", "stream.contentType", "application/json", "json.filter", "'where_s:NY'")
|
client.testJQ(params(CommonParams.STREAM_BODY, "{query:'cat_s:A'}", "stream.contentType", "application/json", "json.filter", "'where_s:NY'")
|
||||||
, "response/numFound==1"
|
, "response/numFound==1"
|
||||||
);
|
);
|
||||||
|
|
||||||
// test that json body in params come "after" (will overwrite)
|
// test that json body in params come "after" (will overwrite)
|
||||||
client.testJQ(params("stream.body", "{query:'*:*', filter:'where_s:NY'}", "stream.contentType", "application/json", "json","{query:'cat_s:A'}")
|
client.testJQ(params(CommonParams.STREAM_BODY, "{query:'*:*', filter:'where_s:NY'}", "stream.contentType", "application/json", "json","{query:'cat_s:A'}")
|
||||||
, "response/numFound==1"
|
, "response/numFound==1"
|
||||||
);
|
);
|
||||||
|
|
||||||
// test that json.x params come after body
|
// test that json.x params come after body
|
||||||
client.testJQ(params("stream.body", "{query:'*:*', filter:'where_s:NY'}", "stream.contentType", "application/json", "json.query","'cat_s:A'")
|
client.testJQ(params(CommonParams.STREAM_BODY, "{query:'*:*', filter:'where_s:NY'}", "stream.contentType", "application/json", "json.query","'cat_s:A'")
|
||||||
, "response/numFound==1"
|
, "response/numFound==1"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
// test facet with json body
|
// test facet with json body
|
||||||
client.testJQ(params("stream.body", "{query:'*:*', facet:{x:'unique(where_s)'}}", "stream.contentType", "application/json")
|
client.testJQ(params(CommonParams.STREAM_BODY, "{query:'*:*', facet:{x:'unique(where_s)'}}", "stream.contentType", "application/json")
|
||||||
, "facets=={count:6,x:2}"
|
, "facets=={count:6,x:2}"
|
||||||
);
|
);
|
||||||
|
|
||||||
// test facet with json body, insert additional facets via query parameter
|
// test facet with json body, insert additional facets via query parameter
|
||||||
client.testJQ(params("stream.body", "{query:'*:*', facet:{x:'unique(where_s)'}}", "stream.contentType", "application/json", "json.facet.y","{terms:{field:where_s}}", "json.facet.z","'unique(where_s)'")
|
client.testJQ(params(CommonParams.STREAM_BODY, "{query:'*:*', facet:{x:'unique(where_s)'}}", "stream.contentType", "application/json", "json.facet.y","{terms:{field:where_s}}", "json.facet.z","'unique(where_s)'")
|
||||||
, "facets=={count:6,x:2, y:{buckets:[{val:NJ,count:3},{val:NY,count:2}]}, z:2}"
|
, "facets=={count:6,x:2, y:{buckets:[{val:NJ,count:3},{val:NY,count:2}]}, z:2}"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -117,6 +117,7 @@ The properties that are configured with these commands are predefined and listed
|
||||||
* `requestDispatcher.requestParsers.multipartUploadLimitInKB`
|
* `requestDispatcher.requestParsers.multipartUploadLimitInKB`
|
||||||
* `requestDispatcher.requestParsers.formdataUploadLimitInKB`
|
* `requestDispatcher.requestParsers.formdataUploadLimitInKB`
|
||||||
* `requestDispatcher.requestParsers.enableRemoteStreaming`
|
* `requestDispatcher.requestParsers.enableRemoteStreaming`
|
||||||
|
* `requestDispatcher.requestParsers.enableStreamBody`
|
||||||
* `requestDispatcher.requestParsers.addHttpRequestToContext`
|
* `requestDispatcher.requestParsers.addHttpRequestToContext`
|
||||||
|
|
||||||
[[ConfigAPI-CommandsforCustomHandlersandLocalComponents]]
|
[[ConfigAPI-CommandsforCustomHandlersandLocalComponents]]
|
||||||
|
|
|
@ -102,7 +102,7 @@ Example of `commit` and `optimize` with optional attributes:
|
||||||
[[NearRealTimeSearching-PassingcommitandcommitWithinparametersaspartoftheURL]]
|
[[NearRealTimeSearching-PassingcommitandcommitWithinparametersaspartoftheURL]]
|
||||||
=== Passing commit and commitWithin Parameters as Part of the URL
|
=== Passing commit and commitWithin Parameters as Part of the URL
|
||||||
|
|
||||||
Update handlers can also get `commit`-related parameters as part of the update URL. This example adds a small test document and causes an explicit commit to happen immediately afterwards:
|
Update handlers can also get `commit`-related parameters as part of the update URL, if the `stream.body` feature is enabled. This example adds a small test document and causes an explicit commit to happen immediately afterwards:
|
||||||
|
|
||||||
[source,text]
|
[source,text]
|
||||||
----
|
----
|
||||||
|
@ -132,6 +132,8 @@ curl http://localhost:8983/solr/my_collection/update?commitWithin=10000
|
||||||
-H "Content-Type: text/xml" --data-binary '<add><doc><field name="id">testdoc</field></doc></add>'
|
-H "Content-Type: text/xml" --data-binary '<add><doc><field name="id">testdoc</field></doc></add>'
|
||||||
----
|
----
|
||||||
|
|
||||||
|
WARNING: While the `stream.body` feature is great for development and testing, it should normally not be enabled in production systems, as it lets a user with READ permissions post data that may alter the system state. The feature is disabled by default. See <<requestdispatcher-in-solrconfig.adoc#RequestDispatcherinSolrConfig-requestParsersElement,RequestDispatcher in SolrConfig>> for details.
|
||||||
|
|
||||||
[[NearRealTimeSearching-ChangingdefaultcommitWithinBehavior]]
|
[[NearRealTimeSearching-ChangingdefaultcommitWithinBehavior]]
|
||||||
=== Changing default commitWithin Behavior
|
=== Changing default commitWithin Behavior
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,8 @@ The `<requestParsers>` sub-element controls values related to parsing requests.
|
||||||
|
|
||||||
The attribute `enableRemoteStreaming` controls whether remote streaming of content is allowed. If omitted or set to `false` (the default), streaming will not be allowed. Setting it to `true` lets you specify the location of content to be streamed using `stream.file` or `stream.url` parameters.
|
The attribute `enableRemoteStreaming` controls whether remote streaming of content is allowed. If omitted or set to `false` (the default), streaming will not be allowed. Setting it to `true` lets you specify the location of content to be streamed using `stream.file` or `stream.url` parameters.
|
||||||
|
|
||||||
|
The attribute `enableStreamBody` controls whether streaming content from the HTTP parameter `stream.body` is allowed. If omitted or set to `false` (the default), streaming will not be allowed. Setting it to `true` lets you pass data in the `stream.body` parameter.
|
||||||
|
|
||||||
If you enable remote streaming, be sure that you have authentication enabled. Otherwise, someone could potentially gain access to your content by accessing arbitrary URLs. It's also a good idea to place Solr behind a firewall to prevent it from being accessed from untrusted clients.
|
If you enable remote streaming, be sure that you have authentication enabled. Otherwise, someone could potentially gain access to your content by accessing arbitrary URLs. It's also a good idea to place Solr behind a firewall to prevent it from being accessed from untrusted clients.
|
||||||
|
|
||||||
The attribute `multipartUploadLimitInKB` sets an upper limit in kilobytes on the size of a document that may be submitted in a multi-part HTTP POST request. The value specified is multiplied by 1024 to determine the size in bytes. A value of `-1` means MAX_INT, which is also the system default if omitted.
|
The attribute `multipartUploadLimitInKB` sets an upper limit in kilobytes on the size of a document that may be submitted in a multi-part HTTP POST request. The value specified is multiplied by 1024 to determine the size in bytes. A value of `-1` means MAX_INT, which is also the system default if omitted.
|
||||||
|
@ -59,11 +61,22 @@ The attribute `addHttpRequestToContext` can be used to indicate that the origina
|
||||||
[source,xml]
|
[source,xml]
|
||||||
----
|
----
|
||||||
<requestParsers enableRemoteStreaming="false"
|
<requestParsers enableRemoteStreaming="false"
|
||||||
|
enableStreamBody="false"
|
||||||
multipartUploadLimitInKB="2048"
|
multipartUploadLimitInKB="2048"
|
||||||
formdataUploadLimitInKB="2048"
|
formdataUploadLimitInKB="2048"
|
||||||
addHttpRequestToContext="false" />
|
addHttpRequestToContext="false" />
|
||||||
----
|
----
|
||||||
|
|
||||||
|
The below command is an example of how to enable RemoteStreaming and BodyStreaming through <<config-api.adoc#ConfigAPI-CreatingandUpdatingCommonProperties,Config API>>:
|
||||||
|
|
||||||
|
[source,bash]
|
||||||
|
----
|
||||||
|
curl http://localhost:8983/solr/gettingstarted/config -H 'Content-type:application/json' -d'{
|
||||||
|
"set-property" : {"requestDispatcher.requestParsers.enableRemoteStreaming":true},
|
||||||
|
"set-property" : {"requestDispatcher.requestParsers.enableStreamBody":true}
|
||||||
|
}'
|
||||||
|
----
|
||||||
|
|
||||||
[[RequestDispatcherinSolrConfig-httpCachingElement]]
|
[[RequestDispatcherinSolrConfig-httpCachingElement]]
|
||||||
== httpCaching Element
|
== httpCaching Element
|
||||||
|
|
||||||
|
|
|
@ -168,7 +168,7 @@ For posting XML messages contained in a file, you can use the alternative form:
|
||||||
curl http://localhost:8983/solr/my_collection/update -H "Content-Type: text/xml" --data-binary @myfile.xml
|
curl http://localhost:8983/solr/my_collection/update -H "Content-Type: text/xml" --data-binary @myfile.xml
|
||||||
----
|
----
|
||||||
|
|
||||||
Short requests can also be sent using a HTTP GET command, URL-encoding the request, as in the following. Note the escaping of "<" and ">":
|
Short requests can also be sent using a HTTP GET command, if enabled in <<requestdispatcher-in-solrconfig.adoc#RequestDispatcherinSolrConfig-requestParsersElement,RequestDispatcher in SolrConfig>> element, URL-encoding the request, as in the following. Note the escaping of "<" and ">":
|
||||||
|
|
||||||
[source,bash]
|
[source,bash]
|
||||||
----
|
----
|
||||||
|
|
Loading…
Reference in New Issue