Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions changelog/unreleased/SOLR-18095.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# See https://github.com/apache/solr/blob/main/dev-docs/changelog.adoc
title: Provide NoOpRequestWriter and NoOpRequestHandler that can be used to disable implicitly configured equivalents.
type: added # added, changed, fixed, deprecated, removed, dependency_update, security, other
authors:
- name: Eric Pugh
links:
- name: SOLR-18095
url: https://issues.apache.org/jira/browse/SOLR-18095
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@
import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.security.AuthorizationContext;

/** Does nothing other than showing a 404 message */
public class NotFoundRequestHandler extends RequestHandlerBase {
/** Does nothing other than showing a 403 message */
public class NoOpRequestHandler extends RequestHandlerBase {
@Override
public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception {
throw new SolrException(
SolrException.ErrorCode.NOT_FOUND, "" + req.getContext().get(PATH) + " is not found");
SolrException.ErrorCode.FORBIDDEN, req.getContext().get(PATH) + " has been disabled");
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.solr.response;

import java.io.IOException;
import java.io.Writer;
import org.apache.solr.request.SolrQueryRequest;

public class NoOpResponseWriter implements TextQueryResponseWriter {
static String MESSAGE = "noop response writer";

@Override
public void write(Writer writer, SolrQueryRequest req, SolrQueryResponse rsp) throws IOException {
writer.write(MESSAGE);
}

@Override
public String getContentType(SolrQueryRequest request, SolrQueryResponse response) {
return QueryResponseWriter.CONTENT_TYPE_TEXT_UTF8;
}
}
57 changes: 57 additions & 0 deletions solr/core/src/test-files/solr/collection1/conf/solrconfig-noop.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?xml version="1.0" ?>

<!--
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.
-->

<!-- Test config that demonstrates overriding implicit handlers and response writers with NoOp versions -->

<config>

<dataDir>${solr.data.dir:}</dataDir>

<schemaFactory class="ClassicIndexSchemaFactory"/>

<luceneMatchVersion>${tests.luceneMatchVersion:LATEST}</luceneMatchVersion>

<updateHandler class="solr.DirectUpdateHandler2">
<updateLog enable="${solr.index.updatelog.enabled:true}">
<str name="dir">${solr.ulog.dir:}</str>
</updateLog>
</updateHandler>

<!--
Override the implicit /schema handler (from ImplicitPlugins.json)
with NoOpRequestHandler to demonstrate that implicit handlers can be disabled
-->
<requestHandler name="/schema" class="solr.NoOpRequestHandler" />

<!-- Standard search handler for testing other functionality still works -->
<requestHandler name="/select" class="solr.SearchHandler">
<lst name="defaults">
<str name="echoParams">explicit</str>
<str name="indent">true</str>
<str name="df">text</str>
</lst>
</requestHandler>

<!--
Override the implicit CSV response writer (from ImplicitPlugins.json)
with NoOpResponseWriter to demonstrate that implicit response writers can be disabled
-->
<queryResponseWriter name="csv" class="solr.NoOpResponseWriter" />

</config>
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* 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.handler;

import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.common.SolrException;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.SolrQueryResponse;
import org.junit.BeforeClass;
import org.junit.Test;

/**
* Test that demonstrates NoOpRequestHandler can be used to disable implicit handlers like
* SchemaHandler that are loaded via ImplicitPlugins.json.
*/
public class NoOpRequestHandlerTest extends SolrTestCaseJ4 {

@BeforeClass
public static void beforeClass() throws Exception {
initCore("solrconfig-noop.xml", "schema.xml");
}

@Test
public void testSchemaHandlerDisabled() {
// Test that /schema endpoint is disabled and returns 403 FORBIDDEN
SolrException exception =
expectThrows(
SolrException.class,
() -> {
try (SolrQueryRequest req = req("qt", "/schema")) {
SolrQueryResponse rsp = new SolrQueryResponse();
h.getCore().execute(h.getCore().getRequestHandler("/schema"), req, rsp);
if (rsp.getException() != null) {
throw rsp.getException();
}
}
});

assertEquals(
"Should return FORBIDDEN status code",
SolrException.ErrorCode.FORBIDDEN.code,
exception.code());
assertTrue(
"Error message should indicate endpoint has been disabled",
exception.getMessage().contains("has been disabled"));
}

@Test
public void testSchemaHandlerSubPathDisabled() {
// Test that /schema/fields endpoint is also disabled
SolrException exception =
expectThrows(
SolrException.class,
() -> {
try (SolrQueryRequest req = req("qt", "/schema/fields")) {
SolrQueryResponse rsp = new SolrQueryResponse();
h.getCore().execute(h.getCore().getRequestHandler("/schema"), req, rsp);
if (rsp.getException() != null) {
throw rsp.getException();
}
}
});

assertEquals(
"Should return FORBIDDEN status code",
SolrException.ErrorCode.FORBIDDEN.code,
exception.code());
}

@Test
public void testNoOpHandlerRegistered() {
// Verify that the NoOpRequestHandler is actually registered at /schema
assertNotNull("Schema handler should be registered", h.getCore().getRequestHandler("/schema"));
assertTrue(
"Handler at /schema should be NoOpRequestHandler",
h.getCore().getRequestHandler("/schema") instanceof NoOpRequestHandler);
}

@Test
public void testOtherHandlersStillWork() {
assertQ("Standard query handler should still work", req("q", "*:*"), "//result[@numFound='0']");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.solr.response;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import org.apache.solr.SolrTestCaseJ4;
import org.junit.BeforeClass;
import org.junit.Test;

/**
* Test that demonstrates NoOpResponseWriter can be used to disable implicit response writers that
* are loaded via ImplicitPlugins.json.
*/
public class NoOpResponseWriterTest extends SolrTestCaseJ4 {

@BeforeClass
public static void beforeClass() throws Exception {
initCore("solrconfig-noop.xml", "schema.xml");
}

@Test
public void testWrite() throws IOException {
NoOpResponseWriter writer = new NoOpResponseWriter();

Writer stringWriter = new StringWriter();

writer.write(stringWriter, null, null);

assertEquals(NoOpResponseWriter.MESSAGE, stringWriter.toString());
}

@Test
public void testGetContentType() {
NoOpResponseWriter writer = new NoOpResponseWriter();

String contentType = writer.getContentType(null, null);
assertEquals(QueryResponseWriter.CONTENT_TYPE_TEXT_UTF8, contentType);
}

@Test
public void testCsvResponseWriterDisabled() throws Exception {
QueryResponseWriter csvWriter = h.getCore().getQueryResponseWriter("csv");

assertNotNull("CSV response writer should be registered", csvWriter);
assertTrue(
"CSV response writer should be NoOpResponseWriter, not the implicit CSVResponseWriter",
csvWriter instanceof NoOpResponseWriter);

// Verify it returns the NoOp message when used
ByteArrayOutputStream out = new ByteArrayOutputStream();
csvWriter.write(out, null, null);
String output = out.toString(StandardCharsets.UTF_8);
assertEquals("CSV writer should return NoOp message", NoOpResponseWriter.MESSAGE, output);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -367,3 +367,15 @@ The response will look similar to:
Because implicit request handlers are not present in `solrconfig.xml`, configuration of their associated `default`, `invariant` and `appends` parameters may be edited via the xref:request-parameters-api.adoc[] using the paramset listed in the above table.
However, other parameters, including SearchHandler components, may not be modified.
The invariants and appends specified in the implicit configuration cannot be overridden.

== How to Disable an Implicit Handler

You may want to disable the loading of an implicit handler.
This is supported by remapping the name of the handler to the `NoOpRequestHandler` in `solrconfig.xml`, which will return a 403 FORBIDDEN status code.

For example, to disable the `/update/csv` handler you would re-define it in `solrconfig.xml` as:

[source,xml]
----
<requestHandler name="/update/csv" class="solr.NoOpRequestHandler"></requestHandler>
----
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ The list below describe shows the most common settings for the `wt` parameter, w
* <<Smile Response Writer,smile>>
* <<Standard XML Response Writer,xml>>
* <<XSLT Response Writer,xslt>>
* <<NoOp Response Writer,noop>>

== JSON Response Writer

Expand Down Expand Up @@ -386,3 +387,15 @@ else:
== Smile Response Writer

The Smile format is a JSON-compatible binary format, described in detail here: https://en.wikipedia.org/wiki/Smile_%28data_interchange_format%29[https://en.wikipedia.org/wiki/Smile_(data_interchange_format)]

== NoOp Response Writer

You may want to disable a specific response writer.
This is supported by remapping the name of the response writer to the `NoOpResponseWriter` in `solrconfig.xml`, which will return a 200 OK status code with the plain text message `noop response writer`.

For example, to disable the `csv` handler you would re-define it in `solrconfig.xml` as:

[source,xml]
----
<queryResponseWriter name="csv" class="solr.NoOpResponseWriter" />
----