You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ja...@apache.org on 2017/07/06 13:03:01 UTC

lucene-solr:master: SOLR-10748: Make stream.body configurable and disabled by default

Repository: lucene-solr
Updated Branches:
  refs/heads/master 112bdda47 -> 80b1430a3


SOLR-10748: Make stream.body configurable and disabled by default


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/80b1430a
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/80b1430a
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/80b1430a

Branch: refs/heads/master
Commit: 80b1430a3ec3f6684ae50483bafc6db10c3cb13d
Parents: 112bdda
Author: Jan Høydahl <ja...@apache.org>
Authored: Thu Jul 6 14:56:58 2017 +0200
Committer: Jan Høydahl <ja...@apache.org>
Committed: Thu Jul 6 15:02:55 2017 +0200

----------------------------------------------------------------------
 solr/CHANGES.txt                                |   2 +
 .../solr/collection1/conf/solrconfig-ltr.xml    |   3 +
 .../collection1/conf/solrconfig-ltr_Th10_10.xml |   5 +-
 .../collection1/conf/solrconfig-multiseg.xml    |   5 +-
 .../java/org/apache/solr/core/SolrConfig.java   |   8 ++
 .../apache/solr/servlet/SolrRequestParsers.java |  15 +-
 .../resources/EditableSolrConfigAttributes.json |   3 +-
 .../conf/solrconfig-managed-schema.xml          |   5 +
 .../collection1/conf/solrconfig-schemaless.xml  |   4 +
 .../solr/collection1/conf/solrconfig-tlog.xml   |   3 +
 .../solr/collection1/conf/solrconfig.xml        |   2 +-
 .../test-files/solr/crazy-path-to-config.xml    |   4 +-
 .../apache/solr/cloud/TestConfigSetsAPI.java    |  40 +-----
 .../org/apache/solr/core/TestConfigOverlay.java |   1 +
 .../apache/solr/core/TestSolrConfigHandler.java |   3 +-
 .../solr/request/TestRemoteStreaming.java       |  30 +---
 .../org/apache/solr/request/TestStreamBody.java | 138 +++++++++++++++++++
 .../solr/search/json/TestJsonRequest.java       |  13 +-
 solr/solr-ref-guide/src/config-api.adoc         |   1 +
 .../src/near-real-time-searching.adoc           |   4 +-
 .../src/requestdispatcher-in-solrconfig.adoc    |  13 ++
 .../src/uploading-data-with-index-handlers.adoc |   2 +-
 22 files changed, 221 insertions(+), 83 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/80b1430a/solr/CHANGES.txt
----------------------------------------------------------------------
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index 8b9202b..49b25cc 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

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/80b1430a/solr/contrib/ltr/src/test-files/solr/collection1/conf/solrconfig-ltr.xml
----------------------------------------------------------------------
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 0e92546..d5f66d3 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 @@
 
  <schemaFactory class="ClassicIndexSchemaFactory" />
 
+ <requestDispatcher>
+   <requestParsers enableStreamBody="true" />
+ </requestDispatcher>
 
  <!-- Query parser used to rerank top docs with a provided model -->
  <queryParser name="ltr"

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/80b1430a/solr/contrib/ltr/src/test-files/solr/collection1/conf/solrconfig-ltr_Th10_10.xml
----------------------------------------------------------------------
diff --git a/solr/contrib/ltr/src/test-files/solr/collection1/conf/solrconfig-ltr_Th10_10.xml b/solr/contrib/ltr/src/test-files/solr/collection1/conf/solrconfig-ltr_Th10_10.xml
index b41bce1..8380653 100644
--- a/solr/contrib/ltr/src/test-files/solr/collection1/conf/solrconfig-ltr_Th10_10.xml
+++ b/solr/contrib/ltr/src/test-files/solr/collection1/conf/solrconfig-ltr_Th10_10.xml
@@ -18,7 +18,10 @@
 
  <schemaFactory class="ClassicIndexSchemaFactory" />
 
-
+ <requestDispatcher>
+   <requestParsers enableStreamBody="true" />
+ </requestDispatcher>
+ 
  <!-- Query parser used to rerank top docs with a provided model -->
  <queryParser name="ltr" class="org.apache.solr.ltr.search.LTRQParserPlugin" >
   <int name="threadModule.totalPoolThreads">10</int> <!-- Maximum threads to use for all queries -->

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/80b1430a/solr/contrib/ltr/src/test-files/solr/collection1/conf/solrconfig-multiseg.xml
----------------------------------------------------------------------
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 b34be8f..7008ec1 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 @@
 
  <schemaFactory class="ClassicIndexSchemaFactory" />
 
