SOLR-6163: Correctly decode special characters in managed stopwords and synonym endpoints.

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1616361 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Timothy Potter 2014-08-06 21:50:40 +00:00
parent ddbd55d24d
commit c119cf89a4
6 changed files with 111 additions and 5 deletions

View File

@ -238,6 +238,9 @@ Bug Fixes
* SOLR-6264: Distributed commit and optimize are executed serially across all * SOLR-6264: Distributed commit and optimize are executed serially across all
replicas. (Mark Miller, Timothy Potter) replicas. (Mark Miller, Timothy Potter)
* SOLR-6163: Correctly decode special characters in managed stopwords and synonym endpoints.
(Vitaliy Zhovtyuk, Timo Schmidt via Timothy Potter)
Optimizations Optimizations
--------------------- ---------------------

View File

@ -66,6 +66,8 @@ public class RestManager {
// used for validating resourceIds provided during registration // used for validating resourceIds provided during registration
private static final Pattern resourceIdRegex = Pattern.compile("(/config|/schema)(/.*)"); private static final Pattern resourceIdRegex = Pattern.compile("(/config|/schema)(/.*)");
private static final boolean DECODE = true;
/** /**
* Used internally to keep track of registrations during core initialization * Used internally to keep track of registrations during core initialization
*/ */
@ -251,21 +253,23 @@ public class RestManager {
* to. ManagedResource implementations are heavy-weight objects that live for the duration of * to. ManagedResource implementations are heavy-weight objects that live for the duration of
* a SolrCore, so this class acts as the proxy between Restlet and a ManagedResource when * a SolrCore, so this class acts as the proxy between Restlet and a ManagedResource when
* doing request processing. * doing request processing.
*
*/ */
public static class ManagedEndpoint extends BaseSolrResource public static class ManagedEndpoint extends BaseSolrResource
implements GETable, PUTable, POSTable, DELETEable implements GETable, PUTable, POSTable, DELETEable
{ {
/** /**
* Determines the ManagedResource resourceId from the Restlet request. * Determines the ManagedResource resourceId from the Restlet request.
*/ */
public static String resolveResourceId(Request restletReq) { public static String resolveResourceId(Request restletReq) {
String resourceId = restletReq.getResourceRef(). String resourceId = restletReq.getResourceRef().
getRelativeRef(restletReq.getRootRef().getParentRef()).getPath(); getRelativeRef(restletReq.getRootRef().getParentRef()).getPath(DECODE);
// all resources are registered with the leading slash // all resources are registered with the leading slash
if (!resourceId.startsWith("/")) if (!resourceId.startsWith("/"))
resourceId = "/"+resourceId; resourceId = "/"+resourceId;
return resourceId; return resourceId;
} }

View File

@ -427,7 +427,7 @@
<!-- A specialized field for geospatial search. If indexed, this fieldType must not be multivalued. --> <!-- A specialized field for geospatial search. If indexed, this fieldType must not be multivalued. -->
<fieldType name="location" class="solr.LatLonType" subFieldSuffix="_coordinate"/> <fieldType name="location" class="solr.LatLonType" subFieldSuffix="_coordinate"/>
<!-- Field type where stopwords are managed by the REST API --> <!-- Field type where english stopwords are managed by the REST API -->
<fieldtype name="managed_en" class="solr.TextField"> <fieldtype name="managed_en" class="solr.TextField">
<analyzer> <analyzer>
<tokenizer class="solr.StandardTokenizerFactory"/> <tokenizer class="solr.StandardTokenizerFactory"/>
@ -436,6 +436,15 @@
</analyzer> </analyzer>
</fieldtype> </fieldtype>
<!-- Field type where german stopwords are managed by the REST API -->
<fieldtype name="managed_de" class="solr.TextField">
<analyzer>
<tokenizer class="solr.StandardTokenizerFactory"/>
<filter class="solr.ManagedStopFilterFactory" managed="german" />
<filter class="solr.ManagedSynonymFilterFactory" managed="german" />
</analyzer>
</fieldtype>
</types> </types>

View File

@ -28,6 +28,8 @@ import org.apache.solr.rest.ManagedResourceStorage.StorageIO;
import org.apache.solr.rest.schema.analysis.ManagedWordSetResource; import org.apache.solr.rest.schema.analysis.ManagedWordSetResource;
import org.junit.Test; import org.junit.Test;
import org.noggit.JSONUtil; import org.noggit.JSONUtil;
import org.restlet.Request;
import org.restlet.data.Reference;
/** /**
* Tests {@link RestManager} functionality, including resource registration, * Tests {@link RestManager} functionality, including resource registration,
@ -248,4 +250,30 @@ public class TestRestManager extends SolrRestletTestBase {
RestManager restManager2 = new RestManager(); RestManager restManager2 = new RestManager();
restManager2.init(loader, initArgs, storageIO); restManager2.init(loader, initArgs, storageIO);
} }
@Test
public void testResolveResourceId () throws Exception {
Request testRequest = new Request();
Reference rootRef = new Reference("http://solr.apache.org/");
testRequest.setRootRef(rootRef);
Reference resourceRef = new Reference("http://solr.apache.org/schema/analysis/synonyms/de");
testRequest.setResourceRef(resourceRef);
String resourceId = RestManager.ManagedEndpoint.resolveResourceId(testRequest);
assertEquals(resourceId, "/schema/analysis/synonyms/de");
}
@Test
public void testResolveResourceIdDecodeUrlEntities () throws Exception {
Request testRequest = new Request();
Reference rootRef = new Reference("http://solr.apache.org/");
testRequest.setRootRef(rootRef);
Reference resourceRef = new Reference("http://solr.apache.org/schema/analysis/synonyms/de/%C3%84ndern");
testRequest.setResourceRef(resourceRef);
String resourceId = RestManager.ManagedEndpoint.resolveResourceId(testRequest);
assertEquals(resourceId, "/schema/analysis/synonyms/de/Ändern");
}
} }

View File

@ -185,4 +185,29 @@ public class TestManagedStopFilterFactory extends RestTestBase {
// should fail with 404 as foo doesn't exist // should fail with 404 as foo doesn't exist
assertJDelete(endpoint + "/foo", "/error/code==404"); assertJDelete(endpoint + "/foo", "/error/code==404");
} }
/**
* Can we add and remove stopwords with umlauts
*/
@Test
public void testCanHandleDecodingAndEncodingForStopwords() throws Exception {
String endpoint = "/schema/analysis/stopwords/german";
//initially it should not exist
assertJQ(endpoint + "/schön", "/error/code==404");
//now we put a stopword with an umlaut
assertJPut(endpoint,
JSONUtil.toJSON(Arrays.asList("schön")),
"/responseHeader/status==0");
//let's check if it exists
assertJQ(endpoint + "/schön", "/schön=='schön'");
//now let's remove it
assertJDelete(endpoint + "/schön", "/responseHeader/status==0");
//and of it is unavailable again
assertJQ(endpoint + "/schön", "/error/code==404");
}
} }

View File

@ -196,4 +196,41 @@ public class TestManagedSynonymFilterFactory extends RestTestBase {
assertJQ(endpoint+"/MB", assertJQ(endpoint+"/MB",
"/MB==['Megabyte','MiB','megabyte']"); "/MB==['Megabyte','MiB','megabyte']");
} }
/**
* Can we add and remove stopwords with umlauts
*/
@Test
public void testCanHandleDecodingAndEncodingForSynonyms() throws Exception {
String endpoint = "/schema/analysis/synonyms/german";
assertJQ(endpoint,
"/synonymMappings/initArgs/ignoreCase==false",
"/synonymMappings/managedMap=={}");
// does not exist
assertJQ(endpoint+"/fröhlich",
"/error/code==404");
Map<String,List<String>> syns = new HashMap<>();
// now put a synonym
syns.put("fröhlich", Arrays.asList("glücklick"));
assertJPut(endpoint,
JSONUtil.toJSON(syns),
"/responseHeader/status==0");
// and check if it exists
assertJQ(endpoint,
"/synonymMappings/managedMap/fröhlich==['glücklick']");
// verify delete works
assertJDelete(endpoint+"/fröhlich",
"/responseHeader/status==0");
// was it really deleted?
assertJDelete(endpoint+"/fröhlich",
"/error/code==404");
}
} }