package de.tud.kom.socom.util; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.security.GeneralSecurityException; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileItemFactory; import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.eclipse.jetty.util.Utf8Appendable.NotUtf8Exception; import de.tud.kom.socom.GlobalConfig; import de.tud.kom.socom.util.exceptions.CookieNotFoundException; import de.tud.kom.socom.util.exceptions.CurrentGameInstanceNotIncludedException; import de.tud.kom.socom.util.exceptions.IllegalAccessException; import de.tud.kom.socom.util.exceptions.IllegalParameterException; import de.tud.kom.socom.util.exceptions.ParseException; import de.tud.kom.socom.util.exceptions.UIDNotIncludedException; /** * * @author rhaban * */ public class SocomRequest { private static final String SESSION_GAME_KEY = "game"; private static final String SESSION_UID_KEY = "id"; private static final String CONTENT_RETURN_TYPE_JSON_TEXT = "text/html"; // text/html works better with browsers to parse JSON... "application/json"; private HttpServletRequest request; private HttpServletResponse response; private Map<String, String> params = null; private StringBuilder out; private String url; private long uid, currentGameInst; private Logger logger = LoggerFactory.getLogger(); private StringBuffer debugLog; public SocomRequest(HttpServletRequest request, HttpServletResponse response) { this.request = request; this.response = response; this.url = request.getServletPath(); this.uid = determineID(); this.currentGameInst = determineCurrentGameInst(); this.out = new StringBuilder(); if(GlobalConfig.DEBUG) { showRequest(); } } private void showRequest() { StringBuffer sb = new StringBuffer(); try { if(uid != -1) sb.append("Request: User #").append(uid).append(" | "); else sb.append("Request: No User | "); sb.append(getHandlerString() + "/" + getMethodString() + " ("); if(request.getMethod().contains("GET")) { // do ONLY on GET, otherwise the stream will be unusable try { for(String param : getParams().keySet()) { sb.append("\"").append(param).append("\"=\"").append(getParam(param)).append("\" "); } } catch (NotUtf8Exception e) { } } else if(request.getMethod().contains("POST")) { sb.append("Cookies: "); for(Cookie param : request.getCookies()) { sb.append("\"").append(param.getName()).append("\"=\"").append(param.getValue()).append("\" "); } } sb.append(") [").append(request.getMethod()).append("]"); this.debugLog = sb; } catch (Throwable t) { logger.Error("Show Request abort: " + t); } } private void showResponse(String response) { debugLog.append("\nResponse: ").append(response); logger.Debug(debugLog.toString()); } private long determineID() { Object inSessionId = request.getSession().getAttribute(SESSION_UID_KEY); if (inSessionId == null) return -1L; byte[] encUid = (byte[]) inSessionId; long uid = Long.parseLong(EasyEncrypter.getInstance().decryptString(encUid)); return uid; } private long determineCurrentGameInst() { Object currentGameInst = request.getSession().getAttribute(SESSION_GAME_KEY); if (currentGameInst == null) currentGameInst = -1L; return (Long) currentGameInst; } private String parseMethod() throws ParseException { String method = null; try { method = url.split("/")[2]; } catch (ArrayIndexOutOfBoundsException e) { throw new ParseException("method"); } return method; } private String parseHandler() throws ParseException { String handler = null; try { handler = url.split("/")[1]; } catch (ArrayIndexOutOfBoundsException e) { throw new ParseException("handler"); } return handler; } /** * parse all parameter of the requests into a (key,value) map. * * @return map with params * @throws ParseException */ private Map<String, String> parseParams() throws ParseException { Map<String, String> params = new HashMap<String, String>(); Enumeration<String> keys = request.getParameterNames(); while (keys.hasMoreElements()) { String key = keys.nextElement(); try { String param = request.getParameter(key); if (param != null) { param = URLDecoder.decode(param, "UTF-8"); params.put(key, param); } } catch (NotUtf8Exception e) { // TODO make this a childclass of ParseException saying that UTF8 is needed throw new ParseException(key); } catch (UnsupportedEncodingException e) { // TODO make this a childclass of ParseException saying that UTF8 is needed throw new ParseException(key); } } return params; } /** * append output * * @param output * string you want to write */ public void addOutput(String output) { out.append(output); } /** * overwrites already included output with given string * * @param output * new output string */ public void setOutput(String output) { out = new StringBuilder(); addOutput(output); } /** * finishes the request */ public void finish() { try { if (!out.toString().isEmpty()) { response.setContentType(CONTENT_RETURN_TYPE_JSON_TEXT); response.setCharacterEncoding("UTF-8"); response.getWriter().print(out.toString()); response.flushBuffer(); if(GlobalConfig.DEBUG) showResponse(out.toString()); } else getOutputStream().flush(); } catch (IOException e) { e.printStackTrace(); } } /** * @return the params as map * @throws ParseException */ public Map<String, String> getParams() throws ParseException { if (params == null) params = parseParams(); return params; } public String getParam(String key) throws IllegalParameterException { // String result = getParams().get(key); String result = request.getParameter(key); if (result == null) throw new IllegalParameterException(key); try { result = URLDecoder.decode(result, "UTF-8"); } catch (UnsupportedEncodingException e) { // TODO make this a childclass of ParseException saying that UTF8 is needed throw new IllegalParameterException(key); } return result; } public String getParam(String key, String defaultValue) { String result = request.getParameter(key); if (result == null) return defaultValue; return result; } public long getParam(String key, long defaultValue) { String result = request.getParameter(key); if (result == null) return defaultValue; return Long.parseLong(result); } public int getParam(String key, int defaultValue) { String result = request.getParameter(key); if (result == null) return defaultValue; return Integer.parseInt(result); } public boolean getParam(String key, boolean defaultValue) { String result = request.getParameter(key); if (result == null) return defaultValue; return Boolean.parseBoolean(result); } public boolean containsParam(String key) throws ParseException { return getParams().containsKey(key); } /** * @return parses the handler * @throws ParseException */ public String getHandlerString() throws ParseException { return parseHandler(); } /** * @return the method * @throws ParseException */ public String getMethodString() throws ParseException { return parseMethod(); } /** * gives the inputstream if its a post * * @return inputstream * @throws IOException */ public InputStream getInputStream() throws IOException { return request.getInputStream(); } /** * gives the output stream * * @return the output stream */ public OutputStream getOutputStream() { try { return response.getOutputStream(); } catch (IOException e) { setOutput(e.getMessage()); return null; } } /** * sets the filename for file sent through outputstream * @param filename */ public void setOutputFilename(String filename) { response.setHeader("Content-Disposition", "fileName=" + filename); } /** * @return the id * @throws UIDNotIncludedException */ public long getUid() throws UIDNotIncludedException { if (uid == -1) throw new UIDNotIncludedException(); return uid; } /** * @param uid * the id to set * @throws GeneralSecurityException * @throws UnsupportedEncodingException */ public void setUid(long uid) { this.uid = uid; byte[] encUid = EasyEncrypter.getInstance().encryptString(String.valueOf(uid)); request.getSession().setAttribute(SESSION_UID_KEY, encUid); } public void removeUid() { request.getSession().removeAttribute(SESSION_UID_KEY); } /** * @return the current game instance * @throws CurrentGameInstanceNotIncludedException */ public long getCurrentGameInst() throws CurrentGameInstanceNotIncludedException { if (currentGameInst == -1) throw new CurrentGameInstanceNotIncludedException(); return currentGameInst; } /** * @param uid * the id to set */ public void setCurrentGameInst(long currentGameInst) { this.currentGameInst = currentGameInst; request.getSession().setAttribute(SESSION_GAME_KEY, this.currentGameInst); } public void removeGameInst() { request.getSession().removeAttribute(SESSION_GAME_KEY); } /** * @return the value of cookie with given key * @throws CookieNotFoundException */ public String getCookieVal(String key) throws CookieNotFoundException { for (Cookie c : request.getCookies()) if (c.getName().equalsIgnoreCase(key)) return c.getValue(); throw new CookieNotFoundException(key); } /** * adds a cookie to response */ public void addCookie(String key, String value) { response.addCookie(new Cookie(key, value)); } public boolean isMultipartContent() { return ServletFileUpload.isMultipartContent(request); } public Map<String, FileItem> getMultipartContent() throws FileUploadException, IllegalAccessException { if (!ServletFileUpload.isMultipartContent(request)) throw new IllegalAccessException(); FileItemFactory factory = new DiskFileItemFactory(); ServletFileUpload upload = new ServletFileUpload(factory); Map<String, FileItem> result = new HashMap<String, FileItem>(); @SuppressWarnings("unchecked") List<FileItem> items = upload.parseRequest(request); for (FileItem fi : items) { result.put(fi.getFieldName(), fi); } return result; } }