REST API: Failure to index docs that have their ids URL encoded and contain `/`, closes #681.

This commit is contained in:
kimchy 2011-02-10 03:18:01 +02:00
parent 89ac4d108a
commit 57108c8575
9 changed files with 78 additions and 37 deletions

View File

@ -30,20 +30,37 @@ import static org.elasticsearch.common.collect.MapBuilder.*;
* @author kimchy (Shay Banon) * @author kimchy (Shay Banon)
*/ */
public class PathTrie<T> { 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 TrieNode<T> root;
private final Pattern pattern; private final Pattern pattern;
private T rootValue; private T rootValue;
public PathTrie() { 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); pattern = Pattern.compile(separator);
root = new TrieNode<T>(separator, null, null, wildcard); root = new TrieNode<T>(separator, null, null, wildcard);
} }
public static class TrieNode<T> { public class TrieNode<T> {
private transient String key; private transient String key;
private transient T value; private transient T value;
private boolean isWildcard; private boolean isWildcard;
@ -169,6 +186,10 @@ public class PathTrie<T> {
return res; 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) { public void insert(String path, T value) {
@ -204,8 +225,4 @@ public class PathTrie<T> {
} }
return root.retrieve(strings, index, params); return root.retrieve(strings, index, params);
} }
private static void put(Map<String, String> params, String key, String value) {
params.put(key, value);
}
} }

View File

@ -29,6 +29,7 @@ import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.StringRestResponse; import org.elasticsearch.rest.StringRestResponse;
import org.elasticsearch.rest.XContentThrowableRestResponse; import org.elasticsearch.rest.XContentThrowableRestResponse;
import org.elasticsearch.rest.support.RestUtils;
import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.threadpool.ThreadPool;
import java.io.IOException; import java.io.IOException;
@ -48,12 +49,12 @@ public class HttpServer extends AbstractLifecycleComponent<HttpServer> {
private final TransportNodesInfoAction nodesInfoAction; private final TransportNodesInfoAction nodesInfoAction;
private final PathTrie<HttpServerHandler> getHandlers = new PathTrie<HttpServerHandler>(); private final PathTrie<HttpServerHandler> getHandlers = new PathTrie<HttpServerHandler>(RestUtils.REST_DECODER);
private final PathTrie<HttpServerHandler> postHandlers = new PathTrie<HttpServerHandler>(); private final PathTrie<HttpServerHandler> postHandlers = new PathTrie<HttpServerHandler>(RestUtils.REST_DECODER);
private final PathTrie<HttpServerHandler> putHandlers = new PathTrie<HttpServerHandler>(); private final PathTrie<HttpServerHandler> putHandlers = new PathTrie<HttpServerHandler>(RestUtils.REST_DECODER);
private final PathTrie<HttpServerHandler> deleteHandlers = new PathTrie<HttpServerHandler>(); private final PathTrie<HttpServerHandler> deleteHandlers = new PathTrie<HttpServerHandler>(RestUtils.REST_DECODER);
private final PathTrie<HttpServerHandler> headHandlers = new PathTrie<HttpServerHandler>(); private final PathTrie<HttpServerHandler> headHandlers = new PathTrie<HttpServerHandler>(RestUtils.REST_DECODER);
private final PathTrie<HttpServerHandler> optionsHandlers = new PathTrie<HttpServerHandler>(); private final PathTrie<HttpServerHandler> optionsHandlers = new PathTrie<HttpServerHandler>(RestUtils.REST_DECODER);
@Inject public HttpServer(Settings settings, HttpServerTransport transport, ThreadPool threadPool, @Inject public HttpServer(Settings settings, HttpServerTransport transport, ThreadPool threadPool,
RestController restController, TransportNodesInfoAction nodesInfoAction) { RestController restController, TransportNodesInfoAction nodesInfoAction) {
@ -166,6 +167,9 @@ public class HttpServer extends AbstractLifecycleComponent<HttpServer> {
} }
private String getPath(HttpRequest request) { 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();
} }
} }

View File

