REST API: Failure to index docs that have their ids URL encoded and contain `/`, closes #681.
This commit is contained in:
parent
89ac4d108a
commit
57108c8575
|
@ -30,20 +30,37 @@ import static org.elasticsearch.common.collect.MapBuilder.*;
|
|||
* @author kimchy (Shay Banon)
|
||||
*/
|
||||
public class PathTrie<T> {
|
||||
|
||||
public static interface Decoder {
|
||||
String decode(String value);
|
||||
}
|
||||
|
||||
public static final Decoder NO_DECODER = new Decoder() {
|
||||
@Override public String decode(String value) {
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
private final Decoder decoder;
|
||||
private final TrieNode<T> root;
|
||||
private final Pattern pattern;
|
||||
private T rootValue;
|
||||
|
||||
public PathTrie() {
|
||||
this("/", "*");
|
||||
this("/", "*", NO_DECODER);
|
||||
}
|
||||
|
||||
public PathTrie(String separator, String wildcard) {
|
||||
public PathTrie(Decoder decoder) {
|
||||
this("/", "*", decoder);
|
||||
}
|
||||
|
||||
public PathTrie(String separator, String wildcard, Decoder decoder) {
|
||||
this.decoder = decoder;
|
||||
pattern = Pattern.compile(separator);
|
||||
root = new TrieNode<T>(separator, null, null, wildcard);
|
||||
}
|
||||
|
||||
public static class TrieNode<T> {
|
||||
public class TrieNode<T> {
|
||||
private transient String key;
|
||||
private transient T value;
|
||||
private boolean isWildcard;
|
||||
|
@ -169,6 +186,10 @@ public class PathTrie<T> {
|
|||
|
||||
return res;
|
||||
}
|
||||
|
||||
private void put(Map<String, String> params, String key, String value) {
|
||||
params.put(key, decoder.decode(value));
|
||||
}
|
||||
}
|
||||
|
||||
public void insert(String path, T value) {
|
||||
|
@ -204,8 +225,4 @@ public class PathTrie<T> {
|
|||
}
|
||||
return root.retrieve(strings, index, params);
|
||||
}
|
||||
|
||||
private static void put(Map<String, String> params, String key, String value) {
|
||||
params.put(key, value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ import org.elasticsearch.rest.RestController;
|
|||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.rest.StringRestResponse;
|
||||
import org.elasticsearch.rest.XContentThrowableRestResponse;
|
||||
import org.elasticsearch.rest.support.RestUtils;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -48,12 +49,12 @@ public class HttpServer extends AbstractLifecycleComponent<HttpServer> {
|
|||
|
||||
private final TransportNodesInfoAction nodesInfoAction;
|
||||
|
||||
private final PathTrie<HttpServerHandler> getHandlers = new PathTrie<HttpServerHandler>();
|
||||
private final PathTrie<HttpServerHandler> postHandlers = new PathTrie<HttpServerHandler>();
|
||||
private final PathTrie<HttpServerHandler> putHandlers = new PathTrie<HttpServerHandler>();
|
||||
private final PathTrie<HttpServerHandler> deleteHandlers = new PathTrie<HttpServerHandler>();
|
||||
private final PathTrie<HttpServerHandler> headHandlers = new PathTrie<HttpServerHandler>();
|
||||
private final PathTrie<HttpServerHandler> optionsHandlers = new PathTrie<HttpServerHandler>();
|
||||
private final PathTrie<HttpServerHandler> getHandlers = new PathTrie<HttpServerHandler>(RestUtils.REST_DECODER);
|
||||
private final PathTrie<HttpServerHandler> postHandlers = new PathTrie<HttpServerHandler>(RestUtils.REST_DECODER);
|
||||
private final PathTrie<HttpServerHandler> putHandlers = new PathTrie<HttpServerHandler>(RestUtils.REST_DECODER);
|
||||
private final PathTrie<HttpServerHandler> deleteHandlers = new PathTrie<HttpServerHandler>(RestUtils.REST_DECODER);
|
||||
private final PathTrie<HttpServerHandler> headHandlers = new PathTrie<HttpServerHandler>(RestUtils.REST_DECODER);
|
||||
private final PathTrie<HttpServerHandler> optionsHandlers = new PathTrie<HttpServerHandler>(RestUtils.REST_DECODER);
|
||||
|
||||
@Inject public HttpServer(Settings settings, HttpServerTransport transport, ThreadPool threadPool,
|
||||
RestController restController, TransportNodesInfoAction nodesInfoAction) {
|
||||
|
@ -166,6 +167,9 @@ public class HttpServer extends AbstractLifecycleComponent<HttpServer> {
|
|||
}
|
||||
|
||||
private String getPath(HttpRequest request) {
|
||||
return request.path();
|
||||
// we use rawPath since we don't want to decode it while processing the path resolution
|
||||
// so we can handle things like:
|
||||
// my_index/my_type/http%3A%2F%2Fwww.google.com
|
||||
return request.rawPath();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ public class NettyHttpRequest extends AbstractRestRequest implements HttpRequest
|
|||
|
||||
private final Map<String, String> params;
|
||||
|
||||
private final String path;
|
||||
private final String rawPath;
|
||||
|
||||
private byte[] cachedData;
|
||||
|
||||
|
@ -50,9 +50,9 @@ public class NettyHttpRequest extends AbstractRestRequest implements HttpRequest
|
|||
String uri = request.getUri();
|
||||
int pathEndPos = uri.indexOf('?');
|
||||
if (pathEndPos < 0) {
|
||||
this.path = RestUtils.decodeComponent(uri);
|
||||
this.rawPath = uri;
|
||||
} else {
|
||||
this.path = RestUtils.decodeComponent(uri.substring(0, pathEndPos));
|
||||
this.rawPath = uri.substring(0, pathEndPos);
|
||||
RestUtils.decodeQueryString(uri, pathEndPos + 1, params);
|
||||
}
|
||||
}
|
||||
|
@ -86,8 +86,8 @@ public class NettyHttpRequest extends AbstractRestRequest implements HttpRequest
|
|||
return request.getUri();
|
||||
}
|
||||
|
||||
@Override public String path() {
|
||||
return path;
|
||||
@Override public String rawPath() {
|
||||
return rawPath;
|
||||
}
|
||||
|
||||
@Override public Map<String, String> params() {
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.elasticsearch.common.component.AbstractLifecycleComponent;
|
|||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.path.PathTrie;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.rest.support.RestUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
@ -33,12 +34,12 @@ import java.io.IOException;
|
|||
*/
|
||||
public class RestController extends AbstractLifecycleComponent<RestController> {
|
||||
|
||||
private final PathTrie<RestHandler> getHandlers = new PathTrie<RestHandler>();
|
||||
private final PathTrie<RestHandler> postHandlers = new PathTrie<RestHandler>();
|
||||
private final PathTrie<RestHandler> putHandlers = new PathTrie<RestHandler>();
|
||||
private final PathTrie<RestHandler> deleteHandlers = new PathTrie<RestHandler>();
|
||||
private final PathTrie<RestHandler> headHandlers = new PathTrie<RestHandler>();
|
||||
private final PathTrie<RestHandler> optionsHandlers = new PathTrie<RestHandler>();
|
||||
private final PathTrie<RestHandler> getHandlers = new PathTrie<RestHandler>(RestUtils.REST_DECODER);
|
||||
private final PathTrie<RestHandler> postHandlers = new PathTrie<RestHandler>(RestUtils.REST_DECODER);
|
||||
private final PathTrie<RestHandler> putHandlers = new PathTrie<RestHandler>(RestUtils.REST_DECODER);
|
||||
private final PathTrie<RestHandler> deleteHandlers = new PathTrie<RestHandler>(RestUtils.REST_DECODER);
|
||||
private final PathTrie<RestHandler> headHandlers = new PathTrie<RestHandler>(RestUtils.REST_DECODER);
|
||||
private final PathTrie<RestHandler> optionsHandlers = new PathTrie<RestHandler>(RestUtils.REST_DECODER);
|
||||
|
||||
@Inject public RestController(Settings settings) {
|
||||
super(settings);
|
||||
|
@ -116,6 +117,9 @@ public class RestController extends AbstractLifecycleComponent<RestController> {
|
|||
}
|
||||
|
||||
private String getPath(RestRequest request) {
|
||||
return request.path();
|
||||
// we use rawPath since we don't want to decode it while processing the path resolution
|
||||
// so we can handle things like:
|
||||
// my_index/my_type/http%3A%2F%2Fwww.google.com
|
||||
return request.rawPath();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,12 @@ public interface RestRequest extends ToXContent.Params {
|
|||
String uri();
|
||||
|
||||
/**
|
||||
* The path part of the URI (without the query string).
|
||||
* The non decoded, raw path provided.
|
||||
*/
|
||||
String rawPath();
|
||||
|
||||
/**
|
||||
* The path part of the URI (without the query string), decoded.
|
||||
*/
|
||||
String path();
|
||||
|
||||
|
|
|
@ -37,6 +37,10 @@ public abstract class AbstractRestRequest implements RestRequest {
|
|||
|
||||
private static final Pattern commaPattern = Pattern.compile(",");
|
||||
|
||||
@Override public final String path() {
|
||||
return RestUtils.decodeComponent(rawPath());
|
||||
}
|
||||
|
||||
@Override public float paramAsFloat(String key, float defaultValue) {
|
||||
String sValue = param(key);
|
||||
if (sValue == null) {
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
package org.elasticsearch.rest.support;
|
||||
|
||||
import org.elasticsearch.common.base.Charsets;
|
||||
import org.elasticsearch.common.path.PathTrie;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Map;
|
||||
|
@ -29,6 +30,12 @@ import java.util.Map;
|
|||
*/
|
||||
public class RestUtils {
|
||||
|
||||
public static PathTrie.Decoder REST_DECODER = new PathTrie.Decoder() {
|
||||
@Override public String decode(String value) {
|
||||
return RestUtils.decodeComponent(value);
|
||||
}
|
||||
};
|
||||
|
||||
public static void decodeQueryString(String s, int fromIndex, Map<String, String> params) {
|
||||
if (fromIndex < 0) {
|
||||
return;
|
||||
|
|
|
@ -45,7 +45,7 @@ public class MemcachedRestRequest extends AbstractRestRequest {
|
|||
|
||||
private final Map<String, String> params;
|
||||
|
||||
private final String path;
|
||||
private final String rawPath;
|
||||
|
||||
private byte[] data;
|
||||
|
||||
|
@ -62,9 +62,9 @@ public class MemcachedRestRequest extends AbstractRestRequest {
|
|||
this.params = new HashMap<String, String>();
|
||||
int pathEndPos = uri.indexOf('?');
|
||||
if (pathEndPos < 0) {
|
||||
this.path = uri;
|
||||
this.rawPath = uri;
|
||||
} else {
|
||||
this.path = uri.substring(0, pathEndPos);
|
||||
this.rawPath = uri.substring(0, pathEndPos);
|
||||
RestUtils.decodeQueryString(uri, pathEndPos + 1, params);
|
||||
}
|
||||
}
|
||||
|
@ -77,8 +77,8 @@ public class MemcachedRestRequest extends AbstractRestRequest {
|
|||
return this.uri;
|
||||
}
|
||||
|
||||
@Override public String path() {
|
||||
return this.path;
|
||||
@Override public String rawPath() {
|
||||
return this.rawPath;
|
||||
}
|
||||
|
||||
public byte[] getUriBytes() {
|
||||
|
|
|
@ -36,7 +36,7 @@ public class ThriftRestRequest extends AbstractRestRequest implements org.elasti
|
|||
|
||||
private final org.elasticsearch.thrift.RestRequest request;
|
||||
|
||||
private final String path;
|
||||
private final String rawPath;
|
||||
|
||||
private final Map<String, String> params;
|
||||
|
||||
|
@ -46,9 +46,9 @@ public class ThriftRestRequest extends AbstractRestRequest implements org.elasti
|
|||
|
||||
int pathEndPos = request.getUri().indexOf('?');
|
||||
if (pathEndPos < 0) {
|
||||
this.path = request.getUri();
|
||||
this.rawPath = request.getUri();
|
||||
} else {
|
||||
this.path = request.getUri().substring(0, pathEndPos);
|
||||
this.rawPath = request.getUri().substring(0, pathEndPos);
|
||||
RestUtils.decodeQueryString(request.getUri(), pathEndPos + 1, params);
|
||||
}
|
||||
}
|
||||
|
@ -75,8 +75,8 @@ public class ThriftRestRequest extends AbstractRestRequest implements org.elasti
|
|||
return request.getUri();
|
||||
}
|
||||
|
||||
@Override public String path() {
|
||||
return this.path;
|
||||
@Override public String rawPath() {
|
||||
return this.rawPath;
|
||||
}
|
||||
|
||||
@Override public boolean hasContent() {
|
||||
|
|
Loading…
Reference in New Issue