/** * Copyright (c) 2008, Aberystwyth University * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * - Neither the name of the Centre for Advanced Software and * Intelligent Systems (CASIS) nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ package org.purl.sword.server; import java.io.IOException; import java.io.PrintWriter; import java.util.StringTokenizer; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.codec.binary.Base64; import org.apache.log4j.Logger; import org.purl.sword.base.HttpHeaders; import org.purl.sword.base.SWORDAuthenticationException; import org.purl.sword.base.SWORDErrorException; import org.purl.sword.base.SWORDException; import org.purl.sword.base.ServiceDocument; import org.purl.sword.base.ServiceDocumentRequest; /** * ServiceDocumentServlet * * @author Stuart Lewis */ public class ServiceDocumentServlet extends HttpServlet { /** The repository */ private SWORDServer myRepository; /** Authentication type. */ private String authN; /** Maximum file upload size in kB **/ private int maxUploadSize; /** Logger */ private static Logger log = Logger.getLogger(ServiceDocumentServlet.class); /** * Initialise the servlet. * * @throws ServletException */ public void init() throws ServletException { // Instantiate the correct SWORD Server class String className = getServletContext().getInitParameter("sword-server-class"); if (className == null) { log.fatal("Unable to read value of 'sword-server-class' from Servlet context"); } else { try { myRepository = (SWORDServer) Class.forName(className) .newInstance(); log.info("Using " + className + " as the SWORDServer"); } catch (Exception e) { log.fatal("Unable to instantiate class from 'server-class': " + className); throw new ServletException( "Unable to instantiate class from 'server-class': " + className); } } // Set the authentication method authN = getServletContext().getInitParameter("authentication-method"); if ((authN == null) || ("".equals(authN))) { authN = "None"; } log.info("Authentication type set to: " + authN); String maxUploadSizeStr = getServletContext().getInitParameter("maxUploadSize"); if ((maxUploadSizeStr == null) || (maxUploadSizeStr.equals("")) || (maxUploadSizeStr.equals("-1"))) { maxUploadSize = -1; log.warn("No maxUploadSize set, so setting max file upload size to unlimited."); } else { try { maxUploadSize = Integer.parseInt(maxUploadSizeStr); log.info("Setting max file upload size to " + maxUploadSize); } catch (NumberFormatException nfe) { maxUploadSize = -1; log.warn("maxUploadSize not a number, so setting max file upload size to unlimited."); } } } /** * Process the get request. */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Create the ServiceDocumentRequest ServiceDocumentRequest sdr = new ServiceDocumentRequest(); // Are there any authentication details? String usernamePassword = getUsernamePassword(request); if ((usernamePassword != null) && (!usernamePassword.equals(""))) { int p = usernamePassword.indexOf(":"); if (p != -1) { sdr.setUsername(usernamePassword.substring(0, p)); sdr.setPassword(usernamePassword.substring(p + 1)); } } else if (authenticateWithBasic()) { String s = "Basic realm=\"SWORD\""; response.setHeader("WWW-Authenticate", s); response.setStatus(401); return; } // Set the x-on-behalf-of header sdr.setOnBehalfOf(request.getHeader(HttpHeaders.X_ON_BEHALF_OF .toString())); // Set the IP address sdr.setIPAddress(request.getRemoteAddr()); // Set the deposit location sdr.setLocation(getUrl(request)); // Get the ServiceDocument try { ServiceDocument sd = myRepository.doServiceDocument(sdr); if ((sd.getService().getMaxUploadSize() == -1) && (maxUploadSize != -1)) { sd.getService().setMaxUploadSize(maxUploadSize); } // Print out the Service Document response.setContentType("application/atomsvc+xml; charset=UTF-8"); PrintWriter out = response.getWriter(); out.write(sd.marshall()); out.flush(); } catch (SWORDAuthenticationException sae) { if (authN.equals("Basic")) { String s = "Basic realm=\"SWORD\""; response.setHeader("WWW-Authenticate", s); response.setStatus(401); } } catch (SWORDErrorException see) { // Return the relevant HTTP status code response.sendError(see.getStatus(), see.getDescription()); } catch (SWORDException se) { se.printStackTrace(); // Throw a HTTP 500 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, se.getMessage()); } } /** * Process the post request. This will return an unimplemented response. */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Send a '501 Not Implemented' response.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED); } /** * Utiliy method to return the username and password (separated by a colon * ':') * * @param request * @return The username and password combination */ private String getUsernamePassword(HttpServletRequest request) { try { String authHeader = request.getHeader("Authorization"); if (authHeader != null) { StringTokenizer st = new StringTokenizer(authHeader); if (st.hasMoreTokens()) { String basic = st.nextToken(); if (basic.equalsIgnoreCase("Basic")) { String credentials = st.nextToken(); String userPass = new String(Base64 .decodeBase64(credentials.getBytes())); return userPass; } } } } catch (Exception e) { log.debug(e.toString()); } return null; } /** * Utility method to decide if we are using HTTP Basic authentication * * @return if HTTP Basic authentication is in use or not */ private boolean authenticateWithBasic() { if (authN.equalsIgnoreCase("Basic")) { return true; } else { return false; } } /** * Utility method to construct the URL called for this Servlet * * @param req The request object * @return The URL */ private static String getUrl(HttpServletRequest req) { String reqUrl = req.getRequestURL().toString(); String queryString = req.getQueryString(); log.debug("Requested url is: " + reqUrl); if (queryString != null) { reqUrl += "?" + queryString; } log.debug("Requested url with Query String is: " + reqUrl); return reqUrl; } }