001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 //======================================================================== 018 //Copyright 2007 CSC - Scientific Computing Ltd. 019 //======================================================================== 020 package org.apache.activemq.util; 021 022 023 import java.io.File; 024 import java.io.FileOutputStream; 025 import java.io.IOException; 026 import java.net.HttpURLConnection; 027 import java.net.URL; 028 029 import javax.servlet.Filter; 030 import javax.servlet.FilterChain; 031 import javax.servlet.FilterConfig; 032 import javax.servlet.ServletException; 033 import javax.servlet.ServletRequest; 034 import javax.servlet.ServletResponse; 035 import javax.servlet.UnavailableException; 036 import javax.servlet.http.HttpServletRequest; 037 import javax.servlet.http.HttpServletResponse; 038 039 import org.mortbay.log.Log; 040 import org.mortbay.util.IO; 041 import org.mortbay.util.URIUtil; 042 043 /** 044 * <p> 045 * Adds support for HTTP PUT, MOVE and DELETE methods. If init parameters 046 * read-permission-role and write-permission-role are defined then all requests 047 * are authorized using the defined roles. Also GET methods are authorized. 048 * </p> 049 * 050 * @author Aleksi Kallio 051 */ 052 public class RestFilter implements Filter { 053 054 private static final String HTTP_HEADER_DESTINATION = "Destination"; 055 private static final String HTTP_METHOD_MOVE = "MOVE"; 056 private static final String HTTP_METHOD_PUT = "PUT"; 057 private static final String HTTP_METHOD_GET = "GET"; 058 private static final String HTTP_METHOD_DELETE = "DELETE"; 059 060 private String readPermissionRole; 061 private String writePermissionRole; 062 private FilterConfig filterConfig; 063 064 public void init(FilterConfig filterConfig) throws UnavailableException { 065 this.filterConfig = filterConfig; 066 readPermissionRole = filterConfig.getInitParameter("read-permission-role"); 067 writePermissionRole = filterConfig.getInitParameter("write-permission-role"); 068 } 069 070 private File locateFile(HttpServletRequest request) { 071 return new File(filterConfig.getServletContext().getRealPath(URIUtil.addPaths(request.getServletPath(), request.getPathInfo()))); 072 } 073 074 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { 075 if (!(request instanceof HttpServletRequest && response instanceof HttpServletResponse)) { 076 if (Log.isDebugEnabled()) { 077 Log.debug("request not HTTP, can not understand: " + request.toString()); 078 } 079 chain.doFilter(request, response); 080 return; 081 } 082 083 HttpServletRequest httpRequest = (HttpServletRequest)request; 084 HttpServletResponse httpResponse = (HttpServletResponse)response; 085 086 if (httpRequest.getMethod().equals(HTTP_METHOD_MOVE)) { 087 doMove(httpRequest, httpResponse); 088 } else if (httpRequest.getMethod().equals(HTTP_METHOD_PUT)) { 089 doPut(httpRequest, httpResponse); 090 } else if (httpRequest.getMethod().equals(HTTP_METHOD_GET)) { 091 if (checkGet(httpRequest, httpResponse)) { 092 chain.doFilter(httpRequest, httpResponse); // actual processing 093 // done elsewhere 094 } 095 } else if (httpRequest.getMethod().equals(HTTP_METHOD_DELETE)) { 096 doDelete(httpRequest, httpResponse); 097 } else { 098 chain.doFilter(httpRequest, httpResponse); 099 } 100 } 101 102 protected void doMove(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 103 if (Log.isDebugEnabled()) { 104 Log.debug("RESTful file access: MOVE request for " + request.getRequestURI()); 105 } 106 107 if (writePermissionRole != null && !request.isUserInRole(writePermissionRole)) { 108 response.sendError(HttpURLConnection.HTTP_FORBIDDEN); 109 return; 110 } 111 112 File file = locateFile(request); 113 String destination = request.getHeader(HTTP_HEADER_DESTINATION); 114 115 if (destination == null) { 116 response.sendError(HttpURLConnection.HTTP_BAD_REQUEST, "Destination header not found"); 117 return; 118 } 119 120 try { 121 URL destinationUrl = new URL(destination); 122 IO.copyFile(file, new File(destinationUrl.getFile())); 123 IO.delete(file); 124 } catch (IOException e) { 125 response.sendError(HttpURLConnection.HTTP_INTERNAL_ERROR); // file 126 // could 127 // not 128 // be 129 // moved 130 return; 131 } 132 133 response.setStatus(HttpURLConnection.HTTP_NO_CONTENT); // we return no 134 // content 135 } 136 137 protected boolean checkGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 138 if (Log.isDebugEnabled()) { 139 Log.debug("RESTful file access: GET request for " + request.getRequestURI()); 140 } 141 142 if (readPermissionRole != null && !request.isUserInRole(readPermissionRole)) { 143 response.sendError(HttpURLConnection.HTTP_FORBIDDEN); 144 return false; 145 } else { 146 return true; 147 } 148 } 149 150 protected void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 151 if (Log.isDebugEnabled()) { 152 Log.debug("RESTful file access: PUT request for " + request.getRequestURI()); 153 } 154 155 if (writePermissionRole != null && !request.isUserInRole(writePermissionRole)) { 156 response.sendError(HttpURLConnection.HTTP_FORBIDDEN); 157 return; 158 } 159 160 File file = locateFile(request); 161 162 if (file.exists()) { 163 boolean success = file.delete(); // replace file if it exists 164 if (!success) { 165 response.sendError(HttpURLConnection.HTTP_INTERNAL_ERROR); // file 166 // existed 167 // and 168 // could 169 // not 170 // be 171 // deleted 172 return; 173 } 174 } 175 176 FileOutputStream out = new FileOutputStream(file); 177 try { 178 IO.copy(request.getInputStream(), out); 179 } catch (IOException e) { 180 Log.warn(Log.EXCEPTION, e); // is this obsolete? 181 out.close(); 182 throw e; 183 } 184 185 response.setStatus(HttpURLConnection.HTTP_NO_CONTENT); // we return no 186 // content 187 } 188 189 protected void doDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 190 if (Log.isDebugEnabled()) { 191 Log.debug("RESTful file access: DELETE request for " + request.getRequestURI()); 192 } 193 194 if (writePermissionRole != null && !request.isUserInRole(writePermissionRole)) { 195 response.sendError(HttpURLConnection.HTTP_FORBIDDEN); 196 return; 197 } 198 199 File file = locateFile(request); 200 201 if (!file.exists()) { 202 response.sendError(HttpURLConnection.HTTP_NOT_FOUND); // file not 203 // found 204 return; 205 } 206 207 boolean success = IO.delete(file); // actual delete operation 208 209 if (success) { 210 response.setStatus(HttpURLConnection.HTTP_NO_CONTENT); // we return 211 // no 212 // content 213 } else { 214 response.sendError(HttpURLConnection.HTTP_INTERNAL_ERROR); // could 215 // not 216 // be 217 // deleted 218 // due 219 // to 220 // internal 221 // error 222 } 223 } 224 225 public void destroy() { 226 // nothing to destroy 227 } 228 }