Skip to content

Commit

Permalink
Merge branch '1.x' of git://github.com/alexpanov/zuul into alexpanov-1.x
Browse files Browse the repository at this point in the history
  • Loading branch information
kerumai committed Apr 6, 2016
2 parents 70bae0b + 5449df3 commit 4e94d0a
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 81 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,12 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
Expand Down Expand Up @@ -83,11 +79,6 @@ public class FilterScriptManagerServlet extends HttpServlet {
private static final long serialVersionUID = -1L;
private static final Logger logger = LoggerFactory.getLogger(FilterScriptManagerServlet.class);

/* actions that we permit as an immutable Set */
private static final Set<String> VALID_GET_ACTIONS = Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(new String[]{"LIST", "DOWNLOAD"})));
private static final Set<String> VALID_PUT_ACTIONS = Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(new String[]{"UPLOAD", "ACTIVATE", "DEACTIVATE", "RUN", "CANARY"})));


/* DAO for performing CRUD operations with scripts */
private static ZuulFilterDAO scriptDAO;

Expand Down Expand Up @@ -458,31 +449,7 @@ private Map<String, Object> createEndpointScriptJSON(FilterInfo script) {
private static boolean isValidAction(HttpServletRequest request, HttpServletResponse response) {
String action = request.getParameter("action");
if (action != null) {
action = action.trim().toUpperCase();
/* test for GET actions */
if (VALID_GET_ACTIONS.contains(action)) {
if (!request.getMethod().equals("GET")) {
// valid action, wrong method
setUsageError(405, "ERROR: Invalid HTTP method for action type.", response);
return false;
}
// valid action and method
return true;
}

if (VALID_PUT_ACTIONS.contains(action)) {
if (!(request.getMethod().equals("PUT") || request.getMethod().equals("POST"))) {
// valid action, wrong method
setUsageError(405, "ERROR: Invalid HTTP method for action type.", response);
return false;
}
// valid action and method
return true;
}

// wrong action
setUsageError(400, "ERROR: Unknown action type.", response);
return false;
return new ValidActionEvaluation(request, response).isValid();
} else {
setUsageError(400, "ERROR: Invalid arguments.", response);
return false;
Expand All @@ -496,17 +463,7 @@ private static boolean isValidAction(HttpServletRequest request, HttpServletResp
* @param response
*/
private static void setUsageError(int statusCode, String message, HttpServletResponse response) {
response.setStatus(statusCode);
try {
Writer w = response.getWriter();
if (message != null) {
w.write(message + "\n\n");
}
w.write(getUsageDoc());
} catch (Exception e) {
logger.error("Failed to output usage error.", e);
// won't throw exception because this is not critical, logging the error is enough
}
new UsageError(statusCode, message).setOn(response);
}

/**
Expand All @@ -525,42 +482,7 @@ private static void setUsageError(int statusCode, HttpServletResponse response)
* @return
*/
private static String getUsageDoc() {
StringBuilder s = new StringBuilder();
s.append("Usage: /scriptManager?action=<ACTION_TYPE>&<ARGS>").append("\n");
s.append(" Actions:").append("\n");
s.append(" LIST: List all endpoints with scripts or all scripts for a given endpoint.").append("\n");
s.append(" Arguments:").append("\n");
s.append(" endpoint: [Optional (Default: All endpoints)] The endpoint of script revisions to list.").append("\n");
s.append(" Examples:").append("\n");
s.append(" GET /scriptManager?action=LIST").append("\n");
s.append(" GET /scriptManager?action=LIST&endpoint=/ps3/home").append("\n");
s.append("\n");

s.append(" DOWNLOAD: Download a given script.").append("\n");
s.append(" Arguments:").append("\n");
s.append(" endpoint: [Required] The endpoint of script to download.").append("\n");
s.append(" revision: [Optional (Default: last revision)] The revision to download.").append("\n");
s.append(" Examples:").append("\n");
s.append(" GET /scriptManager?action=DOWNLOAD&endpoint=/ps3/home").append("\n");
s.append(" GET /scriptManager?action=DOWNLOAD&endpoint=/ps3/home&revision=23").append("\n");
s.append("\n");

s.append(" UPLOAD: Upload a script for a given endpoint.").append("\n");
s.append(" Arguments:").append("\n");
s.append(" endpoint: [Required] The endpoint to associated the script with. If it doesn't exist it will be created.").append("\n");
s.append(" userAuthenticationRequired: [Optional (Default: true)] Whether the script requires an authenticated user to execute.").append("\n");
s.append(" Example:").append("\n");
s.append(" POST /scriptManager?action=UPLOAD&endpoint=/ps3/home").append("\n");
s.append(" POST /scriptManager?action=UPLOAD&endpoint=/ps3/home&userAuthenticationRequired=false").append("\n");
s.append("\n");

s.append(" ACTIVATE: Mark a particular script revision as active for production.").append("\n");
s.append(" Arguments:").append("\n");
s.append(" endpoint: [Required] The endpoint for which a script revision should be activated.").append("\n");
s.append(" revision: [Required] The script revision to activate.").append("\n");
s.append(" Example:").append("\n");
s.append(" PUT /scriptManager?action=ACTIVATE&endpoint=/ps3/home&revision=22").append("\n");
return s.toString();
return new UsageDoc().get();
}

public static class UnitTest {
Expand Down Expand Up @@ -977,4 +899,5 @@ private FilterInfo mockEndpointScript() {
return script;
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.netflix.zuul.scriptManager;

final class UsageDoc {

String get() {
StringBuilder s = new StringBuilder();
s.append("Usage: /scriptManager?action=<ACTION_TYPE>&<ARGS>").append("\n");
s.append(" Actions:").append("\n");
s.append(" LIST: List all endpoints with scripts or all scripts for a given endpoint.").append("\n");
s.append(" Arguments:").append("\n");
s.append(" endpoint: [Optional (Default: All endpoints)] The endpoint of script revisions to list.").append("\n");
s.append(" Examples:").append("\n");
s.append(" GET /scriptManager?action=LIST").append("\n");
s.append(" GET /scriptManager?action=LIST&endpoint=/ps3/home").append("\n");
s.append("\n");

s.append(" DOWNLOAD: Download a given script.").append("\n");
s.append(" Arguments:").append("\n");
s.append(" endpoint: [Required] The endpoint of script to download.").append("\n");
s.append(" revision: [Optional (Default: last revision)] The revision to download.")
.append("\n");
s.append(" Examples:").append("\n");
s.append(" GET /scriptManager?action=DOWNLOAD&endpoint=/ps3/home").append("\n");
s.append(" GET /scriptManager?action=DOWNLOAD&endpoint=/ps3/home&revision=23").append("\n");
s.append("\n");

s.append(" UPLOAD: Upload a script for a given endpoint.").append("\n");
s.append(" Arguments:").append("\n");
s.append(" endpoint: [Required] The endpoint to associated the script with. If it doesn't exist it will be created.").append("\n");
s.append(" userAuthenticationRequired: [Optional (Default: true)] Whether the script requires an authenticated user to execute.").append("\n");
s.append(" Example:").append("\n");
s.append(" POST /scriptManager?action=UPLOAD&endpoint=/ps3/home").append("\n");
s.append(" POST /scriptManager?action=UPLOAD&endpoint=/ps3/home&userAuthenticationRequired=false").append("\n");
s.append("\n");

s.append(" ACTIVATE: Mark a particular script revision as active for production.").append("\n");
s.append(" Arguments:").append("\n");
s.append(" endpoint: [Required] The endpoint for which a script revision should be activated.").append("\n");
s.append(" revision: [Required] The script revision to activate.").append("\n");
s.append(" Example:").append("\n");
s.append(" PUT /scriptManager?action=ACTIVATE&endpoint=/ps3/home&revision=22").append("\n");
return s.toString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.netflix.zuul.scriptManager;

import java.io.Writer;

import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

class UsageError {

private static final Logger LOGGER = LoggerFactory.getLogger(UsageError.class);

private final int statusCode;
private final String message;

UsageError(int statusCode, String message) {
this.statusCode = statusCode;
this.message = message;
}

void setOn(HttpServletResponse response) {
response.setStatus(statusCode);
try {
Writer w = response.getWriter();
if (message != null) {
w.write(message + "\n\n");
}
w.write(new UsageDoc().get());
} catch (Exception e) {
LOGGER.error("Failed to output usage error.", e);
// won't throw exception because this is not critical, logging the error is enough
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.netflix.zuul.scriptManager;

import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import static com.google.common.collect.Sets.newHashSet;
import static java.util.Collections.unmodifiableSet;

class ValidActionEvaluation {

private static final Set<String> VALID_GET_ACTIONS = unmodifiableSet(newHashSet("LIST", "DOWNLOAD"));
private static final Set<String> VALID_PUT_ACTIONS =
unmodifiableSet(newHashSet("UPLOAD", "ACTIVATE", "DEACTIVATE", "RUN", "CANARY"));

private final boolean result;

ValidActionEvaluation(HttpServletRequest request, HttpServletResponse response) {
this.result = resultOfEvaluation(request, response);
}

private boolean resultOfEvaluation(HttpServletRequest request, HttpServletResponse response) {
String action = request.getParameter("action").trim().toUpperCase();
if (VALID_GET_ACTIONS.contains(action)) {
return validateGetAction(request, response);
}

if (VALID_PUT_ACTIONS.contains(action)) {
return validatePutAction(request, response);
}

// wrong action
new UsageError(400, "ERROR: Unknown action type.").setOn(response);
return false;
}

private boolean validatePutAction(HttpServletRequest request, HttpServletResponse response) {
if ((request.getMethod().equals("PUT") || request.getMethod().equals("POST"))) {
return true;
}
addValidActionWrongMethodError(response);
return false;
}

private void addValidActionWrongMethodError(HttpServletResponse response) {
new UsageError(405, "ERROR: Invalid HTTP method for action type.").setOn(response);
}

private boolean validateGetAction(HttpServletRequest request, HttpServletResponse response) {
if (request.getMethod().equals("GET")) {
return true;
}
addValidActionWrongMethodError(response);
return false;
}

public boolean isValid() {
return result;
}
}

0 comments on commit 4e94d0a

Please sign in to comment.