- admin can toggle verbose logging of all requests on and off
- admin page shows user hostname - servlets log request and response if logging is enabled
This commit is contained in:
parent
5e95299801
commit
a26221c2bb
|
@ -13,6 +13,19 @@ String remoteAddr = request.getRemoteAddr();
|
|||
if (!(remoteAddr.equals("0:0:0:0:0:0:0:1") || remoteAddr.equals("127.0.0.1"))) {
|
||||
response.sendError(403, "Access is restricted to known hosts");
|
||||
}
|
||||
|
||||
ServletContext servletContext = pageContext.getServletContext();
|
||||
|
||||
// process verbose toggle
|
||||
String verboseParam = request.getParameter("verbose");
|
||||
if (verboseParam != null) {
|
||||
if (verboseParam.equals("on")) {
|
||||
servletContext.setAttribute(StartupUtils.VERBOSE_DEBUG, Boolean.TRUE);
|
||||
} else {
|
||||
servletContext.setAttribute(StartupUtils.VERBOSE_DEBUG, Boolean.FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
%>
|
||||
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
|
@ -33,7 +46,6 @@ th, td {
|
|||
<body>
|
||||
|
||||
<%
|
||||
ServletContext servletContext = pageContext.getServletContext();
|
||||
Injector injector = (Injector) servletContext.getAttribute(StartupUtils.INJECTOR);
|
||||
%>
|
||||
|
||||
|
@ -83,17 +95,28 @@ Collection<User> users = connectedUsers.getUsers();
|
|||
<table>
|
||||
<tr>
|
||||
<th>Username</th>
|
||||
<th>Host</th>
|
||||
</tr>
|
||||
<%
|
||||
for (User u : users) {
|
||||
%>
|
||||
<tr>
|
||||
<td><% out.print(u.getNickname()); %></td>
|
||||
<td><% out.print(u.getHostName()); %></td>
|
||||
</tr>
|
||||
<%
|
||||
}
|
||||
%>
|
||||
</table>
|
||||
|
||||
<%
|
||||
Boolean verboseDebugObj = (Boolean) servletContext.getAttribute(StartupUtils.VERBOSE_DEBUG);
|
||||
boolean verboseDebug = verboseDebugObj != null ? verboseDebugObj.booleanValue() : false;
|
||||
%>
|
||||
<p>
|
||||
Verbose logging is currently <strong><% out.print(verboseDebug ? "ON" : "OFF"); %></strong>.
|
||||
<a href="?verbose=on">Turn on.</a> <a href="?verbose=off">Turn off.</a>
|
||||
</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -14,6 +14,8 @@ import net.socialgamer.cah.Constants.AjaxRequest;
|
|||
import net.socialgamer.cah.Constants.AjaxResponse;
|
||||
import net.socialgamer.cah.Constants.ErrorCode;
|
||||
import net.socialgamer.cah.Constants.ReturnableData;
|
||||
import net.socialgamer.cah.Constants.SessionAttribute;
|
||||
import net.socialgamer.cah.data.User;
|
||||
import net.socialgamer.cah.handlers.Handler;
|
||||
import net.socialgamer.cah.handlers.Handlers;
|
||||
|
||||
|
@ -36,19 +38,20 @@ public class AjaxServlet extends CahServlet {
|
|||
final HttpServletResponse response, final HttpSession hSession) throws ServletException,
|
||||
IOException {
|
||||
final PrintWriter out = response.getWriter();
|
||||
final User user = (User) hSession.getAttribute(SessionAttribute.USER);
|
||||
int serial = -1;
|
||||
if (request.getParameter(AjaxRequest.SERIAL.toString()) != null) {
|
||||
try {
|
||||
serial = Integer.parseInt(request.getParameter(AjaxRequest.SERIAL.toString()));
|
||||
} catch (final NumberFormatException nfe) {
|
||||
returnError(out, ErrorCode.BAD_REQUEST);
|
||||
returnError(user, out, ErrorCode.BAD_REQUEST);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
final String op = request.getParameter(AjaxRequest.OP.toString());
|
||||
if (op == null || op.equals("")) {
|
||||
returnError(out, ErrorCode.OP_NOT_SPECIFIED, serial);
|
||||
returnError(user, out, ErrorCode.OP_NOT_SPECIFIED, serial);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -58,12 +61,12 @@ public class AjaxServlet extends CahServlet {
|
|||
} catch (final Exception e) {
|
||||
System.err.println("Exception creating handler for " + op);
|
||||
e.printStackTrace(System.err);
|
||||
returnError(out, ErrorCode.BAD_OP, serial);
|
||||
returnError(user, out, ErrorCode.BAD_OP, serial);
|
||||
return;
|
||||
}
|
||||
final Map<ReturnableData, Object> data = handler.handle(new RequestWrapper(request), hSession);
|
||||
data.put(AjaxResponse.SERIAL, serial);
|
||||
returnData(out, data);
|
||||
returnData(user, out, data);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,8 @@ package net.socialgamer.cah;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -23,6 +25,7 @@ import org.json.simple.JSONObject;
|
|||
import org.json.simple.JSONValue;
|
||||
|
||||
import com.google.inject.Injector;
|
||||
import com.sun.istack.internal.Nullable;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -32,13 +35,7 @@ import com.google.inject.Injector;
|
|||
public abstract class CahServlet extends HttpServlet {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* @see HttpServlet#HttpServlet()
|
||||
*/
|
||||
public CahServlet() {
|
||||
super();
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
private final boolean debugLog = false;
|
||||
|
||||
/**
|
||||
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
|
||||
|
@ -50,6 +47,21 @@ public abstract class CahServlet extends HttpServlet {
|
|||
response.setCharacterEncoding("UTF-8");
|
||||
|
||||
final HttpSession hSession = request.getSession(true);
|
||||
final User user = (User) hSession.getAttribute(SessionAttribute.USER);
|
||||
|
||||
if (verboseDebug()) {
|
||||
// TODO if we have any sort of authentication later, we need to make sure to not log passwords!
|
||||
// I could use getParameterMap, but that returns an array, and getting pretty strings out of
|
||||
// array values is a lot of work.
|
||||
final Map<String, Object> params = new HashMap<String, Object>();
|
||||
final Enumeration<String> paramNames = request.getParameterNames();
|
||||
while (paramNames.hasMoreElements()) {
|
||||
final String name = paramNames.nextElement();
|
||||
params.put(name, request.getParameter(name));
|
||||
}
|
||||
log(user, "Request: " + JSONValue.toJSONString(params));
|
||||
}
|
||||
|
||||
final String op = request.getParameter(AjaxRequest.OP.toString());
|
||||
final boolean skipSessionUserCheck = op != null
|
||||
&& (op.equals(AjaxOperation.REGISTER.toString())
|
||||
|
@ -57,24 +69,31 @@ public abstract class CahServlet extends HttpServlet {
|
|||
if (hSession.isNew()) {
|
||||
// they should have gotten a session from the index page.
|
||||
// they probably don't have cookies on.
|
||||
returnError(response.getWriter(), ErrorCode.NO_SESSION);
|
||||
returnError(user, response.getWriter(), ErrorCode.NO_SESSION);
|
||||
} else if (!skipSessionUserCheck && hSession.getAttribute(SessionAttribute.USER) == null) {
|
||||
returnError(response.getWriter(), ErrorCode.NOT_REGISTERED);
|
||||
} else if (hSession.getAttribute(SessionAttribute.USER) != null
|
||||
&& !(((User) hSession.getAttribute(SessionAttribute.USER)).isValid())) {
|
||||
returnError(user, response.getWriter(), ErrorCode.NOT_REGISTERED);
|
||||
} else if (user != null && !user.isValid()) {
|
||||
// user probably pinged out
|
||||
hSession.invalidate();
|
||||
returnError(response.getWriter(), ErrorCode.SESSION_EXPIRED);
|
||||
returnError(user, response.getWriter(), ErrorCode.SESSION_EXPIRED);
|
||||
} else {
|
||||
try {
|
||||
handleRequest(request, response, hSession);
|
||||
} catch (final AssertionError ae) {
|
||||
log("Assertion failed", ae);
|
||||
getServletContext().log(ae.toString());
|
||||
ae.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean verboseDebug() {
|
||||
final Boolean verboseDebugObj = (Boolean) getServletContext().getAttribute(
|
||||
StartupUtils.VERBOSE_DEBUG);
|
||||
final boolean verboseDebug = verboseDebugObj != null ? verboseDebugObj.booleanValue() : false;
|
||||
return verboseDebug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a request from a CAH client. A session is guaranteed to exist at this point.
|
||||
*
|
||||
|
@ -96,8 +115,9 @@ public abstract class CahServlet extends HttpServlet {
|
|||
* @param code
|
||||
* Error code that the js code knows how to handle.
|
||||
*/
|
||||
protected void returnError(final PrintWriter writer, final ErrorCode code) {
|
||||
returnError(writer, code, -1);
|
||||
protected void returnError(@Nullable final User user, final PrintWriter writer,
|
||||
final ErrorCode code) {
|
||||
returnError(user, writer, code, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -107,7 +127,9 @@ public abstract class CahServlet extends HttpServlet {
|
|||
* @param serial
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void returnError(final PrintWriter writer, final ErrorCode code, final int serial) {
|
||||
protected void returnError(@Nullable final User user, final PrintWriter writer,
|
||||
final ErrorCode code,
|
||||
final int serial) {
|
||||
final JSONObject ret = new JSONObject();
|
||||
ret.put(AjaxResponse.ERROR, Boolean.TRUE);
|
||||
ret.put(AjaxResponse.ERROR_CODE, code.toString());
|
||||
|
@ -122,8 +144,9 @@ public abstract class CahServlet extends HttpServlet {
|
|||
* @param data
|
||||
* Key-value data to return as the response.
|
||||
*/
|
||||
protected void returnData(final PrintWriter writer, final Map<ReturnableData, Object> data) {
|
||||
returnObject(writer, data);
|
||||
protected void returnData(@Nullable final User user, final PrintWriter writer,
|
||||
final Map<ReturnableData, Object> data) {
|
||||
returnObject(user, writer, data);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -134,18 +157,28 @@ public abstract class CahServlet extends HttpServlet {
|
|||
* @param data_list
|
||||
* List of key-value data to return as the response.
|
||||
*/
|
||||
protected void returnArray(final PrintWriter writer,
|
||||
protected void returnArray(@Nullable final User user, final PrintWriter writer,
|
||||
final List<Map<ReturnableData, Object>> data_list) {
|
||||
returnObject(writer, data_list);
|
||||
returnObject(user, writer, data_list);
|
||||
}
|
||||
|
||||
private void returnObject(final PrintWriter writer, final Object object) {
|
||||
private void returnObject(@Nullable final User user, final PrintWriter writer, final Object object) {
|
||||
final String ret = JSONValue.toJSONString(object);
|
||||
writer.println(ret);
|
||||
// System.out.println(">>>> " + ret + " <<<<");
|
||||
if (verboseDebug()) {
|
||||
log(user, "Response: " + ret);
|
||||
}
|
||||
}
|
||||
|
||||
protected Injector getInjector() {
|
||||
return (Injector) getServletContext().getAttribute(StartupUtils.INJECTOR);
|
||||
}
|
||||
|
||||
protected void log(@Nullable final User user, final String message) {
|
||||
String userStr = "unknown user";
|
||||
if (user != null) {
|
||||
userStr = user.getNickname();
|
||||
}
|
||||
log("For " + userStr + ": " + message);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -82,7 +82,7 @@ public class LongPollServlet extends CahServlet {
|
|||
for (final QueuedMessage qm : msgs) {
|
||||
data.add(qm.getData());
|
||||
}
|
||||
returnArray(out, data);
|
||||
returnArray(user, out, data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -90,6 +90,6 @@ public class LongPollServlet extends CahServlet {
|
|||
final Map<ReturnableData, Object> data = new HashMap<ReturnableData, Object>();
|
||||
data.put(LongPollResponse.EVENT, LongPollEvent.NOOP.toString());
|
||||
data.put(LongPollResponse.TIMESTAMP, System.currentTimeMillis());
|
||||
returnData(out, data);
|
||||
returnData(user, out, data);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,4 +22,12 @@ public class RequestWrapper {
|
|||
public String getParameter(final AjaxRequest parameter) {
|
||||
return request.getParameter(parameter.toString());
|
||||
}
|
||||
|
||||
public String getRemoteAddr() {
|
||||
return request.getRemoteAddr();
|
||||
}
|
||||
|
||||
public String getRemoteHost() {
|
||||
return request.getRemoteHost();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@ public class StartupUtils extends GuiceServletContextListener {
|
|||
|
||||
public static final String DATE_NAME = "started_at";
|
||||
|
||||
public static final String VERBOSE_DEBUG = "verbose_debug";
|
||||
|
||||
private Date serverStarted;
|
||||
|
||||
@Override
|
||||
|
|
|
@ -17,13 +17,16 @@ public class User {
|
|||
|
||||
private Game currentGame;
|
||||
|
||||
private final String hostName;
|
||||
|
||||
/**
|
||||
* Reset when this user object is no longer valid, most likely because it pinged out.
|
||||
*/
|
||||
private boolean valid = true;
|
||||
|
||||
public User(final String nickname) {
|
||||
public User(final String nickname, final String hostName) {
|
||||
this.nickname = nickname;
|
||||
this.hostName = hostName;
|
||||
queuedMessages = new PriorityBlockingQueue<QueuedMessage>();
|
||||
}
|
||||
|
||||
|
@ -79,6 +82,10 @@ public class User {
|
|||
return nickname;
|
||||
}
|
||||
|
||||
public String getHostName() {
|
||||
return hostName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getNickname();
|
||||
|
|
|
@ -52,7 +52,7 @@ public class RegisterHandler extends Handler {
|
|||
} else if (users.hasUser(nick)) {
|
||||
return error(ErrorCode.NICK_IN_USE);
|
||||
} else {
|
||||
final User user = new User(nick);
|
||||
final User user = new User(nick, request.getRemoteHost());
|
||||
users.newUser(user);
|
||||
session.setAttribute(SessionAttribute.USER, user);
|
||||
|
||||
|
|
Loading…
Reference in New Issue