public void process(Request request, HttpServletResponse response) {
Client client = null;
boolean adminMode = false;
Continuation continuation = ContinuationSupport.getContinuation(request);
continuation.suspend(response);
String jsonp = null;
try {
// first check for a catalog update and purge the cached connections
// if one has happened since we were here last
if (m_shouldUpdateCatalog.compareAndSet(true, false))
{
m_connections.closeAll();
// Just null the old object so we'll create a new one with
// updated state below
m_connections = null;
}
if (m_connections == null) {
int port = VoltDB.instance().getConfig().m_port;
int adminPort = VoltDB.instance().getConfig().m_adminPort;
String externalInterface = VoltDB.instance().getConfig().m_externalInterface;
String adminInterface = "localhost";
String clientInterface = "localhost";
if (externalInterface != null && !externalInterface.isEmpty()) {
clientInterface = externalInterface;
adminInterface = externalInterface;
}
//If individual override is available use them.
if (VoltDB.instance().getConfig().m_clientInterface.length() > 0) {
clientInterface = VoltDB.instance().getConfig().m_clientInterface;
}
if (VoltDB.instance().getConfig().m_adminInterface.length() > 0) {
adminInterface = VoltDB.instance().getConfig().m_adminInterface;
}
m_connections = new AuthenticatedConnectionCache(10, clientInterface, port, adminInterface, adminPort);
}
jsonp = request.getParameter("jsonp");
if (request.getMethod().equalsIgnoreCase("POST")) {
int queryParamSize = request.getContentLength();
if (queryParamSize > 150000) {
// We don't want to be building huge strings
throw new Exception("Query string too large: " + String.valueOf(request.getContentLength()));
}
if (queryParamSize == 0) {
throw new Exception("Received POST with no parameters in the body.");
}
}
String username = request.getParameter("User");
String password = request.getParameter("Password");
String hashedPassword = request.getParameter("Hashedpassword");
String procName = request.getParameter("Procedure");
String params = request.getParameter("Parameters");
String admin = request.getParameter("admin");
// check for admin mode
if (admin != null) {
if (admin.compareToIgnoreCase("true") == 0) {
adminMode = true;
}
}
// null procs are bad news
if (procName == null) {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
continuation.complete();
return;
}
// The SHA-1 hash of the password
byte[] hashedPasswordBytes = null;
if (password != null) {
try {
// Create a MessageDigest every time because MessageDigest is not thread safe (ENG-5438)
MessageDigest md = MessageDigest.getInstance("SHA-1");
hashedPasswordBytes = md.digest(password.getBytes("UTF-8"));
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("JVM doesn't support SHA-1 hashing. Please use a supported JVM", e);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("JVM doesn't support UTF-8. Please use a supported JVM", e);
}
}
// note that HTTP Var "Hashedpassword" has a higher priority
// Hashedassword must be a 40-byte hex-encoded SHA-1 hash (20 bytes unencoded)
if (hashedPassword != null) {
if (hashedPassword.length() != 40) {
throw new Exception("Hashedpassword must be a 40-byte hex-encoded SHA-1 hash (20 bytes unencoded).");
}
try {
hashedPasswordBytes = Encoder.hexDecode(hashedPassword);
}
catch (Exception e) {
throw new Exception("Hashedpassword must be a 40-byte hex-encoded SHA-1 hash (20 bytes unencoded).");
}
}
assert((hashedPasswordBytes == null) || (hashedPasswordBytes.length == 20));
// get a connection to localhost from the pool
client = m_connections.getClient(username, password, hashedPasswordBytes, adminMode);
JSONProcCallback cb = new JSONProcCallback(request, continuation, jsonp);
boolean success;
if (params != null) {
ParameterSet paramSet = null;
try {
paramSet = ParameterSet.fromJSONString(params);
}
// if decoding params has a fail, then fail
catch (Exception e) {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
continuation.complete();
return;
}
// if the paramset has content, but decodes to null, fail
if (paramSet == null) {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
continuation.complete();
return;
}
success = client.callProcedure(cb, procName, paramSet.toArray());
}
else {
success = client.callProcedure(cb, procName);
}
if (!success) {
throw new Exception("Server is not accepting work at this time.");
}
if (adminMode) {
cb.waitForResponse();
}
}
catch (java.net.ConnectException c_ex)
{
// Clients may attempt to connect to VoltDB before the server
// is completely initialized (our tests do this, for example).
// Don't print a stack trace, and return a server unavailable reason.
ClientResponseImpl rimpl = new ClientResponseImpl(ClientResponse.SERVER_UNAVAILABLE, new VoltTable[0], c_ex.getMessage());
String msg = rimpl.toJSONString();
if (jsonp != null) {
msg = String.format("%s( %s )", jsonp, msg);
}
response.setStatus(HttpServletResponse.SC_OK);
request.setHandled(true);
try {
response.getWriter().print(msg);
continuation.complete();
} catch (IOException e1) {}
}
catch (Exception e) {
String msg = e.getMessage();
m_rate_limited_log.log("JSON interface exception: " + msg, EstTime.currentTimeMillis());
ClientResponseImpl rimpl = new ClientResponseImpl(ClientResponse.UNEXPECTED_FAILURE, new VoltTable[0], msg);
msg = rimpl.toJSONString();
if (jsonp != null) {
msg = String.format("%s( %s )", jsonp, msg);
}
response.setStatus(HttpServletResponse.SC_OK);
request.setHandled(true);
try {
response.getWriter().print(msg);
continuation.complete();
} catch (IOException e1) {}
}
finally {
if (client != null) {
assert(m_connections != null);