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.apache.commons.logging.Log;
040 import org.apache.commons.logging.LogFactory;
041
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 private static final Log LOG = LogFactory.getLog(RestFilter.class);
054
055 private static final String HTTP_HEADER_DESTINATION = "Destination";
056 private static final String HTTP_METHOD_MOVE = "MOVE";
057 private static final String HTTP_METHOD_PUT = "PUT";
058 private static final String HTTP_METHOD_GET = "GET";
059 private static final String HTTP_METHOD_DELETE = "DELETE";
060
061 private String readPermissionRole;
062 private String writePermissionRole;
063 private FilterConfig filterConfig;
064
065 public void init(FilterConfig filterConfig) throws UnavailableException {
066 this.filterConfig = filterConfig;
067 readPermissionRole = filterConfig.getInitParameter("read-permission-role");
068 writePermissionRole = filterConfig.getInitParameter("write-permission-role");
069 }
070
071 private File locateFile(HttpServletRequest request) {
072 return new File(filterConfig.getServletContext().getRealPath(request.getServletPath()), request.getPathInfo());
073 }
074
075 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
076 if (!(request instanceof HttpServletRequest && response instanceof HttpServletResponse)) {
077 if (LOG.isDebugEnabled()) {
078 LOG.debug("request not HTTP, can not understand: " + request.toString());
079 }
080 chain.doFilter(request, response);
081 return;
082 }
083
084 HttpServletRequest httpRequest = (HttpServletRequest)request;
085 HttpServletResponse httpResponse = (HttpServletResponse)response;
086
087 if (httpRequest.getMethod().equals(HTTP_METHOD_MOVE)) {
088 doMove(httpRequest, httpResponse);
089 } else if (httpRequest.getMethod().equals(HTTP_METHOD_PUT)) {
090 doPut(httpRequest, httpResponse);
091 } else if (httpRequest.getMethod().equals(HTTP_METHOD_GET)) {
092 if (checkGet(httpRequest, httpResponse)) {
093 chain.doFilter(httpRequest, httpResponse); // actual processing
094 // done elsewhere
095 }
096 } else if (httpRequest.getMethod().equals(HTTP_METHOD_DELETE)) {
097 doDelete(httpRequest, httpResponse);
098 } else {
099 chain.doFilter(httpRequest, httpResponse);
100 }
101 }
102
103 protected void doMove(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
104 if (LOG.isDebugEnabled()) {
105 LOG.debug("RESTful file access: MOVE request for " + request.getRequestURI());
106 }
107
108 if (writePermissionRole != null && !request.isUserInRole(writePermissionRole)) {
109 response.sendError(HttpURLConnection.HTTP_FORBIDDEN);
110 return;
111 }
112
113 File file = locateFile(request);
114 String destination = request.getHeader(HTTP_HEADER_DESTINATION);
115
116 if (destination == null) {
117 response.sendError(HttpURLConnection.HTTP_BAD_REQUEST, "Destination header not found");
118 return;
119 }
120
121 try {
122 URL destinationUrl = new URL(destination);
123 IOHelper.copyFile(file, new File(destinationUrl.getFile()));
124 IOHelper.deleteFile(file);
125 } catch (IOException e) {
126 response.sendError(HttpURLConnection.HTTP_INTERNAL_ERROR); // file
127 // could
128 // not
129 // be
130 // moved
131 return;
132 }
133
134 response.setStatus(HttpURLConnection.HTTP_NO_CONTENT); // we return no
135 // content
136 }
137
138 protected boolean checkGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
139 if (LOG.isDebugEnabled()) {
140 LOG.debug("RESTful file access: GET request for " + request.getRequestURI());
141 }
142
143 if (readPermissionRole != null && !request.isUserInRole(readPermissionRole)) {
144 response.sendError(HttpURLConnection.HTTP_FORBIDDEN);
145 return false;
146 } else {
147 return true;
148 }
149 }
150
151 protected void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
152 if (LOG.isDebugEnabled()) {
153 LOG.debug("RESTful file access: PUT request for " + request.getRequestURI());
154 }
155
156 if (writePermissionRole != null && !request.isUserInRole(writePermissionRole)) {
157 response.sendError(HttpURLConnection.HTTP_FORBIDDEN);
158 return;
159 }
160
161 File file = locateFile(request);
162
163 if (file.exists()) {
164 boolean success = file.delete(); // replace file if it exists
165 if (!success) {
166 response.sendError(HttpURLConnection.HTTP_INTERNAL_ERROR); // file
167 // existed
168 // and
169 // could
170 // not
171 // be
172 // deleted
173 return;
174 }
175 }
176
177 FileOutputStream out = new FileOutputStream(file);
178 try {
179 IOHelper.copyInputStream(request.getInputStream(), out);
180 } catch (IOException e) {
181 LOG.warn("Exception occured" , e);
182 out.close();
183 throw e;
184 }
185
186 response.setStatus(HttpURLConnection.HTTP_NO_CONTENT); // we return no
187 // content
188 }
189
190 protected void doDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
191 if (LOG.isDebugEnabled()) {
192 LOG.debug("RESTful file access: DELETE request for " + request.getRequestURI());
193 }
194
195 if (writePermissionRole != null && !request.isUserInRole(writePermissionRole)) {
196 response.sendError(HttpURLConnection.HTTP_FORBIDDEN);
197 return;
198 }
199
200 File file = locateFile(request);
201
202 if (!file.exists()) {
203 response.sendError(HttpURLConnection.HTTP_NOT_FOUND); // file not
204 // found
205 return;
206 }
207
208 boolean success = IOHelper.deleteFile(file); // actual delete operation
209
210 if (success) {
211 response.setStatus(HttpURLConnection.HTTP_NO_CONTENT); // we return
212 // no
213 // content
214 } else {
215 response.sendError(HttpURLConnection.HTTP_INTERNAL_ERROR); // could
216 // not
217 // be
218 // deleted
219 // due
220 // to
221 // internal
222 // error
223 }
224 }
225
226 public void destroy() {
227 // nothing to destroy
228 }
229 }