Java tutorial
//============================================================================= //=== Copyright (C) 2001-2005 Food and Agriculture Organization of the //=== United Nations (FAO-UN), United Nations World Food Programme (WFP) //=== and United Nations Environment Programme (UNEP) //=== //=== This library is free software; you can redistribute it and/or //=== modify it under the terms of the GNU Lesser General Public //=== License as published by the Free Software Foundation; either //=== version 2.1 of the License, or (at your option) any later version. //=== //=== This library is distributed in the hope that it will be useful, //=== but WITHOUT ANY WARRANTY; without even the implied warranty of //=== MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU //=== Lesser General Public License for more details. //=== //=== You should have received a copy of the GNU Lesser General Public //=== License along with this library; if not, write to the Free Software //=== Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA //=== //=== Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2, //=== Rome - Italy. email: GeoNetwork@fao.org //============================================================================== package jeeves.server.sources; import jeeves.constants.Jeeves; import jeeves.server.sources.ServiceRequest.InputMethod; import jeeves.server.sources.ServiceRequest.OutputMethod; import jeeves.server.sources.http.HttpServiceRequest; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileUploadBase; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; import jeeves.exceptions.FileUploadTooBigEx; import jeeves.utils.Log; import jeeves.utils.Xml; import org.jdom.Element; import org.jdom.JDOMException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; //============================================================================= public final class ServiceRequestFactory { private static String JSON_URL_FLAG = "@json"; private static String DEBUG_URL_FLAG = "!"; /** * Default constructor. * Builds a ServiceRequestFactory. */ private ServiceRequestFactory() { } /** Builds the request with data supplied by tomcat. * A request is in the form: srv/<language>/<service>[!]<parameters> */ public static ServiceRequest create(HttpServletRequest req, HttpServletResponse res, String uploadDir, int maxUploadSize) throws Exception { String url = req.getPathInfo(); // FIXME: if request character encoding is undefined set it to UTF-8 String encoding = req.getCharacterEncoding(); try { // verify that encoding is valid Charset.forName(encoding); } catch (Exception e) { encoding = null; } if (encoding == null) { try { req.setCharacterEncoding(Jeeves.ENCODING); } catch (UnsupportedEncodingException ex) { ex.printStackTrace(); } } //--- extract basic info HttpServiceRequest srvReq = new HttpServiceRequest(res); srvReq.setDebug(extractDebug(url)); srvReq.setLanguage(extractLanguage(url)); srvReq.setService(extractService(url)); srvReq.setJSONOutput(extractJSONFlag(url)); String ip = req.getRemoteAddr(); String forwardedFor = req.getHeader("x-forwarded-for"); if (forwardedFor != null) ip = forwardedFor; srvReq.setAddress(ip); srvReq.setOutputStream(res.getOutputStream()); //--- discover the input/output methods String accept = req.getHeader("Accept"); if (accept != null) { int soapNDX = accept.indexOf("application/soap+xml"); int xmlNDX = accept.indexOf("application/xml"); int htmlNDX = accept.indexOf("html"); if (soapNDX != -1) srvReq.setOutputMethod(OutputMethod.SOAP); else if (xmlNDX != -1 && htmlNDX == -1) srvReq.setOutputMethod(OutputMethod.XML); } if ("POST".equals(req.getMethod())) { srvReq.setInputMethod(InputMethod.POST); String contType = req.getContentType(); if (contType != null) { if (contType.indexOf("application/soap+xml") != -1) { srvReq.setInputMethod(InputMethod.SOAP); srvReq.setOutputMethod(OutputMethod.SOAP); } else if (contType.indexOf("application/xml") != -1 || contType.indexOf("text/xml") != -1) srvReq.setInputMethod(InputMethod.XML); } } //--- retrieve input parameters InputMethod input = srvReq.getInputMethod(); if ((input == InputMethod.XML) || (input == InputMethod.SOAP)) { if (req.getMethod().equals("GET")) srvReq.setParams(extractParameters(req, uploadDir, maxUploadSize)); else srvReq.setParams(extractXmlParameters(req)); } else { //--- GET or POST srvReq.setParams(extractParameters(req, uploadDir, maxUploadSize)); } srvReq.setHeaders(extractHeaders(req)); return srvReq; } /** * Build up a map of the HTTP headers. * @param req The web request * @return Map of header keys and values. */ @SuppressWarnings("unchecked") private static Map<String, String> extractHeaders(HttpServletRequest req) { Map<String, String> headerMap = new HashMap<String, String>(); for (Enumeration<String> e = req.getHeaderNames(); e.hasMoreElements();) { String key = e.nextElement(); headerMap.put(key, req.getHeader(key)); } // The remote user needs to be saved as a header also if (req.getRemoteUser() != null) { headerMap.put("REMOTE_USER", req.getRemoteUser()); } return headerMap; } //--------------------------------------------------------------------------- //--- //--- Input retrieving methods //--- //--------------------------------------------------------------------------- /** Extracts the debug option from the url */ private static boolean extractDebug(String url) { if (url == null) return false; return url.indexOf(DEBUG_URL_FLAG) != -1; } /** * Extracts the JSON output flag from the url */ private static boolean extractJSONFlag(String url) { if (url == null) return false; return url.indexOf(JSON_URL_FLAG) != -1; } //--------------------------------------------------------------------------- /** * Extracts the language code from the url. */ public static String extractLanguage(String url) { if (url == null) { return null; } url = url.substring(1); int pos = url.indexOf('/'); if (pos == -1) { return null; } return url.substring(0, pos); } //--------------------------------------------------------------------------- /** Extracts the service name from the url */ private static String extractService(String url) { if (url == null) return null; if (url.endsWith(DEBUG_URL_FLAG)) url = url.substring(0, url.length() - 1); if (url.endsWith(JSON_URL_FLAG)) url = url.substring(0, url.length() - JSON_URL_FLAG.length()); int pos = url.lastIndexOf('/'); if (pos == -1) return null; return url.substring(pos + 1); } //--------------------------------------------------------------------------- private static Element extractXmlParameters(HttpServletRequest req) throws IOException, JDOMException { return Xml.loadStream(req.getInputStream()); } //--------------------------------------------------------------------------- @SuppressWarnings("unchecked") private static Element extractParameters(HttpServletRequest req, String uploadDir, int maxUploadSize) throws Exception { //--- set parameters from multipart request if (ServletFileUpload.isMultipartContent(req)) return getMultipartParams(req, uploadDir, maxUploadSize); Element params = new Element(Jeeves.Elem.REQUEST); //--- add parameters from POST request for (Enumeration<String> e = req.getParameterNames(); e.hasMoreElements();) { String name = e.nextElement(); String values[] = req.getParameterValues(name); //--- we don't overwrite params given in the url if (!name.equals("")) if (params.getChild(name) == null) for (int i = 0; i < values.length; i++) params.addContent(new Element(name).setText(values[i])); } return params; } //--------------------------------------------------------------------------- private static Element getMultipartParams(HttpServletRequest req, String uploadDir, int maxUploadSize) throws Exception { Element params = new Element("params"); DiskFileItemFactory fif = new DiskFileItemFactory(); ServletFileUpload sfu = new ServletFileUpload(fif); sfu.setSizeMax(((long) maxUploadSize) * 1024L * 1024L); try { for (Object i : sfu.parseRequest(req)) { FileItem item = (FileItem) i; String name = item.getFieldName(); if (item.isFormField()) { String encoding = req.getCharacterEncoding(); params.addContent(new Element(name).setText(item.getString(encoding))); } else { String file = item.getName(); String type = item.getContentType(); long size = item.getSize(); if (Log.isDebugEnabled(Log.REQUEST)) Log.debug(Log.REQUEST, "Uploading file " + file + " type: " + type + " size: " + size); //--- remove path information from file (some browsers put it, like IE) file = simplifyName(file); if (Log.isDebugEnabled(Log.REQUEST)) Log.debug(Log.REQUEST, "File is called " + file + " after simplification"); //--- we could get troubles if 2 users upload files with the same name item.write(new File(uploadDir, file)); Element elem = new Element(name).setAttribute("type", "file") .setAttribute("size", Long.toString(size)).setText(file); if (type != null) elem.setAttribute("content-type", type); if (Log.isDebugEnabled(Log.REQUEST)) Log.debug(Log.REQUEST, "Adding to parameters: " + Xml.getString(elem)); params.addContent(elem); } } } catch (FileUploadBase.SizeLimitExceededException e) { throw new FileUploadTooBigEx(); } return params; } //--------------------------------------------------------------------------- private static String simplifyName(String file) { //--- get the file name without path file = new File(file).getName(); //--- the previous getName method is not enough //--- with IE and a server running on Linux we still have a path problem int pos1 = file.lastIndexOf("\\"); int pos2 = file.lastIndexOf('/'); int pos = Math.max(pos1, pos2); if (pos != -1) file = file.substring(pos + 1).trim(); //--- we need to sanitize the filename here - make it UTF8, no ctrl //--- characters and only containing [A-Z][a-z][0-9],_.- //--- start by converting to UTF-8 try { byte[] utf8Bytes = file.getBytes("UTF8"); file = new String(utf8Bytes, "UTF8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } //--- replace whitespace with underscore file = file.replaceAll("\\s", "_"); //--- remove everything that isn't [0-9][a-z][A-Z],#_.- file = file.replaceAll("[^\\w&&[^,_.-]]", ""); return file; } } //=============================================================================