diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt index 8b9202bf1e3..49b25cc5512 100644 --- a/solr/CHANGES.txt +++ b/solr/CHANGES.txt @@ -77,6 +77,8 @@ Other Changes * SOLR-10957: Changed SolrCoreParser.init to use the resource loader from getSchema() instead of the resource loader from getCore(). (Christine Poerschke) +* SOLR-10748: Make stream.body configurable and disabled by default (janhoy) + ================== 7.0.0 ================== Versions of Major Components diff --git a/solr/contrib/ltr/src/test-files/solr/collection1/conf/solrconfig-ltr.xml b/solr/contrib/ltr/src/test-files/solr/collection1/conf/solrconfig-ltr.xml index 0e92546723f..d5f66d3f8be 100644 --- a/solr/contrib/ltr/src/test-files/solr/collection1/conf/solrconfig-ltr.xml +++ b/solr/contrib/ltr/src/test-files/solr/collection1/conf/solrconfig-ltr.xml @@ -18,6 +18,9 @@ + + + - + + + + 10 diff --git a/solr/contrib/ltr/src/test-files/solr/collection1/conf/solrconfig-multiseg.xml b/solr/contrib/ltr/src/test-files/solr/collection1/conf/solrconfig-multiseg.xml index b34be8f3af8..7008ec1f5d5 100644 --- a/solr/contrib/ltr/src/test-files/solr/collection1/conf/solrconfig-multiseg.xml +++ b/solr/contrib/ltr/src/test-files/solr/collection1/conf/solrconfig-multiseg.xml @@ -18,7 +18,10 @@ - + + + + diff --git a/solr/core/src/java/org/apache/solr/core/SolrConfig.java b/solr/core/src/java/org/apache/solr/core/SolrConfig.java index 99423239fa7..6c6764596f2 100644 --- a/solr/core/src/java/org/apache/solr/core/SolrConfig.java +++ b/solr/core/src/java/org/apache/solr/core/SolrConfig.java @@ -123,6 +123,7 @@ public class SolrConfig extends Config implements MapSerializable { private int formUploadLimitKB; private boolean enableRemoteStreams; + private boolean enableStreamBody; private boolean handleSelect; @@ -308,6 +309,9 @@ public class SolrConfig extends Config implements MapSerializable { enableRemoteStreams = getBool( "requestDispatcher/requestParsers/@enableRemoteStreaming", false); + enableStreamBody = getBool( + "requestDispatcher/requestParsers/@enableStreamBody", false); + handleSelect = getBool( "requestDispatcher/@handleSelect", !luceneMatchVersion.onOrAfter(Version.LUCENE_7_0_0)); @@ -784,6 +788,10 @@ public class SolrConfig extends Config implements MapSerializable { return enableRemoteStreams; } + public boolean isEnableStreamBody() { + return enableStreamBody; + } + @Override public int getInt(String path) { return getInt(path, 0); diff --git a/solr/core/src/java/org/apache/solr/servlet/SolrRequestParsers.java b/solr/core/src/java/org/apache/solr/servlet/SolrRequestParsers.java index 1300bd9872b..60b6d2f4118 100644 --- a/solr/core/src/java/org/apache/solr/servlet/SolrRequestParsers.java +++ b/solr/core/src/java/org/apache/solr/servlet/SolrRequestParsers.java @@ -84,6 +84,7 @@ public class SolrRequestParsers private final HashMap parsers = new HashMap<>(); private final boolean enableRemoteStreams; + private final boolean enableStreamBody; private StandardRequestParser standard; private boolean handleSelect = true; private boolean addHttpRequestToContext; @@ -101,8 +102,9 @@ public class SolrRequestParsers final int multipartUploadLimitKB, formUploadLimitKB; if( globalConfig == null ) { multipartUploadLimitKB = formUploadLimitKB = Integer.MAX_VALUE; - enableRemoteStreams = true; - handleSelect = true; + enableRemoteStreams = false; + enableStreamBody = false; + handleSelect = false; addHttpRequestToContext = false; } else { multipartUploadLimitKB = globalConfig.getMultipartUploadLimitKB(); @@ -110,6 +112,7 @@ public class SolrRequestParsers formUploadLimitKB = globalConfig.getFormUploadLimitKB(); enableRemoteStreams = globalConfig.isEnableRemoteStreams(); + enableStreamBody = globalConfig.isEnableStreamBody(); // Let this filter take care of /select?xxx format handleSelect = globalConfig.isHandleSelect(); @@ -121,9 +124,10 @@ public class SolrRequestParsers private SolrRequestParsers() { enableRemoteStreams = false; + enableStreamBody = false; handleSelect = false; addHttpRequestToContext = false; - init(2048, 2048); + init(Integer.MAX_VALUE, Integer.MAX_VALUE); } private void init( int multipartUploadLimitKB, int formUploadLimitKB) { @@ -202,7 +206,7 @@ public class SolrRequestParsers strs = params.getParams( CommonParams.STREAM_FILE ); if( strs != null ) { 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 ) { ContentStreamBase stream = new ContentStreamBase.FileStream( new File(file) ); @@ -216,6 +220,9 @@ public class SolrRequestParsers // Check for streams in the request parameters strs = params.getParams( CommonParams.STREAM_BODY ); 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 ) { ContentStreamBase stream = new ContentStreamBase.StringStream( body ); if( contentType != null ) { diff --git a/solr/core/src/resources/EditableSolrConfigAttributes.json b/solr/core/src/resources/EditableSolrConfigAttributes.json index ce9d1ada13e..ed61e1ffa89 100644 --- a/solr/core/src/resources/EditableSolrConfigAttributes.json +++ b/solr/core/src/resources/EditableSolrConfigAttributes.json @@ -65,7 +65,8 @@ "requestParsers":{ "multipartUploadLimitInKB":0, "formdataUploadLimitInKB":0, - "enableRemoteStreaming":0, + "enableRemoteStreaming":10, + "enableStreamBody":10, "addHttpRequestToContext":0}}, "peerSync":{ "useRangeVersions":11 diff --git a/solr/core/src/test-files/solr/collection1/conf/solrconfig-managed-schema.xml b/solr/core/src/test-files/solr/collection1/conf/solrconfig-managed-schema.xml index 739ad2215ab..84307ffcf53 100644 --- a/solr/core/src/test-files/solr/collection1/conf/solrconfig-managed-schema.xml +++ b/solr/core/src/test-files/solr/collection1/conf/solrconfig-managed-schema.xml @@ -29,6 +29,11 @@ + + + + + + + + + true diff --git a/solr/core/src/test-files/solr/collection1/conf/solrconfig-tlog.xml b/solr/core/src/test-files/solr/collection1/conf/solrconfig-tlog.xml index 12e5089363c..10c7ccdf995 100644 --- a/solr/core/src/test-files/solr/collection1/conf/solrconfig-tlog.xml +++ b/solr/core/src/test-files/solr/collection1/conf/solrconfig-tlog.xml @@ -31,6 +31,9 @@ ${solr.hdfs.blockcache.global:true} + + + ${solr.data.dir:} diff --git a/solr/core/src/test-files/solr/collection1/conf/solrconfig.xml b/solr/core/src/test-files/solr/collection1/conf/solrconfig.xml index 41726ce417e..9422a4d8e79 100644 --- a/solr/core/src/test-files/solr/collection1/conf/solrconfig.xml +++ b/solr/core/src/test-files/solr/collection1/conf/solrconfig.xml @@ -457,7 +457,7 @@ - + max-age=30, public diff --git a/solr/core/src/test-files/solr/crazy-path-to-config.xml b/solr/core/src/test-files/solr/crazy-path-to-config.xml index 00781a98f2a..45dc070130c 100644 --- a/solr/core/src/test-files/solr/crazy-path-to-config.xml +++ b/solr/core/src/test-files/solr/crazy-path-to-config.xml @@ -38,7 +38,9 @@ - + + + diff --git a/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPI.java b/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPI.java index 364108cab6a..ec45429be64 100644 --- a/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPI.java +++ b/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPI.java @@ -37,6 +37,7 @@ import java.nio.charset.StandardCharsets; import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; import java.util.Arrays; import java.util.Collection; @@ -47,10 +48,10 @@ import java.util.LinkedList; import java.util.Map; import java.util.Properties; import java.util.Set; -import java.nio.file.SimpleFileVisitor; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; +import com.google.common.collect.ImmutableMap; import org.apache.commons.io.FileUtils; import org.apache.http.HttpEntity; 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.solr.SolrTestCaseJ4; 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.SolrServerException; import org.apache.solr.client.solrj.embedded.JettySolrRunner; import org.apache.solr.client.solrj.impl.CloudSolrClient; 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.Create; import org.apache.solr.client.solrj.request.ConfigSetAdminRequest.Delete; import org.apache.solr.client.solrj.request.QueryRequest; import org.apache.solr.client.solrj.response.CollectionAdminResponse; 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.cloud.SolrZkClient; import org.apache.solr.common.cloud.ZkConfigManager; import org.apache.solr.common.cloud.ZkStateReader; 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.ConfigSetAction; import org.apache.solr.common.params.ModifiableSolrParams; @@ -104,8 +100,6 @@ import org.noggit.ObjectBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.collect.ImmutableMap; - /** * 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); // try to create a collection with the uploaded configset createCollection("newcollection", "regular" + suffix, 1, 1, solrCluster.getSolrClient()); - xsltRequest("newcollection"); } @Test @@ -506,35 +499,6 @@ public class TestConfigSetsAPI extends SolrTestCaseJ4 { 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 = - "" + - " " + - " " + - " " + - " " + - " " + - " " + - " " + - ""; - - 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 { SolrClient client = solrCluster.getSolrClient(); diff --git a/solr/core/src/test/org/apache/solr/core/TestConfigOverlay.java b/solr/core/src/test/org/apache/solr/core/TestConfigOverlay.java index 633dde3552d..b41f33262d7 100644 --- a/solr/core/src/test/org/apache/solr/core/TestConfigOverlay.java +++ b/solr/core/src/test/org/apache/solr/core/TestConfigOverlay.java @@ -53,6 +53,7 @@ public class TestConfigOverlay extends LuceneTestCase { assertTrue(isEditableProp("requestDispatcher.requestParsers.multipartUploadLimitInKB", false, null)); assertTrue(isEditableProp("requestDispatcher.requestParsers.formdataUploadLimitInKB", 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.handleSelect", false, null)); diff --git a/solr/core/src/test/org/apache/solr/core/TestSolrConfigHandler.java b/solr/core/src/test/org/apache/solr/core/TestSolrConfigHandler.java index 13d4d0161f7..bbad8219aac 100644 --- a/solr/core/src/test/org/apache/solr/core/TestSolrConfigHandler.java +++ b/solr/core/src/test/org/apache/solr/core/TestSolrConfigHandler.java @@ -182,7 +182,8 @@ public class TestSolrConfigHandler extends RestTestBase { log.info("going to send config command. path {} , payload: {}", uri, payload); String response = harness.post(uri, json); 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? } diff --git a/solr/core/src/test/org/apache/solr/request/TestRemoteStreaming.java b/solr/core/src/test/org/apache/solr/request/TestRemoteStreaming.java index 16a8bf1e759..08e69bd3869 100644 --- a/solr/core/src/test/org/apache/solr/request/TestRemoteStreaming.java +++ b/solr/core/src/test/org/apache/solr/request/TestRemoteStreaming.java @@ -20,15 +20,14 @@ import org.apache.commons.io.IOUtils; import org.apache.lucene.util.LuceneTestCase; import org.apache.solr.SolrJettyTestBase; 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.SolrQuery; import org.apache.solr.client.solrj.SolrServerException; 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.common.SolrException; -import org.apache.solr.common.SolrInputDocument; import org.apache.solr.common.SolrException.ErrorCode; +import org.apache.solr.common.SolrInputDocument; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; @@ -120,30 +119,7 @@ public class TestRemoteStreaming extends SolrJettyTestBase { 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","*:*"); - - 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. */ private String makeDeleteAllUrl() throws UnsupportedEncodingException { HttpSolrClient client = (HttpSolrClient) getSolrClient(); diff --git a/solr/core/src/test/org/apache/solr/request/TestStreamBody.java b/solr/core/src/test/org/apache/solr/request/TestStreamBody.java new file mode 100644 index 00000000000..15eb02098f8 --- /dev/null +++ b/solr/core/src/test/org/apache/solr/request/TestStreamBody.java @@ -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 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,"*:*"); + + 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,"*:*"); + 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); + } +} diff --git a/solr/core/src/test/org/apache/solr/search/json/TestJsonRequest.java b/solr/core/src/test/org/apache/solr/search/json/TestJsonRequest.java index 370ae7e5ff5..9c151c1d133 100644 --- a/solr/core/src/test/org/apache/solr/search/json/TestJsonRequest.java +++ b/solr/core/src/test/org/apache/solr/search/json/TestJsonRequest.java @@ -20,6 +20,7 @@ import org.apache.lucene.util.LuceneTestCase; import org.apache.solr.JSONTestUtil; import org.apache.solr.SolrTestCaseHS; +import org.apache.solr.common.params.CommonParams; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; @@ -181,33 +182,33 @@ public class TestJsonRequest extends SolrTestCaseHS { // // 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" ); // 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" ); // 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" ); // 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" ); // 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}" ); // 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}" ); diff --git a/solr/solr-ref-guide/src/config-api.adoc b/solr/solr-ref-guide/src/config-api.adoc index 1b330d0201a..8f2d23b806d 100644 --- a/solr/solr-ref-guide/src/config-api.adoc +++ b/solr/solr-ref-guide/src/config-api.adoc @@ -117,6 +117,7 @@ The properties that are configured with these commands are predefined and listed * `requestDispatcher.requestParsers.multipartUploadLimitInKB` * `requestDispatcher.requestParsers.formdataUploadLimitInKB` * `requestDispatcher.requestParsers.enableRemoteStreaming` +* `requestDispatcher.requestParsers.enableStreamBody` * `requestDispatcher.requestParsers.addHttpRequestToContext` [[ConfigAPI-CommandsforCustomHandlersandLocalComponents]] diff --git a/solr/solr-ref-guide/src/near-real-time-searching.adoc b/solr/solr-ref-guide/src/near-real-time-searching.adoc index fe0e44988bd..fccf7b3f9f1 100644 --- a/solr/solr-ref-guide/src/near-real-time-searching.adoc +++ b/solr/solr-ref-guide/src/near-real-time-searching.adoc @@ -102,7 +102,7 @@ Example of `commit` and `optimize` with optional attributes: [[NearRealTimeSearching-PassingcommitandcommitWithinparametersaspartoftheURL]] === 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] ---- @@ -132,6 +132,8 @@ curl http://localhost:8983/solr/my_collection/update?commitWithin=10000 -H "Content-Type: text/xml" --data-binary 'testdoc' ---- +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 <> for details. + [[NearRealTimeSearching-ChangingdefaultcommitWithinBehavior]] === Changing default commitWithin Behavior diff --git a/solr/solr-ref-guide/src/requestdispatcher-in-solrconfig.adoc b/solr/solr-ref-guide/src/requestdispatcher-in-solrconfig.adoc index 659dd415177..e20b55ccc4f 100644 --- a/solr/solr-ref-guide/src/requestdispatcher-in-solrconfig.adoc +++ b/solr/solr-ref-guide/src/requestdispatcher-in-solrconfig.adoc @@ -48,6 +48,8 @@ The `` 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 `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. 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] ---- ---- +The below command is an example of how to enable RemoteStreaming and BodyStreaming through <>: + +[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]] == httpCaching Element diff --git a/solr/solr-ref-guide/src/uploading-data-with-index-handlers.adoc b/solr/solr-ref-guide/src/uploading-data-with-index-handlers.adoc index a8c56bbf12f..6a8ad9967c7 100644 --- a/solr/solr-ref-guide/src/uploading-data-with-index-handlers.adoc +++ b/solr/solr-ref-guide/src/uploading-data-with-index-handlers.adoc @@ -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 ---- -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 <> element, URL-encoding the request, as in the following. Note the escaping of "<" and ">": [source,bash] ----