-
+ <requestDispatcher>
+   <requestParsers enableStreamBody="true" />
+ </requestDispatcher>
+ 
  <!-- Query parser used to rerank top docs with a provided model -->
  <queryParser name="ltr" class="org.apache.solr.ltr.search.LTRQParserPlugin" />
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/80b1430a/solr/core/src/java/org/apache/solr/core/SolrConfig.java
----------------------------------------------------------------------
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 9942323..6c67645 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);

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/80b1430a/solr/core/src/java/org/apache/solr/servlet/SolrRequestParsers.java
----------------------------------------------------------------------
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 1300bd9..60b6d2f 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<String, SolrRequestParser> 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 ) {

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/80b1430a/solr/core/src/resources/EditableSolrConfigAttributes.json
----------------------------------------------------------------------
diff --git a/solr/core/src/resources/EditableSolrConfigAttributes.json b/solr/core/src/resources/EditableSolrConfigAttributes.json
index ce9d1ad..ed61e1f 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

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/80b1430a/solr/core/src/test-files/solr/collection1/conf/solrconfig-managed-schema.xml
----------------------------------------------------------------------
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 739ad22..84307ff 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 @@
 
   <codecFactory class="solr.SchemaCodecFactory"/>
 
+  <requestDispatcher>
+    <!-- Tests rely on stream.body -->
+    <requestParsers enableStreamBody="true" />
+  </requestDispatcher>
+  
   <query>
     <filterCache
         enabled="${filterCache.enabled:false}"

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/80b1430a/solr/core/src/test-files/solr/collection1/conf/solrconfig-schemaless.xml
----------------------------------------------------------------------
diff --git a/solr/core/src/test-files/solr/collection1/conf/solrconfig-schemaless.xml b/solr/core/src/test-files/solr/collection1/conf/solrconfig-schemaless.xml
index 04ba1f2..4f10a8e 100644
--- a/solr/core/src/test-files/solr/collection1/conf/solrconfig-schemaless.xml
+++ b/solr/core/src/test-files/solr/collection1/conf/solrconfig-schemaless.xml
@@ -35,6 +35,10 @@
     </updateLog>
   </updateHandler>
 
+  <requestDispatcher>
+    <requestParsers enableStreamBody="true" />
+  </requestDispatcher>
+  
   <requestHandler name="/select" class="solr.SearchHandler">
     <bool name="httpCaching">true</bool>
   </requestHandler>

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/80b1430a/solr/core/src/test-files/solr/collection1/conf/solrconfig-tlog.xml
----------------------------------------------------------------------
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 12e5089..10c7ccd 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 @@
     <str name="solr.hdfs.blockcache.global">${solr.hdfs.blockcache.global:true}</str>
   </directoryFactory>
   <schemaFactory class="ClassicIndexSchemaFactory"/>
+  <requestDispatcher>
+    <requestParsers enableStreamBody="true" />
+  </requestDispatcher>
   
   <dataDir>${solr.data.dir:}</dataDir>
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/80b1430a/solr/core/src/test-files/solr/collection1/conf/solrconfig.xml
----------------------------------------------------------------------
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 41726ce..9422a4d 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 @@
   </searchComponent>
 
   <requestDispatcher>
-    <requestParsers enableRemoteStreaming="true" multipartUploadLimitInKB="-1" />
+    <requestParsers enableRemoteStreaming="true" enableStreamBody="true" multipartUploadLimitInKB="-1" />
     <httpCaching lastModifiedFrom="openTime" etagSeed="Solr" never304="false">
       <cacheControl>max-age=30, public</cacheControl>
     </httpCaching>

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/80b1430a/solr/core/src/test-files/solr/crazy-path-to-config.xml
----------------------------------------------------------------------
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 00781a9..45dc070 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 @@
     <boolTofilterOptimizer enabled="true" cacheSize="32" threshold=".05"/>
   </query>
 
-  <requestDispatcher/>
+  <requestDispatcher>
+    <requestParsers enableStreamBody="true" />
+  </requestDispatcher>
 
   <requestHandler name="/select" class="solr.SearchHandler" />
   <requestHandler name="/crazy_custom_qt" class="solr.SearchHandler">

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/80b1430a/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPI.java
----------------------------------------------------------------------
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 364108c..ec45429 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 = 
-          "<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 {
     SolrClient client = solrCluster.getSolrClient();

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/80b1430a/solr/core/src/test/org/apache/solr/core/TestConfigOverlay.java
----------------------------------------------------------------------
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 633dde3..b41f332 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));

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/80b1430a/solr/core/src/test/org/apache/solr/core/TestSolrConfigHandler.java
----------------------------------------------------------------------
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 13d4d01..bbad821 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?
   }
 
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/80b1430a/solr/core/src/test/org/apache/solr/request/TestRemoteStreaming.java
----------------------------------------------------------------------
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 16a8bf1..08e69bd 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","<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. */
   private String makeDeleteAllUrl() throws UnsupportedEncodingException {
     HttpSolrClient client = (HttpSolrClient) getSolrClient();

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/80b1430a/solr/core/src/test/org/apache/solr/request/TestStreamBody.java
----------------------------------------------------------------------
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 0000000..15eb020
--- /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<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);
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/80b1430a/solr/core/src/test/org/apache/solr/search/json/TestJsonRequest.java
----------------------------------------------------------------------
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 370ae7e..9c151c1 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}"
     );
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/80b1430a/solr/solr-ref-guide/src/config-api.adoc
----------------------------------------------------------------------
diff --git a/solr/solr-ref-guide/src/config-api.adoc b/solr/solr-ref-guide/src/config-api.adoc
index 1b330d0..8f2d23b 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]]

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/80b1430a/solr/solr-ref-guide/src/near-real-time-searching.adoc
----------------------------------------------------------------------
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 fe0e449..fccf7b3 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 '<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]]
 === Changing default commitWithin Behavior
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/80b1430a/solr/solr-ref-guide/src/requestdispatcher-in-solrconfig.adoc
----------------------------------------------------------------------
diff --git a/solr/solr-ref-guide/src/requestdispatcher-in-solrconfig.adoc b/solr/solr-ref-guide/src/requestdispatcher-in-solrconfig.adoc
index 659dd41..e20b55c 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 `<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 `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]
 ----
 <requestParsers enableRemoteStreaming="false"
+                enableStreamBody="false"
                 multipartUploadLimitInKB="2048"
                 formdataUploadLimitInKB="2048"
                 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]]
 == httpCaching Element
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/80b1430a/solr/solr-ref-guide/src/uploading-data-with-index-handlers.adoc
----------------------------------------------------------------------
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 a8c56bb..6a8ad99 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 <<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]
 ----