Skip to content

Commit

Permalink
Made HTTP Request method checking consistent, fixes a few cases where…
Browse files Browse the repository at this point in the history
… behavior is unexpected.

Simplified loading of internal RPC Handlers

Fixes OpenTSDB#831
Fixes OpenTSDB#830
  • Loading branch information
johann8384 committed Jul 6, 2016
1 parent 1409b55 commit a1620ab
Show file tree
Hide file tree
Showing 18 changed files with 295 additions and 222 deletions.
2 changes: 2 additions & 0 deletions Makefile.am
Expand Up @@ -147,6 +147,7 @@ tsdb_SRC := \
src/tsd/AnnotationRpc.java \
src/tsd/BadRequestException.java \
src/tsd/ConnectionManager.java \
src/tsd/DropCachesRpc.java \
src/tsd/GnuplotException.java \
src/tsd/GraphHandler.java \
src/tsd/HttpJsonSerializer.java \
Expand All @@ -164,6 +165,7 @@ tsdb_SRC := \
src/tsd/RpcHandler.java \
src/tsd/RpcPlugin.java \
src/tsd/RpcManager.java \
src/tsd/RpcUtil.java \
src/tsd/RTPublisher.java \
src/tsd/SearchRpc.java \
src/tsd/StaticFileRpc.java \
Expand Down
15 changes: 5 additions & 10 deletions src/tsd/AnnotationRpc.java
Expand Up @@ -47,7 +47,9 @@ final class AnnotationRpc implements HttpRpc {
*/
public void execute(final TSDB tsdb, HttpQuery query) throws IOException {
final HttpMethod method = query.getAPIMethod();


RpcUtil.allowedMethods(method, HttpMethod.GET.getName(), HttpMethod.POST.getName(), HttpMethod.DELETE.getName(), HttpMethod.PUT.getName());

final String[] uri = query.explodeAPIPath();
final String endpoint = uri.length > 1 ? uri[1] : "";
if (endpoint != null && endpoint.toLowerCase().endsWith("bulk")) {
Expand Down Expand Up @@ -125,11 +127,6 @@ public Deferred<Annotation> call(Boolean success) throws Exception {
throw new RuntimeException(e);
}
query.sendStatusOnly(HttpResponseStatus.NO_CONTENT);

} else {
throw new BadRequestException(HttpResponseStatus.METHOD_NOT_ALLOWED,
"Method not allowed", "The HTTP method [" + method.getName() +
"] is not permitted for this endpoint");
}
}

Expand All @@ -141,14 +138,12 @@ public Deferred<Annotation> call(Boolean success) throws Exception {
* @param query The query to parse and respond to
*/
void executeBulk(final TSDB tsdb, final HttpMethod method, HttpQuery query) {
RpcUtil.allowedMethods(query.method(), HttpMethod.PUT.getName(), HttpMethod.POST.getName(), HttpMethod.DELETE.getName());

if (method == HttpMethod.POST || method == HttpMethod.PUT) {
executeBulkUpdate(tsdb, method, query);
} else if (method == HttpMethod.DELETE) {
executeBulkDelete(tsdb, query);
} else {
throw new BadRequestException(HttpResponseStatus.METHOD_NOT_ALLOWED,
"Method not allowed", "The HTTP method [" + query.method().getName() +
"] is not permitted for this endpoint");
}
}

Expand Down
88 changes: 88 additions & 0 deletions src/tsd/DropCachesRpc.java
@@ -0,0 +1,88 @@
// This file is part of OpenTSDB.
// Copyright (C) 2013 The OpenTSDB Authors.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 2.1 of the License, or (at your
// option) any later version. This program is distributed in the hope that it
// will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
// General Public License for more details. You should have received a copy
// of the GNU Lesser General Public License along with this program. If not,
// see <http://www.gnu.org/licenses/>.
package net.opentsdb.tsd;

import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Pattern;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.Atomics;
import com.stumbleupon.async.Callback;
import com.stumbleupon.async.Deferred;

import org.jboss.netty.channel.Channel;
import org.jboss.netty.handler.codec.http.HttpMethod;
import org.jboss.netty.handler.codec.http.HttpResponseStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import net.opentsdb.tools.BuildData;
import net.opentsdb.core.Aggregators;
import net.opentsdb.core.TSDB;
import net.opentsdb.query.filter.TagVFilter;
import net.opentsdb.stats.StatsCollector;
import net.opentsdb.utils.Config;
import net.opentsdb.utils.JSON;
import net.opentsdb.utils.PluginLoader;

import java.io.IOException;

/** The "dropcaches" command. */
public final class DropCachesRpc implements TelnetRpc, HttpRpc {
private static final Logger LOG = LoggerFactory.getLogger(DropCachesRpc.class);

public Deferred<Object> execute(final TSDB tsdb, final Channel chan,
final String[] cmd) {
dropCaches(tsdb, chan);
chan.write("Caches dropped.\n");
return Deferred.fromResult(null);
}

public void execute(final TSDB tsdb, final HttpQuery query)
throws IOException {

// only accept GET
RpcUtil.allowedMethods(query.method(), HttpMethod.GET.getName(), HttpMethod.DELETE.getName());

dropCaches(tsdb, query.channel());

if (query.apiVersion() > 0) {
final HashMap<String, String> response = new HashMap<String, String>();
response.put("status", "200");
response.put("message", "Caches dropped");
query.sendReply(query.serializer().formatDropCachesV1(response));
} else { // deprecated API
query.sendReply("Caches dropped.\n");
}
}

/** Drops in memory caches. */
private void dropCaches(final TSDB tsdb, final Channel chan) {
LOG.warn(chan + " Dropping all in-memory caches.");
tsdb.dropCaches();
}
}
5 changes: 5 additions & 0 deletions src/tsd/GraphHandler.java
Expand Up @@ -35,6 +35,7 @@
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;

import org.jboss.netty.handler.codec.http.HttpMethod;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -106,6 +107,10 @@ public GraphHandler() {
}

public void execute(final TSDB tsdb, final HttpQuery query) {

// only accept GET/POST
RpcUtil.allowedMethods(query.method(), HttpMethod.GET.getName(), HttpMethod.POST.getName());

if (!query.hasQueryStringParam("json")
&& !query.hasQueryStringParam("png")
&& !query.hasQueryStringParam("ascii")) {
Expand Down
2 changes: 1 addition & 1 deletion src/tsd/HttpRpc.java
Expand Up @@ -26,6 +26,6 @@ interface HttpRpc {
* @param tsdb The TSDB to use.
* @param query The HTTP query to execute.
*/
void execute(TSDB tsdb, HttpQuery query) throws IOException;
void execute(TSDB tsdb, HttpQuery query) throws BadRequestException, IOException;

}
8 changes: 7 additions & 1 deletion src/tsd/LogsRpc.java
Expand Up @@ -12,6 +12,7 @@
// see <http://www.gnu.org/licenses/>.
package net.opentsdb.tsd;

import org.jboss.netty.handler.codec.http.HttpMethod;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.core.JsonGenerationException;
Expand All @@ -35,8 +36,13 @@
final class LogsRpc implements HttpRpc {

public void execute(final TSDB tsdb, final HttpQuery query)
throws JsonGenerationException, IOException {
throws BadRequestException, IOException {

// only accept GET/POST
RpcUtil.allowedMethods(query.method(), HttpMethod.GET.getName(), HttpMethod.POST.getName());

LogIterator logmsgs = new LogIterator();

if (query.hasQueryStringParam("json")) {
ArrayList<String> logs = new ArrayList<String>();
for (String log : logmsgs) {
Expand Down
13 changes: 5 additions & 8 deletions src/tsd/PutDataPointRpc.java
Expand Up @@ -109,16 +109,13 @@ public String toString() {
* @since 2.0
*/
public void execute(final TSDB tsdb, final HttpQuery query)
throws IOException {
throws BadRequestException, IOException {
requests.incrementAndGet();



// only accept POST
if (query.method() != HttpMethod.POST) {
throw new BadRequestException(HttpResponseStatus.METHOD_NOT_ALLOWED,
"Method not allowed", "The HTTP method [" + query.method().getName() +
"] is not permitted for this endpoint");
}

RpcUtil.allowedMethods(query.method(), HttpMethod.POST.getName());

final List<IncomingDataPoint> dps = query.serializer().parsePutV1();
if (dps.size() < 1) {
throw new BadRequestException("No datapoints found in content");
Expand Down
14 changes: 5 additions & 9 deletions src/tsd/QueryRpc.java
Expand Up @@ -81,16 +81,12 @@ final class QueryRpc implements HttpRpc {
*/
@Override
public void execute(final TSDB tsdb, final HttpQuery query)
throws IOException {
throws BadRequestException, IOException {

// only accept GET/POST/DELETE
if (query.method() != HttpMethod.GET && query.method() != HttpMethod.POST &&
query.method() != HttpMethod.DELETE) {
throw new BadRequestException(HttpResponseStatus.METHOD_NOT_ALLOWED,
"Method not allowed", "The HTTP method [" + query.method().getName() +
"] is not permitted for this endpoint");
}
if (query.method() == HttpMethod.DELETE &&
RpcUtil.allowedMethods(query.method(), HttpMethod.GET.getName(), HttpMethod.DELETE.getName(), HttpMethod.POST.getName());

if (query.method() == HttpMethod.DELETE &&
!tsdb.getConfig().getBoolean("tsd.http.query.allow_delete")) {
throw new BadRequestException(HttpResponseStatus.BAD_REQUEST,
"Bad request",
Expand Down
8 changes: 8 additions & 0 deletions src/tsd/RpcHandler.java
Expand Up @@ -249,6 +249,14 @@ private boolean applyCorsConfig(final HttpRequest req, final AbstractHttpQuery q
* @param req The parsed HTTP request.
*/
private void handleHttpQuery(final TSDB tsdb, final Channel chan, final HttpRequest req) {
// quick bail if not GET/POST/OPTIONS/PUT/DELETE, no other methods are allowed anywhere
try {
RpcUtil.allowedMethods(req.getMethod(), HttpMethod.GET.getName(), HttpMethod.POST.getName(),
HttpMethod.OPTIONS.getName(), HttpMethod.PUT.getName(), HttpMethod.DELETE.getName());
} catch (BadRequestException bre) {
sendStatusAndClose(chan, HttpResponseStatus.METHOD_NOT_ALLOWED);
}

AbstractHttpQuery abstractQuery = null;
try {
abstractQuery = createQueryInstance(tsdb, req, chan);
Expand Down

0 comments on commit a1620ab

Please sign in to comment.