From d3de21cf67d58d19ba088661c63e8088db6efbe3 Mon Sep 17 00:00:00 2001 From: Brendan Teich Date: Sun, 29 Jan 2017 22:44:19 -0500 Subject: [PATCH 01/13] Refactored the GNSHttpProxy to be a parent of GNSHttpServer. Fixed a null pointer exception that arose when GNSHttpsServer called GNSHttpServer, but GNSHttpProxy was running before the requestHandler had been set. --- .../cs/gnsserver/httpserver/GNSHttpProxy.java | 433 ++++++++++ .../gnsserver/httpserver/GNSHttpServer.java | 745 ++++++++---------- 2 files changed, 740 insertions(+), 438 deletions(-) create mode 100644 src/edu/umass/cs/gnsserver/httpserver/GNSHttpProxy.java diff --git a/src/edu/umass/cs/gnsserver/httpserver/GNSHttpProxy.java b/src/edu/umass/cs/gnsserver/httpserver/GNSHttpProxy.java new file mode 100644 index 000000000..a320d309e --- /dev/null +++ b/src/edu/umass/cs/gnsserver/httpserver/GNSHttpProxy.java @@ -0,0 +1,433 @@ +/* + * + * Copyright (c) 2015 University of Massachusetts + * + * Licensed under the Apache License, Version 2.0 (the "License"); you + * may not use this file except in compliance with the License. You + * may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + * + * Initial developer(s): Westy + * + */ +package edu.umass.cs.gnsserver.httpserver; + +/** + * + * @author westy + */ +import com.sun.net.httpserver.Headers; +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; + +import edu.umass.cs.gnsclient.client.GNSClient; +import edu.umass.cs.gnscommon.CommandType; +import edu.umass.cs.gnsserver.main.GNSConfig; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.InetSocketAddress; +import java.net.URI; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.concurrent.Executors; + +import edu.umass.cs.gnscommon.ResponseCode; +import static edu.umass.cs.gnsserver.httpserver.Defs.QUERYPREFIX; + +import edu.umass.cs.gnsserver.gnsapp.clientCommandProcessor.commands.CommandModule; +import edu.umass.cs.gnscommon.exceptions.client.ClientException; +import edu.umass.cs.gnscommon.exceptions.server.InternalRequestException; +import edu.umass.cs.gnscommon.packets.CommandPacket; +import edu.umass.cs.gnscommon.utils.Base64; +import edu.umass.cs.gnscommon.utils.CanonicalJSON; +import edu.umass.cs.gnscommon.utils.Format; +import edu.umass.cs.gnsserver.gnsapp.clientCommandProcessor.commandSupport.CommandResponse; +import edu.umass.cs.gnsserver.utils.Util; +import edu.umass.cs.nio.JSONPacket; +import edu.umass.cs.reconfiguration.ReconfigurationConfig; +import edu.umass.cs.utils.Config; + +import java.util.Date; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.apache.commons.lang.time.DurationFormatUtils; +import org.json.JSONException; +import org.json.JSONObject; + +import edu.umass.cs.gnscommon.GNSProtocol; + +import java.io.UnsupportedEncodingException; + +/** + * + * + * @author Brendan + * Created by refactoring Westy's GNSHttpServer into a parent class, so most of the code was + * written by him for that class. + */ +public class GNSHttpProxy { + + /** + * + */ + protected static final String GNS_PATH = Config.getGlobalString(GNSConfig.GNSC.HTTP_SERVER_GNS_URL_PATH); + protected HttpServer httpServer = null; + protected int port; + // handles command processing + protected final CommandModule commandModule; + // newer handles command processing + protected GNSClient client = null; + + /** + * + */ + final protected Date serverStartDate = new Date(); + + private final static Logger LOGGER = Logger.getLogger(GNSHttpProxy.class.getName()); + + /** + * This does not call runServer on construction because GNSHttpServer may + * set a requestHandler first. runServer must be explicitly called later! + * @param requestHandler + */ + public GNSHttpProxy() { + this.commandModule = new CommandModule(); + try { + this.client = new GNSClient() { + public String getLabel() { + return GNSHttpProxy.class.getSimpleName(); + } + }; + } catch (IOException e) { + LOGGER.log(Level.SEVERE, "Unable to start GNS client:" + e); + } + } + + /** + * Creates and runs a GNSHttpProxy that receives commands over HTTP + * and executed them using a GNSClient. + */ + public static void main(String[] args){ + GNSHttpProxy proxy = new GNSHttpProxy(); + proxy.runServer(8080); + } + + /** + * Start the server. + * + * @param startingPort + */ + public final void runServer(int startingPort) { + int cnt = 0; + do { + // Find the first port after starting port that actually works. + // Usually if 8080 is busy we can get 8081. + if (tryPort(startingPort + cnt)) { + port = startingPort + cnt; + break; + } + edu.umass.cs.utils.Util.suicide(GNSConfig.getLogger(), "Unable to start GNS HTTP server; exiting"); + } while (cnt++ < 100); + } + + /** + * Stop everything. + */ + public void stop() { + if (httpServer != null) { + httpServer.stop(0); + } + } + + /** + * Try to start the http server at the port. + * + * @param port + * @return true if it was started + */ + public boolean tryPort(int port) { + try { + InetSocketAddress addr = new InetSocketAddress(port); + httpServer = HttpServer.create(addr, 0); + + httpServer.createContext("/", new EchoHttpHandler()); + httpServer.createContext("/" + GNS_PATH, new ProxyHttpHandler()); + httpServer.setExecutor(Executors.newCachedThreadPool()); + httpServer.start(); + + LOGGER.log(Level.INFO, + "HTTP server is listening on port {0}", port); + return true; + } catch (IOException e) { + LOGGER.log(Level.FINE, + "HTTP server failed to start on port {0} due to {1}", + new Object[]{port, e}); + return false; + } + } + + /** + * The default handler. + */ + protected class ProxyHttpHandler implements HttpHandler { + + /** + * + * @param exchange + */ + @Override + public void handle(HttpExchange exchange) { + try { + String requestMethod = exchange.getRequestMethod(); + if (requestMethod.equalsIgnoreCase("GET")) { + Headers requestHeaders = exchange.getRequestHeaders(); + String host = requestHeaders.getFirst("Host"); + Headers responseHeaders = exchange.getResponseHeaders(); + responseHeaders.set("Content-Type", "text/plain"); + exchange.sendResponseHeaders(HttpURLConnection.HTTP_OK, 0); + + OutputStream responseBody = exchange.getResponseBody(); + + URI uri = exchange.getRequestURI(); + LOGGER.log(Level.FINE, + "HTTP SERVER REQUEST FROM {0}: {1}", new Object[]{exchange.getRemoteAddress().getHostName(), uri.toString()}); + String path = uri.getPath(); + String query = uri.getQuery() != null ? uri.getQuery() : ""; // stupidly it returns null for empty query + + String commandName = path.replaceFirst("/" + GNS_PATH + "/", ""); + + CommandResponse response; + if (!commandName.isEmpty()) { + LOGGER.log(Level.FINE, "Action: {0} Query:{1}", new Object[]{commandName, query}); + response = processQuery(host, commandName, query); + } else { + response = new CommandResponse(ResponseCode.OPERATION_NOT_SUPPORTED, GNSProtocol.BAD_RESPONSE.toString() + + " " + GNSProtocol.OPERATION_NOT_SUPPORTED.toString() + " Don't understand " + commandName + " " + query); + } + LOGGER.log(Level.FINER, "Response: " + response); + // FIXME: This totally ignores the error code. + responseBody.write(response.getReturnValue().getBytes()); + responseBody.close(); + } + } catch (Exception e) { + LOGGER.log(Level.SEVERE, "Error: " + e); + e.printStackTrace(); + try { + String response = GNSProtocol.BAD_RESPONSE.toString() + " " + GNSProtocol.QUERY_PROCESSING_ERROR.toString() + " " + e; + OutputStream responseBody = exchange.getResponseBody(); + responseBody.write(response.getBytes()); + responseBody.close(); + } catch (Exception f) { + // at this point screw it + } + } + } + } + + /** + * Process queries for the http service. Converts the URI of e the HTTP query into + * the JSON Object format that is used by the CommandModeule class, then finds + * executes the matching command. + * + * @throws InternalRequestException + */ + protected CommandResponse processQuery(String host, String commandName, String queryString) throws InternalRequestException { + // Convert the URI into a JSONObject, stuffing in some extra relevant fields like + // the signature, and the message signed. + try { + // Note that the commandName is not part of the queryString string here so + // it doesn't end up in the jsonCommand. Also see below where we put the + // command integer into the jsonCommand. + JSONObject jsonCommand = Util.parseURIQueryStringIntoJSONObject(queryString); + // If the signature exists it is Base64 encoded so decode it now. + if (jsonCommand.has(GNSProtocol.SIGNATURE.toString())) { + jsonCommand.put(GNSProtocol.SIGNATURE.toString(), + new String(Base64.decode(jsonCommand.getString(GNSProtocol.SIGNATURE.toString())), + GNSProtocol.CHARSET.toString())); + } + // getCommandForHttp allows for "dump" as well as "Dump" + CommandType commandType = CommandType.getCommandForHttp(commandName); + if (commandType == null) { + return new CommandResponse(ResponseCode.OPERATION_NOT_SUPPORTED, + GNSProtocol.BAD_RESPONSE.toString() + " " + GNSProtocol.OPERATION_NOT_SUPPORTED.toString() + + " Sorry, don't understand " + commandName + QUERYPREFIX + queryString); + } + // The client currently just uses the command name (which is not part of the + // query string above) so we need to stuff + // in the Command integer for the signature check and execution. + jsonCommand.put(GNSProtocol.COMMAND_INT.toString(), commandType.getInt()); + // Optionally does some sanity checking on the message if that was enabled at the client. + // This makes necessary changes to the jsonCommand so don't remove this call + // unless you know what you're doing and also change the code in the HTTP client. + sanityCheckMessage(jsonCommand); + // This proxy invokes the GNS client to send commands out. + + + // Send the command remotely using a client + try { + LOGGER.log(Level.FINE, "Sending command out to a remote server: " + jsonCommand); + CommandPacket commandResponsePacket = getResponseUsingGNSClient(client, jsonCommand); + return new CommandResponse(ResponseCode.NO_ERROR, + // Some crap here to make single field reads return just the value for backward compatibility + // There is similar code to this other places. + specialCaseSingleFieldRead(commandResponsePacket.getResultString(), + commandType, jsonCommand)); + } catch (IOException | ClientException e) { + return new CommandResponse(ResponseCode.UNSPECIFIED_ERROR, GNSProtocol.BAD_RESPONSE.toString() + " " + + GNSProtocol.UNSPECIFIED_ERROR.toString() + " " + e.toString()); + // } catch (ClientException e) { + // return new CommandResponse(ResponseCode.GNSProtocol.UNSPECIFIED_ERROR.toString(), + // GNSProtocol.BAD_RESPONSE.toString() + " " + GNSProtocol.OPERATION_NOT_SUPPORTED.toString() + // + " Sorry, don't understand " + commandName + QUERYPREFIX + queryString); + } + + } catch (JSONException | UnsupportedEncodingException e) { + return new CommandResponse(ResponseCode.UNSPECIFIED_ERROR, GNSProtocol.BAD_RESPONSE.toString() + " " + + GNSProtocol.UNSPECIFIED_ERROR.toString() + " " + e.toString()); + } + } + + protected static void sanityCheckMessage(JSONObject jsonCommand) throws JSONException, + UnsupportedEncodingException { + if (jsonCommand.has("originalMessageBase64")) { + String originalMessage = new String(Base64.decode(jsonCommand.getString("originalMessageBase64")), + GNSProtocol.CHARSET.toString()); + jsonCommand.remove("originalMessageBase64"); + String commandSansSignature = CanonicalJSON.getCanonicalForm(jsonCommand); + if (!originalMessage.equals(commandSansSignature)) { + LOGGER.log(Level.SEVERE, "signature message mismatch! original: " + originalMessage + + " computed for signature: " + commandSansSignature); + } else { + LOGGER.log(Level.FINE, "######## original: " + originalMessage); + } + } + } + + + //make single field reads return just the value for backward compatibility + protected static String specialCaseSingleFieldRead(String response, CommandType commandType, + JSONObject jsonFormattedArguments) { + try { + if (commandType.isRead() && jsonFormattedArguments.has(GNSProtocol.FIELD.toString()) + && !jsonFormattedArguments.getString(GNSProtocol.FIELD.toString()).equals(GNSProtocol.ENTIRE_RECORD.toString()) + && JSONPacket.couldBeJSON(response) && response.startsWith("{")) { + String key = jsonFormattedArguments.getString(GNSProtocol.FIELD.toString()); + JSONObject json = new JSONObject(response); + return json.getString(key); + } + } catch (JSONException e) { + LOGGER.log(Level.SEVERE, "Problem getting single key reponse for : " + e); + // just return the response if there is some issue + } + return response; + } + + private CommandPacket getResponseUsingGNSClient(GNSClient client, + JSONObject jsonFormattedArguments) throws ClientException, IOException, JSONException { + LOGGER.log(Level.FINE, "jsonFormattedCommand =" + jsonFormattedArguments.toString()); + + CommandPacket outgoingPacket = new CommandPacket((long) (Math.random() * Long.MAX_VALUE), jsonFormattedArguments, false); + //GNSCommand.createGNSCommandFromJSONObject(jsonFormattedArguments); + + LOGGER.log(Level.FINE, "outgoingPacket =" + outgoingPacket.toString()); + + CommandPacket returnPacket = client.execute(outgoingPacket); + + LOGGER.log(Level.FINE, "returnPacket =" + returnPacket.toString()); + /** + * Can also invoke getResponse(), getResponseString(), getResponseJSONObject() + * etc. on {@link CommandPacket} as documented in {@link GNSCommand}. + */ + return returnPacket; + + } + + /** + * Returns info about the server. + */ + protected class EchoHttpHandler implements HttpHandler { + + /** + * + * @param exchange + * @throws IOException + */ + @Override + public void handle(HttpExchange exchange) throws IOException { + String requestMethod = exchange.getRequestMethod(); + if (requestMethod.equalsIgnoreCase("GET")) { + Headers responseHeaders = exchange.getResponseHeaders(); + responseHeaders.set("Content-Type", "text/HTML"); + exchange.sendResponseHeaders(200, 0); + + OutputStream responseBody = exchange.getResponseBody(); + Headers requestHeaders = exchange.getRequestHeaders(); + Set keySet = requestHeaders.keySet(); + Iterator iter = keySet.iterator(); + + String buildVersion = GNSConfig.readBuildVersion(); + String buildVersionInfo = "Build Version: Unable to lookup!"; + if (buildVersion != null) { + buildVersionInfo = "Build Version: " + buildVersion; + } + String responsePreamble = "GNS Server Status

"; + String responsePostamble = "

"; + String serverStartDateString = "Server start time: " + Format.formatDualDate(serverStartDate); + String serverUpTimeString = "Server uptime: " + DurationFormatUtils.formatDurationWords(new Date().getTime() - serverStartDate.getTime(), true, true); + String serverSSLMode = "Server SSL mode: " + ReconfigurationConfig.getServerSSLMode().toString(); + String clientSSLMode = "Client SSL mode: " + ReconfigurationConfig.getClientSSLMode().toString(); + String reconAddresses = "Recon addresses: " + ReconfigurationConfig.getReconfiguratorAddresses().toString(); + + String recordsClass = "Records Class: " + GNSConfig.GNSC.getNoSqlRecordsClass(); + + // Build the response + responseBody.write(responsePreamble.getBytes()); + responseBody.write(buildVersionInfo.getBytes()); + responseBody.write("
".getBytes()); + responseBody.write(serverStartDateString.getBytes()); + responseBody.write("
".getBytes()); + responseBody.write(serverUpTimeString.getBytes()); + responseBody.write("
".getBytes()); + responseBody.write(reconAddresses.getBytes()); + responseBody.write("
".getBytes()); + responseBody.write(serverSSLMode.getBytes()); + responseBody.write("
".getBytes()); + responseBody.write(clientSSLMode.getBytes()); + responseBody.write("
".getBytes()); + + // responseBody.write(nodeAddressesString.getBytes()); + // responseBody.write("
".getBytes()); + // responseBody.write(reconfiguratorsString.getBytes()); + // responseBody.write("
".getBytes()); + // responseBody.write(activeReplicasString.getBytes()); + // responseBody.write("
".getBytes()); + responseBody.write(recordsClass.getBytes()); + responseBody.write("
".getBytes()); + responseBody.write("
".getBytes()); + responseBody.write("Request Headers:".getBytes()); + responseBody.write("
".getBytes()); + while (iter.hasNext()) { + String key = iter.next(); + List values = requestHeaders.get(key); + String s = key + " = " + values.toString() + "\n"; + responseBody.write(s.getBytes()); + responseBody.write("
".getBytes()); + } + responseBody.write(responsePostamble.getBytes()); + responseBody.close(); + } + } + } +} diff --git a/src/edu/umass/cs/gnsserver/httpserver/GNSHttpServer.java b/src/edu/umass/cs/gnsserver/httpserver/GNSHttpServer.java index 7b2ace831..18fa980f5 100644 --- a/src/edu/umass/cs/gnsserver/httpserver/GNSHttpServer.java +++ b/src/edu/umass/cs/gnsserver/httpserver/GNSHttpServer.java @@ -34,9 +34,7 @@ import java.io.IOException; import java.io.OutputStream; -import java.net.HttpURLConnection; import java.net.InetSocketAddress; -import java.net.URI; import java.util.Iterator; import java.util.List; import java.util.Set; @@ -46,7 +44,6 @@ import static edu.umass.cs.gnsserver.httpserver.Defs.QUERYPREFIX; import edu.umass.cs.gnsserver.gnsapp.clientCommandProcessor.ClientRequestHandlerInterface; import edu.umass.cs.gnsserver.gnsapp.clientCommandProcessor.commandSupport.CommandHandler; -import edu.umass.cs.gnsserver.gnsapp.clientCommandProcessor.commands.CommandModule; import edu.umass.cs.gnsserver.gnsapp.clientCommandProcessor.commands.AbstractCommand; import edu.umass.cs.gnscommon.exceptions.client.ClientException; import edu.umass.cs.gnscommon.exceptions.server.InternalRequestException; @@ -57,7 +54,6 @@ import edu.umass.cs.gnsserver.gnsapp.clientCommandProcessor.commandSupport.CommandResponse; import edu.umass.cs.gnsserver.main.GNSConfig.GNSC; import edu.umass.cs.gnsserver.utils.Util; -import edu.umass.cs.nio.JSONPacket; import edu.umass.cs.reconfiguration.ReconfigurationConfig; import edu.umass.cs.utils.Config; @@ -78,438 +74,311 @@ * * @author westy */ -public class GNSHttpServer { - - /** - * - */ - protected static final String GNS_PATH = Config.getGlobalString(GNSConfig.GNSC.HTTP_SERVER_GNS_URL_PATH); - private HttpServer httpServer = null; - private int port; - // handles command processing - private final CommandModule commandModule; - // newer handles command processing - private GNSClient client = null; - - /** - * - */ - protected final ClientRequestHandlerInterface requestHandler; - private final Date serverStartDate = new Date(); - - private final static Logger LOGGER = Logger.getLogger(GNSHttpServer.class.getName()); - - /** - * - * @param port - * @param requestHandler - */ - public GNSHttpServer(int port, ClientRequestHandlerInterface requestHandler) { - this.commandModule = new CommandModule(); - this.requestHandler = requestHandler; - if (!Config.getGlobalBoolean(GNSC.DISABLE_MULTI_SERVER_HTTP)) { - try { - this.client = new GNSClient() { - public String getLabel() { - return GNSHttpServer.class.getSimpleName(); - } - }; - } catch (IOException e) { - LOGGER.log(Level.SEVERE, "Unable to start GNS client:" + e); - } - } - runServer(port); - } - - /** - * Start the server. - * - * @param startingPort - */ - public final void runServer(int startingPort) { - int cnt = 0; - do { - // Find the first port after starting port that actually works. - // Usually if 8080 is busy we can get 8081. - if (tryPort(startingPort + cnt)) { - port = startingPort + cnt; - break; - } - edu.umass.cs.utils.Util.suicide(GNSConfig.getLogger(), "Unable to start GNS HTTP server; exiting"); - } while (cnt++ < 100); - } - - /** - * Stop everything. - */ - public void stop() { - if (httpServer != null) { - httpServer.stop(0); - } - } - - /** - * Try to start the http server at the port. - * - * @param port - * @return true if it was started - */ - public boolean tryPort(int port) { - try { - InetSocketAddress addr = new InetSocketAddress(port); - httpServer = HttpServer.create(addr, 0); - - httpServer.createContext("/", new EchoHttpHandler()); - httpServer.createContext("/" + GNS_PATH, new DefaultHttpHandler()); - httpServer.setExecutor(Executors.newCachedThreadPool()); - httpServer.start(); - // Need to do this for the places where we expose the insecure http service to the user - requestHandler.setHttpServerPort(port); - LOGGER.log(Level.INFO, - "HTTP server is listening on port {0}", port); - return true; - } catch (IOException e) { - LOGGER.log(Level.FINE, - "HTTP server failed to start on port {0} due to {1}", - new Object[]{port, e}); - return false; - } - } - - /** - * The default handler. - */ - protected class DefaultHttpHandler implements HttpHandler { - - /** - * - * @param exchange - */ - @Override - public void handle(HttpExchange exchange) { - try { - String requestMethod = exchange.getRequestMethod(); - if (requestMethod.equalsIgnoreCase("GET")) { - Headers requestHeaders = exchange.getRequestHeaders(); - String host = requestHeaders.getFirst("Host"); - Headers responseHeaders = exchange.getResponseHeaders(); - responseHeaders.set("Content-Type", "text/plain"); - exchange.sendResponseHeaders(HttpURLConnection.HTTP_OK, 0); - - OutputStream responseBody = exchange.getResponseBody(); - - URI uri = exchange.getRequestURI(); - LOGGER.log(Level.FINE, - "HTTP SERVER REQUEST FROM {0}: {1}", new Object[]{exchange.getRemoteAddress().getHostName(), uri.toString()}); - String path = uri.getPath(); - String query = uri.getQuery() != null ? uri.getQuery() : ""; // stupidly it returns null for empty query - - String commandName = path.replaceFirst("/" + GNS_PATH + "/", ""); - - CommandResponse response; - if (!commandName.isEmpty()) { - LOGGER.log(Level.FINE, "Action: {0} Query:{1}", new Object[]{commandName, query}); - response = processQuery(host, commandName, query); - } else { - response = new CommandResponse(ResponseCode.OPERATION_NOT_SUPPORTED, GNSProtocol.BAD_RESPONSE.toString() - + " " + GNSProtocol.OPERATION_NOT_SUPPORTED.toString() + " Don't understand " + commandName + " " + query); - } - LOGGER.log(Level.FINER, "Response: " + response); - // FIXME: This totally ignores the error code. - responseBody.write(response.getReturnValue().getBytes()); - responseBody.close(); - } - } catch (Exception e) { - LOGGER.log(Level.SEVERE, "Error: " + e); - e.printStackTrace(); - try { - String response = GNSProtocol.BAD_RESPONSE.toString() + " " + GNSProtocol.QUERY_PROCESSING_ERROR.toString() + " " + e; - OutputStream responseBody = exchange.getResponseBody(); - responseBody.write(response.getBytes()); - responseBody.close(); - } catch (Exception f) { - // at this point screw it - } - } - } - } - - /** - * Process queries for the http service. Converts the URI of e the HTTP query into - * the JSON Object format that is used by the CommandModeule class, then finds - * executes the matching command. - * - * @throws InternalRequestException - */ - private CommandResponse processQuery(String host, String commandName, String queryString) throws InternalRequestException { - // Convert the URI into a JSONObject, stuffing in some extra relevant fields like - // the signature, and the message signed. - try { - // Note that the commandName is not part of the queryString string here so - // it doesn't end up in the jsonCommand. Also see below where we put the - // command integer into the jsonCommand. - JSONObject jsonCommand = Util.parseURIQueryStringIntoJSONObject(queryString); - // If the signature exists it is Base64 encoded so decode it now. - if (jsonCommand.has(GNSProtocol.SIGNATURE.toString())) { - jsonCommand.put(GNSProtocol.SIGNATURE.toString(), - new String(Base64.decode(jsonCommand.getString(GNSProtocol.SIGNATURE.toString())), - GNSProtocol.CHARSET.toString())); - } - // getCommandForHttp allows for "dump" as well as "Dump" - CommandType commandType = CommandType.getCommandForHttp(commandName); - if (commandType == null) { - return new CommandResponse(ResponseCode.OPERATION_NOT_SUPPORTED, - GNSProtocol.BAD_RESPONSE.toString() + " " + GNSProtocol.OPERATION_NOT_SUPPORTED.toString() - + " Sorry, don't understand " + commandName + QUERYPREFIX + queryString); - } - // The client currently just uses the command name (which is not part of the - // query string above) so we need to stuff - // in the Command integer for the signature check and execution. - jsonCommand.put(GNSProtocol.COMMAND_INT.toString(), commandType.getInt()); - // Optionally does some sanity checking on the message if that was enabled at the client. - // This makes necessary changes to the jsonCommand so don't remove this call - // unless you know what you're doing and also change the code in the HTTP client. - sanityCheckMessage(jsonCommand); - // Hair below is to handle some commands locally (creates, delets, selects, admin) - // and the rest by invoking the GNS client and sending them out. - // Client will be null if GNSC.DISABLE_MULTI_SERVER_HTTP (see above) - // is true (or there was a problem). - if (client == null || commandType.isLocallyHandled()) { - // EXECUTE IT LOCALLY - AbstractCommand command; - try { - command = commandModule.lookupCommand(commandType); - // Do some work to get the signature and message into the command for - // signature checking that happens later on. - // This only happens for local execution because remote handling (in the - // other side of the if) already does this. - processSignature(jsonCommand); - if (command != null) { - return CommandHandler.executeCommand(command, - new CommandPacket((long) (Math.random() * Long.MAX_VALUE), jsonCommand, false), - requestHandler); - } - LOGGER.log(Level.FINE, "lookupCommand returned null for {0}", commandName); - } catch (IllegalArgumentException e) { - LOGGER.log(Level.FINE, "lookupCommand failed for {0}", commandName); - } - return new CommandResponse(ResponseCode.OPERATION_NOT_SUPPORTED, - GNSProtocol.BAD_RESPONSE.toString() + " " + GNSProtocol.OPERATION_NOT_SUPPORTED.toString() - + " Sorry, don't understand " + commandName + QUERYPREFIX + queryString); - } else { - // Send the command remotely using a client - try { - LOGGER.log(Level.FINE, "Sending command out to a remote server: " + jsonCommand); - CommandPacket commandResponsePacket = getResponseUsingGNSClient(client, jsonCommand); - return new CommandResponse(ResponseCode.NO_ERROR, - // Some crap here to make single field reads return just the value for backward compatibility - // There is similar code to this other places. - specialCaseSingleFieldRead(commandResponsePacket.getResultString(), - commandType, jsonCommand)); - } catch (IOException | ClientException e) { - return new CommandResponse(ResponseCode.UNSPECIFIED_ERROR, GNSProtocol.BAD_RESPONSE.toString() + " " - + GNSProtocol.UNSPECIFIED_ERROR.toString() + " " + e.toString()); -// } catch (ClientException e) { -// return new CommandResponse(ResponseCode.GNSProtocol.UNSPECIFIED_ERROR.toString(), -// GNSProtocol.BAD_RESPONSE.toString() + " " + GNSProtocol.OPERATION_NOT_SUPPORTED.toString() -// + " Sorry, don't understand " + commandName + QUERYPREFIX + queryString); - } - } - } catch (JSONException | UnsupportedEncodingException e) { - return new CommandResponse(ResponseCode.UNSPECIFIED_ERROR, GNSProtocol.BAD_RESPONSE.toString() + " " - + GNSProtocol.UNSPECIFIED_ERROR.toString() + " " + e.toString()); - } - } - - private static void sanityCheckMessage(JSONObject jsonCommand) throws JSONException, - UnsupportedEncodingException { - if (jsonCommand.has("originalMessageBase64")) { - String originalMessage = new String(Base64.decode(jsonCommand.getString("originalMessageBase64")), - GNSProtocol.CHARSET.toString()); - jsonCommand.remove("originalMessageBase64"); - String commandSansSignature = CanonicalJSON.getCanonicalForm(jsonCommand); - if (!originalMessage.equals(commandSansSignature)) { - LOGGER.log(Level.SEVERE, "signature message mismatch! original: " + originalMessage - + " computed for signature: " + commandSansSignature); - } else { - LOGGER.log(Level.FINE, "######## original: " + originalMessage); - } - } - } - - private static void processSignature(JSONObject jsonCommand) throws JSONException { - if (jsonCommand.has(GNSProtocol.SIGNATURE.toString())) { - // Squirrel away the signature. - String signature = jsonCommand.getString(GNSProtocol.SIGNATURE.toString()); - // Pull it out of the command because we don't want to have it there when we check the message. - jsonCommand.remove(GNSProtocol.SIGNATURE.toString()); - // Convert it to a conanical string (the message) that we can use later to check against the signature. - String commandSansSignature = CanonicalJSON.getCanonicalForm(jsonCommand); - // Put the decoded signature back as well as the message that we're going to - // later compare the signature against. - jsonCommand.put(GNSProtocol.SIGNATURE.toString(), signature).put(GNSProtocol.SIGNATUREFULLMESSAGE.toString(), - commandSansSignature); - - } - } - - //make single field reads return just the value for backward compatibility - private static String specialCaseSingleFieldRead(String response, CommandType commandType, - JSONObject jsonFormattedArguments) { - try { - if (commandType.isRead() && jsonFormattedArguments.has(GNSProtocol.FIELD.toString()) - && !jsonFormattedArguments.getString(GNSProtocol.FIELD.toString()).equals(GNSProtocol.ENTIRE_RECORD.toString()) - && JSONPacket.couldBeJSON(response) && response.startsWith("{")) { - String key = jsonFormattedArguments.getString(GNSProtocol.FIELD.toString()); - JSONObject json = new JSONObject(response); - return json.getString(key); - } - } catch (JSONException e) { - LOGGER.log(Level.SEVERE, "Problem getting single key reponse for : " + e); - // just return the response if there is some issue - } - return response; - } - - private CommandPacket getResponseUsingGNSClient(GNSClient client, - JSONObject jsonFormattedArguments) throws ClientException, IOException, JSONException { - LOGGER.log(Level.FINE, "jsonFormattedCommand =" + jsonFormattedArguments.toString()); - - CommandPacket outgoingPacket = new CommandPacket((long) (Math.random() * Long.MAX_VALUE), jsonFormattedArguments, false); - //GNSCommand.createGNSCommandFromJSONObject(jsonFormattedArguments); - - LOGGER.log(Level.FINE, "outgoingPacket =" + outgoingPacket.toString()); - - CommandPacket returnPacket = client.execute(outgoingPacket); - - LOGGER.log(Level.FINE, "returnPacket =" + returnPacket.toString()); - /** - * Can also invoke getResponse(), getResponseString(), getResponseJSONObject() - * etc. on {@link CommandPacket} as documented in {@link GNSCommand}. - */ - return returnPacket; - - } - - /** - * Returns info about the server. - */ - protected class EchoHttpHandler implements HttpHandler { - - /** - * - * @param exchange - * @throws IOException - */ - @Override - public void handle(HttpExchange exchange) throws IOException { - String requestMethod = exchange.getRequestMethod(); - if (requestMethod.equalsIgnoreCase("GET")) { - Headers responseHeaders = exchange.getResponseHeaders(); - responseHeaders.set("Content-Type", "text/HTML"); - exchange.sendResponseHeaders(200, 0); - - OutputStream responseBody = exchange.getResponseBody(); - Headers requestHeaders = exchange.getRequestHeaders(); - Set keySet = requestHeaders.keySet(); - Iterator iter = keySet.iterator(); - - String buildVersion = GNSConfig.readBuildVersion(); - String buildVersionInfo = "Build Version: Unable to lookup!"; - if (buildVersion != null) { - buildVersionInfo = "Build Version: " + buildVersion; - } - String responsePreamble = "GNS Server Status

"; - String responsePostamble = "

"; - String serverStartDateString = "Server start time: " + Format.formatDualDate(serverStartDate); - String serverUpTimeString = "Server uptime: " + DurationFormatUtils.formatDurationWords(new Date().getTime() - serverStartDate.getTime(), true, true); - String serverSSLMode = "Server SSL mode: " + ReconfigurationConfig.getServerSSLMode().toString(); - String clientSSLMode = "Client SSL mode: " + ReconfigurationConfig.getClientSSLMode().toString(); - String reconAddresses = "Recon addresses: " + ReconfigurationConfig.getReconfiguratorAddresses().toString(); - String numberOfNameServers = "Server count: " + requestHandler.getGnsNodeConfig().getNumberOfNodes(); - String recordsClass = "Records Class: " + GNSConfig.GNSC.getNoSqlRecordsClass(); - //StringBuilder resultString = new StringBuilder(); - // Servers -// resultString.append("Servers:"); -// for (String topLevelNode : requestHandler.getGnsNodeConfig().getNodeIDs()) { -// resultString.append("
  "); -// resultString.append(topLevelNode); -// resultString.append(" => "); -// resultString.append(requestHandler.getGnsNodeConfig().getBindAddress(topLevelNode)); -// resultString.append("  Public IP: "); -// resultString.append(requestHandler.getGnsNodeConfig().getNodeAddress(topLevelNode)); -// } -// String nodeAddressesString = resultString.toString(); - //Reconfigurators -// resultString = new StringBuilder(); -// String prefix = ""; -// for (String recon : requestHandler.getGnsNodeConfig().getReconfigurators()) { -// resultString.append("
  "); -// //resultString.append(prefix); -// resultString.append(recon); -// resultString.append(" => "); -// //resultString.append("("); -// resultString.append(requestHandler.getGnsNodeConfig().getNodeAddress(recon).getHostName()); -// resultString.append(":"); -// resultString.append(requestHandler.getGnsNodeConfig().getNodePort(recon)); -// //resultString.append(")"); -// //prefix = ", "; -// } -// String reconfiguratorsString = "Reconfigurators: " + resultString.toString(); - // Replicas -// resultString = new StringBuilder(); -// prefix = ""; -// for (String activeReplica : requestHandler.getGnsNodeConfig().getActiveReplicas()) { -// resultString.append("
  "); -// //resultString.append(prefix); -// resultString.append(activeReplica); -// resultString.append(" => "); -// //resultString.append("("); -// resultString.append(requestHandler.getGnsNodeConfig().getNodeAddress(activeReplica).getHostName()); -// resultString.append(":"); -// resultString.append(requestHandler.getGnsNodeConfig().getNodePort(activeReplica)); -// //resultString.append(")"); -// //prefix = ", "; -// } -// String activeReplicasString = "Active replicas: " + resultString.toString(); - // Build the response - responseBody.write(responsePreamble.getBytes()); - responseBody.write(buildVersionInfo.getBytes()); - responseBody.write("
".getBytes()); - responseBody.write(serverStartDateString.getBytes()); - responseBody.write("
".getBytes()); - responseBody.write(serverUpTimeString.getBytes()); - responseBody.write("
".getBytes()); - responseBody.write(numberOfNameServers.getBytes()); - responseBody.write("
".getBytes()); - responseBody.write(reconAddresses.getBytes()); - responseBody.write("
".getBytes()); - responseBody.write(serverSSLMode.getBytes()); - responseBody.write("
".getBytes()); - responseBody.write(clientSSLMode.getBytes()); - responseBody.write("
".getBytes()); - -// responseBody.write(nodeAddressesString.getBytes()); -// responseBody.write("
".getBytes()); -// responseBody.write(reconfiguratorsString.getBytes()); -// responseBody.write("
".getBytes()); -// responseBody.write(activeReplicasString.getBytes()); -// responseBody.write("
".getBytes()); - responseBody.write(recordsClass.getBytes()); - responseBody.write("
".getBytes()); - responseBody.write("
".getBytes()); - responseBody.write("Request Headers:".getBytes()); - responseBody.write("
".getBytes()); - while (iter.hasNext()) { - String key = iter.next(); - List values = requestHeaders.get(key); - String s = key + " = " + values.toString() + "\n"; - responseBody.write(s.getBytes()); - responseBody.write("
".getBytes()); - } - responseBody.write(responsePostamble.getBytes()); - responseBody.close(); - } - } - } +public class GNSHttpServer extends GNSHttpProxy{ + + + /** + * + */ + protected final ClientRequestHandlerInterface requestHandler; + + private final static Logger LOGGER = Logger.getLogger(GNSHttpServer.class.getName()); + + /** + * + * @param port + * @param requestHandler + */ + public GNSHttpServer(int port, ClientRequestHandlerInterface requestHandler) { + super(); + this.requestHandler = requestHandler; + if (Config.getGlobalBoolean(GNSC.DISABLE_MULTI_SERVER_HTTP)) { + client.close(); + client = null; + } + runServer(port); + } + + + /** + * Try to start the http server at the port. + * + * @param port + * @return true if it was started + */ + public boolean tryPort(int port) { + try { + InetSocketAddress addr = new InetSocketAddress(port); + httpServer = HttpServer.create(addr, 0); + + httpServer.createContext("/", new EchoHttpHandler()); + httpServer.createContext("/" + GNS_PATH, new DefaultHttpHandler()); + httpServer.setExecutor(Executors.newCachedThreadPool()); + httpServer.start(); + + LOGGER.log(Level.INFO, + "HTTP server is listening on port {0}", port); + return true; + } catch (IOException e) { + LOGGER.log(Level.FINE, + "HTTP server failed to start on port {0} due to {1}", + new Object[]{port, e}); + return false; + } + } + + /** + * The default handler. + */ + protected class DefaultHttpHandler extends ProxyHttpHandler { + + + /** + * Process queries for the http service. Converts the URI of e the HTTP query into + * the JSON Object format that is used by the CommandModeule class, then finds + * executes the matching command. + * + * @throws InternalRequestException + */ + @SuppressWarnings("unused") //This is called in the parent class (ProxyHttpHandler) in the handle method. + private CommandResponse processQuery(String host, String commandName, String queryString) throws InternalRequestException { + // Convert the URI into a JSONObject, stuffing in some extra relevant fields like + // the signature, and the message signed. + try { + // Note that the commandName is not part of the queryString string here so + // it doesn't end up in the jsonCommand. Also see below where we put the + // command integer into the jsonCommand. + JSONObject jsonCommand = Util.parseURIQueryStringIntoJSONObject(queryString); + // If the signature exists it is Base64 encoded so decode it now. + if (jsonCommand.has(GNSProtocol.SIGNATURE.toString())) { + jsonCommand.put(GNSProtocol.SIGNATURE.toString(), + new String(Base64.decode(jsonCommand.getString(GNSProtocol.SIGNATURE.toString())), + GNSProtocol.CHARSET.toString())); + } + // getCommandForHttp allows for "dump" as well as "Dump" + CommandType commandType = CommandType.getCommandForHttp(commandName); + if (commandType == null) { + return new CommandResponse(ResponseCode.OPERATION_NOT_SUPPORTED, + GNSProtocol.BAD_RESPONSE.toString() + " " + GNSProtocol.OPERATION_NOT_SUPPORTED.toString() + + " Sorry, don't understand " + commandName + QUERYPREFIX + queryString); + } + // The client currently just uses the command name (which is not part of the + // query string above) so we need to stuff + // in the Command integer for the signature check and execution. + jsonCommand.put(GNSProtocol.COMMAND_INT.toString(), commandType.getInt()); + // Optionally does some sanity checking on the message if that was enabled at the client. + // This makes necessary changes to the jsonCommand so don't remove this call + // unless you know what you're doing and also change the code in the HTTP client. + sanityCheckMessage(jsonCommand); + // Hair below is to handle some commands locally (creates, delets, selects, admin) + // and the rest by invoking the GNS client and sending them out. + // Client will be null if GNSC.DISABLE_MULTI_SERVER_HTTP (see above) + // is true (or there was a problem). + if (client == null || commandType.isLocallyHandled()) { + // EXECUTE IT LOCALLY + AbstractCommand command; + try { + command = commandModule.lookupCommand(commandType); + // Do some work to get the signature and message into the command for + // signature checking that happens later on. + // This only happens for local execution because remote handling (in the + // other side of the if) already does this. + processSignature(jsonCommand); + if (command != null) { + return CommandHandler.executeCommand(command, + new CommandPacket((long) (Math.random() * Long.MAX_VALUE), jsonCommand, false), + requestHandler); + } + LOGGER.log(Level.FINE, "lookupCommand returned null for {0}", commandName); + } catch (IllegalArgumentException e) { + LOGGER.log(Level.FINE, "lookupCommand failed for {0}", commandName); + } + return new CommandResponse(ResponseCode.OPERATION_NOT_SUPPORTED, + GNSProtocol.BAD_RESPONSE.toString() + " " + GNSProtocol.OPERATION_NOT_SUPPORTED.toString() + + " Sorry, don't understand " + commandName + QUERYPREFIX + queryString); + } else { + // Send the command remotely using a client + try { + LOGGER.log(Level.FINE, "Sending command out to a remote server: " + jsonCommand); + CommandPacket commandResponsePacket = getResponseUsingGNSClient(client, jsonCommand); + return new CommandResponse(ResponseCode.NO_ERROR, + // Some crap here to make single field reads return just the value for backward compatibility + // There is similar code to this other places. + specialCaseSingleFieldRead(commandResponsePacket.getResultString(), + commandType, jsonCommand)); + } catch (IOException | ClientException e) { + return new CommandResponse(ResponseCode.UNSPECIFIED_ERROR, GNSProtocol.BAD_RESPONSE.toString() + " " + + GNSProtocol.UNSPECIFIED_ERROR.toString() + " " + e.toString()); + // } catch (ClientException e) { + // return new CommandResponse(ResponseCode.GNSProtocol.UNSPECIFIED_ERROR.toString(), + // GNSProtocol.BAD_RESPONSE.toString() + " " + GNSProtocol.OPERATION_NOT_SUPPORTED.toString() + // + " Sorry, don't understand " + commandName + QUERYPREFIX + queryString); + } + } + } catch (JSONException | UnsupportedEncodingException e) { + return new CommandResponse(ResponseCode.UNSPECIFIED_ERROR, GNSProtocol.BAD_RESPONSE.toString() + " " + + GNSProtocol.UNSPECIFIED_ERROR.toString() + " " + e.toString()); + } + } + + private void processSignature(JSONObject jsonCommand) throws JSONException { + if (jsonCommand.has(GNSProtocol.SIGNATURE.toString())) { + // Squirrel away the signature. + String signature = jsonCommand.getString(GNSProtocol.SIGNATURE.toString()); + // Pull it out of the command because we don't want to have it there when we check the message. + jsonCommand.remove(GNSProtocol.SIGNATURE.toString()); + // Convert it to a conanical string (the message) that we can use later to check against the signature. + String commandSansSignature = CanonicalJSON.getCanonicalForm(jsonCommand); + // Put the decoded signature back as well as the message that we're going to + // later compare the signature against. + jsonCommand.put(GNSProtocol.SIGNATURE.toString(), signature).put(GNSProtocol.SIGNATUREFULLMESSAGE.toString(), + commandSansSignature); + + } + } + + + + private CommandPacket getResponseUsingGNSClient(GNSClient client, + JSONObject jsonFormattedArguments) throws ClientException, IOException, JSONException { + LOGGER.log(Level.FINE, "jsonFormattedCommand =" + jsonFormattedArguments.toString()); + + CommandPacket outgoingPacket = new CommandPacket((long) (Math.random() * Long.MAX_VALUE), jsonFormattedArguments, false); + //GNSCommand.createGNSCommandFromJSONObject(jsonFormattedArguments); + + LOGGER.log(Level.FINE, "outgoingPacket =" + outgoingPacket.toString()); + + CommandPacket returnPacket = client.execute(outgoingPacket); + + LOGGER.log(Level.FINE, "returnPacket =" + returnPacket.toString()); + /** + * Can also invoke getResponse(), getResponseString(), getResponseJSONObject() + * etc. on {@link CommandPacket} as documented in {@link GNSCommand}. + */ + return returnPacket; + + } + + /** + * Returns info about the server. + */ + protected class EchoHttpHandler implements HttpHandler { + + /** + * + * @param exchange + * @throws IOException + */ + @Override + public void handle(HttpExchange exchange) throws IOException { + String requestMethod = exchange.getRequestMethod(); + if (requestMethod.equalsIgnoreCase("GET")) { + Headers responseHeaders = exchange.getResponseHeaders(); + responseHeaders.set("Content-Type", "text/HTML"); + exchange.sendResponseHeaders(200, 0); + + OutputStream responseBody = exchange.getResponseBody(); + Headers requestHeaders = exchange.getRequestHeaders(); + Set keySet = requestHeaders.keySet(); + Iterator iter = keySet.iterator(); + + String buildVersion = GNSConfig.readBuildVersion(); + String buildVersionInfo = "Build Version: Unable to lookup!"; + if (buildVersion != null) { + buildVersionInfo = "Build Version: " + buildVersion; + } + String responsePreamble = "GNS Server Status

"; + String responsePostamble = "

"; + String serverStartDateString = "Server start time: " + Format.formatDualDate(serverStartDate); + String serverUpTimeString = "Server uptime: " + DurationFormatUtils.formatDurationWords(new Date().getTime() - serverStartDate.getTime(), true, true); + String serverSSLMode = "Server SSL mode: " + ReconfigurationConfig.getServerSSLMode().toString(); + String clientSSLMode = "Client SSL mode: " + ReconfigurationConfig.getClientSSLMode().toString(); + String reconAddresses = "Recon addresses: " + ReconfigurationConfig.getReconfiguratorAddresses().toString(); + String numberOfNameServers = "Server count: " + requestHandler.getGnsNodeConfig().getNumberOfNodes(); + String recordsClass = "Records Class: " + GNSConfig.GNSC.getNoSqlRecordsClass(); + //StringBuilder resultString = new StringBuilder(); + // Servers + // resultString.append("Servers:"); + // for (String topLevelNode : requestHandler.getGnsNodeConfig().getNodeIDs()) { + // resultString.append("
  "); + // resultString.append(topLevelNode); + // resultString.append(" => "); + // resultString.append(requestHandler.getGnsNodeConfig().getBindAddress(topLevelNode)); + // resultString.append("  Public IP: "); + // resultString.append(requestHandler.getGnsNodeConfig().getNodeAddress(topLevelNode)); + // } + // String nodeAddressesString = resultString.toString(); + //Reconfigurators + // resultString = new StringBuilder(); + // String prefix = ""; + // for (String recon : requestHandler.getGnsNodeConfig().getReconfigurators()) { + // resultString.append("
  "); + // //resultString.append(prefix); + // resultString.append(recon); + // resultString.append(" => "); + // //resultString.append("("); + // resultString.append(requestHandler.getGnsNodeConfig().getNodeAddress(recon).getHostName()); + // resultString.append(":"); + // resultString.append(requestHandler.getGnsNodeConfig().getNodePort(recon)); + // //resultString.append(")"); + // //prefix = ", "; + // } + // String reconfiguratorsString = "Reconfigurators: " + resultString.toString(); + // Replicas + // resultString = new StringBuilder(); + // prefix = ""; + // for (String activeReplica : requestHandler.getGnsNodeConfig().getActiveReplicas()) { + // resultString.append("
  "); + // //resultString.append(prefix); + // resultString.append(activeReplica); + // resultString.append(" => "); + // //resultString.append("("); + // resultString.append(requestHandler.getGnsNodeConfig().getNodeAddress(activeReplica).getHostName()); + // resultString.append(":"); + // resultString.append(requestHandler.getGnsNodeConfig().getNodePort(activeReplica)); + // //resultString.append(")"); + // //prefix = ", "; + // } + // String activeReplicasString = "Active replicas: " + resultString.toString(); + // Build the response + responseBody.write(responsePreamble.getBytes()); + responseBody.write(buildVersionInfo.getBytes()); + responseBody.write("
".getBytes()); + responseBody.write(serverStartDateString.getBytes()); + responseBody.write("
".getBytes()); + responseBody.write(serverUpTimeString.getBytes()); + responseBody.write("
".getBytes()); + responseBody.write(numberOfNameServers.getBytes()); + responseBody.write("
".getBytes()); + responseBody.write(reconAddresses.getBytes()); + responseBody.write("
".getBytes()); + responseBody.write(serverSSLMode.getBytes()); + responseBody.write("
".getBytes()); + responseBody.write(clientSSLMode.getBytes()); + responseBody.write("
".getBytes()); + + // responseBody.write(nodeAddressesString.getBytes()); + // responseBody.write("
".getBytes()); + // responseBody.write(reconfiguratorsString.getBytes()); + // responseBody.write("
".getBytes()); + // responseBody.write(activeReplicasString.getBytes()); + // responseBody.write("
".getBytes()); + responseBody.write(recordsClass.getBytes()); + responseBody.write("
".getBytes()); + responseBody.write("
".getBytes()); + responseBody.write("Request Headers:".getBytes()); + responseBody.write("
".getBytes()); + while (iter.hasNext()) { + String key = iter.next(); + List values = requestHeaders.get(key); + String s = key + " = " + values.toString() + "\n"; + responseBody.write(s.getBytes()); + responseBody.write("
".getBytes()); + } + responseBody.write(responsePostamble.getBytes()); + responseBody.close(); + } + } + } + } } From 7247b55d9f0930157e8ce0a8b8a032158d29eb4e Mon Sep 17 00:00:00 2001 From: Brendan Teich Date: Sun, 29 Jan 2017 23:23:12 -0500 Subject: [PATCH 02/13] Added HttpProxyTest, which is a copy of HttpClientTest except it uses the default GNSHttpProxy port. --- .../client/singletests/HttpProxyTest.java | 743 ++++++++++++++++++ 1 file changed, 743 insertions(+) create mode 100644 test/edu/umass/cs/gnsclient/client/singletests/HttpProxyTest.java diff --git a/test/edu/umass/cs/gnsclient/client/singletests/HttpProxyTest.java b/test/edu/umass/cs/gnsclient/client/singletests/HttpProxyTest.java new file mode 100644 index 000000000..20a91e917 --- /dev/null +++ b/test/edu/umass/cs/gnsclient/client/singletests/HttpProxyTest.java @@ -0,0 +1,743 @@ +/* + * Copyright (C) 2016 + * University of Massachusetts + * All Rights Reserved + * + * Initial developer(s): Westy. + */ +package edu.umass.cs.gnsclient.client.singletests; + +import edu.umass.cs.gnsclient.client.http.HttpClient; +import edu.umass.cs.gnsclient.client.util.GuidEntry; +import edu.umass.cs.gnsclient.client.util.GuidUtils; +import edu.umass.cs.gnsclient.client.util.JSONUtils; +import edu.umass.cs.gnsclient.jsonassert.JSONAssert; +import edu.umass.cs.gnsclient.jsonassert.JSONCompareMode; +import edu.umass.cs.gnscommon.AclAccessType; +import edu.umass.cs.gnscommon.GNSProtocol; +import edu.umass.cs.gnscommon.exceptions.client.ClientException; +import edu.umass.cs.gnscommon.utils.RandomString; +import edu.umass.cs.gnsserver.utils.DefaultGNSTest; +import edu.umass.cs.utils.Utils; +import java.awt.geom.Point2D; +import java.io.IOException; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import org.hamcrest.Matchers; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.junit.Test; +import org.junit.FixMethodOrder; +import org.junit.runners.MethodSorters; +import org.junit.Assert; + +/** + * + * @author Brendan + * This is a direct copy of Westy's HttpClientTest. I only changed the port number to be the + * GNSHttpProxy default. + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class HttpProxyTest extends DefaultGNSTest { + + private HttpClient httpClient; + private static GuidEntry masterGuid; + private static GuidEntry httpOneEntry; + private static GuidEntry httpTwoEntry; + private static GuidEntry guidToDeleteEntry; + private static GuidEntry mygroupEntry; + private static final Set createdGuids = new HashSet<>(); + + /** + * + */ + public HttpProxyTest() { + if (httpClient == null) { + // This should look up the appropriate port somehow + httpClient = new HttpClient("127.0.0.1", 8080); + } + } + + /** + * + */ + @Test + public void test_899_Http_CreateAccountGuid() { + try { + masterGuid = GuidUtils.getGUIDKeys(globalAccountName); + + } catch (Exception e) { + Utils.failWithStackTrace("Exception while creating master guid: ", e); + } + } + + /** + * + */ + @Test + public void test_900_Http_LookupGuid() { + try { + Assert.assertEquals(masterGuid.getGuid(), httpClient.lookupGuid(globalAccountName)); + } catch (IOException | ClientException e) { + Utils.failWithStackTrace("Exception in LookupGuid: ", e); + } + } + + /** + * + */ + @Test + public void test_901_Http_CreateGuids() { + try { + httpOneEntry = httpClient.guidCreate(masterGuid, "httpOneEntry" + RandomString.randomString(12)); + httpTwoEntry = httpClient.guidCreate(masterGuid, "httpTwoEntry" + RandomString.randomString(12)); + System.out.println("Created: " + httpOneEntry); + System.out.println("Created: " + httpTwoEntry); + } catch (IOException | ClientException | NoSuchAlgorithmException e) { + Utils.failWithStackTrace("Exception in Http_CreateFields: ", e); + } + } + + /** + * + */ + @Test + public void test_902_Http_RemoveACL() { + try { + // remove default read acces for this test + httpClient.aclRemove(AclAccessType.READ_WHITELIST, httpOneEntry, + GNSProtocol.ENTIRE_RECORD.toString(), GNSProtocol.ALL_GUIDS.toString()); + } catch (IOException | ClientException e) { + Utils.failWithStackTrace("Exception in Http_RemoveACL: ", e); + } + } + + /** + * + */ + @Test + public void test_910_Http_UpdateFields() { + try { + httpClient.fieldUpdate(httpOneEntry.getGuid(), "environment", "work", httpOneEntry); + httpClient.fieldUpdate(httpOneEntry.getGuid(), "ssn", "000-00-0000", httpOneEntry); + httpClient.fieldUpdate(httpOneEntry.getGuid(), "password", "666flapJack", httpOneEntry); + httpClient.fieldUpdate(httpOneEntry.getGuid(), "address", "100 Hinkledinkle Drive", httpOneEntry); + } catch (IOException | ClientException | JSONException e) { + Utils.failWithStackTrace("Exception in Http_UpdateFields: ", e); + } + } + + /** + * + */ + @Test + public void test_911_Http_CheckFields() { + try { + // read my own field + Assert.assertEquals("work", + httpClient.fieldRead(httpOneEntry.getGuid(), "environment", httpOneEntry)); + // read another field + Assert.assertEquals("000-00-0000", + httpClient.fieldRead(httpOneEntry.getGuid(), "ssn", httpOneEntry)); + // read another field + Assert.assertEquals("666flapJack", + httpClient.fieldRead(httpOneEntry.getGuid(), "password", httpOneEntry)); + } catch (IOException | ClientException e) { + Utils.failWithStackTrace("Exception in Http_CheckFields: ", e); + } + } + + /** + * + */ + @Test + public void test_913_Http_CheckFieldsFail() { + try { + try { + String result = httpClient.fieldRead(httpOneEntry.getGuid(), "environment", httpTwoEntry); + Utils.failWithStackTrace("Result of read of httpOneEntry's environment by httpTwoEntry is " + result + + " which is wrong because it should have been rejected."); + } catch (ClientException e) { + } catch (IOException e) { + Utils.failWithStackTrace("Exception during read of westy's environment by sam: ", e); + } + } catch (Exception e) { + Utils.failWithStackTrace("Exception in Http_CheckFieldsFail: ", e); + } + } + + /** + * + */ + @Test + public void test_920_Http_ACLAdd() { + try { + System.out.println("Using:" + httpOneEntry); + System.out.println("Using:" + httpTwoEntry); + try { + httpClient.aclAdd(AclAccessType.READ_WHITELIST, httpOneEntry, "environment", + httpTwoEntry.getGuid()); + } catch (IOException | ClientException e) { + Utils.failWithStackTrace("Exception adding Sam to Westy's readlist: ", e); + } + } catch (Exception e) { + Utils.failWithStackTrace("Exception in Http_ACLAdd: ", e); + } + } + + /** + * + */ + @Test + public void test_921_Http_CheckAccess() { + try { + try { + Assert.assertEquals("work", + httpClient.fieldRead(httpOneEntry.getGuid(), "environment", httpTwoEntry)); + } catch (IOException | ClientException e) { + Utils.failWithStackTrace("Exception while Sam reading Westy's field: ", e); + } + } catch (Exception e) { + Utils.failWithStackTrace("Exception in Http_CheckAccess: ", e); + } + } + + /** + * + */ + @Test + public void test_932_Update() { + try { + JSONObject json = new JSONObject(); + JSONObject subJson = new JSONObject(); + subJson.put("sally", "red"); + subJson.put("sammy", "green"); + JSONObject subsubJson = new JSONObject(); + subsubJson.put("right", "seven"); + subsubJson.put("left", "eight"); + subJson.put("sally", subsubJson); + json.put("flapjack", subJson); + httpClient.update(httpOneEntry, json); + } catch (JSONException | IOException | ClientException e) { + Utils.failWithStackTrace("Exception while adding field \"flapjack\": ", e); + } + } + + /** + * + */ + @Test + public void test_933_ReadAll() { + try { + JSONObject expected = new JSONObject(); + JSONObject subJson = new JSONObject(); + subJson.put("sammy", "green"); + JSONObject subsubJson = new JSONObject(); + subsubJson.put("right", "seven"); + subsubJson.put("left", "eight"); + subJson.put("sally", subsubJson); + expected.put("flapjack", subJson); + expected.put("environment", "work"); + expected.put("ssn", "000-00-0000"); + expected.put("password", "666flapJack"); + expected.put("address", "100 Hinkledinkle Drive"); + JSONObject actual = httpClient.read(httpOneEntry); + JSONAssert.assertEquals(expected, actual, JSONCompareMode.NON_EXTENSIBLE); + //System.out.println(actual); + } catch (JSONException | IOException | ClientException e) { + Utils.failWithStackTrace("Exception while reading JSON: ", e); + } + } + + /** + * + */ + @Test + public void test_934_ReadDeep() { + try { + String actual = httpClient.fieldRead(httpOneEntry.getGuid(), "flapjack.sally.right", httpOneEntry); + Assert.assertEquals("seven", actual); + } catch (IOException | ClientException e) { + Utils.failWithStackTrace("Exception while reading \"flapjack.sally.right\": ", e); + } + } + + /** + * + */ + @Test + public void test_935_ReadMid() { + try { + String actual = httpClient.fieldRead(httpOneEntry.getGuid(), "flapjack.sally", httpOneEntry); + String expected = "{ \"left\" : \"eight\" , \"right\" : \"seven\"}"; + //System.out.println("expected:" + expected); + //System.out.println("actual:" + actual); + JSONAssert.assertEquals(expected, actual, JSONCompareMode.NON_EXTENSIBLE); + } catch (IOException | ClientException | JSONException e) { + Utils.failWithStackTrace("Exception while reading \"flapjack.sally\": ", e); + } + } + + /** + * + */ + @Test + public void test_936_ReadShallow() { + try { + String actual = httpClient.fieldRead(httpOneEntry.getGuid(), "flapjack", httpOneEntry); + String expected = "{ \"sammy\" : \"green\" , \"sally\" : { \"left\" : \"eight\" , \"right\" : \"seven\"}}"; + //System.out.println("expected:" + expected); + //System.out.println("actual:" + actual); + JSONAssert.assertEquals(expected, actual, JSONCompareMode.NON_EXTENSIBLE); + } catch (IOException | ClientException | JSONException e) { + Utils.failWithStackTrace("Exception while reading \"flapjack\": ", e); + } + } + + /** + * + */ + @Test + public void test_951_Http_createCats() { + try { + httpClient.fieldCreateSingleElementList(httpOneEntry.getGuid(), "cats", "whacky", httpOneEntry); + } catch (IOException | ClientException e) { + Utils.failWithStackTrace("Exception when we were not expecting testing cats: ", e); + } + } + + /** + * + */ + @Test + public void test_952_Http_testCats() { + try { + Assert.assertEquals("whacky", + httpClient.fieldReadFirstElement(httpOneEntry.getGuid(), "cats", httpOneEntry)); + } catch (IOException | ClientException e) { + Utils.failWithStackTrace("Exception when we were not expecting testing cats: ", e); + } + } + + /** + * + */ + @Test + public void test_953_Http_createMoreCats() { + try { + httpClient.fieldAppendWithSetSemantics(httpOneEntry.getGuid(), "cats", new JSONArray( + Arrays.asList("hooch", "maya", "red", "sox", "toby")), httpOneEntry); + + } catch (IOException | ClientException e) { + Utils.failWithStackTrace("Exception in createMoreCats: ", e); + } + } + + /** + * + */ + @Test + public void test_954_Http_checkMoreCats() { + try { + HashSet expected = new HashSet<>(Arrays.asList("hooch", + "maya", "red", "sox", "toby", "whacky")); + HashSet actual = JSONUtils.JSONArrayToHashSet(httpClient.fieldReadArray(httpOneEntry.getGuid(), + "cats", httpOneEntry)); + Assert.assertEquals(expected, actual); + + } catch (IOException | ClientException | JSONException e) { + Utils.failWithStackTrace("Exception in checkMoreCats: ", e); + } + } + + /** + * + */ + @Test + public void test_955_Http_clearCats() { + try { + httpClient.fieldClear(httpOneEntry.getGuid(), "cats", new JSONArray( + Arrays.asList("maya", "toby")), httpOneEntry); + } catch (IOException | ClientException e) { + Utils.failWithStackTrace("Exception in clearCats: ", e); + } + } + + /** + * + */ + @Test + public void test_956_Http_checkClearCats() { + try { + HashSet expected = new HashSet<>(Arrays.asList("hooch", "red", "sox", + "whacky")); + HashSet actual = JSONUtils.JSONArrayToHashSet(httpClient.fieldReadArray( + httpOneEntry.getGuid(), "cats", httpOneEntry)); + Assert.assertEquals(expected, actual); + + } catch (IOException | ClientException | JSONException e) { + Utils.failWithStackTrace("Exception in checkClearCats: ", e); + } + } + + /** + * + */ + @Test + public void test_957_Http_createEvenMoreCats() { + try { + httpClient.fieldAppendWithSetSemantics(httpOneEntry.getGuid(), "cats", "fred", httpOneEntry); + } catch (IOException | ClientException e) { + Utils.failWithStackTrace("Exception in createEvenMoreCats: ", e); + } + } + + /** + * + */ + @Test + public void test_958_Http_checkEvenMoreCats() { + try { + httpClient.fieldAppendWithSetSemantics(httpOneEntry.getGuid(), "cats", "fred", httpOneEntry); + HashSet expected = new HashSet<>(Arrays.asList("hooch", "red", "sox", + "whacky", "fred")); + HashSet actual = JSONUtils.JSONArrayToHashSet(httpClient.fieldReadArray( + httpOneEntry.getGuid(), "cats", httpOneEntry)); + Assert.assertEquals(expected, actual); + } catch (IOException | ClientException | JSONException e) { + Utils.failWithStackTrace("Exception in checkEvenMoreCats: ", e); + } + } + + /** + * + */ + @Test + public void test_960_Http_BasicSelect() { + try { + JSONArray result = httpClient.select("cats", "fred"); + // best we can do since there will be one, but possibly more objects in results + Assert.assertThat(result.length(), Matchers.greaterThanOrEqualTo(1)); + } catch (IOException | ClientException | JSONException e) { + Utils.failWithStackTrace("Exception when we were not expecting it: ", e); + } + } + + /** + * + */ + @Test + public void test_961_Http_GeoSpatialSelect() { + try { + for (int cnt = 0; cnt < 5; cnt++) { + GuidEntry testEntry = httpClient.guidCreate(masterGuid, "geoTest-" + RandomString.randomString(12)); + createdGuids.add(testEntry); // save them so we can delete them later + httpClient.setLocation(0.0, 0.0, testEntry); + } + } catch (IOException | ClientException | NoSuchAlgorithmException e) { + Utils.failWithStackTrace("Exception when we were not expecting it: ", e); + } + + try { + + JSONArray loc = new JSONArray(); + loc.put(1.0); + loc.put(1.0); + JSONArray result = httpClient.selectNear(GNSProtocol.LOCATION_FIELD_NAME.toString(), loc, 2000000.0); + // best we can do should be at least 5, but possibly more objects in results + Assert.assertThat(result.length(), Matchers.greaterThanOrEqualTo(5)); + } catch (JSONException | IOException | ClientException e) { + Utils.failWithStackTrace("Exception executing selectNear: ", e); + } + + try { + + JSONArray rect = new JSONArray(); + JSONArray upperLeft = new JSONArray(); + upperLeft.put(1.0); + upperLeft.put(1.0); + JSONArray lowerRight = new JSONArray(); + lowerRight.put(-1.0); + lowerRight.put(-1.0); + rect.put(upperLeft); + rect.put(lowerRight); + JSONArray result = httpClient.selectWithin(GNSProtocol.LOCATION_FIELD_NAME.toString(), rect); + // best we can do should be at least 5, but possibly more objects in results + Assert.assertThat(result.length(), Matchers.greaterThanOrEqualTo(5)); + } catch (JSONException | IOException | ClientException e) { + Utils.failWithStackTrace("Exception executing selectWithin: ", e); + } + } + + /** + * + */ + @Test + public void test_962_Http_QuerySelect() { + String fieldName = "testQuery"; + try { + for (int cnt = 0; cnt < 5; cnt++) { + GuidEntry testEntry = httpClient.guidCreate(masterGuid, "queryTest-" + RandomString.randomString(12)); + createdGuids.add(testEntry); // save them so we can delete them later + JSONArray array = new JSONArray(Arrays.asList(25)); + httpClient.fieldReplaceOrCreateList(testEntry.getGuid(), fieldName, array, testEntry); + } + } catch (IOException | ClientException | NoSuchAlgorithmException e) { + Utils.failWithStackTrace("Exception while tryint to create the guids: ", e); + } + + try { + String query = "~" + fieldName + " : ($gt: 0)"; + JSONArray result = httpClient.selectQuery(query); + for (int i = 0; i < result.length(); i++) { + System.out.println(result.get(i).toString()); + } + // best we can do should be at least 5, but possibly more objects in results + Assert.assertThat(result.length(), Matchers.greaterThanOrEqualTo(5)); + } catch (IOException | ClientException | JSONException e) { + Utils.failWithStackTrace("Exception executing selectNear: ", e); + } + + try { + + JSONArray rect = new JSONArray(); + JSONArray upperLeft = new JSONArray(); + upperLeft.put(1.0); + upperLeft.put(1.0); + JSONArray lowerRight = new JSONArray(); + lowerRight.put(-1.0); + lowerRight.put(-1.0); + rect.put(upperLeft); + rect.put(lowerRight); + JSONArray result = httpClient.selectWithin(GNSProtocol.LOCATION_FIELD_NAME.toString(), rect); + // best we can do should be at least 5, but possibly more objects in results + Assert.assertThat(result.length(), Matchers.greaterThanOrEqualTo(5)); + } catch (JSONException | IOException | ClientException e) { + Utils.failWithStackTrace("Exception executing selectWithin: ", e); + } + } + + private static String createIndexTestField; + + /** + * + */ + @Test + public void test_970_Http_CreateField() { + createIndexTestField = "testField" + RandomString.randomString(12); + try { + httpClient.fieldUpdate(masterGuid, createIndexTestField, createGeoJSONPolygon(AREA_EXTENT)); + } catch (JSONException | IOException | ClientException e) { + Utils.failWithStackTrace("Exception during create field: ", e); + } + } + + /** + * + */ + @Test + public void test_971_Http_CreateIndex() { + try { + httpClient.fieldCreateIndex(masterGuid, createIndexTestField, "2dsphere"); + } catch (IOException | ClientException | JSONException e) { + Utils.failWithStackTrace("Exception while creating index: ", e); + } + } + + /** + * + */ + @Test + public void test_972_Http_SelectPass() { + try { + JSONArray result = httpClient.selectQuery(buildQuery(createIndexTestField, AREA_EXTENT)); + for (int i = 0; i < result.length(); i++) { + System.out.println(result.get(i).toString()); + } + // best we can do should be at least 5, but possibly more objects in results + Assert.assertThat(result.length(), Matchers.greaterThanOrEqualTo(1)); + } catch (JSONException | IOException | ClientException e) { + Utils.failWithStackTrace("Exception executing second selectNear: ", e); + } + } + + /** + * + */ + @Test + public void test_980_Http_GroupCreate() { + String mygroupName = "mygroup" + RandomString.randomString(12); + try { + try { + httpClient.lookupGuid(mygroupName); + Utils.failWithStackTrace(mygroupName + " entity should not exist"); + } catch (ClientException e) { + } + guidToDeleteEntry = httpClient.guidCreate(masterGuid, "deleteMe" + RandomString.randomString(12)); + mygroupEntry = httpClient.guidCreate(masterGuid, mygroupName); + } catch (IOException | ClientException | NoSuchAlgorithmException e) { + Utils.failWithStackTrace("Exception while creating guids: ", e); + } + } + + /** + * + */ + @Test + public void test_981_Http_GroupAddHttpOne() { + try { + httpClient.groupAddGuid(mygroupEntry.getGuid(), httpOneEntry.getGuid(), mygroupEntry); + } catch (IOException | ClientException e) { + Utils.failWithStackTrace("Exception while adding Westy: ", e); + } + } + + /** + * + */ + @Test + public void test_982_GroupAddSam() { + try { + httpClient.groupAddGuid(mygroupEntry.getGuid(), httpTwoEntry.getGuid(), mygroupEntry); + } catch (IOException | ClientException e) { + Utils.failWithStackTrace("Exception while adding Sam: ", e); + } + } + + /** + * + */ + @Test + public void test_983_GroupAddGuidToDelete() { + try { + httpClient.groupAddGuid(mygroupEntry.getGuid(), guidToDeleteEntry.getGuid(), mygroupEntry); + } catch (IOException | ClientException e) { + Utils.failWithStackTrace("Exception while adding GuidToDelete: ", e); + } + } + + /** + * + */ + @Test + public void test_984_GroupAddCheck() { + try { + HashSet expected = new HashSet<>(Arrays.asList(httpOneEntry.getGuid(), httpTwoEntry.getGuid(), guidToDeleteEntry.getGuid())); + HashSet actual = JSONUtils.JSONArrayToHashSet(httpClient.groupGetMembers(mygroupEntry.getGuid(), mygroupEntry)); + Assert.assertEquals(expected, actual); + + expected = new HashSet<>(Arrays.asList(mygroupEntry.getGuid())); + actual = JSONUtils.JSONArrayToHashSet(httpClient.guidGetGroups(httpOneEntry.getGuid(), httpOneEntry)); + Assert.assertEquals(expected, actual); + + } catch (IOException | ClientException | JSONException e) { + Utils.failWithStackTrace("Exception while getting members and groups: ", e); + } + } + + /** + * + */ + @Test + public void test_985_GroupRemoveGuid() { + // now remove a guid and check for group updates + try { + httpClient.guidRemove(masterGuid, guidToDeleteEntry.getGuid()); + } catch (IOException | ClientException e) { + Utils.failWithStackTrace("Exception while removing testGuid: ", e); + } + try { + httpClient.lookupGuidRecord(guidToDeleteEntry.getGuid()); + Utils.failWithStackTrace("Lookup testGuid should have throw an exception."); + } catch (ClientException e) { + + } catch (IOException e) { + Utils.failWithStackTrace("Exception while doing Lookup testGuid: ", e); + } + } + + /** + * + */ + @Test + public void test_986_GroupRemoveCheck() { + try { + HashSet expected = new HashSet<>(Arrays.asList(httpOneEntry.getGuid(), httpTwoEntry.getGuid())); + HashSet actual = JSONUtils.JSONArrayToHashSet(httpClient.groupGetMembers(mygroupEntry.getGuid(), mygroupEntry)); + Assert.assertEquals(expected, actual); + + } catch (IOException | ClientException | JSONException e) { + Utils.failWithStackTrace("Exception during remove guid group update test: ", e); + System.exit(2); + } + } + + /* + * + */ + @Test + public void test_999_Cleanup() { + try { + httpClient.guidRemove(masterGuid, httpOneEntry.getGuid()); + httpClient.guidRemove(masterGuid, httpTwoEntry.getGuid()); + httpClient.guidRemove(masterGuid, mygroupEntry.getGuid()); + for (GuidEntry guid : createdGuids) { + httpClient.guidRemove(masterGuid, guid.getGuid()); + } + createdGuids.clear(); + } catch (ClientException | IOException e) { + Utils.failWithStackTrace("Exception while removing guids: " + e); + } + } + + // HELPER STUFF + private static final String POLYGON = "Polygon"; + private static final String COORDINATES = "coordinates"; + private static final String TYPE = "type"; + + private static JSONObject createGeoJSONPolygon(List coordinates) throws JSONException { + JSONArray ring = new JSONArray(); + for (int i = 0; i < coordinates.size(); i++) { + ring.put(i, new JSONArray( + Arrays.asList(coordinates.get(i).getX(), coordinates.get(i).getY()))); + } + JSONArray jsonCoordinates = new JSONArray(); + jsonCoordinates.put(0, ring); + JSONObject json = new JSONObject(); + json.put(TYPE, POLYGON); + json.put(COORDINATES, jsonCoordinates); + return json; + } + + private static final double LEFT = -98.08; + private static final double RIGHT = -96.01; + private static final double TOP = 33.635; + private static final double BOTTOM = 31.854; + + private static final Point2D UPPER_LEFT = new Point2D.Double(LEFT, TOP); + //private static final GlobalCoordinate UPPER_LEFT = new GlobalCoordinate(33.45, -98.08); + private static final Point2D UPPER_RIGHT = new Point2D.Double(RIGHT, TOP); + //private static final GlobalCoordinate UPPER_RIGHT = new GlobalCoordinate(33.45, -96.01); + private static final Point2D LOWER_RIGHT = new Point2D.Double(RIGHT, BOTTOM); + //private static final GlobalCoordinate LOWER_RIGHT = new GlobalCoordinate(32.23, -96.01); + private static final Point2D LOWER_LEFT = new Point2D.Double(LEFT, BOTTOM); + //private static final GlobalCoordinate LOWER_LEFT = new GlobalCoordinate(32.23, -98.08); + + private static final List AREA_EXTENT = new ArrayList<>( + Arrays.asList(UPPER_LEFT, UPPER_RIGHT, LOWER_RIGHT, LOWER_LEFT, UPPER_LEFT)); + + private static String buildQuery(String locationField, List coordinates) throws JSONException { + return "~" + locationField + ":{" + + "$geoIntersects :{" + + "$geometry:" + + createGeoJSONPolygon(coordinates).toString() + + "}" + + "}"; + } + +} From 211384d3acad173e970ad48dccd2555a0d64f6fe Mon Sep 17 00:00:00 2001 From: Brendan Teich Date: Mon, 30 Jan 2017 11:49:38 -0500 Subject: [PATCH 03/13] Refactored HttpProxyTest to instead extend HttpClientTest in order to remove duplicate code. Added system parameters to set the gns proxy's listening port and accepted remote hostnames. --- .../cs/gnsserver/httpserver/GNSHttpProxy.java | 42 +- .../gnsserver/httpserver/GNSHttpServer.java | 12 +- .../client/singletests/HttpClientTest.java | 2 +- .../client/singletests/HttpProxyTest.java | 693 +----------------- 4 files changed, 50 insertions(+), 699 deletions(-) diff --git a/src/edu/umass/cs/gnsserver/httpserver/GNSHttpProxy.java b/src/edu/umass/cs/gnsserver/httpserver/GNSHttpProxy.java index a320d309e..7e814d2cc 100644 --- a/src/edu/umass/cs/gnsserver/httpserver/GNSHttpProxy.java +++ b/src/edu/umass/cs/gnsserver/httpserver/GNSHttpProxy.java @@ -115,13 +115,20 @@ public String getLabel() { } } + /** * Creates and runs a GNSHttpProxy that receives commands over HTTP * and executed them using a GNSClient. */ public static void main(String[] args){ + String portString = System.getProperty("gnsProxy.port", "8080"); + int port = Integer.parseInt(portString); + + String hostname = System.getProperty("gnsProxy.remoteHostname", "localhost"); + + GNSHttpProxy proxy = new GNSHttpProxy(); - proxy.runServer(8080); + proxy.runServer(port, hostname); } /** @@ -134,13 +141,32 @@ public final void runServer(int startingPort) { do { // Find the first port after starting port that actually works. // Usually if 8080 is busy we can get 8081. - if (tryPort(startingPort + cnt)) { + if (tryPort(startingPort + cnt, null)) { port = startingPort + cnt; break; } edu.umass.cs.utils.Util.suicide(GNSConfig.getLogger(), "Unable to start GNS HTTP server; exiting"); } while (cnt++ < 100); } + + /** + * Start the server. + * + * @param startingPort + */ + public final void runServer(int startingPort, String hostname) { + int cnt = 0; + do { + // Find the first port after starting port that actually works. + // Usually if 8080 is busy we can get 8081. + if (tryPort(startingPort + cnt, hostname)) { + port = startingPort + cnt; + break; + } + edu.umass.cs.utils.Util.suicide(GNSConfig.getLogger(), "Unable to start GNS HTTP server; exiting"); + } while (cnt++ < 100); + } + /** * Stop everything. @@ -157,9 +183,15 @@ public void stop() { * @param port * @return true if it was started */ - public boolean tryPort(int port) { + public boolean tryPort(int port, String hostname) { try { - InetSocketAddress addr = new InetSocketAddress(port); + InetSocketAddress addr; + if (hostname == null){ + addr = new InetSocketAddress(port); + } + else{ + addr = new InetSocketAddress(hostname, port); + } httpServer = HttpServer.create(addr, 0); httpServer.createContext("/", new EchoHttpHandler()); @@ -168,7 +200,7 @@ public boolean tryPort(int port) { httpServer.start(); LOGGER.log(Level.INFO, - "HTTP server is listening on port {0}", port); + "HTTP server is listening on port {0} for {1}", new Object[]{port, hostname}); return true; } catch (IOException e) { LOGGER.log(Level.FINE, diff --git a/src/edu/umass/cs/gnsserver/httpserver/GNSHttpServer.java b/src/edu/umass/cs/gnsserver/httpserver/GNSHttpServer.java index 18fa980f5..422304769 100644 --- a/src/edu/umass/cs/gnsserver/httpserver/GNSHttpServer.java +++ b/src/edu/umass/cs/gnsserver/httpserver/GNSHttpServer.java @@ -106,12 +106,20 @@ public GNSHttpServer(int port, ClientRequestHandlerInterface requestHandler) { * @param port * @return true if it was started */ - public boolean tryPort(int port) { + public boolean tryPort(int port, String hostname) { try { - InetSocketAddress addr = new InetSocketAddress(port); + InetSocketAddress addr; + if (hostname == null){ + addr = new InetSocketAddress(port); + } + else{ + addr = new InetSocketAddress(hostname, port); + } httpServer = HttpServer.create(addr, 0); httpServer.createContext("/", new EchoHttpHandler()); + + //This line here is what differs from the parent class, it uses a different HTTP Handler. httpServer.createContext("/" + GNS_PATH, new DefaultHttpHandler()); httpServer.setExecutor(Executors.newCachedThreadPool()); httpServer.start(); diff --git a/test/edu/umass/cs/gnsclient/client/singletests/HttpClientTest.java b/test/edu/umass/cs/gnsclient/client/singletests/HttpClientTest.java index f95cf4df2..9b04df06d 100644 --- a/test/edu/umass/cs/gnsclient/client/singletests/HttpClientTest.java +++ b/test/edu/umass/cs/gnsclient/client/singletests/HttpClientTest.java @@ -43,7 +43,7 @@ @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class HttpClientTest extends DefaultGNSTest { - private HttpClient httpClient; + protected HttpClient httpClient; private static GuidEntry masterGuid; private static GuidEntry httpOneEntry; private static GuidEntry httpTwoEntry; diff --git a/test/edu/umass/cs/gnsclient/client/singletests/HttpProxyTest.java b/test/edu/umass/cs/gnsclient/client/singletests/HttpProxyTest.java index 20a91e917..a10167a3f 100644 --- a/test/edu/umass/cs/gnsclient/client/singletests/HttpProxyTest.java +++ b/test/edu/umass/cs/gnsclient/client/singletests/HttpProxyTest.java @@ -43,701 +43,12 @@ * GNSHttpProxy default. */ @FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class HttpProxyTest extends DefaultGNSTest { - - private HttpClient httpClient; - private static GuidEntry masterGuid; - private static GuidEntry httpOneEntry; - private static GuidEntry httpTwoEntry; - private static GuidEntry guidToDeleteEntry; - private static GuidEntry mygroupEntry; - private static final Set createdGuids = new HashSet<>(); +public class HttpProxyTest extends HttpClientTest { /** * */ public HttpProxyTest() { - if (httpClient == null) { - // This should look up the appropriate port somehow httpClient = new HttpClient("127.0.0.1", 8080); - } - } - - /** - * - */ - @Test - public void test_899_Http_CreateAccountGuid() { - try { - masterGuid = GuidUtils.getGUIDKeys(globalAccountName); - - } catch (Exception e) { - Utils.failWithStackTrace("Exception while creating master guid: ", e); - } - } - - /** - * - */ - @Test - public void test_900_Http_LookupGuid() { - try { - Assert.assertEquals(masterGuid.getGuid(), httpClient.lookupGuid(globalAccountName)); - } catch (IOException | ClientException e) { - Utils.failWithStackTrace("Exception in LookupGuid: ", e); - } - } - - /** - * - */ - @Test - public void test_901_Http_CreateGuids() { - try { - httpOneEntry = httpClient.guidCreate(masterGuid, "httpOneEntry" + RandomString.randomString(12)); - httpTwoEntry = httpClient.guidCreate(masterGuid, "httpTwoEntry" + RandomString.randomString(12)); - System.out.println("Created: " + httpOneEntry); - System.out.println("Created: " + httpTwoEntry); - } catch (IOException | ClientException | NoSuchAlgorithmException e) { - Utils.failWithStackTrace("Exception in Http_CreateFields: ", e); - } - } - - /** - * - */ - @Test - public void test_902_Http_RemoveACL() { - try { - // remove default read acces for this test - httpClient.aclRemove(AclAccessType.READ_WHITELIST, httpOneEntry, - GNSProtocol.ENTIRE_RECORD.toString(), GNSProtocol.ALL_GUIDS.toString()); - } catch (IOException | ClientException e) { - Utils.failWithStackTrace("Exception in Http_RemoveACL: ", e); - } - } - - /** - * - */ - @Test - public void test_910_Http_UpdateFields() { - try { - httpClient.fieldUpdate(httpOneEntry.getGuid(), "environment", "work", httpOneEntry); - httpClient.fieldUpdate(httpOneEntry.getGuid(), "ssn", "000-00-0000", httpOneEntry); - httpClient.fieldUpdate(httpOneEntry.getGuid(), "password", "666flapJack", httpOneEntry); - httpClient.fieldUpdate(httpOneEntry.getGuid(), "address", "100 Hinkledinkle Drive", httpOneEntry); - } catch (IOException | ClientException | JSONException e) { - Utils.failWithStackTrace("Exception in Http_UpdateFields: ", e); - } - } - - /** - * - */ - @Test - public void test_911_Http_CheckFields() { - try { - // read my own field - Assert.assertEquals("work", - httpClient.fieldRead(httpOneEntry.getGuid(), "environment", httpOneEntry)); - // read another field - Assert.assertEquals("000-00-0000", - httpClient.fieldRead(httpOneEntry.getGuid(), "ssn", httpOneEntry)); - // read another field - Assert.assertEquals("666flapJack", - httpClient.fieldRead(httpOneEntry.getGuid(), "password", httpOneEntry)); - } catch (IOException | ClientException e) { - Utils.failWithStackTrace("Exception in Http_CheckFields: ", e); - } - } - - /** - * - */ - @Test - public void test_913_Http_CheckFieldsFail() { - try { - try { - String result = httpClient.fieldRead(httpOneEntry.getGuid(), "environment", httpTwoEntry); - Utils.failWithStackTrace("Result of read of httpOneEntry's environment by httpTwoEntry is " + result - + " which is wrong because it should have been rejected."); - } catch (ClientException e) { - } catch (IOException e) { - Utils.failWithStackTrace("Exception during read of westy's environment by sam: ", e); - } - } catch (Exception e) { - Utils.failWithStackTrace("Exception in Http_CheckFieldsFail: ", e); - } - } - - /** - * - */ - @Test - public void test_920_Http_ACLAdd() { - try { - System.out.println("Using:" + httpOneEntry); - System.out.println("Using:" + httpTwoEntry); - try { - httpClient.aclAdd(AclAccessType.READ_WHITELIST, httpOneEntry, "environment", - httpTwoEntry.getGuid()); - } catch (IOException | ClientException e) { - Utils.failWithStackTrace("Exception adding Sam to Westy's readlist: ", e); - } - } catch (Exception e) { - Utils.failWithStackTrace("Exception in Http_ACLAdd: ", e); - } - } - - /** - * - */ - @Test - public void test_921_Http_CheckAccess() { - try { - try { - Assert.assertEquals("work", - httpClient.fieldRead(httpOneEntry.getGuid(), "environment", httpTwoEntry)); - } catch (IOException | ClientException e) { - Utils.failWithStackTrace("Exception while Sam reading Westy's field: ", e); - } - } catch (Exception e) { - Utils.failWithStackTrace("Exception in Http_CheckAccess: ", e); - } - } - - /** - * - */ - @Test - public void test_932_Update() { - try { - JSONObject json = new JSONObject(); - JSONObject subJson = new JSONObject(); - subJson.put("sally", "red"); - subJson.put("sammy", "green"); - JSONObject subsubJson = new JSONObject(); - subsubJson.put("right", "seven"); - subsubJson.put("left", "eight"); - subJson.put("sally", subsubJson); - json.put("flapjack", subJson); - httpClient.update(httpOneEntry, json); - } catch (JSONException | IOException | ClientException e) { - Utils.failWithStackTrace("Exception while adding field \"flapjack\": ", e); - } } - - /** - * - */ - @Test - public void test_933_ReadAll() { - try { - JSONObject expected = new JSONObject(); - JSONObject subJson = new JSONObject(); - subJson.put("sammy", "green"); - JSONObject subsubJson = new JSONObject(); - subsubJson.put("right", "seven"); - subsubJson.put("left", "eight"); - subJson.put("sally", subsubJson); - expected.put("flapjack", subJson); - expected.put("environment", "work"); - expected.put("ssn", "000-00-0000"); - expected.put("password", "666flapJack"); - expected.put("address", "100 Hinkledinkle Drive"); - JSONObject actual = httpClient.read(httpOneEntry); - JSONAssert.assertEquals(expected, actual, JSONCompareMode.NON_EXTENSIBLE); - //System.out.println(actual); - } catch (JSONException | IOException | ClientException e) { - Utils.failWithStackTrace("Exception while reading JSON: ", e); - } - } - - /** - * - */ - @Test - public void test_934_ReadDeep() { - try { - String actual = httpClient.fieldRead(httpOneEntry.getGuid(), "flapjack.sally.right", httpOneEntry); - Assert.assertEquals("seven", actual); - } catch (IOException | ClientException e) { - Utils.failWithStackTrace("Exception while reading \"flapjack.sally.right\": ", e); - } - } - - /** - * - */ - @Test - public void test_935_ReadMid() { - try { - String actual = httpClient.fieldRead(httpOneEntry.getGuid(), "flapjack.sally", httpOneEntry); - String expected = "{ \"left\" : \"eight\" , \"right\" : \"seven\"}"; - //System.out.println("expected:" + expected); - //System.out.println("actual:" + actual); - JSONAssert.assertEquals(expected, actual, JSONCompareMode.NON_EXTENSIBLE); - } catch (IOException | ClientException | JSONException e) { - Utils.failWithStackTrace("Exception while reading \"flapjack.sally\": ", e); - } - } - - /** - * - */ - @Test - public void test_936_ReadShallow() { - try { - String actual = httpClient.fieldRead(httpOneEntry.getGuid(), "flapjack", httpOneEntry); - String expected = "{ \"sammy\" : \"green\" , \"sally\" : { \"left\" : \"eight\" , \"right\" : \"seven\"}}"; - //System.out.println("expected:" + expected); - //System.out.println("actual:" + actual); - JSONAssert.assertEquals(expected, actual, JSONCompareMode.NON_EXTENSIBLE); - } catch (IOException | ClientException | JSONException e) { - Utils.failWithStackTrace("Exception while reading \"flapjack\": ", e); - } - } - - /** - * - */ - @Test - public void test_951_Http_createCats() { - try { - httpClient.fieldCreateSingleElementList(httpOneEntry.getGuid(), "cats", "whacky", httpOneEntry); - } catch (IOException | ClientException e) { - Utils.failWithStackTrace("Exception when we were not expecting testing cats: ", e); - } - } - - /** - * - */ - @Test - public void test_952_Http_testCats() { - try { - Assert.assertEquals("whacky", - httpClient.fieldReadFirstElement(httpOneEntry.getGuid(), "cats", httpOneEntry)); - } catch (IOException | ClientException e) { - Utils.failWithStackTrace("Exception when we were not expecting testing cats: ", e); - } - } - - /** - * - */ - @Test - public void test_953_Http_createMoreCats() { - try { - httpClient.fieldAppendWithSetSemantics(httpOneEntry.getGuid(), "cats", new JSONArray( - Arrays.asList("hooch", "maya", "red", "sox", "toby")), httpOneEntry); - - } catch (IOException | ClientException e) { - Utils.failWithStackTrace("Exception in createMoreCats: ", e); - } - } - - /** - * - */ - @Test - public void test_954_Http_checkMoreCats() { - try { - HashSet expected = new HashSet<>(Arrays.asList("hooch", - "maya", "red", "sox", "toby", "whacky")); - HashSet actual = JSONUtils.JSONArrayToHashSet(httpClient.fieldReadArray(httpOneEntry.getGuid(), - "cats", httpOneEntry)); - Assert.assertEquals(expected, actual); - - } catch (IOException | ClientException | JSONException e) { - Utils.failWithStackTrace("Exception in checkMoreCats: ", e); - } - } - - /** - * - */ - @Test - public void test_955_Http_clearCats() { - try { - httpClient.fieldClear(httpOneEntry.getGuid(), "cats", new JSONArray( - Arrays.asList("maya", "toby")), httpOneEntry); - } catch (IOException | ClientException e) { - Utils.failWithStackTrace("Exception in clearCats: ", e); - } - } - - /** - * - */ - @Test - public void test_956_Http_checkClearCats() { - try { - HashSet expected = new HashSet<>(Arrays.asList("hooch", "red", "sox", - "whacky")); - HashSet actual = JSONUtils.JSONArrayToHashSet(httpClient.fieldReadArray( - httpOneEntry.getGuid(), "cats", httpOneEntry)); - Assert.assertEquals(expected, actual); - - } catch (IOException | ClientException | JSONException e) { - Utils.failWithStackTrace("Exception in checkClearCats: ", e); - } - } - - /** - * - */ - @Test - public void test_957_Http_createEvenMoreCats() { - try { - httpClient.fieldAppendWithSetSemantics(httpOneEntry.getGuid(), "cats", "fred", httpOneEntry); - } catch (IOException | ClientException e) { - Utils.failWithStackTrace("Exception in createEvenMoreCats: ", e); - } - } - - /** - * - */ - @Test - public void test_958_Http_checkEvenMoreCats() { - try { - httpClient.fieldAppendWithSetSemantics(httpOneEntry.getGuid(), "cats", "fred", httpOneEntry); - HashSet expected = new HashSet<>(Arrays.asList("hooch", "red", "sox", - "whacky", "fred")); - HashSet actual = JSONUtils.JSONArrayToHashSet(httpClient.fieldReadArray( - httpOneEntry.getGuid(), "cats", httpOneEntry)); - Assert.assertEquals(expected, actual); - } catch (IOException | ClientException | JSONException e) { - Utils.failWithStackTrace("Exception in checkEvenMoreCats: ", e); - } - } - - /** - * - */ - @Test - public void test_960_Http_BasicSelect() { - try { - JSONArray result = httpClient.select("cats", "fred"); - // best we can do since there will be one, but possibly more objects in results - Assert.assertThat(result.length(), Matchers.greaterThanOrEqualTo(1)); - } catch (IOException | ClientException | JSONException e) { - Utils.failWithStackTrace("Exception when we were not expecting it: ", e); - } - } - - /** - * - */ - @Test - public void test_961_Http_GeoSpatialSelect() { - try { - for (int cnt = 0; cnt < 5; cnt++) { - GuidEntry testEntry = httpClient.guidCreate(masterGuid, "geoTest-" + RandomString.randomString(12)); - createdGuids.add(testEntry); // save them so we can delete them later - httpClient.setLocation(0.0, 0.0, testEntry); - } - } catch (IOException | ClientException | NoSuchAlgorithmException e) { - Utils.failWithStackTrace("Exception when we were not expecting it: ", e); - } - - try { - - JSONArray loc = new JSONArray(); - loc.put(1.0); - loc.put(1.0); - JSONArray result = httpClient.selectNear(GNSProtocol.LOCATION_FIELD_NAME.toString(), loc, 2000000.0); - // best we can do should be at least 5, but possibly more objects in results - Assert.assertThat(result.length(), Matchers.greaterThanOrEqualTo(5)); - } catch (JSONException | IOException | ClientException e) { - Utils.failWithStackTrace("Exception executing selectNear: ", e); - } - - try { - - JSONArray rect = new JSONArray(); - JSONArray upperLeft = new JSONArray(); - upperLeft.put(1.0); - upperLeft.put(1.0); - JSONArray lowerRight = new JSONArray(); - lowerRight.put(-1.0); - lowerRight.put(-1.0); - rect.put(upperLeft); - rect.put(lowerRight); - JSONArray result = httpClient.selectWithin(GNSProtocol.LOCATION_FIELD_NAME.toString(), rect); - // best we can do should be at least 5, but possibly more objects in results - Assert.assertThat(result.length(), Matchers.greaterThanOrEqualTo(5)); - } catch (JSONException | IOException | ClientException e) { - Utils.failWithStackTrace("Exception executing selectWithin: ", e); - } - } - - /** - * - */ - @Test - public void test_962_Http_QuerySelect() { - String fieldName = "testQuery"; - try { - for (int cnt = 0; cnt < 5; cnt++) { - GuidEntry testEntry = httpClient.guidCreate(masterGuid, "queryTest-" + RandomString.randomString(12)); - createdGuids.add(testEntry); // save them so we can delete them later - JSONArray array = new JSONArray(Arrays.asList(25)); - httpClient.fieldReplaceOrCreateList(testEntry.getGuid(), fieldName, array, testEntry); - } - } catch (IOException | ClientException | NoSuchAlgorithmException e) { - Utils.failWithStackTrace("Exception while tryint to create the guids: ", e); - } - - try { - String query = "~" + fieldName + " : ($gt: 0)"; - JSONArray result = httpClient.selectQuery(query); - for (int i = 0; i < result.length(); i++) { - System.out.println(result.get(i).toString()); - } - // best we can do should be at least 5, but possibly more objects in results - Assert.assertThat(result.length(), Matchers.greaterThanOrEqualTo(5)); - } catch (IOException | ClientException | JSONException e) { - Utils.failWithStackTrace("Exception executing selectNear: ", e); - } - - try { - - JSONArray rect = new JSONArray(); - JSONArray upperLeft = new JSONArray(); - upperLeft.put(1.0); - upperLeft.put(1.0); - JSONArray lowerRight = new JSONArray(); - lowerRight.put(-1.0); - lowerRight.put(-1.0); - rect.put(upperLeft); - rect.put(lowerRight); - JSONArray result = httpClient.selectWithin(GNSProtocol.LOCATION_FIELD_NAME.toString(), rect); - // best we can do should be at least 5, but possibly more objects in results - Assert.assertThat(result.length(), Matchers.greaterThanOrEqualTo(5)); - } catch (JSONException | IOException | ClientException e) { - Utils.failWithStackTrace("Exception executing selectWithin: ", e); - } - } - - private static String createIndexTestField; - - /** - * - */ - @Test - public void test_970_Http_CreateField() { - createIndexTestField = "testField" + RandomString.randomString(12); - try { - httpClient.fieldUpdate(masterGuid, createIndexTestField, createGeoJSONPolygon(AREA_EXTENT)); - } catch (JSONException | IOException | ClientException e) { - Utils.failWithStackTrace("Exception during create field: ", e); - } - } - - /** - * - */ - @Test - public void test_971_Http_CreateIndex() { - try { - httpClient.fieldCreateIndex(masterGuid, createIndexTestField, "2dsphere"); - } catch (IOException | ClientException | JSONException e) { - Utils.failWithStackTrace("Exception while creating index: ", e); - } - } - - /** - * - */ - @Test - public void test_972_Http_SelectPass() { - try { - JSONArray result = httpClient.selectQuery(buildQuery(createIndexTestField, AREA_EXTENT)); - for (int i = 0; i < result.length(); i++) { - System.out.println(result.get(i).toString()); - } - // best we can do should be at least 5, but possibly more objects in results - Assert.assertThat(result.length(), Matchers.greaterThanOrEqualTo(1)); - } catch (JSONException | IOException | ClientException e) { - Utils.failWithStackTrace("Exception executing second selectNear: ", e); - } - } - - /** - * - */ - @Test - public void test_980_Http_GroupCreate() { - String mygroupName = "mygroup" + RandomString.randomString(12); - try { - try { - httpClient.lookupGuid(mygroupName); - Utils.failWithStackTrace(mygroupName + " entity should not exist"); - } catch (ClientException e) { - } - guidToDeleteEntry = httpClient.guidCreate(masterGuid, "deleteMe" + RandomString.randomString(12)); - mygroupEntry = httpClient.guidCreate(masterGuid, mygroupName); - } catch (IOException | ClientException | NoSuchAlgorithmException e) { - Utils.failWithStackTrace("Exception while creating guids: ", e); - } - } - - /** - * - */ - @Test - public void test_981_Http_GroupAddHttpOne() { - try { - httpClient.groupAddGuid(mygroupEntry.getGuid(), httpOneEntry.getGuid(), mygroupEntry); - } catch (IOException | ClientException e) { - Utils.failWithStackTrace("Exception while adding Westy: ", e); - } - } - - /** - * - */ - @Test - public void test_982_GroupAddSam() { - try { - httpClient.groupAddGuid(mygroupEntry.getGuid(), httpTwoEntry.getGuid(), mygroupEntry); - } catch (IOException | ClientException e) { - Utils.failWithStackTrace("Exception while adding Sam: ", e); - } - } - - /** - * - */ - @Test - public void test_983_GroupAddGuidToDelete() { - try { - httpClient.groupAddGuid(mygroupEntry.getGuid(), guidToDeleteEntry.getGuid(), mygroupEntry); - } catch (IOException | ClientException e) { - Utils.failWithStackTrace("Exception while adding GuidToDelete: ", e); - } - } - - /** - * - */ - @Test - public void test_984_GroupAddCheck() { - try { - HashSet expected = new HashSet<>(Arrays.asList(httpOneEntry.getGuid(), httpTwoEntry.getGuid(), guidToDeleteEntry.getGuid())); - HashSet actual = JSONUtils.JSONArrayToHashSet(httpClient.groupGetMembers(mygroupEntry.getGuid(), mygroupEntry)); - Assert.assertEquals(expected, actual); - - expected = new HashSet<>(Arrays.asList(mygroupEntry.getGuid())); - actual = JSONUtils.JSONArrayToHashSet(httpClient.guidGetGroups(httpOneEntry.getGuid(), httpOneEntry)); - Assert.assertEquals(expected, actual); - - } catch (IOException | ClientException | JSONException e) { - Utils.failWithStackTrace("Exception while getting members and groups: ", e); - } - } - - /** - * - */ - @Test - public void test_985_GroupRemoveGuid() { - // now remove a guid and check for group updates - try { - httpClient.guidRemove(masterGuid, guidToDeleteEntry.getGuid()); - } catch (IOException | ClientException e) { - Utils.failWithStackTrace("Exception while removing testGuid: ", e); - } - try { - httpClient.lookupGuidRecord(guidToDeleteEntry.getGuid()); - Utils.failWithStackTrace("Lookup testGuid should have throw an exception."); - } catch (ClientException e) { - - } catch (IOException e) { - Utils.failWithStackTrace("Exception while doing Lookup testGuid: ", e); - } - } - - /** - * - */ - @Test - public void test_986_GroupRemoveCheck() { - try { - HashSet expected = new HashSet<>(Arrays.asList(httpOneEntry.getGuid(), httpTwoEntry.getGuid())); - HashSet actual = JSONUtils.JSONArrayToHashSet(httpClient.groupGetMembers(mygroupEntry.getGuid(), mygroupEntry)); - Assert.assertEquals(expected, actual); - - } catch (IOException | ClientException | JSONException e) { - Utils.failWithStackTrace("Exception during remove guid group update test: ", e); - System.exit(2); - } - } - - /* - * - */ - @Test - public void test_999_Cleanup() { - try { - httpClient.guidRemove(masterGuid, httpOneEntry.getGuid()); - httpClient.guidRemove(masterGuid, httpTwoEntry.getGuid()); - httpClient.guidRemove(masterGuid, mygroupEntry.getGuid()); - for (GuidEntry guid : createdGuids) { - httpClient.guidRemove(masterGuid, guid.getGuid()); - } - createdGuids.clear(); - } catch (ClientException | IOException e) { - Utils.failWithStackTrace("Exception while removing guids: " + e); - } - } - - // HELPER STUFF - private static final String POLYGON = "Polygon"; - private static final String COORDINATES = "coordinates"; - private static final String TYPE = "type"; - - private static JSONObject createGeoJSONPolygon(List coordinates) throws JSONException { - JSONArray ring = new JSONArray(); - for (int i = 0; i < coordinates.size(); i++) { - ring.put(i, new JSONArray( - Arrays.asList(coordinates.get(i).getX(), coordinates.get(i).getY()))); - } - JSONArray jsonCoordinates = new JSONArray(); - jsonCoordinates.put(0, ring); - JSONObject json = new JSONObject(); - json.put(TYPE, POLYGON); - json.put(COORDINATES, jsonCoordinates); - return json; - } - - private static final double LEFT = -98.08; - private static final double RIGHT = -96.01; - private static final double TOP = 33.635; - private static final double BOTTOM = 31.854; - - private static final Point2D UPPER_LEFT = new Point2D.Double(LEFT, TOP); - //private static final GlobalCoordinate UPPER_LEFT = new GlobalCoordinate(33.45, -98.08); - private static final Point2D UPPER_RIGHT = new Point2D.Double(RIGHT, TOP); - //private static final GlobalCoordinate UPPER_RIGHT = new GlobalCoordinate(33.45, -96.01); - private static final Point2D LOWER_RIGHT = new Point2D.Double(RIGHT, BOTTOM); - //private static final GlobalCoordinate LOWER_RIGHT = new GlobalCoordinate(32.23, -96.01); - private static final Point2D LOWER_LEFT = new Point2D.Double(LEFT, BOTTOM); - //private static final GlobalCoordinate LOWER_LEFT = new GlobalCoordinate(32.23, -98.08); - - private static final List AREA_EXTENT = new ArrayList<>( - Arrays.asList(UPPER_LEFT, UPPER_RIGHT, LOWER_RIGHT, LOWER_LEFT, UPPER_LEFT)); - - private static String buildQuery(String locationField, List coordinates) throws JSONException { - return "~" + locationField + ":{" - + "$geoIntersects :{" - + "$geometry:" - + createGeoJSONPolygon(coordinates).toString() - + "}" - + "}"; - } - -} +} \ No newline at end of file From 6a1383e21bd47d9ecd4bbd15eb3b1eacc3af2ec9 Mon Sep 17 00:00:00 2001 From: Brendan Teich Date: Mon, 30 Jan 2017 11:59:01 -0500 Subject: [PATCH 04/13] Changed the method header for tryport in GNSHttpsServer to include a hostname to match the header for GNSHttpProxy. --- src/edu/umass/cs/gnsserver/httpserver/GNSHttpsServer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/edu/umass/cs/gnsserver/httpserver/GNSHttpsServer.java b/src/edu/umass/cs/gnsserver/httpserver/GNSHttpsServer.java index fbf8ce247..1872fc232 100644 --- a/src/edu/umass/cs/gnsserver/httpserver/GNSHttpsServer.java +++ b/src/edu/umass/cs/gnsserver/httpserver/GNSHttpsServer.java @@ -82,7 +82,7 @@ public final void stop() { * @return true if it was started */ @Override - public boolean tryPort(int port) { + public boolean tryPort(int port, String hostname) { try { InetSocketAddress addr = new InetSocketAddress(port); httpsServer = HttpsServer.create(addr, 0); From 2db904baad3147549aba06c983cb04849a2a7714 Mon Sep 17 00:00:00 2001 From: Brendan Teich Date: Wed, 22 Feb 2017 19:55:47 -0500 Subject: [PATCH 05/13] Using eclipse indentation correction to make merging easier. --- .../gnsserver/httpserver/GNSHttpServer.java | 790 +++++++++--------- 1 file changed, 395 insertions(+), 395 deletions(-) diff --git a/src/edu/umass/cs/gnsserver/httpserver/GNSHttpServer.java b/src/edu/umass/cs/gnsserver/httpserver/GNSHttpServer.java index 0aaeec138..8a677adfa 100644 --- a/src/edu/umass/cs/gnsserver/httpserver/GNSHttpServer.java +++ b/src/edu/umass/cs/gnsserver/httpserver/GNSHttpServer.java @@ -81,399 +81,399 @@ */ public class GNSHttpServer { - /** - * - */ - protected static final String GNS_PATH = Config.getGlobalString(GNSConfig.GNSC.HTTP_SERVER_GNS_URL_PATH); - private HttpServer httpServer = null; - // handles command processing - private final CommandModule commandModule; - // newer handles command processing - private GNSClient client = null; - - /** - * - */ - protected final ClientRequestHandlerInterface requestHandler; - private final Date serverStartDate = new Date(); - - private final static Logger LOGGER = Logger.getLogger(GNSHttpServer.class.getName()); - - /** - * - * @param port - * @param requestHandler - */ - public GNSHttpServer(int port, ClientRequestHandlerInterface requestHandler) { - this.commandModule = new CommandModule(); - this.requestHandler = requestHandler; - if (!Config.getGlobalBoolean(GNSC.DISABLE_MULTI_SERVER_HTTP)) { - try { - this.client = new GNSClient() { - @Override - public String getLabel() { - return GNSHttpServer.class.getSimpleName(); - } - }; - } catch (IOException e) { - LOGGER.log(Level.SEVERE, "Unable to start GNS client:{0}", - e.getMessage()); - } - } - runServer(port); - } - - /** - * Start the server. - * - * @param startingPort - */ - public final void runServer(int startingPort) { - int cnt = 0; - do { - // Find the first port after starting port that actually works. - // Usually if 8080 is busy we can get 8081. - if (tryPort(startingPort + cnt)) { - break; - } - edu.umass.cs.utils.Util.suicide(GNSConfig.getLogger(), "Unable to start GNS HTTP server; exiting"); - } while (cnt++ < 100); - } - - /** - * Stop everything. - */ - public void stop() { - if (httpServer != null) { - httpServer.stop(0); - } - } - - /** - * Try to start the http server at the port. - * - * @param port - * @return true if it was started - */ - public boolean tryPort(int port) { - try { - InetSocketAddress addr = new InetSocketAddress(port); - httpServer = HttpServer.create(addr, 0); - - httpServer.createContext("/", new EchoHttpHandler()); - httpServer.createContext("/" + GNS_PATH, new DefaultHttpHandler()); - httpServer.setExecutor(Executors.newCachedThreadPool()); - httpServer.start(); - // Need to do this for the places where we expose the insecure http service to the user - requestHandler.setHttpServerPort(port); - LOGGER.log(Level.INFO, - "HTTP server is listening on port {0}", port); - return true; - } catch (IOException e) { - LOGGER.log(Level.FINE, - "HTTP server failed to start on port {0} due to {1}", - new Object[]{port, e.getMessage()}); - return false; - } - } - - /** - * The default handler. - */ - protected class DefaultHttpHandler implements HttpHandler { - /** - * - * @param exchange - */ - @Override - public void handle(HttpExchange exchange) { - try { - String requestMethod = exchange.getRequestMethod(); - if (requestMethod.equalsIgnoreCase("GET")) { - Headers requestHeaders = exchange.getRequestHeaders(); - String host = requestHeaders.getFirst("Host"); - Headers responseHeaders = exchange.getResponseHeaders(); - responseHeaders.set("Content-Type", "text/plain"); - exchange.sendResponseHeaders(HttpURLConnection.HTTP_OK, 0); - - try (OutputStream responseBody = exchange.getResponseBody()) { - URI uri = exchange.getRequestURI(); - LOGGER.log(Level.FINE, - "HTTP SERVER REQUEST FROM {0}: {1}", - new Object[]{exchange.getRemoteAddress().getHostName(), uri.toString()}); - String path = uri.getPath(); - String query = uri.getQuery() != null ? uri.getQuery() : ""; // stupidly it returns null for empty query - - String commandName = path.replaceFirst("/" + GNS_PATH + "/", ""); - - CommandResponse response; - if (!commandName.isEmpty()) { - LOGGER.log(Level.FINE, "Action: {0} Query:{1}", new Object[]{commandName, query}); - boolean secureServer = exchange instanceof HttpsExchange; - response = processQuery(host, commandName, query, secureServer); - } else { - response = new CommandResponse(ResponseCode.OPERATION_NOT_SUPPORTED, GNSProtocol.BAD_RESPONSE.toString() - + " " + GNSProtocol.OPERATION_NOT_SUPPORTED.toString() + " Don't understand " + commandName + " " + query); - } - LOGGER.log(Level.FINER, "Response: {0}", response); - // FIXME: This totally ignores the error code. - responseBody.write(response.getReturnValue().getBytes()); - } - } - } catch (Exception e) { - LOGGER.log(Level.SEVERE, "Error: {0}", e.getMessage()); - e.printStackTrace(); - try { - String response = GNSProtocol.BAD_RESPONSE.toString() + " " + GNSProtocol.QUERY_PROCESSING_ERROR.toString() + " " + e; - try (OutputStream responseBody = exchange.getResponseBody()) { - responseBody.write(response.getBytes()); - } - } catch (Exception f) { - // at this point screw it - } - } - } - } - - /* - * Process queries for the http service. Converts the URI of e the HTTP query into - * the JSON Object format that is used by the CommandModeule class, then finds - * executes the matching command. - * - * @throws InternalRequestException - */ - private CommandResponse processQuery(String host, String commandName, String queryString, boolean secureServer) throws InternalRequestException { - - // Convert the URI into a JSONObject, stuffing in some extra relevant fields like - // the signature, and the message signed. - try { - // Note that the commandName is not part of the queryString string here so - // it doesn't end up in the jsonCommand. Also see below where we put the - // command integer into the jsonCommand. - JSONObject jsonCommand = Util.parseURIQueryStringIntoJSONObject(queryString); - // If the signature exists it is Base64 encoded so decode it now. - if (jsonCommand.has(GNSProtocol.SIGNATURE.toString())) { - jsonCommand.put(GNSProtocol.SIGNATURE.toString(), - new String(Base64.decode(jsonCommand.getString(GNSProtocol.SIGNATURE.toString())), - GNSProtocol.CHARSET.toString())); - } - // getCommandForHttp allows for "dump" as well as "Dump" - CommandType commandType = CommandType.getCommandForHttp(commandName); - if (commandType == null) { - return new CommandResponse(ResponseCode.OPERATION_NOT_SUPPORTED, - GNSProtocol.BAD_RESPONSE.toString() + " " + GNSProtocol.OPERATION_NOT_SUPPORTED.toString() - + " Sorry, don't understand " + commandName + QUERYPREFIX + queryString); - } - - //Only allow mutual auth commands if we're on a secure (HTTPS) server - if (commandType.isMutualAuth() && !secureServer) { - return new CommandResponse(ResponseCode.OPERATION_NOT_SUPPORTED, - GNSProtocol.BAD_RESPONSE.toString() + " " + GNSProtocol.OPERATION_NOT_SUPPORTED.toString() - + " Not authorized to execute " + commandName + QUERYPREFIX + queryString); - } - - // The client currently just uses the command name (which is not part of the - // query string above) so we need to stuff - // in the Command integer for the signature check and execution. - jsonCommand.put(GNSProtocol.COMMAND_INT.toString(), commandType.getInt()); - // Optionally does some sanity checking on the message if that was enabled at the client. - // This makes necessary changes to the jsonCommand so don't remove this call - // unless you know what you're doing and also change the code in the HTTP client. - sanityCheckMessage(jsonCommand); - // Hair below is to handle some commands locally (creates, delets, selects, admin) - // and the rest by invoking the GNS client and sending them out. - // Client will be null if GNSC.DISABLE_MULTI_SERVER_HTTP (see above) - // is true (or there was a problem). - if (client == null || commandType.isLocallyHandled()) { - // EXECUTE IT LOCALLY - AbstractCommand command; - try { - command = commandModule.lookupCommand(commandType); - // Do some work to get the signature and message into the command for - // signature checking that happens later on. - // This only happens for local execution because remote handling (in the - // other side of the if) already does this. - processSignature(jsonCommand); - if (command != null) { - return CommandHandler.executeCommand(command, - new CommandPacket((long) (Math.random() * Long.MAX_VALUE), jsonCommand, false), - requestHandler); - } - LOGGER.log(Level.FINE, "lookupCommand returned null for {0}", commandName); - } catch (IllegalArgumentException e) { - LOGGER.log(Level.FINE, "lookupCommand failed for {0}", commandName); - } - return new CommandResponse(ResponseCode.OPERATION_NOT_SUPPORTED, - GNSProtocol.BAD_RESPONSE.toString() + " " + GNSProtocol.OPERATION_NOT_SUPPORTED.toString() - + " Sorry, don't understand " + commandName + QUERYPREFIX + queryString); - } else { - // Send the command remotely using a client - try { - LOGGER.log(Level.FINE, "Sending command out to a remote server: {0}", jsonCommand); - CommandPacket commandResponsePacket = getResponseUsingGNSClient(client, jsonCommand); - return new CommandResponse(ResponseCode.NO_ERROR, - // Some crap here to make single field reads return just the value for backward compatibility - // There is similar code to this other places. - specialCaseSingleFieldRead(commandResponsePacket.getResultString(), - commandType, jsonCommand)); - } catch (IOException | ClientException e) { - return new CommandResponse(ResponseCode.UNSPECIFIED_ERROR, GNSProtocol.BAD_RESPONSE.toString() + " " - + GNSProtocol.UNSPECIFIED_ERROR.toString() + " " + e.toString()); -// } catch (ClientException e) { -// return new CommandResponse(ResponseCode.GNSProtocol.UNSPECIFIED_ERROR.toString(), -// GNSProtocol.BAD_RESPONSE.toString() + " " + GNSProtocol.OPERATION_NOT_SUPPORTED.toString() -// + " Sorry, don't understand " + commandName + QUERYPREFIX + queryString); - } - } - } catch (JSONException | UnsupportedEncodingException e) { - return new CommandResponse(ResponseCode.UNSPECIFIED_ERROR, GNSProtocol.BAD_RESPONSE.toString() + " " - + GNSProtocol.UNSPECIFIED_ERROR.toString() + " " + e.toString()); - } - } - - private static void sanityCheckMessage(JSONObject jsonCommand) throws JSONException, - UnsupportedEncodingException { - if (jsonCommand.has("originalMessageBase64")) { - String originalMessage = new String(Base64.decode(jsonCommand.getString("originalMessageBase64")), - GNSProtocol.CHARSET.toString()); - jsonCommand.remove("originalMessageBase64"); - String commandSansSignature = CanonicalJSON.getCanonicalForm(jsonCommand); - if (!originalMessage.equals(commandSansSignature)) { - LOGGER.log(Level.SEVERE, "signature message mismatch! original: {0} computed for signature: {1}", - new Object[]{originalMessage, commandSansSignature}); - } else { - LOGGER.log(Level.FINE, "######## original: {0}", - originalMessage); - } - } - } - - private static void processSignature(JSONObject jsonCommand) throws JSONException { - if (jsonCommand.has(GNSProtocol.SIGNATURE.toString())) { - // Squirrel away the signature. - String signature = jsonCommand.getString(GNSProtocol.SIGNATURE.toString()); - // Pull it out of the command because we don't want to have it there when we check the message. - jsonCommand.remove(GNSProtocol.SIGNATURE.toString()); - // Convert it to a conanical string (the message) that we can use later to check against the signature. - String commandSansSignature = CanonicalJSON.getCanonicalForm(jsonCommand); - // Put the decoded signature back as well as the message that we're going to - // later compare the signature against. - jsonCommand.put(GNSProtocol.SIGNATURE.toString(), signature).put(GNSProtocol.SIGNATUREFULLMESSAGE.toString(), - commandSansSignature); - - } - } - - //make single field reads return just the value for backward compatibility - private static String specialCaseSingleFieldRead(String response, CommandType commandType, - JSONObject jsonFormattedArguments) { - try { - if (commandType.isRead() && jsonFormattedArguments.has(GNSProtocol.FIELD.toString()) - && !jsonFormattedArguments.getString(GNSProtocol.FIELD.toString()).equals(GNSProtocol.ENTIRE_RECORD.toString()) - && JSONPacket.couldBeJSON(response) && response.startsWith("{")) { - String key = jsonFormattedArguments.getString(GNSProtocol.FIELD.toString()); - JSONObject json = new JSONObject(response); - return json.getString(key); - } - } catch (JSONException e) { - LOGGER.log(Level.SEVERE, "Problem getting single key reponse for : {0}", e.getMessage()); - // just return the response if there is some issue - } - return response; - } - - private CommandPacket getResponseUsingGNSClient(GNSClient client, - JSONObject jsonFormattedArguments) throws ClientException, IOException, JSONException { - LOGGER.log(Level.FINE, "jsonFormattedCommand ={0}", jsonFormattedArguments.toString()); - - CommandPacket outgoingPacket = new CommandPacket((long) (Math.random() * Long.MAX_VALUE), jsonFormattedArguments, false); - //GNSCommand.createGNSCommandFromJSONObject(jsonFormattedArguments); - - LOGGER.log(Level.FINE, "outgoingPacket ={0}", outgoingPacket.toString()); - - CommandPacket returnPacket = client.execute(outgoingPacket); - - LOGGER.log(Level.FINE, "returnPacket ={0}", returnPacket.toString()); - /** - * Can also invoke getResponse(), getResponseString(), getResponseJSONObject() - * etc. on {@link CommandPacket} as documented in {@link GNSCommand}. - */ - return returnPacket; - - } - - /** - * Returns info about the server. - */ - protected class EchoHttpHandler implements HttpHandler { - - /** - * - * @param exchange - * @throws IOException - */ - @Override - public void handle(HttpExchange exchange) throws IOException { - String requestMethod = exchange.getRequestMethod(); - if (requestMethod.equalsIgnoreCase("GET")) { - Headers responseHeaders = exchange.getResponseHeaders(); - responseHeaders.set("Content-Type", "text/HTML"); - exchange.sendResponseHeaders(200, 0); - - try (OutputStream responseBody = exchange.getResponseBody()) { - Headers requestHeaders = exchange.getRequestHeaders(); - Set keySet = requestHeaders.keySet(); - Iterator iter = keySet.iterator(); - - String buildVersion = GNSConfig.readBuildVersion(); - String buildVersionInfo = "Build Version: Unable to lookup!"; - if (buildVersion != null) { - buildVersionInfo = "Build Version: " + buildVersion; - } - String responsePreamble = "GNS Server Status

"; - String responsePostamble = "

"; - String serverStartDateString = "Server start time: " + Format.formatDualDate(serverStartDate); - String serverUpTimeString = "Server uptime: " + DurationFormatUtils.formatDurationWords(new Date().getTime() - serverStartDate.getTime(), true, true); - String serverSSLMode = "Server SSL mode: " + ReconfigurationConfig.getServerSSLMode().toString(); - String clientSSLMode = "Client SSL mode: " + ReconfigurationConfig.getClientSSLMode().toString(); - String reconAddresses = "Recon addresses: " + ReconfigurationConfig.getReconfiguratorAddresses().toString(); - String numberOfNameServers = "Server count: " + requestHandler.getGnsNodeConfig().getNumberOfNodes(); - String recordsClass = "Records Class: " + GNSConfig.GNSC.getNoSqlRecordsClass(); - String secureString = exchange instanceof HttpsExchange ? "Security: Secure" : "Security: Open"; - // Build the response - responseBody.write(responsePreamble.getBytes()); - responseBody.write(buildVersionInfo.getBytes()); - responseBody.write("
".getBytes()); - responseBody.write(serverStartDateString.getBytes()); - responseBody.write("
".getBytes()); - responseBody.write(serverUpTimeString.getBytes()); - responseBody.write("
".getBytes()); - responseBody.write(numberOfNameServers.getBytes()); - responseBody.write("
".getBytes()); - responseBody.write(reconAddresses.getBytes()); - responseBody.write("
".getBytes()); - responseBody.write(serverSSLMode.getBytes()); - responseBody.write("
".getBytes()); - responseBody.write(clientSSLMode.getBytes()); - responseBody.write("
".getBytes()); - responseBody.write(secureString.getBytes()); - responseBody.write("
".getBytes()); - - responseBody.write(recordsClass.getBytes()); - responseBody.write("
".getBytes()); - responseBody.write("
".getBytes()); - responseBody.write("Request Headers:".getBytes()); - responseBody.write("
".getBytes()); - while (iter.hasNext()) { - String key = iter.next(); - List values = requestHeaders.get(key); - String s = key + " = " + values.toString() + "\n"; - responseBody.write(s.getBytes()); - responseBody.write("
".getBytes()); - } - responseBody.write(responsePostamble.getBytes()); - } - } - } - } + /** + * + */ + protected static final String GNS_PATH = Config.getGlobalString(GNSConfig.GNSC.HTTP_SERVER_GNS_URL_PATH); + private HttpServer httpServer = null; + // handles command processing + private final CommandModule commandModule; + // newer handles command processing + private GNSClient client = null; + + /** + * + */ + protected final ClientRequestHandlerInterface requestHandler; + private final Date serverStartDate = new Date(); + + private final static Logger LOGGER = Logger.getLogger(GNSHttpServer.class.getName()); + + /** + * + * @param port + * @param requestHandler + */ + public GNSHttpServer(int port, ClientRequestHandlerInterface requestHandler) { + this.commandModule = new CommandModule(); + this.requestHandler = requestHandler; + if (!Config.getGlobalBoolean(GNSC.DISABLE_MULTI_SERVER_HTTP)) { + try { + this.client = new GNSClient() { + @Override + public String getLabel() { + return GNSHttpServer.class.getSimpleName(); + } + }; + } catch (IOException e) { + LOGGER.log(Level.SEVERE, "Unable to start GNS client:{0}", + e.getMessage()); + } + } + runServer(port); + } + + /** + * Start the server. + * + * @param startingPort + */ + public final void runServer(int startingPort) { + int cnt = 0; + do { + // Find the first port after starting port that actually works. + // Usually if 8080 is busy we can get 8081. + if (tryPort(startingPort + cnt)) { + break; + } + edu.umass.cs.utils.Util.suicide(GNSConfig.getLogger(), "Unable to start GNS HTTP server; exiting"); + } while (cnt++ < 100); + } + + /** + * Stop everything. + */ + public void stop() { + if (httpServer != null) { + httpServer.stop(0); + } + } + + /** + * Try to start the http server at the port. + * + * @param port + * @return true if it was started + */ + public boolean tryPort(int port) { + try { + InetSocketAddress addr = new InetSocketAddress(port); + httpServer = HttpServer.create(addr, 0); + + httpServer.createContext("/", new EchoHttpHandler()); + httpServer.createContext("/" + GNS_PATH, new DefaultHttpHandler()); + httpServer.setExecutor(Executors.newCachedThreadPool()); + httpServer.start(); + // Need to do this for the places where we expose the insecure http service to the user + requestHandler.setHttpServerPort(port); + LOGGER.log(Level.INFO, + "HTTP server is listening on port {0}", port); + return true; + } catch (IOException e) { + LOGGER.log(Level.FINE, + "HTTP server failed to start on port {0} due to {1}", + new Object[]{port, e.getMessage()}); + return false; + } + } + + /** + * The default handler. + */ + protected class DefaultHttpHandler implements HttpHandler { + /** + * + * @param exchange + */ + @Override + public void handle(HttpExchange exchange) { + try { + String requestMethod = exchange.getRequestMethod(); + if (requestMethod.equalsIgnoreCase("GET")) { + Headers requestHeaders = exchange.getRequestHeaders(); + String host = requestHeaders.getFirst("Host"); + Headers responseHeaders = exchange.getResponseHeaders(); + responseHeaders.set("Content-Type", "text/plain"); + exchange.sendResponseHeaders(HttpURLConnection.HTTP_OK, 0); + + try (OutputStream responseBody = exchange.getResponseBody()) { + URI uri = exchange.getRequestURI(); + LOGGER.log(Level.FINE, + "HTTP SERVER REQUEST FROM {0}: {1}", + new Object[]{exchange.getRemoteAddress().getHostName(), uri.toString()}); + String path = uri.getPath(); + String query = uri.getQuery() != null ? uri.getQuery() : ""; // stupidly it returns null for empty query + + String commandName = path.replaceFirst("/" + GNS_PATH + "/", ""); + + CommandResponse response; + if (!commandName.isEmpty()) { + LOGGER.log(Level.FINE, "Action: {0} Query:{1}", new Object[]{commandName, query}); + boolean secureServer = exchange instanceof HttpsExchange; + response = processQuery(host, commandName, query, secureServer); + } else { + response = new CommandResponse(ResponseCode.OPERATION_NOT_SUPPORTED, GNSProtocol.BAD_RESPONSE.toString() + + " " + GNSProtocol.OPERATION_NOT_SUPPORTED.toString() + " Don't understand " + commandName + " " + query); + } + LOGGER.log(Level.FINER, "Response: {0}", response); + // FIXME: This totally ignores the error code. + responseBody.write(response.getReturnValue().getBytes()); + } + } + } catch (Exception e) { + LOGGER.log(Level.SEVERE, "Error: {0}", e.getMessage()); + e.printStackTrace(); + try { + String response = GNSProtocol.BAD_RESPONSE.toString() + " " + GNSProtocol.QUERY_PROCESSING_ERROR.toString() + " " + e; + try (OutputStream responseBody = exchange.getResponseBody()) { + responseBody.write(response.getBytes()); + } + } catch (Exception f) { + // at this point screw it + } + } + } + } + + /* + * Process queries for the http service. Converts the URI of e the HTTP query into + * the JSON Object format that is used by the CommandModeule class, then finds + * executes the matching command. + * + * @throws InternalRequestException + */ + private CommandResponse processQuery(String host, String commandName, String queryString, boolean secureServer) throws InternalRequestException { + + // Convert the URI into a JSONObject, stuffing in some extra relevant fields like + // the signature, and the message signed. + try { + // Note that the commandName is not part of the queryString string here so + // it doesn't end up in the jsonCommand. Also see below where we put the + // command integer into the jsonCommand. + JSONObject jsonCommand = Util.parseURIQueryStringIntoJSONObject(queryString); + // If the signature exists it is Base64 encoded so decode it now. + if (jsonCommand.has(GNSProtocol.SIGNATURE.toString())) { + jsonCommand.put(GNSProtocol.SIGNATURE.toString(), + new String(Base64.decode(jsonCommand.getString(GNSProtocol.SIGNATURE.toString())), + GNSProtocol.CHARSET.toString())); + } + // getCommandForHttp allows for "dump" as well as "Dump" + CommandType commandType = CommandType.getCommandForHttp(commandName); + if (commandType == null) { + return new CommandResponse(ResponseCode.OPERATION_NOT_SUPPORTED, + GNSProtocol.BAD_RESPONSE.toString() + " " + GNSProtocol.OPERATION_NOT_SUPPORTED.toString() + + " Sorry, don't understand " + commandName + QUERYPREFIX + queryString); + } + + //Only allow mutual auth commands if we're on a secure (HTTPS) server + if (commandType.isMutualAuth() && !secureServer) { + return new CommandResponse(ResponseCode.OPERATION_NOT_SUPPORTED, + GNSProtocol.BAD_RESPONSE.toString() + " " + GNSProtocol.OPERATION_NOT_SUPPORTED.toString() + + " Not authorized to execute " + commandName + QUERYPREFIX + queryString); + } + + // The client currently just uses the command name (which is not part of the + // query string above) so we need to stuff + // in the Command integer for the signature check and execution. + jsonCommand.put(GNSProtocol.COMMAND_INT.toString(), commandType.getInt()); + // Optionally does some sanity checking on the message if that was enabled at the client. + // This makes necessary changes to the jsonCommand so don't remove this call + // unless you know what you're doing and also change the code in the HTTP client. + sanityCheckMessage(jsonCommand); + // Hair below is to handle some commands locally (creates, delets, selects, admin) + // and the rest by invoking the GNS client and sending them out. + // Client will be null if GNSC.DISABLE_MULTI_SERVER_HTTP (see above) + // is true (or there was a problem). + if (client == null || commandType.isLocallyHandled()) { + // EXECUTE IT LOCALLY + AbstractCommand command; + try { + command = commandModule.lookupCommand(commandType); + // Do some work to get the signature and message into the command for + // signature checking that happens later on. + // This only happens for local execution because remote handling (in the + // other side of the if) already does this. + processSignature(jsonCommand); + if (command != null) { + return CommandHandler.executeCommand(command, + new CommandPacket((long) (Math.random() * Long.MAX_VALUE), jsonCommand, false), + requestHandler); + } + LOGGER.log(Level.FINE, "lookupCommand returned null for {0}", commandName); + } catch (IllegalArgumentException e) { + LOGGER.log(Level.FINE, "lookupCommand failed for {0}", commandName); + } + return new CommandResponse(ResponseCode.OPERATION_NOT_SUPPORTED, + GNSProtocol.BAD_RESPONSE.toString() + " " + GNSProtocol.OPERATION_NOT_SUPPORTED.toString() + + " Sorry, don't understand " + commandName + QUERYPREFIX + queryString); + } else { + // Send the command remotely using a client + try { + LOGGER.log(Level.FINE, "Sending command out to a remote server: {0}", jsonCommand); + CommandPacket commandResponsePacket = getResponseUsingGNSClient(client, jsonCommand); + return new CommandResponse(ResponseCode.NO_ERROR, + // Some crap here to make single field reads return just the value for backward compatibility + // There is similar code to this other places. + specialCaseSingleFieldRead(commandResponsePacket.getResultString(), + commandType, jsonCommand)); + } catch (IOException | ClientException e) { + return new CommandResponse(ResponseCode.UNSPECIFIED_ERROR, GNSProtocol.BAD_RESPONSE.toString() + " " + + GNSProtocol.UNSPECIFIED_ERROR.toString() + " " + e.toString()); + // } catch (ClientException e) { + // return new CommandResponse(ResponseCode.GNSProtocol.UNSPECIFIED_ERROR.toString(), + // GNSProtocol.BAD_RESPONSE.toString() + " " + GNSProtocol.OPERATION_NOT_SUPPORTED.toString() + // + " Sorry, don't understand " + commandName + QUERYPREFIX + queryString); + } + } + } catch (JSONException | UnsupportedEncodingException e) { + return new CommandResponse(ResponseCode.UNSPECIFIED_ERROR, GNSProtocol.BAD_RESPONSE.toString() + " " + + GNSProtocol.UNSPECIFIED_ERROR.toString() + " " + e.toString()); + } + } + + private static void sanityCheckMessage(JSONObject jsonCommand) throws JSONException, + UnsupportedEncodingException { + if (jsonCommand.has("originalMessageBase64")) { + String originalMessage = new String(Base64.decode(jsonCommand.getString("originalMessageBase64")), + GNSProtocol.CHARSET.toString()); + jsonCommand.remove("originalMessageBase64"); + String commandSansSignature = CanonicalJSON.getCanonicalForm(jsonCommand); + if (!originalMessage.equals(commandSansSignature)) { + LOGGER.log(Level.SEVERE, "signature message mismatch! original: {0} computed for signature: {1}", + new Object[]{originalMessage, commandSansSignature}); + } else { + LOGGER.log(Level.FINE, "######## original: {0}", + originalMessage); + } + } + } + + private static void processSignature(JSONObject jsonCommand) throws JSONException { + if (jsonCommand.has(GNSProtocol.SIGNATURE.toString())) { + // Squirrel away the signature. + String signature = jsonCommand.getString(GNSProtocol.SIGNATURE.toString()); + // Pull it out of the command because we don't want to have it there when we check the message. + jsonCommand.remove(GNSProtocol.SIGNATURE.toString()); + // Convert it to a conanical string (the message) that we can use later to check against the signature. + String commandSansSignature = CanonicalJSON.getCanonicalForm(jsonCommand); + // Put the decoded signature back as well as the message that we're going to + // later compare the signature against. + jsonCommand.put(GNSProtocol.SIGNATURE.toString(), signature).put(GNSProtocol.SIGNATUREFULLMESSAGE.toString(), + commandSansSignature); + + } + } + + //make single field reads return just the value for backward compatibility + private static String specialCaseSingleFieldRead(String response, CommandType commandType, + JSONObject jsonFormattedArguments) { + try { + if (commandType.isRead() && jsonFormattedArguments.has(GNSProtocol.FIELD.toString()) + && !jsonFormattedArguments.getString(GNSProtocol.FIELD.toString()).equals(GNSProtocol.ENTIRE_RECORD.toString()) + && JSONPacket.couldBeJSON(response) && response.startsWith("{")) { + String key = jsonFormattedArguments.getString(GNSProtocol.FIELD.toString()); + JSONObject json = new JSONObject(response); + return json.getString(key); + } + } catch (JSONException e) { + LOGGER.log(Level.SEVERE, "Problem getting single key reponse for : {0}", e.getMessage()); + // just return the response if there is some issue + } + return response; + } + + private CommandPacket getResponseUsingGNSClient(GNSClient client, + JSONObject jsonFormattedArguments) throws ClientException, IOException, JSONException { + LOGGER.log(Level.FINE, "jsonFormattedCommand ={0}", jsonFormattedArguments.toString()); + + CommandPacket outgoingPacket = new CommandPacket((long) (Math.random() * Long.MAX_VALUE), jsonFormattedArguments, false); + //GNSCommand.createGNSCommandFromJSONObject(jsonFormattedArguments); + + LOGGER.log(Level.FINE, "outgoingPacket ={0}", outgoingPacket.toString()); + + CommandPacket returnPacket = client.execute(outgoingPacket); + + LOGGER.log(Level.FINE, "returnPacket ={0}", returnPacket.toString()); + /** + * Can also invoke getResponse(), getResponseString(), getResponseJSONObject() + * etc. on {@link CommandPacket} as documented in {@link GNSCommand}. + */ + return returnPacket; + + } + + /** + * Returns info about the server. + */ + protected class EchoHttpHandler implements HttpHandler { + + /** + * + * @param exchange + * @throws IOException + */ + @Override + public void handle(HttpExchange exchange) throws IOException { + String requestMethod = exchange.getRequestMethod(); + if (requestMethod.equalsIgnoreCase("GET")) { + Headers responseHeaders = exchange.getResponseHeaders(); + responseHeaders.set("Content-Type", "text/HTML"); + exchange.sendResponseHeaders(200, 0); + + try (OutputStream responseBody = exchange.getResponseBody()) { + Headers requestHeaders = exchange.getRequestHeaders(); + Set keySet = requestHeaders.keySet(); + Iterator iter = keySet.iterator(); + + String buildVersion = GNSConfig.readBuildVersion(); + String buildVersionInfo = "Build Version: Unable to lookup!"; + if (buildVersion != null) { + buildVersionInfo = "Build Version: " + buildVersion; + } + String responsePreamble = "GNS Server Status

"; + String responsePostamble = "

"; + String serverStartDateString = "Server start time: " + Format.formatDualDate(serverStartDate); + String serverUpTimeString = "Server uptime: " + DurationFormatUtils.formatDurationWords(new Date().getTime() - serverStartDate.getTime(), true, true); + String serverSSLMode = "Server SSL mode: " + ReconfigurationConfig.getServerSSLMode().toString(); + String clientSSLMode = "Client SSL mode: " + ReconfigurationConfig.getClientSSLMode().toString(); + String reconAddresses = "Recon addresses: " + ReconfigurationConfig.getReconfiguratorAddresses().toString(); + String numberOfNameServers = "Server count: " + requestHandler.getGnsNodeConfig().getNumberOfNodes(); + String recordsClass = "Records Class: " + GNSConfig.GNSC.getNoSqlRecordsClass(); + String secureString = exchange instanceof HttpsExchange ? "Security: Secure" : "Security: Open"; + // Build the response + responseBody.write(responsePreamble.getBytes()); + responseBody.write(buildVersionInfo.getBytes()); + responseBody.write("
".getBytes()); + responseBody.write(serverStartDateString.getBytes()); + responseBody.write("
".getBytes()); + responseBody.write(serverUpTimeString.getBytes()); + responseBody.write("
".getBytes()); + responseBody.write(numberOfNameServers.getBytes()); + responseBody.write("
".getBytes()); + responseBody.write(reconAddresses.getBytes()); + responseBody.write("
".getBytes()); + responseBody.write(serverSSLMode.getBytes()); + responseBody.write("
".getBytes()); + responseBody.write(clientSSLMode.getBytes()); + responseBody.write("
".getBytes()); + responseBody.write(secureString.getBytes()); + responseBody.write("
".getBytes()); + + responseBody.write(recordsClass.getBytes()); + responseBody.write("
".getBytes()); + responseBody.write("
".getBytes()); + responseBody.write("Request Headers:".getBytes()); + responseBody.write("
".getBytes()); + while (iter.hasNext()) { + String key = iter.next(); + List values = requestHeaders.get(key); + String s = key + " = " + values.toString() + "\n"; + responseBody.write(s.getBytes()); + responseBody.write("
".getBytes()); + } + responseBody.write(responsePostamble.getBytes()); + } + } + } + } } From 6d4c7d8aedb533fb0d56dadc8934ff016e75a83f Mon Sep 17 00:00:00 2001 From: Brendan Teich Date: Wed, 22 Feb 2017 19:59:16 -0500 Subject: [PATCH 06/13] Using Eclipse's correct indentation function to make merging easier. --- src/edu/umass/cs/gnsserver/httpserver/GNSHttpServer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/edu/umass/cs/gnsserver/httpserver/GNSHttpServer.java b/src/edu/umass/cs/gnsserver/httpserver/GNSHttpServer.java index 422304769..24182ce25 100644 --- a/src/edu/umass/cs/gnsserver/httpserver/GNSHttpServer.java +++ b/src/edu/umass/cs/gnsserver/httpserver/GNSHttpServer.java @@ -98,7 +98,7 @@ public GNSHttpServer(int port, ClientRequestHandlerInterface requestHandler) { } runServer(port); } - + /** * Try to start the http server at the port. @@ -118,7 +118,7 @@ public boolean tryPort(int port, String hostname) { httpServer = HttpServer.create(addr, 0); httpServer.createContext("/", new EchoHttpHandler()); - + //This line here is what differs from the parent class, it uses a different HTTP Handler. httpServer.createContext("/" + GNS_PATH, new DefaultHttpHandler()); httpServer.setExecutor(Executors.newCachedThreadPool()); From 5e1821d1be0ae8791e945090e2fb7b6191c8b3b2 Mon Sep 17 00:00:00 2001 From: Brendan Teich Date: Wed, 22 Feb 2017 20:21:32 -0500 Subject: [PATCH 07/13] Finished merging in the master branch. --- .../gnsserver/httpserver/GNSHttpServer.java | 33 ------------------- 1 file changed, 33 deletions(-) diff --git a/src/edu/umass/cs/gnsserver/httpserver/GNSHttpServer.java b/src/edu/umass/cs/gnsserver/httpserver/GNSHttpServer.java index 1fe5895dc..a0da5fb54 100644 --- a/src/edu/umass/cs/gnsserver/httpserver/GNSHttpServer.java +++ b/src/edu/umass/cs/gnsserver/httpserver/GNSHttpServer.java @@ -291,22 +291,6 @@ private CommandResponse processQuery(String host, String commandName, String que } } - private static void sanityCheckMessage(JSONObject jsonCommand) throws JSONException, - UnsupportedEncodingException { - if (jsonCommand.has("originalMessageBase64")) { - String originalMessage = new String(Base64.decode(jsonCommand.getString("originalMessageBase64")), - GNSProtocol.CHARSET.toString()); - jsonCommand.remove("originalMessageBase64"); - String commandSansSignature = CanonicalJSON.getCanonicalForm(jsonCommand); - if (!originalMessage.equals(commandSansSignature)) { - LOGGER.log(Level.SEVERE, "signature message mismatch! original: {0} computed for signature: {1}", - new Object[]{originalMessage, commandSansSignature}); - } else { - LOGGER.log(Level.FINE, "######## original: {0}", - originalMessage); - } - } - } private static void processSignature(JSONObject jsonCommand) throws JSONException { if (jsonCommand.has(GNSProtocol.SIGNATURE.toString())) { @@ -324,23 +308,6 @@ private static void processSignature(JSONObject jsonCommand) throws JSONExceptio } } - //make single field reads return just the value for backward compatibility - private static String specialCaseSingleFieldRead(String response, CommandType commandType, - JSONObject jsonFormattedArguments) { - try { - if (commandType.isRead() && jsonFormattedArguments.has(GNSProtocol.FIELD.toString()) - && !jsonFormattedArguments.getString(GNSProtocol.FIELD.toString()).equals(GNSProtocol.ENTIRE_RECORD.toString()) - && JSONPacket.couldBeJSON(response) && response.startsWith("{")) { - String key = jsonFormattedArguments.getString(GNSProtocol.FIELD.toString()); - JSONObject json = new JSONObject(response); - return json.getString(key); - } - } catch (JSONException e) { - LOGGER.log(Level.SEVERE, "Problem getting single key reponse for : {0}", e.getMessage()); - // just return the response if there is some issue - } - return response; - } private CommandPacket getResponseUsingGNSClient(GNSClient client, JSONObject jsonFormattedArguments) throws ClientException, IOException, JSONException { From 860b6264e18ffaf645a000937c3af344c27b2110 Mon Sep 17 00:00:00 2001 From: Brendan Teich Date: Thu, 23 Feb 2017 14:38:32 -0500 Subject: [PATCH 08/13] Moved configuration settings from GNSHttpProxy to GNSClientConfig according to coding standards. --- .../cs/gnsclient/client/GNSClientConfig.java | 15 ++++++++++++++- .../cs/gnsserver/httpserver/GNSHttpProxy.java | 7 +++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/edu/umass/cs/gnsclient/client/GNSClientConfig.java b/src/edu/umass/cs/gnsclient/client/GNSClientConfig.java index 395562cca..e93bf5f89 100644 --- a/src/edu/umass/cs/gnsclient/client/GNSClientConfig.java +++ b/src/edu/umass/cs/gnsclient/client/GNSClientConfig.java @@ -87,7 +87,20 @@ public static enum GNSCC implements Config.ConfigurableEnum { /** * The port used by the local name server. */ - LOCAL_NAME_SERVER_PORT(24398); + LOCAL_NAME_SERVER_PORT(24398), + + //HTTP Proxy Settings + /** + * The port that GNSHttpProxy listens for incoming commands on. + */ + HTTP_PROXY_PORT(8080), + + /** + * The hostname that GNSHttpProxy will allow incoming commands from. + * By default this is localhost so it will only allow commands from the local machine. + * If set to 0.0.0.0 it will allow commands from any source host. + */ + HTTP_PROXY_INCOMING_HOSTNAME("localhost"); final Object defaultValue; diff --git a/src/edu/umass/cs/gnsserver/httpserver/GNSHttpProxy.java b/src/edu/umass/cs/gnsserver/httpserver/GNSHttpProxy.java index 7e814d2cc..785c7c921 100644 --- a/src/edu/umass/cs/gnsserver/httpserver/GNSHttpProxy.java +++ b/src/edu/umass/cs/gnsserver/httpserver/GNSHttpProxy.java @@ -29,6 +29,7 @@ import com.sun.net.httpserver.HttpServer; import edu.umass.cs.gnsclient.client.GNSClient; +import edu.umass.cs.gnsclient.client.GNSClientConfig.GNSCC; import edu.umass.cs.gnscommon.CommandType; import edu.umass.cs.gnsserver.main.GNSConfig; @@ -121,10 +122,8 @@ public String getLabel() { * and executed them using a GNSClient. */ public static void main(String[] args){ - String portString = System.getProperty("gnsProxy.port", "8080"); - int port = Integer.parseInt(portString); - - String hostname = System.getProperty("gnsProxy.remoteHostname", "localhost"); + int port = Config.getGlobalInt(GNSCC.HTTP_PROXY_PORT); + String hostname = Config.getGlobalString(GNSCC.HTTP_PROXY_INCOMING_HOSTNAME); GNSHttpProxy proxy = new GNSHttpProxy(); From 89d10ad0ac2fab39135ffd42f193b41a75755901 Mon Sep 17 00:00:00 2001 From: Brendan Teich Date: Wed, 1 Mar 2017 02:37:34 -0500 Subject: [PATCH 09/13] Refactored more of the GNSHttpServer into GNSHttpProxy, and updated HttpProxyTest to automatically create a GNSHttpProxy when run. --- .../cs/gnsserver/httpserver/GNSHttpProxy.java | 272 +++++++++------ .../gnsserver/httpserver/GNSHttpServer.java | 321 +++--------------- .../gnsserver/httpserver/GNSHttpsServer.java | 4 +- .../client/singletests/HttpProxyTest.java | 28 +- 4 files changed, 239 insertions(+), 386 deletions(-) diff --git a/src/edu/umass/cs/gnsserver/httpserver/GNSHttpProxy.java b/src/edu/umass/cs/gnsserver/httpserver/GNSHttpProxy.java index 785c7c921..a082822ef 100644 --- a/src/edu/umass/cs/gnsserver/httpserver/GNSHttpProxy.java +++ b/src/edu/umass/cs/gnsserver/httpserver/GNSHttpProxy.java @@ -27,6 +27,7 @@ import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; +import com.sun.net.httpserver.HttpsExchange; import edu.umass.cs.gnsclient.client.GNSClient; import edu.umass.cs.gnsclient.client.GNSClientConfig.GNSCC; @@ -46,6 +47,7 @@ import edu.umass.cs.gnscommon.ResponseCode; import static edu.umass.cs.gnsserver.httpserver.Defs.QUERYPREFIX; +import edu.umass.cs.gnsserver.gnsapp.clientCommandProcessor.commands.AbstractCommand; import edu.umass.cs.gnsserver.gnsapp.clientCommandProcessor.commands.CommandModule; import edu.umass.cs.gnscommon.exceptions.client.ClientException; import edu.umass.cs.gnscommon.exceptions.server.InternalRequestException; @@ -53,12 +55,14 @@ import edu.umass.cs.gnscommon.utils.Base64; import edu.umass.cs.gnscommon.utils.CanonicalJSON; import edu.umass.cs.gnscommon.utils.Format; +import edu.umass.cs.gnsserver.gnsapp.clientCommandProcessor.commandSupport.CommandHandler; import edu.umass.cs.gnsserver.gnsapp.clientCommandProcessor.commandSupport.CommandResponse; import edu.umass.cs.gnsserver.utils.Util; import edu.umass.cs.nio.JSONPacket; import edu.umass.cs.reconfiguration.ReconfigurationConfig; import edu.umass.cs.utils.Config; +import java.util.ArrayList; import java.util.Date; import java.util.logging.Level; import java.util.logging.Logger; @@ -90,6 +94,8 @@ public class GNSHttpProxy { protected final CommandModule commandModule; // newer handles command processing protected GNSClient client = null; + protected DefaultHttpHandler httpHandler; + protected EchoHttpProxyHandler echoHandler; /** * @@ -105,6 +111,8 @@ public class GNSHttpProxy { */ public GNSHttpProxy() { this.commandModule = new CommandModule(); + this.httpHandler = new DefaultHttpHandler(); + this.echoHandler = new EchoHttpProxyHandler(); try { this.client = new GNSClient() { public String getLabel() { @@ -193,8 +201,8 @@ public boolean tryPort(int port, String hostname) { } httpServer = HttpServer.create(addr, 0); - httpServer.createContext("/", new EchoHttpHandler()); - httpServer.createContext("/" + GNS_PATH, new ProxyHttpHandler()); + httpServer.createContext("/", echoHandler); + httpServer.createContext("/" + GNS_PATH, httpHandler); httpServer.setExecutor(Executors.newCachedThreadPool()); httpServer.start(); @@ -212,7 +220,7 @@ public boolean tryPort(int port, String hostname) { /** * The default handler. */ - protected class ProxyHttpHandler implements HttpHandler { + protected class DefaultHttpHandler implements HttpHandler { /** * @@ -229,43 +237,55 @@ public void handle(HttpExchange exchange) { responseHeaders.set("Content-Type", "text/plain"); exchange.sendResponseHeaders(HttpURLConnection.HTTP_OK, 0); - OutputStream responseBody = exchange.getResponseBody(); - - URI uri = exchange.getRequestURI(); - LOGGER.log(Level.FINE, - "HTTP SERVER REQUEST FROM {0}: {1}", new Object[]{exchange.getRemoteAddress().getHostName(), uri.toString()}); - String path = uri.getPath(); - String query = uri.getQuery() != null ? uri.getQuery() : ""; // stupidly it returns null for empty query - - String commandName = path.replaceFirst("/" + GNS_PATH + "/", ""); - - CommandResponse response; - if (!commandName.isEmpty()) { - LOGGER.log(Level.FINE, "Action: {0} Query:{1}", new Object[]{commandName, query}); - response = processQuery(host, commandName, query); - } else { - response = new CommandResponse(ResponseCode.OPERATION_NOT_SUPPORTED, GNSProtocol.BAD_RESPONSE.toString() - + " " + GNSProtocol.OPERATION_NOT_SUPPORTED.toString() + " Don't understand " + commandName + " " + query); + try (OutputStream responseBody = exchange.getResponseBody()) { + URI uri = exchange.getRequestURI(); + LOGGER.log(Level.FINE, + "HTTP SERVER REQUEST FROM {0}: {1}", + new Object[]{exchange.getRemoteAddress().getHostName(), uri.toString()}); + String path = uri.getPath(); + String query = uri.getQuery() != null ? uri.getQuery() : ""; // stupidly it returns null for empty query + + String commandName = path.replaceFirst("/" + GNS_PATH + "/", ""); + + CommandResponse response; + if (!commandName.isEmpty()) { + LOGGER.log(Level.FINE, "Action: {0} Query:{1}", new Object[]{commandName, query}); + boolean secureServer = exchange instanceof HttpsExchange; + response = processQuery(host, commandName, query, secureServer); + } else { + response = new CommandResponse(ResponseCode.OPERATION_NOT_SUPPORTED, GNSProtocol.BAD_RESPONSE.toString() + + " " + GNSProtocol.OPERATION_NOT_SUPPORTED.toString() + " Don't understand " + commandName + " " + query); + } + LOGGER.log(Level.FINER, "Response: {0}", response); + // FIXME: This totally ignores the error code. + responseBody.write(response.getReturnValue().getBytes()); } - LOGGER.log(Level.FINER, "Response: " + response); - // FIXME: This totally ignores the error code. - responseBody.write(response.getReturnValue().getBytes()); - responseBody.close(); } } catch (Exception e) { - LOGGER.log(Level.SEVERE, "Error: " + e); + LOGGER.log(Level.SEVERE, "Error: {0}", e.getMessage()); e.printStackTrace(); try { String response = GNSProtocol.BAD_RESPONSE.toString() + " " + GNSProtocol.QUERY_PROCESSING_ERROR.toString() + " " + e; - OutputStream responseBody = exchange.getResponseBody(); - responseBody.write(response.getBytes()); - responseBody.close(); + try (OutputStream responseBody = exchange.getResponseBody()) { + responseBody.write(response.getBytes()); + } } catch (Exception f) { // at this point screw it } } } } + + /** + * In GNSHttpProxy this does nothing since it does not handle local commands. + * However, children of this class (such as GNSHttpServer) + * may override this in order to execute commands locally. + * + */ + protected CommandResponse handleCommandLocally(JSONObject jsonCommand, + CommandType commandType, String commandName, String queryString) throws JSONException{ + throw new UnsupportedOperationException("GNSHttpProxy cannot execute commands locally."); + } /** * Process queries for the http service. Converts the URI of e the HTTP query into @@ -274,7 +294,8 @@ public void handle(HttpExchange exchange) { * * @throws InternalRequestException */ - protected CommandResponse processQuery(String host, String commandName, String queryString) throws InternalRequestException { + protected CommandResponse processQuery(String host, String commandName, String queryString, boolean secureServer) throws InternalRequestException { + // Convert the URI into a JSONObject, stuffing in some extra relevant fields like // the signature, and the message signed. try { @@ -295,6 +316,14 @@ protected CommandResponse processQuery(String host, String commandName, String q GNSProtocol.BAD_RESPONSE.toString() + " " + GNSProtocol.OPERATION_NOT_SUPPORTED.toString() + " Sorry, don't understand " + commandName + QUERYPREFIX + queryString); } + + //Only allow mutual auth commands if we're on a secure (HTTPS) server + if (commandType.isMutualAuth() && !secureServer) { + return new CommandResponse(ResponseCode.OPERATION_NOT_SUPPORTED, + GNSProtocol.BAD_RESPONSE.toString() + " " + GNSProtocol.OPERATION_NOT_SUPPORTED.toString() + + " Not authorized to execute " + commandName + QUERYPREFIX + queryString); + } + // The client currently just uses the command name (which is not part of the // query string above) so we need to stuff // in the Command integer for the signature check and execution. @@ -303,27 +332,28 @@ protected CommandResponse processQuery(String host, String commandName, String q // This makes necessary changes to the jsonCommand so don't remove this call // unless you know what you're doing and also change the code in the HTTP client. sanityCheckMessage(jsonCommand); - // This proxy invokes the GNS client to send commands out. - - - // Send the command remotely using a client - try { - LOGGER.log(Level.FINE, "Sending command out to a remote server: " + jsonCommand); - CommandPacket commandResponsePacket = getResponseUsingGNSClient(client, jsonCommand); - return new CommandResponse(ResponseCode.NO_ERROR, - // Some crap here to make single field reads return just the value for backward compatibility - // There is similar code to this other places. - specialCaseSingleFieldRead(commandResponsePacket.getResultString(), - commandType, jsonCommand)); - } catch (IOException | ClientException e) { - return new CommandResponse(ResponseCode.UNSPECIFIED_ERROR, GNSProtocol.BAD_RESPONSE.toString() + " " - + GNSProtocol.UNSPECIFIED_ERROR.toString() + " " + e.toString()); - // } catch (ClientException e) { - // return new CommandResponse(ResponseCode.GNSProtocol.UNSPECIFIED_ERROR.toString(), - // GNSProtocol.BAD_RESPONSE.toString() + " " + GNSProtocol.OPERATION_NOT_SUPPORTED.toString() - // + " Sorry, don't understand " + commandName + QUERYPREFIX + queryString); + // Hair below is to handle some commands locally (creates, delets, selects, admin) + // and the rest by invoking the GNS client and sending them out. + // Client will be null if GNSC.DISABLE_MULTI_SERVER_HTTP (see above) + // is true (or there was a problem). + if (client == null || commandType.isLocallyHandled()) { + // EXECUTE IT LOCALLY + return handleCommandLocally(jsonCommand, commandType, commandName, queryString); + } else { + // Send the command remotely using a client + try { + LOGGER.log(Level.FINE, "Sending command out to a remote server: {0}", jsonCommand); + CommandPacket commandResponsePacket = getResponseUsingGNSClient(client, jsonCommand); + return new CommandResponse(ResponseCode.NO_ERROR, + // Some crap here to make single field reads return just the value for backward compatibility + // There is similar code to this other places. + specialCaseSingleFieldRead(commandResponsePacket.getResultString(), + commandType, jsonCommand)); + } catch (IOException | ClientException e) { + return new CommandResponse(ResponseCode.UNSPECIFIED_ERROR, GNSProtocol.BAD_RESPONSE.toString() + " " + + GNSProtocol.UNSPECIFIED_ERROR.toString() + " " + e.toString()); + } } - } catch (JSONException | UnsupportedEncodingException e) { return new CommandResponse(ResponseCode.UNSPECIFIED_ERROR, GNSProtocol.BAD_RESPONSE.toString() + " " + GNSProtocol.UNSPECIFIED_ERROR.toString() + " " + e.toString()); @@ -365,7 +395,7 @@ protected static String specialCaseSingleFieldRead(String response, CommandType return response; } - private CommandPacket getResponseUsingGNSClient(GNSClient client, + protected CommandPacket getResponseUsingGNSClient(GNSClient client, JSONObject jsonFormattedArguments) throws ClientException, IOException, JSONException { LOGGER.log(Level.FINE, "jsonFormattedCommand =" + jsonFormattedArguments.toString()); @@ -384,11 +414,41 @@ private CommandPacket getResponseUsingGNSClient(GNSClient client, return returnPacket; } + + protected static void processSignature(JSONObject jsonCommand) throws JSONException { + if (jsonCommand.has(GNSProtocol.SIGNATURE.toString())) { + // Squirrel away the signature. + String signature = jsonCommand.getString(GNSProtocol.SIGNATURE.toString()); + // Pull it out of the command because we don't want to have it there when we check the message. + jsonCommand.remove(GNSProtocol.SIGNATURE.toString()); + // Convert it to a conanical string (the message) that we can use later to check against the signature. + String commandSansSignature = CanonicalJSON.getCanonicalForm(jsonCommand); + // Put the decoded signature back as well as the message that we're going to + // later compare the signature against. + jsonCommand.put(GNSProtocol.SIGNATURE.toString(), signature).put(GNSProtocol.SIGNATUREFULLMESSAGE.toString(), + commandSansSignature); + + } + } /** * Returns info about the server. */ - protected class EchoHttpHandler implements HttpHandler { + protected class EchoHttpProxyHandler implements HttpHandler { + + /** + * Any strings in the list returned by this method will be printed in the echo response. + * This method may be overridden in children classes that wish to add more information to + * the response body. + * @return + */ + protected List getAdditionalInformation(){ + List info = new ArrayList(0); + + //Put additional information here, or override this method in a subclass. + + return info; + } /** * @@ -403,61 +463,67 @@ public void handle(HttpExchange exchange) throws IOException { responseHeaders.set("Content-Type", "text/HTML"); exchange.sendResponseHeaders(200, 0); - OutputStream responseBody = exchange.getResponseBody(); - Headers requestHeaders = exchange.getRequestHeaders(); - Set keySet = requestHeaders.keySet(); - Iterator iter = keySet.iterator(); + try (OutputStream responseBody = exchange.getResponseBody()) { + Headers requestHeaders = exchange.getRequestHeaders(); + Set keySet = requestHeaders.keySet(); + Iterator iter = keySet.iterator(); - String buildVersion = GNSConfig.readBuildVersion(); - String buildVersionInfo = "Build Version: Unable to lookup!"; - if (buildVersion != null) { - buildVersionInfo = "Build Version: " + buildVersion; - } - String responsePreamble = "GNS Server Status

"; - String responsePostamble = "

"; - String serverStartDateString = "Server start time: " + Format.formatDualDate(serverStartDate); - String serverUpTimeString = "Server uptime: " + DurationFormatUtils.formatDurationWords(new Date().getTime() - serverStartDate.getTime(), true, true); - String serverSSLMode = "Server SSL mode: " + ReconfigurationConfig.getServerSSLMode().toString(); - String clientSSLMode = "Client SSL mode: " + ReconfigurationConfig.getClientSSLMode().toString(); - String reconAddresses = "Recon addresses: " + ReconfigurationConfig.getReconfiguratorAddresses().toString(); - - String recordsClass = "Records Class: " + GNSConfig.GNSC.getNoSqlRecordsClass(); - - // Build the response - responseBody.write(responsePreamble.getBytes()); - responseBody.write(buildVersionInfo.getBytes()); - responseBody.write("
".getBytes()); - responseBody.write(serverStartDateString.getBytes()); - responseBody.write("
".getBytes()); - responseBody.write(serverUpTimeString.getBytes()); - responseBody.write("
".getBytes()); - responseBody.write(reconAddresses.getBytes()); - responseBody.write("
".getBytes()); - responseBody.write(serverSSLMode.getBytes()); - responseBody.write("
".getBytes()); - responseBody.write(clientSSLMode.getBytes()); - responseBody.write("
".getBytes()); - - // responseBody.write(nodeAddressesString.getBytes()); - // responseBody.write("
".getBytes()); - // responseBody.write(reconfiguratorsString.getBytes()); - // responseBody.write("
".getBytes()); - // responseBody.write(activeReplicasString.getBytes()); - // responseBody.write("
".getBytes()); - responseBody.write(recordsClass.getBytes()); - responseBody.write("
".getBytes()); - responseBody.write("
".getBytes()); - responseBody.write("Request Headers:".getBytes()); - responseBody.write("
".getBytes()); - while (iter.hasNext()) { - String key = iter.next(); - List values = requestHeaders.get(key); - String s = key + " = " + values.toString() + "\n"; - responseBody.write(s.getBytes()); + String buildVersion = GNSConfig.readBuildVersion(); + String buildVersionInfo = "Build Version: Unable to lookup!"; + if (buildVersion != null) { + buildVersionInfo = "Build Version: " + buildVersion; + } + String responsePreamble = "GNS Server Status

"; + String responsePostamble = "

"; + String serverStartDateString = "Server start time: " + Format.formatDualDate(serverStartDate); + String serverUpTimeString = "Server uptime: " + DurationFormatUtils.formatDurationWords(new Date().getTime() - serverStartDate.getTime(), true, true); + String serverSSLMode = "Server SSL mode: " + ReconfigurationConfig.getServerSSLMode().toString(); + String clientSSLMode = "Client SSL mode: " + ReconfigurationConfig.getClientSSLMode().toString(); + String reconAddresses = "Recon addresses: " + ReconfigurationConfig.getReconfiguratorAddresses().toString(); + + + String recordsClass = "Records Class: " + GNSConfig.GNSC.getNoSqlRecordsClass(); + String secureString = exchange instanceof HttpsExchange ? "Security: Secure" : "Security: Open"; + // Build the response + responseBody.write(responsePreamble.getBytes()); + responseBody.write(buildVersionInfo.getBytes()); + responseBody.write("
".getBytes()); + responseBody.write(serverStartDateString.getBytes()); responseBody.write("
".getBytes()); + responseBody.write(serverUpTimeString.getBytes()); + responseBody.write("
".getBytes()); + + //Get any additional (child class) information + List additonalInformation = getAdditionalInformation(); + + for (String info : additonalInformation){ + responseBody.write(info.getBytes()); + responseBody.write("
".getBytes()); + } + + responseBody.write(reconAddresses.getBytes()); + responseBody.write("
".getBytes()); + responseBody.write(serverSSLMode.getBytes()); + responseBody.write("
".getBytes()); + responseBody.write(clientSSLMode.getBytes()); + responseBody.write("
".getBytes()); + responseBody.write(secureString.getBytes()); + responseBody.write("
".getBytes()); + responseBody.write(recordsClass.getBytes()); + responseBody.write("
".getBytes()); + responseBody.write("
".getBytes()); + responseBody.write("Request Headers:".getBytes()); + responseBody.write("
".getBytes()); + while (iter.hasNext()) { + String key = iter.next(); + List values = requestHeaders.get(key); + String s = key + " = " + values.toString() + "\n"; + responseBody.write(s.getBytes()); + responseBody.write("
".getBytes()); + } + responseBody.write(responsePostamble.getBytes()); + } - responseBody.write(responsePostamble.getBytes()); - responseBody.close(); } } } diff --git a/src/edu/umass/cs/gnsserver/httpserver/GNSHttpServer.java b/src/edu/umass/cs/gnsserver/httpserver/GNSHttpServer.java index a0da5fb54..365af57f4 100644 --- a/src/edu/umass/cs/gnsserver/httpserver/GNSHttpServer.java +++ b/src/edu/umass/cs/gnsserver/httpserver/GNSHttpServer.java @@ -60,6 +60,7 @@ import edu.umass.cs.reconfiguration.ReconfigurationConfig; import edu.umass.cs.utils.Config; +import java.util.ArrayList; import java.util.Date; import java.util.logging.Level; import java.util.logging.Logger; @@ -94,6 +95,7 @@ public class GNSHttpServer extends GNSHttpProxy{ */ public GNSHttpServer(int port, ClientRequestHandlerInterface requestHandler) { super(); + echoHandler = new EchoHttpServerHandler(); this.requestHandler = requestHandler; if (Config.getGlobalBoolean(GNSC.DISABLE_MULTI_SERVER_HTTP)) { client.close(); @@ -103,236 +105,48 @@ public GNSHttpServer(int port, ClientRequestHandlerInterface requestHandler) { } - /** - * Try to start the http server at the port. - * - * @param port - * @return true if it was started - */ - public boolean tryPort(int port, String hostname) { - try { - InetSocketAddress addr; - if (hostname == null){ - addr = new InetSocketAddress(port); - } - else{ - addr = new InetSocketAddress(hostname, port); - } - httpServer = HttpServer.create(addr, 0); - - httpServer.createContext("/", new EchoHttpHandler()); - //This line here is what differs from the parent class, it uses a different HTTP Handler. - httpServer.createContext("/" + GNS_PATH, new DefaultHttpHandler()); - httpServer.setExecutor(Executors.newCachedThreadPool()); - httpServer.start(); - - LOGGER.log(Level.INFO, - "HTTP server is listening on port {0}", port); - return true; - } catch (IOException e) { - LOGGER.log(Level.FINE, - "HTTP server failed to start on port {0} due to {1}", - new Object[]{port, e.getMessage()}); - return false; - } - } - - /** - * The default handler. - */ - protected class DefaultHttpHandler extends ProxyHttpHandler { - /** - * - * @param exchange - */ - @Override - public void handle(HttpExchange exchange) { - try { - String requestMethod = exchange.getRequestMethod(); - if (requestMethod.equalsIgnoreCase("GET")) { - Headers requestHeaders = exchange.getRequestHeaders(); - String host = requestHeaders.getFirst("Host"); - Headers responseHeaders = exchange.getResponseHeaders(); - responseHeaders.set("Content-Type", "text/plain"); - exchange.sendResponseHeaders(HttpURLConnection.HTTP_OK, 0); - - try (OutputStream responseBody = exchange.getResponseBody()) { - URI uri = exchange.getRequestURI(); - LOGGER.log(Level.FINE, - "HTTP SERVER REQUEST FROM {0}: {1}", - new Object[]{exchange.getRemoteAddress().getHostName(), uri.toString()}); - String path = uri.getPath(); - String query = uri.getQuery() != null ? uri.getQuery() : ""; // stupidly it returns null for empty query - String commandName = path.replaceFirst("/" + GNS_PATH + "/", ""); - CommandResponse response; - if (!commandName.isEmpty()) { - LOGGER.log(Level.FINE, "Action: {0} Query:{1}", new Object[]{commandName, query}); - boolean secureServer = exchange instanceof HttpsExchange; - response = processQuery(host, commandName, query, secureServer); - } else { - response = new CommandResponse(ResponseCode.OPERATION_NOT_SUPPORTED, GNSProtocol.BAD_RESPONSE.toString() - + " " + GNSProtocol.OPERATION_NOT_SUPPORTED.toString() + " Don't understand " + commandName + " " + query); - } - LOGGER.log(Level.FINER, "Response: {0}", response); - // FIXME: This totally ignores the error code. - responseBody.write(response.getReturnValue().getBytes()); - } - } - } catch (Exception e) { - LOGGER.log(Level.SEVERE, "Error: {0}", e.getMessage()); - e.printStackTrace(); - try { - String response = GNSProtocol.BAD_RESPONSE.toString() + " " + GNSProtocol.QUERY_PROCESSING_ERROR.toString() + " " + e; - try (OutputStream responseBody = exchange.getResponseBody()) { - responseBody.write(response.getBytes()); - } - } catch (Exception f) { - // at this point screw it - } - } - } - } - - /* - * Process queries for the http service. Converts the URI of e the HTTP query into - * the JSON Object format that is used by the CommandModeule class, then finds - * executes the matching command. - * - * @throws InternalRequestException - */ - private CommandResponse processQuery(String host, String commandName, String queryString, boolean secureServer) throws InternalRequestException { - - // Convert the URI into a JSONObject, stuffing in some extra relevant fields like - // the signature, and the message signed. +/** + * Executes the command with the given information locally. + * @param jsonCommand The JSONObject containing the command. + * @param commandType The CommandType of the command. + * @param commandName The name of the command. + * @return + * @throws JSONException + */ + protected CommandResponse handleCommandLocally(JSONObject jsonCommand, + CommandType commandType, String commandName, String queryString) throws JSONException{ + AbstractCommand command; try { - // Note that the commandName is not part of the queryString string here so - // it doesn't end up in the jsonCommand. Also see below where we put the - // command integer into the jsonCommand. - JSONObject jsonCommand = Util.parseURIQueryStringIntoJSONObject(queryString); - // If the signature exists it is Base64 encoded so decode it now. - if (jsonCommand.has(GNSProtocol.SIGNATURE.toString())) { - jsonCommand.put(GNSProtocol.SIGNATURE.toString(), - new String(Base64.decode(jsonCommand.getString(GNSProtocol.SIGNATURE.toString())), - GNSProtocol.CHARSET.toString())); - } - // getCommandForHttp allows for "dump" as well as "Dump" - CommandType commandType = CommandType.getCommandForHttp(commandName); - if (commandType == null) { - return new CommandResponse(ResponseCode.OPERATION_NOT_SUPPORTED, - GNSProtocol.BAD_RESPONSE.toString() + " " + GNSProtocol.OPERATION_NOT_SUPPORTED.toString() - + " Sorry, don't understand " + commandName + QUERYPREFIX + queryString); + command = commandModule.lookupCommand(commandType); + // Do some work to get the signature and message into the command for + // signature checking that happens later on. + // This only happens for local execution because remote handling (in the + // other side of the if) already does this. + processSignature(jsonCommand); + if (command != null) { + return CommandHandler.executeCommand(command, + new CommandPacket((long) (Math.random() * Long.MAX_VALUE), jsonCommand, false), + requestHandler); } - - //Only allow mutual auth commands if we're on a secure (HTTPS) server - if (commandType.isMutualAuth() && !secureServer) { - return new CommandResponse(ResponseCode.OPERATION_NOT_SUPPORTED, - GNSProtocol.BAD_RESPONSE.toString() + " " + GNSProtocol.OPERATION_NOT_SUPPORTED.toString() - + " Not authorized to execute " + commandName + QUERYPREFIX + queryString); - } - - // The client currently just uses the command name (which is not part of the - // query string above) so we need to stuff - // in the Command integer for the signature check and execution. - jsonCommand.put(GNSProtocol.COMMAND_INT.toString(), commandType.getInt()); - // Optionally does some sanity checking on the message if that was enabled at the client. - // This makes necessary changes to the jsonCommand so don't remove this call - // unless you know what you're doing and also change the code in the HTTP client. - sanityCheckMessage(jsonCommand); - // Hair below is to handle some commands locally (creates, delets, selects, admin) - // and the rest by invoking the GNS client and sending them out. - // Client will be null if GNSC.DISABLE_MULTI_SERVER_HTTP (see above) - // is true (or there was a problem). - if (client == null || commandType.isLocallyHandled()) { - // EXECUTE IT LOCALLY - AbstractCommand command; - try { - command = commandModule.lookupCommand(commandType); - // Do some work to get the signature and message into the command for - // signature checking that happens later on. - // This only happens for local execution because remote handling (in the - // other side of the if) already does this. - processSignature(jsonCommand); - if (command != null) { - return CommandHandler.executeCommand(command, - new CommandPacket((long) (Math.random() * Long.MAX_VALUE), jsonCommand, false), - requestHandler); - } - LOGGER.log(Level.FINE, "lookupCommand returned null for {0}", commandName); - } catch (IllegalArgumentException e) { - LOGGER.log(Level.FINE, "lookupCommand failed for {0}", commandName); - } - return new CommandResponse(ResponseCode.OPERATION_NOT_SUPPORTED, - GNSProtocol.BAD_RESPONSE.toString() + " " + GNSProtocol.OPERATION_NOT_SUPPORTED.toString() - + " Sorry, don't understand " + commandName + QUERYPREFIX + queryString); - } else { - // Send the command remotely using a client - try { - LOGGER.log(Level.FINE, "Sending command out to a remote server: {0}", jsonCommand); - CommandPacket commandResponsePacket = getResponseUsingGNSClient(client, jsonCommand); - return new CommandResponse(ResponseCode.NO_ERROR, - // Some crap here to make single field reads return just the value for backward compatibility - // There is similar code to this other places. - specialCaseSingleFieldRead(commandResponsePacket.getResultString(), - commandType, jsonCommand)); - } catch (IOException | ClientException e) { - return new CommandResponse(ResponseCode.UNSPECIFIED_ERROR, GNSProtocol.BAD_RESPONSE.toString() + " " - + GNSProtocol.UNSPECIFIED_ERROR.toString() + " " + e.toString()); - // } catch (ClientException e) { - // return new CommandResponse(ResponseCode.GNSProtocol.UNSPECIFIED_ERROR.toString(), - // GNSProtocol.BAD_RESPONSE.toString() + " " + GNSProtocol.OPERATION_NOT_SUPPORTED.toString() - // + " Sorry, don't understand " + commandName + QUERYPREFIX + queryString); - } - } - } catch (JSONException | UnsupportedEncodingException e) { - return new CommandResponse(ResponseCode.UNSPECIFIED_ERROR, GNSProtocol.BAD_RESPONSE.toString() + " " - + GNSProtocol.UNSPECIFIED_ERROR.toString() + " " + e.toString()); - } - } - - - private static void processSignature(JSONObject jsonCommand) throws JSONException { - if (jsonCommand.has(GNSProtocol.SIGNATURE.toString())) { - // Squirrel away the signature. - String signature = jsonCommand.getString(GNSProtocol.SIGNATURE.toString()); - // Pull it out of the command because we don't want to have it there when we check the message. - jsonCommand.remove(GNSProtocol.SIGNATURE.toString()); - // Convert it to a conanical string (the message) that we can use later to check against the signature. - String commandSansSignature = CanonicalJSON.getCanonicalForm(jsonCommand); - // Put the decoded signature back as well as the message that we're going to - // later compare the signature against. - jsonCommand.put(GNSProtocol.SIGNATURE.toString(), signature).put(GNSProtocol.SIGNATUREFULLMESSAGE.toString(), - commandSansSignature); - + LOGGER.log(Level.FINE, "lookupCommand returned null for {0}", commandName); + } catch (IllegalArgumentException e) { + LOGGER.log(Level.FINE, "lookupCommand failed for {0}", commandName); } + return new CommandResponse(ResponseCode.OPERATION_NOT_SUPPORTED, + GNSProtocol.BAD_RESPONSE.toString() + " " + GNSProtocol.OPERATION_NOT_SUPPORTED.toString() + + " Sorry, don't understand " + commandName + QUERYPREFIX + queryString); } - private CommandPacket getResponseUsingGNSClient(GNSClient client, - JSONObject jsonFormattedArguments) throws ClientException, IOException, JSONException { - LOGGER.log(Level.FINE, "jsonFormattedCommand ={0}", jsonFormattedArguments.toString()); - - CommandPacket outgoingPacket = new CommandPacket((long) (Math.random() * Long.MAX_VALUE), jsonFormattedArguments, false); - //GNSCommand.createGNSCommandFromJSONObject(jsonFormattedArguments); - - LOGGER.log(Level.FINE, "outgoingPacket ={0}", outgoingPacket.toString()); - - CommandPacket returnPacket = client.execute(outgoingPacket); - - LOGGER.log(Level.FINE, "returnPacket ={0}", returnPacket.toString()); - /** - * Can also invoke getResponse(), getResponseString(), getResponseJSONObject() - * etc. on {@link CommandPacket} as documented in {@link GNSCommand}. - */ - return returnPacket; - - } /** - * Returns info about the server. + * Returns info about the server. This overrides the getAdditionalInformation method + * of its parent echoHttpProxyHandler in order to print the number of name servers + * in echo http replies. */ - protected class EchoHttpHandler implements HttpHandler { + protected class EchoHttpServerHandler extends EchoHttpProxyHandler { /** * @@ -340,67 +154,14 @@ protected class EchoHttpHandler implements HttpHandler { * @throws IOException */ @Override - public void handle(HttpExchange exchange) throws IOException { - String requestMethod = exchange.getRequestMethod(); - if (requestMethod.equalsIgnoreCase("GET")) { - Headers responseHeaders = exchange.getResponseHeaders(); - responseHeaders.set("Content-Type", "text/HTML"); - exchange.sendResponseHeaders(200, 0); - - try (OutputStream responseBody = exchange.getResponseBody()) { - Headers requestHeaders = exchange.getRequestHeaders(); - Set keySet = requestHeaders.keySet(); - Iterator iter = keySet.iterator(); - - String buildVersion = GNSConfig.readBuildVersion(); - String buildVersionInfo = "Build Version: Unable to lookup!"; - if (buildVersion != null) { - buildVersionInfo = "Build Version: " + buildVersion; - } - String responsePreamble = "GNS Server Status

"; - String responsePostamble = "

"; - String serverStartDateString = "Server start time: " + Format.formatDualDate(serverStartDate); - String serverUpTimeString = "Server uptime: " + DurationFormatUtils.formatDurationWords(new Date().getTime() - serverStartDate.getTime(), true, true); - String serverSSLMode = "Server SSL mode: " + ReconfigurationConfig.getServerSSLMode().toString(); - String clientSSLMode = "Client SSL mode: " + ReconfigurationConfig.getClientSSLMode().toString(); - String reconAddresses = "Recon addresses: " + ReconfigurationConfig.getReconfiguratorAddresses().toString(); - String numberOfNameServers = "Server count: " + requestHandler.getGnsNodeConfig().getNumberOfNodes(); - String recordsClass = "Records Class: " + GNSConfig.GNSC.getNoSqlRecordsClass(); - String secureString = exchange instanceof HttpsExchange ? "Security: Secure" : "Security: Open"; - // Build the response - responseBody.write(responsePreamble.getBytes()); - responseBody.write(buildVersionInfo.getBytes()); - responseBody.write("
".getBytes()); - responseBody.write(serverStartDateString.getBytes()); - responseBody.write("
".getBytes()); - responseBody.write(serverUpTimeString.getBytes()); - responseBody.write("
".getBytes()); - responseBody.write(numberOfNameServers.getBytes()); - responseBody.write("
".getBytes()); - responseBody.write(reconAddresses.getBytes()); - responseBody.write("
".getBytes()); - responseBody.write(serverSSLMode.getBytes()); - responseBody.write("
".getBytes()); - responseBody.write(clientSSLMode.getBytes()); - responseBody.write("
".getBytes()); - responseBody.write(secureString.getBytes()); - responseBody.write("
".getBytes()); - responseBody.write(recordsClass.getBytes()); - responseBody.write("
".getBytes()); - responseBody.write("
".getBytes()); - responseBody.write("Request Headers:".getBytes()); - responseBody.write("
".getBytes()); - while (iter.hasNext()) { - String key = iter.next(); - List values = requestHeaders.get(key); - String s = key + " = " + values.toString() + "\n"; - responseBody.write(s.getBytes()); - responseBody.write("
".getBytes()); - } - responseBody.write(responsePostamble.getBytes()); - - } - } + protected List getAdditionalInformation(){ + List info = new ArrayList(); + + String numberOfNameServers = "Server count: " + requestHandler.getGnsNodeConfig().getNumberOfNodes(); + info.add(numberOfNameServers); + + return info; } + } } diff --git a/src/edu/umass/cs/gnsserver/httpserver/GNSHttpsServer.java b/src/edu/umass/cs/gnsserver/httpserver/GNSHttpsServer.java index 929d973c8..eeecc6572 100644 --- a/src/edu/umass/cs/gnsserver/httpserver/GNSHttpsServer.java +++ b/src/edu/umass/cs/gnsserver/httpserver/GNSHttpsServer.java @@ -65,7 +65,7 @@ public GNSHttpsServer(int port, ClientRequestHandlerInterface requestHandler) { } /** - * Try to start the http server at the port. + * Try to start the https server at the port. * * @param port * @return true if it was started @@ -94,7 +94,7 @@ public void configure(HttpsParameters parameters) { } }); - httpsServer.createContext("/", new EchoHttpHandler()); + httpsServer.createContext("/", echoHandler); httpsServer.createContext("/" + GNS_PATH, new DefaultHttpHandler()); httpsServer.setExecutor(Executors.newCachedThreadPool()); httpsServer.start(); diff --git a/test/edu/umass/cs/gnsclient/client/singletests/HttpProxyTest.java b/test/edu/umass/cs/gnsclient/client/singletests/HttpProxyTest.java index a10167a3f..bc97c0f49 100644 --- a/test/edu/umass/cs/gnsclient/client/singletests/HttpProxyTest.java +++ b/test/edu/umass/cs/gnsclient/client/singletests/HttpProxyTest.java @@ -7,6 +7,7 @@ */ package edu.umass.cs.gnsclient.client.singletests; +import edu.umass.cs.gnsclient.client.GNSClientConfig.GNSCC; import edu.umass.cs.gnsclient.client.http.HttpClient; import edu.umass.cs.gnsclient.client.util.GuidEntry; import edu.umass.cs.gnsclient.client.util.GuidUtils; @@ -17,7 +18,9 @@ import edu.umass.cs.gnscommon.GNSProtocol; import edu.umass.cs.gnscommon.exceptions.client.ClientException; import edu.umass.cs.gnscommon.utils.RandomString; +import edu.umass.cs.gnsserver.httpserver.GNSHttpProxy; import edu.umass.cs.gnsserver.utils.DefaultGNSTest; +import edu.umass.cs.utils.Config; import edu.umass.cs.utils.Utils; import java.awt.geom.Point2D; import java.io.IOException; @@ -34,7 +37,9 @@ import org.junit.Test; import org.junit.FixMethodOrder; import org.junit.runners.MethodSorters; +import org.junit.AfterClass; import org.junit.Assert; +import org.junit.BeforeClass; /** * @@ -44,11 +49,32 @@ */ @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class HttpProxyTest extends HttpClientTest { + private static GNSHttpProxy proxy; /** * */ public HttpProxyTest() { - httpClient = new HttpClient("127.0.0.1", 8080); + httpClient = new HttpClient("127.0.0.1", 8080); + } + + /** + * Launch a new GNSHttpProxy for these tests. + */ + @BeforeClass + public static void setupBeforeClass(){ + + int port = Config.getGlobalInt(GNSCC.HTTP_PROXY_PORT); + String hostname = Config.getGlobalString(GNSCC.HTTP_PROXY_INCOMING_HOSTNAME); + proxy = new GNSHttpProxy(); + proxy.runServer(port, hostname); + } + + /** + * Stop the GNSHttpProxy that was running for these tests. + */ + @AfterClass + public static void teardownAfterClass(){ + proxy.stop(); } } \ No newline at end of file From c6d18341c6a96a8098660fa728174c1db625a9d1 Mon Sep 17 00:00:00 2001 From: Brendan Teich Date: Wed, 1 Mar 2017 02:43:32 -0500 Subject: [PATCH 10/13] Removed unused imports from GNSHttpServer. --- .../cs/gnsserver/httpserver/GNSHttpProxy.java | 3 +-- .../gnsserver/httpserver/GNSHttpServer.java | 24 ------------------- 2 files changed, 1 insertion(+), 26 deletions(-) diff --git a/src/edu/umass/cs/gnsserver/httpserver/GNSHttpProxy.java b/src/edu/umass/cs/gnsserver/httpserver/GNSHttpProxy.java index a082822ef..1d0c1743f 100644 --- a/src/edu/umass/cs/gnsserver/httpserver/GNSHttpProxy.java +++ b/src/edu/umass/cs/gnsserver/httpserver/GNSHttpProxy.java @@ -47,7 +47,7 @@ import edu.umass.cs.gnscommon.ResponseCode; import static edu.umass.cs.gnsserver.httpserver.Defs.QUERYPREFIX; -import edu.umass.cs.gnsserver.gnsapp.clientCommandProcessor.commands.AbstractCommand; + import edu.umass.cs.gnsserver.gnsapp.clientCommandProcessor.commands.CommandModule; import edu.umass.cs.gnscommon.exceptions.client.ClientException; import edu.umass.cs.gnscommon.exceptions.server.InternalRequestException; @@ -55,7 +55,6 @@ import edu.umass.cs.gnscommon.utils.Base64; import edu.umass.cs.gnscommon.utils.CanonicalJSON; import edu.umass.cs.gnscommon.utils.Format; -import edu.umass.cs.gnsserver.gnsapp.clientCommandProcessor.commandSupport.CommandHandler; import edu.umass.cs.gnsserver.gnsapp.clientCommandProcessor.commandSupport.CommandResponse; import edu.umass.cs.gnsserver.utils.Util; import edu.umass.cs.nio.JSONPacket; diff --git a/src/edu/umass/cs/gnsserver/httpserver/GNSHttpServer.java b/src/edu/umass/cs/gnsserver/httpserver/GNSHttpServer.java index 365af57f4..a8f153498 100644 --- a/src/edu/umass/cs/gnsserver/httpserver/GNSHttpServer.java +++ b/src/edu/umass/cs/gnsserver/httpserver/GNSHttpServer.java @@ -23,55 +23,31 @@ * * @author westy */ -import com.sun.net.httpserver.Headers; -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; -import com.sun.net.httpserver.HttpServer; -import com.sun.net.httpserver.HttpsExchange; -import edu.umass.cs.gnsclient.client.GNSClient; import edu.umass.cs.gnscommon.CommandType; -import edu.umass.cs.gnsserver.main.GNSConfig; import java.io.IOException; -import java.io.OutputStream; -import java.net.HttpURLConnection; -import java.net.InetSocketAddress; -import java.net.URI; -import java.util.Iterator; import java.util.List; -import java.util.Set; -import java.util.concurrent.Executors; import edu.umass.cs.gnscommon.ResponseCode; import static edu.umass.cs.gnsserver.httpserver.Defs.QUERYPREFIX; import edu.umass.cs.gnsserver.gnsapp.clientCommandProcessor.ClientRequestHandlerInterface; import edu.umass.cs.gnsserver.gnsapp.clientCommandProcessor.commandSupport.CommandHandler; import edu.umass.cs.gnsserver.gnsapp.clientCommandProcessor.commands.AbstractCommand; -import edu.umass.cs.gnscommon.exceptions.client.ClientException; -import edu.umass.cs.gnscommon.exceptions.server.InternalRequestException; import edu.umass.cs.gnscommon.packets.CommandPacket; -import edu.umass.cs.gnscommon.utils.Base64; -import edu.umass.cs.gnscommon.utils.CanonicalJSON; -import edu.umass.cs.gnscommon.utils.Format; import edu.umass.cs.gnsserver.gnsapp.clientCommandProcessor.commandSupport.CommandResponse; import edu.umass.cs.gnsserver.main.GNSConfig.GNSC; -import edu.umass.cs.gnsserver.utils.Util; -import edu.umass.cs.reconfiguration.ReconfigurationConfig; import edu.umass.cs.utils.Config; import java.util.ArrayList; -import java.util.Date; import java.util.logging.Level; import java.util.logging.Logger; -import org.apache.commons.lang.time.DurationFormatUtils; import org.json.JSONException; import org.json.JSONObject; import edu.umass.cs.gnscommon.GNSProtocol; -import java.io.UnsupportedEncodingException; /** * From 9fbaa43ab482861f28298b55c3c7954bc0d4c3fc Mon Sep 17 00:00:00 2001 From: Brendan Teich Date: Thu, 2 Mar 2017 14:18:26 -0500 Subject: [PATCH 11/13] Merged in changes from the main branch, modified GNSClientConfig to give the proxy server a different default port from the http server, and moved HttpProxyTest to failingtests since it essentially just runs HttpClientTest, which is currently failing. --- src/edu/umass/cs/gnsclient/client/GNSClientConfig.java | 2 +- .../client/singletests/{ => failingtests}/HttpProxyTest.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) rename test/edu/umass/cs/gnsclient/client/singletests/{ => failingtests}/HttpProxyTest.java (96%) diff --git a/src/edu/umass/cs/gnsclient/client/GNSClientConfig.java b/src/edu/umass/cs/gnsclient/client/GNSClientConfig.java index e93bf5f89..cee8ba98c 100644 --- a/src/edu/umass/cs/gnsclient/client/GNSClientConfig.java +++ b/src/edu/umass/cs/gnsclient/client/GNSClientConfig.java @@ -93,7 +93,7 @@ public static enum GNSCC implements Config.ConfigurableEnum { /** * The port that GNSHttpProxy listens for incoming commands on. */ - HTTP_PROXY_PORT(8080), + HTTP_PROXY_PORT(8090), /** * The hostname that GNSHttpProxy will allow incoming commands from. diff --git a/test/edu/umass/cs/gnsclient/client/singletests/HttpProxyTest.java b/test/edu/umass/cs/gnsclient/client/singletests/failingtests/HttpProxyTest.java similarity index 96% rename from test/edu/umass/cs/gnsclient/client/singletests/HttpProxyTest.java rename to test/edu/umass/cs/gnsclient/client/singletests/failingtests/HttpProxyTest.java index bc97c0f49..9a00d71c3 100644 --- a/test/edu/umass/cs/gnsclient/client/singletests/HttpProxyTest.java +++ b/test/edu/umass/cs/gnsclient/client/singletests/failingtests/HttpProxyTest.java @@ -55,7 +55,7 @@ public class HttpProxyTest extends HttpClientTest { * */ public HttpProxyTest() { - httpClient = new HttpClient("127.0.0.1", 8080); + httpClient = new HttpClient("127.0.0.1", Config.getGlobalInt(GNSCC.HTTP_PROXY_PORT)); } /** @@ -77,4 +77,4 @@ public static void setupBeforeClass(){ public static void teardownAfterClass(){ proxy.stop(); } -} \ No newline at end of file +} From 581e608b1ff0fa1bb3fe7f731dddbce04965a39e Mon Sep 17 00:00:00 2001 From: Brendan Teich Date: Thu, 2 Mar 2017 15:11:37 -0500 Subject: [PATCH 12/13] Fixed a compilation error caused by the merge since the merge moved HttpClientTest and HttpProxyTest relies on it. --- .../failingtests/HttpProxyTest.java | 27 +------------------ 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/test/edu/umass/cs/gnsclient/client/singletests/failingtests/HttpProxyTest.java b/test/edu/umass/cs/gnsclient/client/singletests/failingtests/HttpProxyTest.java index 9a00d71c3..4de5251f7 100644 --- a/test/edu/umass/cs/gnsclient/client/singletests/failingtests/HttpProxyTest.java +++ b/test/edu/umass/cs/gnsclient/client/singletests/failingtests/HttpProxyTest.java @@ -5,40 +5,15 @@ * * Initial developer(s): Westy. */ -package edu.umass.cs.gnsclient.client.singletests; +package edu.umass.cs.gnsclient.client.singletests.failingtests; import edu.umass.cs.gnsclient.client.GNSClientConfig.GNSCC; import edu.umass.cs.gnsclient.client.http.HttpClient; -import edu.umass.cs.gnsclient.client.util.GuidEntry; -import edu.umass.cs.gnsclient.client.util.GuidUtils; -import edu.umass.cs.gnsclient.client.util.JSONUtils; -import edu.umass.cs.gnsclient.jsonassert.JSONAssert; -import edu.umass.cs.gnsclient.jsonassert.JSONCompareMode; -import edu.umass.cs.gnscommon.AclAccessType; -import edu.umass.cs.gnscommon.GNSProtocol; -import edu.umass.cs.gnscommon.exceptions.client.ClientException; -import edu.umass.cs.gnscommon.utils.RandomString; import edu.umass.cs.gnsserver.httpserver.GNSHttpProxy; -import edu.umass.cs.gnsserver.utils.DefaultGNSTest; import edu.umass.cs.utils.Config; -import edu.umass.cs.utils.Utils; -import java.awt.geom.Point2D; -import java.io.IOException; -import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import org.hamcrest.Matchers; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.junit.Test; import org.junit.FixMethodOrder; import org.junit.runners.MethodSorters; import org.junit.AfterClass; -import org.junit.Assert; import org.junit.BeforeClass; /** From 41e52f29616342aa8472b74745ff7db353d4d0a6 Mon Sep 17 00:00:00 2001 From: Brendan Teich Date: Thu, 16 Mar 2017 12:09:35 -0400 Subject: [PATCH 13/13] Moved HttpClientTest and HttpProxyTest back into singletests after fixing them both to work with changes in the master branch. --- src/edu/umass/cs/gnsserver/httpserver/GNSHttpProxy.java | 5 ++++- src/edu/umass/cs/gnsserver/httpserver/GNSHttpServer.java | 1 + .../singletests/{failingtests => }/HttpClientTest.java | 2 +- .../client/singletests/{failingtests => }/HttpProxyTest.java | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) rename test/edu/umass/cs/gnsclient/client/singletests/{failingtests => }/HttpClientTest.java (99%) rename test/edu/umass/cs/gnsclient/client/singletests/{failingtests => }/HttpProxyTest.java (95%) diff --git a/src/edu/umass/cs/gnsserver/httpserver/GNSHttpProxy.java b/src/edu/umass/cs/gnsserver/httpserver/GNSHttpProxy.java index 1d0c1743f..c715dee6f 100644 --- a/src/edu/umass/cs/gnsserver/httpserver/GNSHttpProxy.java +++ b/src/edu/umass/cs/gnsserver/httpserver/GNSHttpProxy.java @@ -95,6 +95,8 @@ public class GNSHttpProxy { protected GNSClient client = null; protected DefaultHttpHandler httpHandler; protected EchoHttpProxyHandler echoHandler; + //Does this proxy allow commands to be executed locally? (Should be false in this class, and true in GNSHttpServer.) + protected boolean localExecution; /** * @@ -109,6 +111,7 @@ public class GNSHttpProxy { * @param requestHandler */ public GNSHttpProxy() { + this.localExecution = false; this.commandModule = new CommandModule(); this.httpHandler = new DefaultHttpHandler(); this.echoHandler = new EchoHttpProxyHandler(); @@ -335,7 +338,7 @@ protected CommandResponse processQuery(String host, String commandName, String q // and the rest by invoking the GNS client and sending them out. // Client will be null if GNSC.DISABLE_MULTI_SERVER_HTTP (see above) // is true (or there was a problem). - if (client == null || commandType.isLocallyHandled()) { + if (client == null || (localExecution && commandType.isLocallyHandled())) { // EXECUTE IT LOCALLY return handleCommandLocally(jsonCommand, commandType, commandName, queryString); } else { diff --git a/src/edu/umass/cs/gnsserver/httpserver/GNSHttpServer.java b/src/edu/umass/cs/gnsserver/httpserver/GNSHttpServer.java index a8f153498..c1fce50dc 100644 --- a/src/edu/umass/cs/gnsserver/httpserver/GNSHttpServer.java +++ b/src/edu/umass/cs/gnsserver/httpserver/GNSHttpServer.java @@ -73,6 +73,7 @@ public GNSHttpServer(int port, ClientRequestHandlerInterface requestHandler) { super(); echoHandler = new EchoHttpServerHandler(); this.requestHandler = requestHandler; + localExecution = true; if (Config.getGlobalBoolean(GNSC.DISABLE_MULTI_SERVER_HTTP)) { client.close(); client = null; diff --git a/test/edu/umass/cs/gnsclient/client/singletests/failingtests/HttpClientTest.java b/test/edu/umass/cs/gnsclient/client/singletests/HttpClientTest.java similarity index 99% rename from test/edu/umass/cs/gnsclient/client/singletests/failingtests/HttpClientTest.java rename to test/edu/umass/cs/gnsclient/client/singletests/HttpClientTest.java index 0735bd424..64af95079 100644 --- a/test/edu/umass/cs/gnsclient/client/singletests/failingtests/HttpClientTest.java +++ b/test/edu/umass/cs/gnsclient/client/singletests/HttpClientTest.java @@ -5,7 +5,7 @@ * * Initial developer(s): Westy. */ -package edu.umass.cs.gnsclient.client.singletests.failingtests; +package edu.umass.cs.gnsclient.client.singletests; import edu.umass.cs.gnsclient.client.http.HttpClient; import edu.umass.cs.gnsclient.client.util.GuidEntry; diff --git a/test/edu/umass/cs/gnsclient/client/singletests/failingtests/HttpProxyTest.java b/test/edu/umass/cs/gnsclient/client/singletests/HttpProxyTest.java similarity index 95% rename from test/edu/umass/cs/gnsclient/client/singletests/failingtests/HttpProxyTest.java rename to test/edu/umass/cs/gnsclient/client/singletests/HttpProxyTest.java index 4de5251f7..fabae17e0 100644 --- a/test/edu/umass/cs/gnsclient/client/singletests/failingtests/HttpProxyTest.java +++ b/test/edu/umass/cs/gnsclient/client/singletests/HttpProxyTest.java @@ -5,7 +5,7 @@ * * Initial developer(s): Westy. */ -package edu.umass.cs.gnsclient.client.singletests.failingtests; +package edu.umass.cs.gnsclient.client.singletests; import edu.umass.cs.gnsclient.client.GNSClientConfig.GNSCC; import edu.umass.cs.gnsclient.client.http.HttpClient;