@ -39,7 +39,7 @@ public class NettyHttpRequest extends AbstractRestRequest implements HttpRequest
private final Map<String, String> params; private final Map<String, String> params;
private final String path; private final String rawPath;
private byte[] cachedData; private byte[] cachedData;
@ -50,9 +50,9 @@ public class NettyHttpRequest extends AbstractRestRequest implements HttpRequest
String uri = request.getUri(); String uri = request.getUri();
int pathEndPos = uri.indexOf('?'); int pathEndPos = uri.indexOf('?');
if (pathEndPos < 0) { if (pathEndPos < 0) {
this.path = RestUtils.decodeComponent(uri); this.rawPath = uri;
} else { } else {
this.path = RestUtils.decodeComponent(uri.substring(0, pathEndPos)); this.rawPath = uri.substring(0, pathEndPos);
RestUtils.decodeQueryString(uri, pathEndPos + 1, params); RestUtils.decodeQueryString(uri, pathEndPos + 1, params);
} }
} }
@ -86,8 +86,8 @@ public class NettyHttpRequest extends AbstractRestRequest implements HttpRequest
return request.getUri(); return request.getUri();
} }
@Override public String path() { @Override public String rawPath() {
return path; return rawPath;
} }
@Override public Map<String, String> params() { @Override public Map<String, String> params() {

View File

@ -25,6 +25,7 @@ import org.elasticsearch.common.component.AbstractLifecycleComponent;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.path.PathTrie; import org.elasticsearch.common.path.PathTrie;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.rest.support.RestUtils;
import java.io.IOException; import java.io.IOException;
@ -33,12 +34,12 @@ import java.io.IOException;
*/ */
public class RestController extends AbstractLifecycleComponent<RestController> { public class RestController extends AbstractLifecycleComponent<RestController> {
private final PathTrie<RestHandler> getHandlers = new PathTrie<RestHandler>(); private final PathTrie<RestHandler> getHandlers = new PathTrie<RestHandler>(RestUtils.REST_DECODER);
private final PathTrie<RestHandler> postHandlers = new PathTrie<RestHandler>(); private final PathTrie<RestHandler> postHandlers = new PathTrie<RestHandler>(RestUtils.REST_DECODER);
private final PathTrie<RestHandler> putHandlers = new PathTrie<RestHandler>(); private final PathTrie<RestHandler> putHandlers = new PathTrie<RestHandler>(RestUtils.REST_DECODER);
private final PathTrie<RestHandler> deleteHandlers = new PathTrie<RestHandler>(); private final PathTrie<RestHandler> deleteHandlers = new PathTrie<RestHandler>(RestUtils.REST_DECODER);
private final PathTrie<RestHandler> headHandlers = new PathTrie<RestHandler>(); private final PathTrie<RestHandler> headHandlers = new PathTrie<RestHandler>(RestUtils.REST_DECODER);
private final PathTrie<RestHandler> optionsHandlers = new PathTrie<RestHandler>(); private final PathTrie<RestHandler> optionsHandlers = new PathTrie<RestHandler>(RestUtils.REST_DECODER);
@Inject public RestController(Settings settings) { @Inject public RestController(Settings settings) {
super(settings); super(settings);
@ -116,6 +117,9 @@ public class RestController extends AbstractLifecycleComponent<RestController> {
} }
private String getPath(RestRequest request) { 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();
} }
} }

View File

@ -43,7 +43,12 @@ public interface RestRequest extends ToXContent.Params {
String uri(); 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(); String path();

View File

@ -37,6 +37,10 @@ public abstract class AbstractRestRequest implements RestRequest {
private static final Pattern commaPattern = Pattern.compile(","); private static final Pattern commaPattern = Pattern.compile(",");
@Override public final String path() {
return RestUtils.decodeComponent(rawPath());
}
@Override public float paramAsFloat(String key, float defaultValue) { @Override public float paramAsFloat(String key, float defaultValue) {
String sValue = param(key); String sValue = param(key);
if (sValue == null) { if (sValue == null) {

View File

@ -20,6 +20,7 @@
package org.elasticsearch.rest.support; package org.elasticsearch.rest.support;
import org.elasticsearch.common.base.Charsets; import org.elasticsearch.common.base.Charsets;
import org.elasticsearch.common.path.PathTrie;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.Map; import java.util.Map;
@ -29,6 +30,12 @@ import java.util.Map;
*/ */
public class RestUtils { 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) { public static void decodeQueryString(String s, int fromIndex, Map<String, String> params) {
if (fromIndex < 0) { if (fromIndex < 0) {
return; return;

View File

@ -45,7 +45,7 @@ public class MemcachedRestRequest extends AbstractRestRequest {
private final Map<String, String> params; private final Map<String, String> params;
private final String path; private final String rawPath;
private byte[] data; private byte[] data;
@ -62,9 +62,9 @@ public class MemcachedRestRequest extends AbstractRestRequest {
this.params = new HashMap<String, String>(); this.params = new HashMap<String, String>();
int pathEndPos = uri.indexOf('?'); int pathEndPos = uri.indexOf('?');
if (pathEndPos < 0) { if (pathEndPos < 0) {
this.path = uri; this.rawPath = uri;
} else { } else {
this.path = uri.substring(0, pathEndPos); this.rawPath = uri.substring(0, pathEndPos);
RestUtils.decodeQueryString(uri, pathEndPos + 1, params); RestUtils.decodeQueryString(uri, pathEndPos + 1, params);
} }
} }
@ -77,8 +77,8 @@ public class MemcachedRestRequest extends AbstractRestRequest {
return this.uri; return this.uri;
} }
@Override public String path() { @Override public String rawPath() {
return this.path; return this.rawPath;
} }
public byte[] getUriBytes() { public byte[] getUriBytes() {

View File

@ -36,7 +36,7 @@ public class ThriftRestRequest extends AbstractRestRequest implements org.elasti
private final org.elasticsearch.thrift.RestRequest request; private final org.elasticsearch.thrift.RestRequest request;
private final String path; private final String rawPath;
private final Map<String, String> params; private final Map<String, String> params;
@ -46,9 +46,9 @@ public class ThriftRestRequest extends AbstractRestRequest implements org.elasti
int pathEndPos = request.getUri().indexOf('?'); int pathEndPos = request.getUri().indexOf('?');
if (pathEndPos < 0) { if (pathEndPos < 0) {
this.path = request.getUri(); this.rawPath = request.getUri();
} else { } else {
this.path = request.getUri().substring(0, pathEndPos); this.rawPath = request.getUri().substring(0, pathEndPos);
RestUtils.decodeQueryString(request.getUri(), pathEndPos + 1, params); RestUtils.decodeQueryString(request.getUri(), pathEndPos + 1, params);
} }
} }
@ -75,8 +75,8 @@ public class ThriftRestRequest extends AbstractRestRequest implements org.elasti
return request.getUri(); return request.getUri();
} }
@Override public String path() { @Override public String rawPath() {
return this.path; return this.rawPath;
} }
@Override public boolean hasContent() { @Override public boolean hasContent() {