root / src / gr / ebs / gss / server / rest / FilesHandler.java @ 086c7250
History | View | Annotate | Download (84.7 kB)
1 | 14ad7326 | pastith | /*
|
---|---|---|---|
2 | c62f0b96 | Natasa Kapravelou | * Copyright 2008, 2009, 2010 Electronic Business Systems Ltd.
|
3 | 14ad7326 | pastith | *
|
4 | 14ad7326 | pastith | * This file is part of GSS.
|
5 | 14ad7326 | pastith | *
|
6 | 14ad7326 | pastith | * GSS is free software: you can redistribute it and/or modify
|
7 | 14ad7326 | pastith | * it under the terms of the GNU General Public License as published by
|
8 | 14ad7326 | pastith | * the Free Software Foundation, either version 3 of the License, or
|
9 | 14ad7326 | pastith | * (at your option) any later version.
|
10 | 14ad7326 | pastith | *
|
11 | 14ad7326 | pastith | * GSS is distributed in the hope that it will be useful,
|
12 | 14ad7326 | pastith | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 | 14ad7326 | pastith | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 | 14ad7326 | pastith | * GNU General Public License for more details.
|
15 | 14ad7326 | pastith | *
|
16 | 14ad7326 | pastith | * You should have received a copy of the GNU General Public License
|
17 | 14ad7326 | pastith | * along with GSS. If not, see <http://www.gnu.org/licenses/>.
|
18 | 14ad7326 | pastith | */
|
19 | 14ad7326 | pastith | package gr.ebs.gss.server.rest; |
20 | 14ad7326 | pastith | |
21 | a91ef7e8 | Panagiotis Astithas | import static gr.ebs.gss.server.configuration.GSSConfigurationFactory.getConfiguration; |
22 | af6aa461 | Christos V. Stathis | import gr.ebs.gss.common.exceptions.DuplicateNameException; |
23 | af6aa461 | Christos V. Stathis | import gr.ebs.gss.common.exceptions.GSSIOException; |
24 | af6aa461 | Christos V. Stathis | import gr.ebs.gss.common.exceptions.InsufficientPermissionsException; |
25 | af6aa461 | Christos V. Stathis | import gr.ebs.gss.common.exceptions.ObjectNotFoundException; |
26 | af6aa461 | Christos V. Stathis | import gr.ebs.gss.common.exceptions.QuotaExceededException; |
27 | af6aa461 | Christos V. Stathis | import gr.ebs.gss.common.exceptions.RpcException; |
28 | a91ef7e8 | Panagiotis Astithas | import gr.ebs.gss.server.Login; |
29 | f7c44c33 | fstamatelopoulos | import gr.ebs.gss.server.domain.FileBody; |
30 | f7c44c33 | fstamatelopoulos | import gr.ebs.gss.server.domain.FileHeader; |
31 | f5903adf | pastith | import gr.ebs.gss.server.domain.FileUploadStatus; |
32 | f7c44c33 | fstamatelopoulos | import gr.ebs.gss.server.domain.Folder; |
33 | f7c44c33 | fstamatelopoulos | import gr.ebs.gss.server.domain.Group; |
34 | f7c44c33 | fstamatelopoulos | import gr.ebs.gss.server.domain.Permission; |
35 | 14ad7326 | pastith | import gr.ebs.gss.server.domain.User; |
36 | e150a336 | pastith | import gr.ebs.gss.server.ejb.ExternalAPI; |
37 | 3b6b7f25 | Dimitris Routsis | import gr.ebs.gss.server.ejb.TransactionHelper; |
38 | 14ad7326 | pastith | |
39 | 14ad7326 | pastith | import java.io.BufferedReader; |
40 | 14ad7326 | pastith | import java.io.ByteArrayInputStream; |
41 | 14ad7326 | pastith | import java.io.ByteArrayOutputStream; |
42 | 14ad7326 | pastith | import java.io.File; |
43 | 14ad7326 | pastith | import java.io.FileInputStream; |
44 | 14ad7326 | pastith | import java.io.FileNotFoundException; |
45 | 14ad7326 | pastith | import java.io.IOException; |
46 | 14ad7326 | pastith | import java.io.InputStream; |
47 | 95da8819 | koutsoub | import java.io.InputStreamReader; |
48 | 14ad7326 | pastith | import java.io.OutputStreamWriter; |
49 | 14ad7326 | pastith | import java.io.PrintWriter; |
50 | 5e2b8ec6 | koutsoub | import java.io.UnsupportedEncodingException; |
51 | 14ad7326 | pastith | import java.net.URI; |
52 | 14ad7326 | pastith | import java.net.URISyntaxException; |
53 | 47d800f9 | pastith | import java.net.URLDecoder; |
54 | 47d800f9 | pastith | import java.net.URLEncoder; |
55 | 14ad7326 | pastith | import java.util.ArrayList; |
56 | a91ef7e8 | Panagiotis Astithas | import java.util.Arrays; |
57 | fc5ef2cc | droutsis | import java.util.Collection; |
58 | 8f128261 | droutsis | import java.util.Date; |
59 | 14ad7326 | pastith | import java.util.HashSet; |
60 | 31e19588 | Natasa Kapravelou | import java.util.Iterator; |
61 | 14ad7326 | pastith | import java.util.List; |
62 | 14ad7326 | pastith | import java.util.Set; |
63 | 5e2b8ec6 | koutsoub | import java.util.StringTokenizer; |
64 | 204107fb | Panagiotis Astithas | import java.util.concurrent.Callable; |
65 | 14ad7326 | pastith | |
66 | 14ad7326 | pastith | import javax.servlet.ServletContext; |
67 | 14ad7326 | pastith | import javax.servlet.ServletException; |
68 | 14ad7326 | pastith | import javax.servlet.ServletOutputStream; |
69 | a91ef7e8 | Panagiotis Astithas | import javax.servlet.http.Cookie; |
70 | 14ad7326 | pastith | import javax.servlet.http.HttpServletRequest; |
71 | 14ad7326 | pastith | import javax.servlet.http.HttpServletResponse; |
72 | 14ad7326 | pastith | |
73 | a91ef7e8 | Panagiotis Astithas | import org.apache.commons.codec.binary.Base64; |
74 | e150a336 | pastith | import org.apache.commons.fileupload.FileItemIterator; |
75 | e150a336 | pastith | import org.apache.commons.fileupload.FileItemStream; |
76 | e150a336 | pastith | import org.apache.commons.fileupload.FileUploadException; |
77 | e150a336 | pastith | import org.apache.commons.fileupload.ProgressListener; |
78 | e150a336 | pastith | import org.apache.commons.fileupload.servlet.ServletFileUpload; |
79 | bda7d76d | pastith | import org.apache.commons.fileupload.util.Streams; |
80 | bda7d76d | pastith | import org.apache.commons.httpclient.util.DateParseException; |
81 | bda7d76d | pastith | import org.apache.commons.httpclient.util.DateUtil; |
82 | 14ad7326 | pastith | import org.apache.commons.logging.Log; |
83 | 14ad7326 | pastith | import org.apache.commons.logging.LogFactory; |
84 | 14ad7326 | pastith | import org.json.JSONArray; |
85 | 14ad7326 | pastith | import org.json.JSONException; |
86 | 14ad7326 | pastith | import org.json.JSONObject; |
87 | 14ad7326 | pastith | |
88 | 14ad7326 | pastith | |
89 | 14ad7326 | pastith | /**
|
90 | 14ad7326 | pastith | * A class that handles operations on the 'files' namespace.
|
91 | 14ad7326 | pastith | *
|
92 | 14ad7326 | pastith | * @author past
|
93 | 14ad7326 | pastith | */
|
94 | 14ad7326 | pastith | public class FilesHandler extends RequestHandler { |
95 | 14ad7326 | pastith | /**
|
96 | 14ad7326 | pastith | * The request parameter name for fetching a different version.
|
97 | 14ad7326 | pastith | */
|
98 | 14ad7326 | pastith | private static final String VERSION_PARAM = "version"; |
99 | 14ad7326 | pastith | |
100 | 14ad7326 | pastith | /**
|
101 | 14ad7326 | pastith | * The request attribute containing the owner of the destination URI
|
102 | 14ad7326 | pastith | * in a copy or move request.
|
103 | 14ad7326 | pastith | */
|
104 | 14ad7326 | pastith | private static final String DESTINATION_OWNER_ATTRIBUTE = "destOwner"; |
105 | 14ad7326 | pastith | |
106 | e150a336 | pastith | private static final int TRACK_PROGRESS_PERCENT = 5; |
107 | e150a336 | pastith | |
108 | 14ad7326 | pastith | /**
|
109 | bda7d76d | pastith | * The form parameter name that contains the signature in a browser POST upload.
|
110 | bda7d76d | pastith | */
|
111 | bda7d76d | pastith | private static final String AUTHORIZATION_PARAMETER = "Authorization"; |
112 | bda7d76d | pastith | |
113 | bda7d76d | pastith | /**
|
114 | bda7d76d | pastith | * The form parameter name that contains the date in a browser POST upload.
|
115 | bda7d76d | pastith | */
|
116 | bda7d76d | pastith | private static final String DATE_PARAMETER = "Date"; |
117 | bda7d76d | pastith | |
118 | bda7d76d | pastith | /**
|
119 | f5903adf | pastith | * The request parameter name for making an upload progress request.
|
120 | f5903adf | pastith | */
|
121 | f5903adf | pastith | private static final String PROGRESS_PARAMETER = "progress"; |
122 | f5903adf | pastith | |
123 | f5903adf | pastith | /**
|
124 | 39c34533 | pastith | * The request parameter name for restoring a previous version of a file.
|
125 | 39c34533 | pastith | */
|
126 | 39c34533 | pastith | private static final String RESTORE_VERSION_PARAMETER = "restoreVersion"; |
127 | 39c34533 | pastith | |
128 | 39c34533 | pastith | /**
|
129 | 14ad7326 | pastith | * The logger.
|
130 | 14ad7326 | pastith | */
|
131 | 14ad7326 | pastith | private static Log logger = LogFactory.getLog(FilesHandler.class); |
132 | 14ad7326 | pastith | |
133 | 14ad7326 | pastith | /**
|
134 | 14ad7326 | pastith | * The servlet context provided by the call site.
|
135 | 14ad7326 | pastith | */
|
136 | 14ad7326 | pastith | private ServletContext context;
|
137 | 14ad7326 | pastith | |
138 | 14ad7326 | pastith | /**
|
139 | 31e19588 | Natasa Kapravelou | * The style sheet for displaying the directory listings.
|
140 | 31e19588 | Natasa Kapravelou | */
|
141 | 31e19588 | Natasa Kapravelou | private static final String GSS_CSS = "H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} " + "H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} " + "H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} " + "BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} " + "B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} " + "P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}" + "A {color : black;}" + "A.name {color : black;}" + "HR {color : #525D76;}"; |
142 | 31e19588 | Natasa Kapravelou | |
143 | 31e19588 | Natasa Kapravelou | |
144 | 31e19588 | Natasa Kapravelou | /**
|
145 | 14ad7326 | pastith | * @param servletContext
|
146 | 14ad7326 | pastith | */
|
147 | 14ad7326 | pastith | public FilesHandler(ServletContext servletContext) {
|
148 | 14ad7326 | pastith | context = servletContext; |
149 | 14ad7326 | pastith | } |
150 | 14ad7326 | pastith | |
151 | 2f1a60e0 | Dimitris Routsis | private void updateAccounting(final User user, final Date date, final long bandwidthDiff) { |
152 | 2f1a60e0 | Dimitris Routsis | try {
|
153 | 2f1a60e0 | Dimitris Routsis | new TransactionHelper<Void>().tryExecute(new Callable<Void>() { |
154 | 2f1a60e0 | Dimitris Routsis | @Override
|
155 | 2f1a60e0 | Dimitris Routsis | public Void call() throws Exception { |
156 | 2f1a60e0 | Dimitris Routsis | getService().updateAccounting(user, date, bandwidthDiff); |
157 | 2f1a60e0 | Dimitris Routsis | return null; |
158 | 2f1a60e0 | Dimitris Routsis | } |
159 | 2f1a60e0 | Dimitris Routsis | }); |
160 | 2f1a60e0 | Dimitris Routsis | } catch (RuntimeException e) { |
161 | 2f1a60e0 | Dimitris Routsis | throw e;
|
162 | 2f1a60e0 | Dimitris Routsis | } catch (Exception e) { |
163 | 2f1a60e0 | Dimitris Routsis | // updateAccounting() doesn't throw any checked exceptions
|
164 | 2f1a60e0 | Dimitris Routsis | assert false; |
165 | 2f1a60e0 | Dimitris Routsis | } |
166 | 2f1a60e0 | Dimitris Routsis | } |
167 | 2f1a60e0 | Dimitris Routsis | |
168 | 14ad7326 | pastith | /**
|
169 | 14ad7326 | pastith | * Serve the specified resource, optionally including the data content.
|
170 | 14ad7326 | pastith | *
|
171 | 14ad7326 | pastith | * @param req The servlet request we are processing
|
172 | 14ad7326 | pastith | * @param resp The servlet response we are creating
|
173 | 14ad7326 | pastith | * @param content Should the content be included?
|
174 | 14ad7326 | pastith | *
|
175 | 14ad7326 | pastith | * @exception IOException if an input/output error occurs
|
176 | 14ad7326 | pastith | * @exception ServletException if a servlet-specified error occurs
|
177 | 14ad7326 | pastith | * @throws RpcException
|
178 | 14ad7326 | pastith | * @throws InsufficientPermissionsException
|
179 | 14ad7326 | pastith | * @throws ObjectNotFoundException
|
180 | 14ad7326 | pastith | */
|
181 | 14ad7326 | pastith | @Override
|
182 | 14ad7326 | pastith | protected void serveResource(HttpServletRequest req, HttpServletResponse resp, boolean content) |
183 | 14ad7326 | pastith | throws IOException, ServletException { |
184 | 14ad7326 | pastith | boolean authDeferred = getAuthDeferred(req);
|
185 | 14ad7326 | pastith | String path = getInnerPath(req, PATH_FILES);
|
186 | 14ad7326 | pastith | if (path.equals("")) |
187 | 14ad7326 | pastith | path = "/";
|
188 | 8fa7f8ff | pastith | try {
|
189 | 8fa7f8ff | pastith | path = URLDecoder.decode(path, "UTF-8"); |
190 | 8fa7f8ff | pastith | } catch (IllegalArgumentException e) { |
191 | 8fa7f8ff | pastith | resp.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage()); |
192 | 8fa7f8ff | pastith | return;
|
193 | 8fa7f8ff | pastith | } |
194 | f5903adf | pastith | String progress = req.getParameter(PROGRESS_PARAMETER);
|
195 | 14ad7326 | pastith | |
196 | 8e471ce5 | Natasa Kapravelou | if (logger.isDebugEnabled())
|
197 | 14ad7326 | pastith | if (content)
|
198 | 14ad7326 | pastith | logger.debug("Serving resource '" + path + "' headers and data"); |
199 | 14ad7326 | pastith | else
|
200 | 14ad7326 | pastith | logger.debug("Serving resource '" + path + "' headers only"); |
201 | 14ad7326 | pastith | |
202 | 14ad7326 | pastith | User user = getUser(req); |
203 | 14ad7326 | pastith | User owner = getOwner(req); |
204 | 14ad7326 | pastith | boolean exists = true; |
205 | 14ad7326 | pastith | Object resource = null; |
206 | f7c44c33 | fstamatelopoulos | FileHeader file = null;
|
207 | f7c44c33 | fstamatelopoulos | Folder folder = null;
|
208 | 14ad7326 | pastith | try {
|
209 | 68410d59 | pastith | resource = getService().getResourceAtPath(owner.getId(), path, false);
|
210 | 14ad7326 | pastith | } catch (ObjectNotFoundException e) {
|
211 | 14ad7326 | pastith | exists = false;
|
212 | 14ad7326 | pastith | } catch (RpcException e) {
|
213 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path); |
214 | 14ad7326 | pastith | return;
|
215 | 14ad7326 | pastith | } |
216 | 14ad7326 | pastith | |
217 | bdf739a9 | Natasa Kapravelou | if (!exists && authDeferred) {
|
218 | bdf739a9 | Natasa Kapravelou | // We do not want to leak information if the request
|
219 | bdf739a9 | Natasa Kapravelou | // was not authenticated.
|
220 | bdf739a9 | Natasa Kapravelou | resp.sendError(HttpServletResponse.SC_FORBIDDEN); |
221 | 14ad7326 | pastith | return;
|
222 | 14ad7326 | pastith | } |
223 | 14ad7326 | pastith | |
224 | f7c44c33 | fstamatelopoulos | if (resource instanceof Folder) |
225 | f7c44c33 | fstamatelopoulos | folder = (Folder) resource; |
226 | 14ad7326 | pastith | else
|
227 | f7c44c33 | fstamatelopoulos | file = (FileHeader) resource; // Note that file will be null, if (!exists).
|
228 | 14ad7326 | pastith | |
229 | 14ad7326 | pastith | // Now it's time to perform the deferred authentication check.
|
230 | 14ad7326 | pastith | // Since regular signature checking was already performed,
|
231 | 1d36b941 | pastith | // we need to check the read-all flag or the signature-in-parameters.
|
232 | eaf8360b | Christos V. Stathis | if (authDeferred) {
|
233 | d235f94f | Natasa Kapravelou | if (file != null && !file.isReadForAll() && content) { |
234 | 1d36b941 | pastith | // Check for GET with the signature in the request parameters.
|
235 | 1d36b941 | pastith | String auth = req.getParameter(AUTHORIZATION_PARAMETER);
|
236 | 1d36b941 | pastith | String dateParam = req.getParameter(DATE_PARAMETER);
|
237 | 1d36b941 | pastith | if (auth == null || dateParam == null) { |
238 | a91ef7e8 | Panagiotis Astithas | // Check for a valid authentication cookie.
|
239 | a91ef7e8 | Panagiotis Astithas | if (req.getCookies() != null) { |
240 | 6567092b | Panagiotis Astithas | boolean found = false; |
241 | a91ef7e8 | Panagiotis Astithas | for (Cookie cookie : req.getCookies())
|
242 | a91ef7e8 | Panagiotis Astithas | if (Login.AUTH_COOKIE.equals(cookie.getName())) {
|
243 | a91ef7e8 | Panagiotis Astithas | String cookieauth = cookie.getValue();
|
244 | a91ef7e8 | Panagiotis Astithas | int sepIndex = cookieauth.indexOf(Login.COOKIE_SEPARATOR);
|
245 | a91ef7e8 | Panagiotis Astithas | if (sepIndex == -1) { |
246 | a91ef7e8 | Panagiotis Astithas | handleAuthFailure(req, resp); |
247 | a91ef7e8 | Panagiotis Astithas | return;
|
248 | a91ef7e8 | Panagiotis Astithas | } |
249 | a91ef7e8 | Panagiotis Astithas | String username = URLDecoder.decode(cookieauth.substring(0, sepIndex), "US-ASCII"); |
250 | a91ef7e8 | Panagiotis Astithas | user = null;
|
251 | a91ef7e8 | Panagiotis Astithas | try {
|
252 | a91ef7e8 | Panagiotis Astithas | user = getService().findUser(username); |
253 | a91ef7e8 | Panagiotis Astithas | } catch (RpcException e) {
|
254 | a91ef7e8 | Panagiotis Astithas | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path); |
255 | a91ef7e8 | Panagiotis Astithas | return;
|
256 | a91ef7e8 | Panagiotis Astithas | } |
257 | a91ef7e8 | Panagiotis Astithas | if (user == null) { |
258 | a91ef7e8 | Panagiotis Astithas | resp.sendError(HttpServletResponse.SC_FORBIDDEN); |
259 | a91ef7e8 | Panagiotis Astithas | return;
|
260 | a91ef7e8 | Panagiotis Astithas | } |
261 | a91ef7e8 | Panagiotis Astithas | req.setAttribute(USER_ATTRIBUTE, user); |
262 | a91ef7e8 | Panagiotis Astithas | String token = cookieauth.substring(sepIndex + 1); |
263 | a91ef7e8 | Panagiotis Astithas | if (user.getAuthToken() == null) { |
264 | a91ef7e8 | Panagiotis Astithas | resp.sendError(HttpServletResponse.SC_FORBIDDEN); |
265 | a91ef7e8 | Panagiotis Astithas | return;
|
266 | a91ef7e8 | Panagiotis Astithas | } |
267 | a91ef7e8 | Panagiotis Astithas | if (!Arrays.equals(user.getAuthToken(), Base64.decodeBase64(token))) { |
268 | a91ef7e8 | Panagiotis Astithas | resp.sendError(HttpServletResponse.SC_FORBIDDEN); |
269 | a91ef7e8 | Panagiotis Astithas | return;
|
270 | a91ef7e8 | Panagiotis Astithas | } |
271 | 6567092b | Panagiotis Astithas | found = true;
|
272 | a91ef7e8 | Panagiotis Astithas | break;
|
273 | a91ef7e8 | Panagiotis Astithas | } |
274 | 6567092b | Panagiotis Astithas | if (!found) {
|
275 | 6567092b | Panagiotis Astithas | handleAuthFailure(req, resp); |
276 | 6567092b | Panagiotis Astithas | return;
|
277 | 6567092b | Panagiotis Astithas | } |
278 | a91ef7e8 | Panagiotis Astithas | } else {
|
279 | a91ef7e8 | Panagiotis Astithas | handleAuthFailure(req, resp); |
280 | a91ef7e8 | Panagiotis Astithas | return;
|
281 | a91ef7e8 | Panagiotis Astithas | } |
282 | a91ef7e8 | Panagiotis Astithas | } else {
|
283 | a91ef7e8 | Panagiotis Astithas | long timestamp;
|
284 | a91ef7e8 | Panagiotis Astithas | try {
|
285 | a91ef7e8 | Panagiotis Astithas | timestamp = DateUtil.parseDate(dateParam).getTime(); |
286 | a91ef7e8 | Panagiotis Astithas | } catch (DateParseException e) {
|
287 | a91ef7e8 | Panagiotis Astithas | resp.sendError(HttpServletResponse.SC_FORBIDDEN, e.getMessage()); |
288 | a91ef7e8 | Panagiotis Astithas | return;
|
289 | a91ef7e8 | Panagiotis Astithas | } |
290 | a91ef7e8 | Panagiotis Astithas | if (!isTimeValid(timestamp)) {
|
291 | a91ef7e8 | Panagiotis Astithas | resp.sendError(HttpServletResponse.SC_FORBIDDEN); |
292 | a91ef7e8 | Panagiotis Astithas | return;
|
293 | a91ef7e8 | Panagiotis Astithas | } |
294 | a91ef7e8 | Panagiotis Astithas | |
295 | a91ef7e8 | Panagiotis Astithas | // Fetch the Authorization parameter and find the user specified in it.
|
296 | a91ef7e8 | Panagiotis Astithas | String[] authParts = auth.split(" "); |
297 | a91ef7e8 | Panagiotis Astithas | if (authParts.length != 2) { |
298 | a91ef7e8 | Panagiotis Astithas | resp.sendError(HttpServletResponse.SC_FORBIDDEN); |
299 | a91ef7e8 | Panagiotis Astithas | return;
|
300 | a91ef7e8 | Panagiotis Astithas | } |
301 | a91ef7e8 | Panagiotis Astithas | String username = authParts[0]; |
302 | a91ef7e8 | Panagiotis Astithas | String signature = authParts[1]; |
303 | a91ef7e8 | Panagiotis Astithas | user = null;
|
304 | a91ef7e8 | Panagiotis Astithas | try {
|
305 | a91ef7e8 | Panagiotis Astithas | user = getService().findUser(username); |
306 | a91ef7e8 | Panagiotis Astithas | } catch (RpcException e) {
|
307 | a91ef7e8 | Panagiotis Astithas | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path); |
308 | a91ef7e8 | Panagiotis Astithas | return;
|
309 | a91ef7e8 | Panagiotis Astithas | } |
310 | a91ef7e8 | Panagiotis Astithas | if (user == null) { |
311 | a91ef7e8 | Panagiotis Astithas | resp.sendError(HttpServletResponse.SC_FORBIDDEN); |
312 | a91ef7e8 | Panagiotis Astithas | return;
|
313 | a91ef7e8 | Panagiotis Astithas | } |
314 | a91ef7e8 | Panagiotis Astithas | req.setAttribute(USER_ATTRIBUTE, user); |
315 | a91ef7e8 | Panagiotis Astithas | |
316 | a91ef7e8 | Panagiotis Astithas | // Remove the servlet path from the request URI.
|
317 | a91ef7e8 | Panagiotis Astithas | String p = req.getRequestURI();
|
318 | a91ef7e8 | Panagiotis Astithas | String servletPath = req.getContextPath() + req.getServletPath();
|
319 | a91ef7e8 | Panagiotis Astithas | p = p.substring(servletPath.length()); |
320 | a91ef7e8 | Panagiotis Astithas | // Validate the signature in the Authorization parameter.
|
321 | a91ef7e8 | Panagiotis Astithas | String data = req.getMethod() + dateParam + p;
|
322 | a91ef7e8 | Panagiotis Astithas | if (!isSignatureValid(signature, user, data)) {
|
323 | a91ef7e8 | Panagiotis Astithas | resp.sendError(HttpServletResponse.SC_FORBIDDEN); |
324 | a91ef7e8 | Panagiotis Astithas | return;
|
325 | a91ef7e8 | Panagiotis Astithas | } |
326 | 1d36b941 | pastith | } |
327 | c9ffbe84 | pastith | } |
328 | eaf8360b | Christos V. Stathis | else if(folder != null && folder.isReadForAll() || file != null && file.isReadForAll()){ |
329 | eaf8360b | Christos V. Stathis | //This case refers to a folder or file with public privileges
|
330 | eaf8360b | Christos V. Stathis | //For a read-for-all folder request, pretend the owner is making it.
|
331 | eaf8360b | Christos V. Stathis | user = owner; |
332 | eaf8360b | Christos V. Stathis | req.setAttribute(USER_ATTRIBUTE, user); |
333 | eaf8360b | Christos V. Stathis | }else if(folder != null && !folder.isReadForAll()){ |
334 | eaf8360b | Christos V. Stathis | resp.sendError(HttpServletResponse.SC_FORBIDDEN); |
335 | eaf8360b | Christos V. Stathis | return;
|
336 | eaf8360b | Christos V. Stathis | } |
337 | eaf8360b | Christos V. Stathis | else{
|
338 | eaf8360b | Christos V. Stathis | resp.sendError(HttpServletResponse.SC_FORBIDDEN); |
339 | eaf8360b | Christos V. Stathis | return;
|
340 | eaf8360b | Christos V. Stathis | } |
341 | d235f94f | Natasa Kapravelou | } |
342 | 14ad7326 | pastith | // If the resource is not a collection, and the resource path
|
343 | 14ad7326 | pastith | // ends with "/" or "\", return NOT FOUND.
|
344 | 14ad7326 | pastith | if (folder == null) |
345 | 14ad7326 | pastith | if (path.endsWith("/") || path.endsWith("\\")) { |
346 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_NOT_FOUND, req.getRequestURI()); |
347 | 14ad7326 | pastith | return;
|
348 | 14ad7326 | pastith | } |
349 | 14ad7326 | pastith | |
350 | a3349f1f | pastith | // Workaround for IE's broken caching behavior.
|
351 | 470a59a7 | pastith | if (folder != null) |
352 | 470a59a7 | pastith | resp.setHeader("Expires", "-1"); |
353 | a3349f1f | pastith | |
354 | f5903adf | pastith | // A request for upload progress.
|
355 | f5903adf | pastith | if (progress != null && content) { |
356 | f5903adf | pastith | serveProgress(req, resp, progress, user, file); |
357 | f5903adf | pastith | return;
|
358 | f5903adf | pastith | } |
359 | f5903adf | pastith | |
360 | 14ad7326 | pastith | // Fetch the version to retrieve, if specified.
|
361 | 14ad7326 | pastith | String verStr = req.getParameter(VERSION_PARAM);
|
362 | 14ad7326 | pastith | int version = 0; |
363 | f7c44c33 | fstamatelopoulos | FileBody oldBody = null;
|
364 | 14ad7326 | pastith | if (verStr != null && file != null) |
365 | 14ad7326 | pastith | try {
|
366 | 14ad7326 | pastith | version = Integer.valueOf(verStr);
|
367 | 14ad7326 | pastith | } catch (NumberFormatException e) { |
368 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_BAD_REQUEST, req.getRequestURI()); |
369 | 14ad7326 | pastith | return;
|
370 | 14ad7326 | pastith | } |
371 | 14ad7326 | pastith | if (version > 0) |
372 | 14ad7326 | pastith | try {
|
373 | 14ad7326 | pastith | oldBody = getService().getFileVersion(user.getId(), file.getId(), version); |
374 | 14ad7326 | pastith | } catch (RpcException e) {
|
375 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path); |
376 | 14ad7326 | pastith | return;
|
377 | 14ad7326 | pastith | } catch (ObjectNotFoundException e) {
|
378 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_NOT_FOUND); |
379 | 14ad7326 | pastith | return;
|
380 | 14ad7326 | pastith | } catch (InsufficientPermissionsException e) {
|
381 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); |
382 | 14ad7326 | pastith | return;
|
383 | 14ad7326 | pastith | } |
384 | 14ad7326 | pastith | |
385 | 14ad7326 | pastith | // Check if the conditions specified in the optional If headers are
|
386 | 14ad7326 | pastith | // satisfied. Doing this for folders would require recursive checking
|
387 | 14ad7326 | pastith | // for all of their children, which in turn would defy the purpose of
|
388 | 14ad7326 | pastith | // the optimization.
|
389 | 62f168b2 | Giannis Koutsoubos | if (folder == null){ |
390 | 14ad7326 | pastith | // Checking If headers.
|
391 | 14ad7326 | pastith | if (!checkIfHeaders(req, resp, file, oldBody))
|
392 | 14ad7326 | pastith | return;
|
393 | 62f168b2 | Giannis Koutsoubos | } |
394 | 62f168b2 | Giannis Koutsoubos | else if(!checkIfModifiedSince(req, resp, folder)) |
395 | 62f168b2 | Giannis Koutsoubos | return;
|
396 | 14ad7326 | pastith | |
397 | 14ad7326 | pastith | // Find content type.
|
398 | 14ad7326 | pastith | String contentType = null; |
399 | 4e7b8a39 | Panagiotis Astithas | boolean isContentHtml = false; |
400 | d235f94f | Natasa Kapravelou | boolean expectJSON = false; |
401 | c5b81911 | Natasa Kapravelou | |
402 | 14ad7326 | pastith | if (file != null) { |
403 | f7c44c33 | fstamatelopoulos | contentType = version>0 ? oldBody.getMimeType() : file.getCurrentBody().getMimeType();
|
404 | 14ad7326 | pastith | if (contentType == null) { |
405 | 14ad7326 | pastith | contentType = context.getMimeType(file.getName()); |
406 | f7c44c33 | fstamatelopoulos | file.getCurrentBody().setMimeType(contentType); |
407 | 14ad7326 | pastith | } |
408 | 4e7b8a39 | Panagiotis Astithas | } else { // folder != null |
409 | 4e7b8a39 | Panagiotis Astithas | String accept = req.getHeader("Accept"); |
410 | 4e7b8a39 | Panagiotis Astithas | // The order in this conditional pessimizes the common API case,
|
411 | 4e7b8a39 | Panagiotis Astithas | // but is important for backwards compatibility with existing
|
412 | 4e7b8a39 | Panagiotis Astithas | // clients who send no accept header and expect a JSON response.
|
413 | 4e7b8a39 | Panagiotis Astithas | if (accept != null && accept.contains("text/html")) { |
414 | 4e7b8a39 | Panagiotis Astithas | contentType = "text/html;charset=UTF-8";
|
415 | 4e7b8a39 | Panagiotis Astithas | isContentHtml = true;
|
416 | d235f94f | Natasa Kapravelou | //this is the case when clients send the appropriate headers, the contentType is "text/html"
|
417 | d235f94f | Natasa Kapravelou | //and expect a JSON response. The above check applies to FireGSS client
|
418 | 4497ec95 | Natasa Kapravelou | expectJSON = !authDeferred ? true : false; |
419 | d235f94f | Natasa Kapravelou | } |
420 | db93eeea | Christos V. Stathis | else if (authDeferred && req.getMethod().equals(METHOD_GET)) { |
421 | db93eeea | Christos V. Stathis | contentType = "text/html;charset=UTF-8";
|
422 | db93eeea | Christos V. Stathis | isContentHtml = true;
|
423 | db93eeea | Christos V. Stathis | expectJSON = false;
|
424 | db93eeea | Christos V. Stathis | } |
425 | 4497ec95 | Natasa Kapravelou | else {
|
426 | 4e7b8a39 | Panagiotis Astithas | contentType = "application/json;charset=UTF-8";
|
427 | d235f94f | Natasa Kapravelou | expectJSON = true;
|
428 | d235f94f | Natasa Kapravelou | } |
429 | 4e7b8a39 | Panagiotis Astithas | } |
430 | 31e19588 | Natasa Kapravelou | |
431 | 14ad7326 | pastith | |
432 | 14ad7326 | pastith | ArrayList ranges = null; |
433 | 14ad7326 | pastith | long contentLength = -1L; |
434 | 14ad7326 | pastith | |
435 | 14ad7326 | pastith | if (file != null) { |
436 | 77f75ac4 | pastith | // Parse range specifier.
|
437 | 14ad7326 | pastith | ranges = parseRange(req, resp, file, oldBody); |
438 | 14ad7326 | pastith | // ETag header
|
439 | 14ad7326 | pastith | resp.setHeader("ETag", getETag(file, oldBody));
|
440 | 77f75ac4 | pastith | // Last-Modified header.
|
441 | 14ad7326 | pastith | String lastModified = oldBody == null ? |
442 | 14ad7326 | pastith | getLastModifiedHttp(file.getAuditInfo()) : |
443 | 14ad7326 | pastith | getLastModifiedHttp(oldBody.getAuditInfo()); |
444 | 14ad7326 | pastith | resp.setHeader("Last-Modified", lastModified);
|
445 | 77f75ac4 | pastith | // X-GSS-Metadata header.
|
446 | 14ad7326 | pastith | try {
|
447 | 14ad7326 | pastith | resp.setHeader("X-GSS-Metadata", renderJson(user, file, oldBody));
|
448 | 14ad7326 | pastith | } catch (InsufficientPermissionsException e) {
|
449 | 14ad7326 | pastith | resp.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED); |
450 | 14ad7326 | pastith | return;
|
451 | 14ad7326 | pastith | } |
452 | 77f75ac4 | pastith | // Get content length.
|
453 | f7c44c33 | fstamatelopoulos | contentLength = version>0 ? oldBody.getFileSize() : file.getCurrentBody().getFileSize();
|
454 | 14ad7326 | pastith | // Special case for zero length files, which would cause a
|
455 | 77f75ac4 | pastith | // (silent) ISE when setting the output buffer size.
|
456 | 14ad7326 | pastith | if (contentLength == 0L) |
457 | 14ad7326 | pastith | content = false;
|
458 | 77f75ac4 | pastith | } else
|
459 | 77f75ac4 | pastith | // Set the folder X-GSS-Metadata header.
|
460 | 77f75ac4 | pastith | try {
|
461 | 77f75ac4 | pastith | resp.setHeader("X-GSS-Metadata", renderJsonMetadata(user, folder));
|
462 | 77f75ac4 | pastith | } catch (InsufficientPermissionsException e) {
|
463 | 77f75ac4 | pastith | resp.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED); |
464 | 77f75ac4 | pastith | return;
|
465 | 77f75ac4 | pastith | } |
466 | 14ad7326 | pastith | |
467 | 14ad7326 | pastith | ServletOutputStream ostream = null;
|
468 | 14ad7326 | pastith | PrintWriter writer = null; |
469 | 14ad7326 | pastith | |
470 | 14ad7326 | pastith | if (content)
|
471 | 14ad7326 | pastith | try {
|
472 | 14ad7326 | pastith | ostream = resp.getOutputStream(); |
473 | 14ad7326 | pastith | } catch (IllegalStateException e) { |
474 | 14ad7326 | pastith | // If it fails, we try to get a Writer instead if we're
|
475 | 14ad7326 | pastith | // trying to serve a text file
|
476 | 14ad7326 | pastith | if ( contentType == null |
477 | 14ad7326 | pastith | || contentType.startsWith("text")
|
478 | 14ad7326 | pastith | || contentType.endsWith("xml") )
|
479 | 14ad7326 | pastith | writer = resp.getWriter(); |
480 | 14ad7326 | pastith | else
|
481 | 14ad7326 | pastith | throw e;
|
482 | 14ad7326 | pastith | } |
483 | bdf739a9 | Natasa Kapravelou | if (folder != null || (ranges == null || ranges.isEmpty()) && req.getHeader("Range") == null || ranges == FULL) { |
484 | 14ad7326 | pastith | // Set the appropriate output headers
|
485 | 14ad7326 | pastith | if (contentType != null) { |
486 | 14ad7326 | pastith | if (logger.isDebugEnabled())
|
487 | 14ad7326 | pastith | logger.debug("contentType='" + contentType + "'"); |
488 | 14ad7326 | pastith | resp.setContentType(contentType); |
489 | 14ad7326 | pastith | } |
490 | 14ad7326 | pastith | if (file != null && contentLength >= 0) { |
491 | 14ad7326 | pastith | if (logger.isDebugEnabled())
|
492 | 14ad7326 | pastith | logger.debug("contentLength=" + contentLength);
|
493 | 14ad7326 | pastith | if (contentLength < Integer.MAX_VALUE) |
494 | 14ad7326 | pastith | resp.setContentLength((int) contentLength);
|
495 | e8fd351d | Natasa Kapravelou | |
496 | 14ad7326 | pastith | else
|
497 | 14ad7326 | pastith | // Set the content-length as String to be able to use a long
|
498 | 14ad7326 | pastith | resp.setHeader("content-length", "" + contentLength); |
499 | 14ad7326 | pastith | } |
500 | 14ad7326 | pastith | |
501 | 14ad7326 | pastith | InputStream renderResult = null; |
502 | e8fd351d | Natasa Kapravelou | String relativePath = getRelativePath(req);
|
503 | e8fd351d | Natasa Kapravelou | String contextPath = req.getContextPath();
|
504 | e8fd351d | Natasa Kapravelou | String servletPath = req.getServletPath();
|
505 | e8fd351d | Natasa Kapravelou | String contextServletPath = contextPath + servletPath;
|
506 | e8fd351d | Natasa Kapravelou | if (folder != null && content) |
507 | 31e19588 | Natasa Kapravelou | // Serve the directory browser for a public folder
|
508 | 39ece393 | Christos V. Stathis | if (isContentHtml && !expectJSON) {
|
509 | 39ece393 | Christos V. Stathis | try {
|
510 | 39ece393 | Christos V. Stathis | folder = getService().expandFolder(folder); |
511 | 39ece393 | Christos V. Stathis | } |
512 | 39ece393 | Christos V. Stathis | catch (ObjectNotFoundException e) {
|
513 | 39ece393 | Christos V. Stathis | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path); |
514 | 39ece393 | Christos V. Stathis | return;
|
515 | 39ece393 | Christos V. Stathis | } |
516 | 39ece393 | Christos V. Stathis | catch (RpcException e) {
|
517 | 39ece393 | Christos V. Stathis | //We send 500 instead of 404 because this folder has been loaded before in this method and it is
|
518 | 39ece393 | Christos V. Stathis | //impossible to not be found now
|
519 | 39ece393 | Christos V. Stathis | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path); |
520 | 39ece393 | Christos V. Stathis | return;
|
521 | 39ece393 | Christos V. Stathis | } |
522 | 39ece393 | Christos V. Stathis | renderResult = renderHtml(contextServletPath, relativePath, folder,user); |
523 | 39ece393 | Christos V. Stathis | } |
524 | d235f94f | Natasa Kapravelou | // Serve the directory for an ordinary folder or for fireGSS client
|
525 | 31e19588 | Natasa Kapravelou | else
|
526 | 31e19588 | Natasa Kapravelou | try {
|
527 | 31e19588 | Natasa Kapravelou | renderResult = renderJson(user, folder); |
528 | 31e19588 | Natasa Kapravelou | } catch (InsufficientPermissionsException e) {
|
529 | 31e19588 | Natasa Kapravelou | resp.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED); |
530 | 31e19588 | Natasa Kapravelou | return;
|
531 | 31e19588 | Natasa Kapravelou | } |
532 | 31e19588 | Natasa Kapravelou | |
533 | 31e19588 | Natasa Kapravelou | |
534 | 14ad7326 | pastith | // Copy the input stream to our output stream (if requested)
|
535 | 14ad7326 | pastith | if (content) {
|
536 | 14ad7326 | pastith | try {
|
537 | 14ad7326 | pastith | resp.setBufferSize(output); |
538 | 14ad7326 | pastith | } catch (IllegalStateException e) { |
539 | 14ad7326 | pastith | // Silent catch
|
540 | 14ad7326 | pastith | } |
541 | 14ad7326 | pastith | try {
|
542 | 617fe906 | Dimitris Routsis | if(file != null) |
543 | 617fe906 | Dimitris Routsis | if (needsContentDisposition(req))
|
544 | 31ec597c | Panagiotis Astithas | resp.setHeader("Content-Disposition","attachment; filename*=UTF-8''"+getDispositionFilename(file)); |
545 | 617fe906 | Dimitris Routsis | else
|
546 | 31ec597c | Panagiotis Astithas | resp.setHeader("Content-Disposition","inline; filename*=UTF-8''"+getDispositionFilename(file)); |
547 | 14ad7326 | pastith | if (ostream != null) |
548 | 14ad7326 | pastith | copy(file, renderResult, ostream, req, oldBody); |
549 | 14ad7326 | pastith | else
|
550 | 14ad7326 | pastith | copy(file, renderResult, writer, req, oldBody); |
551 | 2f1a60e0 | Dimitris Routsis | if (file!=null) updateAccounting(owner, new Date(), contentLength); |
552 | 14ad7326 | pastith | } catch (ObjectNotFoundException e) {
|
553 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_NOT_FOUND); |
554 | 14ad7326 | pastith | return;
|
555 | 14ad7326 | pastith | } catch (InsufficientPermissionsException e) {
|
556 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); |
557 | 14ad7326 | pastith | return;
|
558 | 14ad7326 | pastith | } catch (RpcException e) {
|
559 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); |
560 | 14ad7326 | pastith | return;
|
561 | 2f1a60e0 | Dimitris Routsis | } |
562 | 14ad7326 | pastith | } |
563 | 14ad7326 | pastith | } else {
|
564 | 14ad7326 | pastith | if (ranges == null || ranges.isEmpty()) |
565 | 14ad7326 | pastith | return;
|
566 | 14ad7326 | pastith | // Partial content response.
|
567 | 14ad7326 | pastith | resp.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); |
568 | 14ad7326 | pastith | |
569 | 14ad7326 | pastith | if (ranges.size() == 1) { |
570 | 14ad7326 | pastith | Range range = (Range) ranges.get(0);
|
571 | 14ad7326 | pastith | resp.addHeader("Content-Range", "bytes " |
572 | 14ad7326 | pastith | + range.start |
573 | 14ad7326 | pastith | + "-" + range.end + "/" |
574 | 14ad7326 | pastith | + range.length); |
575 | 14ad7326 | pastith | long length = range.end - range.start + 1; |
576 | 14ad7326 | pastith | if (length < Integer.MAX_VALUE) |
577 | 14ad7326 | pastith | resp.setContentLength((int) length);
|
578 | 14ad7326 | pastith | else
|
579 | 14ad7326 | pastith | // Set the content-length as String to be able to use a long
|
580 | 14ad7326 | pastith | resp.setHeader("content-length", "" + length); |
581 | 14ad7326 | pastith | |
582 | 14ad7326 | pastith | if (contentType != null) { |
583 | 14ad7326 | pastith | if (logger.isDebugEnabled())
|
584 | 14ad7326 | pastith | logger.debug("contentType='" + contentType + "'"); |
585 | 14ad7326 | pastith | resp.setContentType(contentType); |
586 | 14ad7326 | pastith | } |
587 | 14ad7326 | pastith | |
588 | 14ad7326 | pastith | if (content) {
|
589 | 14ad7326 | pastith | try {
|
590 | 14ad7326 | pastith | resp.setBufferSize(output); |
591 | 14ad7326 | pastith | } catch (IllegalStateException e) { |
592 | 14ad7326 | pastith | // Silent catch
|
593 | 14ad7326 | pastith | } |
594 | 14ad7326 | pastith | try {
|
595 | 14ad7326 | pastith | if (ostream != null) |
596 | 14ad7326 | pastith | copy(file, ostream, range, req, oldBody); |
597 | 14ad7326 | pastith | else
|
598 | 14ad7326 | pastith | copy(file, writer, range, req, oldBody); |
599 | 2f1a60e0 | Dimitris Routsis | updateAccounting(owner, new Date(), contentLength); |
600 | 14ad7326 | pastith | } catch (ObjectNotFoundException e) {
|
601 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_NOT_FOUND); |
602 | 14ad7326 | pastith | return;
|
603 | 14ad7326 | pastith | } catch (InsufficientPermissionsException e) {
|
604 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); |
605 | 14ad7326 | pastith | return;
|
606 | 14ad7326 | pastith | } catch (RpcException e) {
|
607 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); |
608 | 14ad7326 | pastith | return;
|
609 | 14ad7326 | pastith | } |
610 | 14ad7326 | pastith | } |
611 | 14ad7326 | pastith | } else {
|
612 | 14ad7326 | pastith | resp.setContentType("multipart/byteranges; boundary=" + mimeSeparation);
|
613 | 14ad7326 | pastith | if (content) {
|
614 | 14ad7326 | pastith | try {
|
615 | 14ad7326 | pastith | resp.setBufferSize(output); |
616 | 14ad7326 | pastith | } catch (IllegalStateException e) { |
617 | 14ad7326 | pastith | // Silent catch
|
618 | 14ad7326 | pastith | } |
619 | 14ad7326 | pastith | try {
|
620 | 14ad7326 | pastith | if (ostream != null) |
621 | 14ad7326 | pastith | copy(file, ostream, ranges.iterator(), contentType, req, oldBody); |
622 | 14ad7326 | pastith | else
|
623 | 14ad7326 | pastith | copy(file, writer, ranges.iterator(), contentType, req, oldBody); |
624 | 2f1a60e0 | Dimitris Routsis | updateAccounting(owner, new Date(), contentLength); |
625 | 14ad7326 | pastith | } catch (ObjectNotFoundException e) {
|
626 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_NOT_FOUND); |
627 | 14ad7326 | pastith | return;
|
628 | 14ad7326 | pastith | } catch (InsufficientPermissionsException e) {
|
629 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); |
630 | 14ad7326 | pastith | return;
|
631 | 14ad7326 | pastith | } catch (RpcException e) {
|
632 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); |
633 | 14ad7326 | pastith | return;
|
634 | 14ad7326 | pastith | } |
635 | 14ad7326 | pastith | } |
636 | 14ad7326 | pastith | } |
637 | 14ad7326 | pastith | } |
638 | 14ad7326 | pastith | } |
639 | 14ad7326 | pastith | |
640 | 14ad7326 | pastith | /**
|
641 | a91ef7e8 | Panagiotis Astithas | * Handles an authentication failure. If no Authorization or Date request
|
642 | a91ef7e8 | Panagiotis Astithas | * parameters and no Authorization, Date or X-GSS-Date headers were present,
|
643 | a91ef7e8 | Panagiotis Astithas | * this is a browser request, so redirect to login and then let the user get
|
644 | a91ef7e8 | Panagiotis Astithas | * back to the file. Otherwise it's a bogus client request and Forbidden is
|
645 | a91ef7e8 | Panagiotis Astithas | * returned.
|
646 | a91ef7e8 | Panagiotis Astithas | */
|
647 | a91ef7e8 | Panagiotis Astithas | private void handleAuthFailure(HttpServletRequest req, HttpServletResponse resp) throws IOException { |
648 | a91ef7e8 | Panagiotis Astithas | if (req.getParameter(AUTHORIZATION_PARAMETER) == null && |
649 | a91ef7e8 | Panagiotis Astithas | req.getParameter(DATE_PARAMETER) == null &&
|
650 | a91ef7e8 | Panagiotis Astithas | req.getHeader(AUTHORIZATION_HEADER) == null &&
|
651 | a91ef7e8 | Panagiotis Astithas | req.getDateHeader(DATE_HEADER) == -1 &&
|
652 | a91ef7e8 | Panagiotis Astithas | req.getDateHeader(GSS_DATE_HEADER) == -1)
|
653 | 6567092b | Panagiotis Astithas | resp.sendRedirect(getConfiguration().getString("loginUrl") +
|
654 | a91ef7e8 | Panagiotis Astithas | "?next=" + req.getRequestURL().toString());
|
655 | a91ef7e8 | Panagiotis Astithas | else
|
656 | a91ef7e8 | Panagiotis Astithas | resp.sendError(HttpServletResponse.SC_FORBIDDEN); |
657 | a91ef7e8 | Panagiotis Astithas | } |
658 | a91ef7e8 | Panagiotis Astithas | |
659 | a91ef7e8 | Panagiotis Astithas | /**
|
660 | 31ec597c | Panagiotis Astithas | * Return the filename of the specified file properly formatted for
|
661 | 31ec597c | Panagiotis Astithas | * including in the Content-Disposition header.
|
662 | 31ec597c | Panagiotis Astithas | */
|
663 | f7c44c33 | fstamatelopoulos | private String getDispositionFilename(FileHeader file) throws UnsupportedEncodingException { |
664 | 31ec597c | Panagiotis Astithas | return URLEncoder.encode(file.getName(),"UTF-8").replaceAll("\\+", "%20"); |
665 | 31ec597c | Panagiotis Astithas | } |
666 | 31ec597c | Panagiotis Astithas | |
667 | 31ec597c | Panagiotis Astithas | /**
|
668 | 5942d113 | pastith | * Determines whether the user agent needs the Content-Disposition
|
669 | 5942d113 | pastith | * header to be set, in order to properly download a file.
|
670 | 5942d113 | pastith | *
|
671 | 5942d113 | pastith | * @param req the HTTP request
|
672 | 5942d113 | pastith | * @return true if the Content-Disposition HTTP header must be set
|
673 | 5942d113 | pastith | */
|
674 | 5942d113 | pastith | private boolean needsContentDisposition(HttpServletRequest req) { |
675 | 617fe906 | Dimitris Routsis | /*String agent = req.getHeader("user-agent");
|
676 | 50364cd8 | pastith | if (agent != null && agent.contains("MSIE"))
|
677 | 617fe906 | Dimitris Routsis | return true;*/
|
678 | 617fe906 | Dimitris Routsis | String dl = req.getParameter("dl"); |
679 | 617fe906 | Dimitris Routsis | if ("1".equals(dl)) |
680 | 5942d113 | pastith | return true; |
681 | 5942d113 | pastith | return false; |
682 | 5942d113 | pastith | } |
683 | 5942d113 | pastith | |
684 | 5942d113 | pastith | /**
|
685 | f5903adf | pastith | * Sends a progress update on the amount of bytes received until now for
|
686 | f5903adf | pastith | * a file that the current user is currently uploading.
|
687 | f5903adf | pastith | *
|
688 | f5903adf | pastith | * @param req the HTTP request
|
689 | f5903adf | pastith | * @param resp the HTTP response
|
690 | f5903adf | pastith | * @param parameter the value for the progress request parameter
|
691 | f5903adf | pastith | * @param user the current user
|
692 | f5903adf | pastith | * @param file the file being uploaded, or null if the request is about a new file
|
693 | f5903adf | pastith | * @throws IOException if an I/O error occurs
|
694 | f5903adf | pastith | */
|
695 | f5903adf | pastith | private void serveProgress(HttpServletRequest req, HttpServletResponse resp, |
696 | f7c44c33 | fstamatelopoulos | String parameter, User user, FileHeader file) throws IOException { |
697 | f5903adf | pastith | String filename = file == null ? parameter : file.getName(); |
698 | f5903adf | pastith | try {
|
699 | f5903adf | pastith | FileUploadStatus status = getService().getFileUploadStatus(user.getId(), filename); |
700 | f5903adf | pastith | if (status == null) { |
701 | f5903adf | pastith | resp.sendError(HttpServletResponse.SC_NOT_FOUND); |
702 | f5903adf | pastith | return;
|
703 | f5903adf | pastith | } |
704 | f5903adf | pastith | JSONObject json = new JSONObject();
|
705 | f5903adf | pastith | json.put("bytesUploaded", status.getBytesUploaded()).
|
706 | f5903adf | pastith | put("bytesTotal", status.getFileSize());
|
707 | f5903adf | pastith | sendJson(req, resp, json.toString()); |
708 | 470a59a7 | pastith | |
709 | 470a59a7 | pastith | // Workaround for IE's broken caching behavior.
|
710 | 470a59a7 | pastith | resp.setHeader("Expires", "-1"); |
711 | f5903adf | pastith | return;
|
712 | f5903adf | pastith | } catch (RpcException e) {
|
713 | f5903adf | pastith | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); |
714 | f5903adf | pastith | return;
|
715 | f5903adf | pastith | } catch (JSONException e) {
|
716 | f5903adf | pastith | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); |
717 | f5903adf | pastith | return;
|
718 | f5903adf | pastith | } |
719 | f5903adf | pastith | } |
720 | f5903adf | pastith | |
721 | f5903adf | pastith | /**
|
722 | 14ad7326 | pastith | * Server a POST request to create/modify a file or folder.
|
723 | 14ad7326 | pastith | *
|
724 | 14ad7326 | pastith | * @param req the HTTP request
|
725 | 14ad7326 | pastith | * @param resp the HTTP response
|
726 | 14ad7326 | pastith | * @exception IOException if an input/output error occurs
|
727 | 14ad7326 | pastith | */
|
728 | 14ad7326 | pastith | void postResource(HttpServletRequest req, HttpServletResponse resp) throws IOException { |
729 | bda7d76d | pastith | boolean authDeferred = getAuthDeferred(req);
|
730 | bda7d76d | pastith | if (!authDeferred && req.getParameterMap().size() > 1) { |
731 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_BAD_REQUEST); |
732 | 14ad7326 | pastith | return;
|
733 | 14ad7326 | pastith | } |
734 | 14ad7326 | pastith | String path = getInnerPath(req, PATH_FILES);
|
735 | 14ad7326 | pastith | path = path.endsWith("/")? path: path + '/'; |
736 | e8b747c4 | pastith | try {
|
737 | e8b747c4 | pastith | path = URLDecoder.decode(path, "UTF-8"); |
738 | e8b747c4 | pastith | } catch (IllegalArgumentException e) { |
739 | e8b747c4 | pastith | resp.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage()); |
740 | e8b747c4 | pastith | return;
|
741 | e8b747c4 | pastith | } |
742 | bda7d76d | pastith | // We only defer authenticating multipart POST requests.
|
743 | bda7d76d | pastith | if (authDeferred) {
|
744 | bda7d76d | pastith | if (!ServletFileUpload.isMultipartContent(req)) {
|
745 | bda7d76d | pastith | resp.sendError(HttpServletResponse.SC_FORBIDDEN); |
746 | bda7d76d | pastith | return;
|
747 | bda7d76d | pastith | } |
748 | bda7d76d | pastith | handleMultipart(req, resp, path); |
749 | bda7d76d | pastith | return;
|
750 | bda7d76d | pastith | } |
751 | bda7d76d | pastith | |
752 | 14ad7326 | pastith | String newName = req.getParameter(NEW_FOLDER_PARAMETER);
|
753 | 891f51ce | Natasa Kapravelou | |
754 | 14ad7326 | pastith | boolean hasUpdateParam = req.getParameterMap().containsKey(RESOURCE_UPDATE_PARAMETER);
|
755 | 14ad7326 | pastith | boolean hasTrashParam = req.getParameterMap().containsKey(RESOURCE_TRASH_PARAMETER);
|
756 | 14ad7326 | pastith | boolean hasRestoreParam = req.getParameterMap().containsKey(RESOURCE_RESTORE_PARAMETER);
|
757 | 14ad7326 | pastith | String copyTo = req.getParameter(RESOURCE_COPY_PARAMETER);
|
758 | 14ad7326 | pastith | String moveTo = req.getParameter(RESOURCE_MOVE_PARAMETER);
|
759 | 39c34533 | pastith | String restoreVersion = req.getParameter(RESTORE_VERSION_PARAMETER);
|
760 | 14ad7326 | pastith | |
761 | 891f51ce | Natasa Kapravelou | if (newName != null){ |
762 | 891f51ce | Natasa Kapravelou | if (!isValidResourceName(newName)) {
|
763 | 891f51ce | Natasa Kapravelou | resp.sendError(HttpServletResponse.SC_BAD_REQUEST); |
764 | 891f51ce | Natasa Kapravelou | return;
|
765 | 891f51ce | Natasa Kapravelou | } |
766 | 14ad7326 | pastith | createFolder(req, resp, path, newName); |
767 | 891f51ce | Natasa Kapravelou | } |
768 | a7bcd018 | droutsis | else if (hasUpdateParam) |
769 | 14ad7326 | pastith | updateResource(req, resp, path); |
770 | 14ad7326 | pastith | else if (hasTrashParam) |
771 | 14ad7326 | pastith | trashResource(req, resp, path); |
772 | 14ad7326 | pastith | else if (hasRestoreParam) |
773 | 14ad7326 | pastith | restoreResource(req, resp, path); |
774 | 14ad7326 | pastith | else if (copyTo != null) |
775 | 14ad7326 | pastith | copyResource(req, resp, path, copyTo); |
776 | 14ad7326 | pastith | else if (moveTo != null) |
777 | 14ad7326 | pastith | moveResource(req, resp, path, moveTo); |
778 | 39c34533 | pastith | else if (restoreVersion != null) |
779 | 39c34533 | pastith | restoreVersion(req, resp, path, restoreVersion); |
780 | 14ad7326 | pastith | else
|
781 | 9fd42cf4 | Panagiotis Astithas | // IE with Gears uses POST for multiple uploads.
|
782 | 9fd42cf4 | Panagiotis Astithas | putResource(req, resp); |
783 | 14ad7326 | pastith | } |
784 | 14ad7326 | pastith | |
785 | 14ad7326 | pastith | /**
|
786 | 39c34533 | pastith | * Restores a previous version for a file.
|
787 | 39c34533 | pastith | *
|
788 | 39c34533 | pastith | * @param req the HTTP request
|
789 | 39c34533 | pastith | * @param resp the HTTP response
|
790 | 39c34533 | pastith | * @param path the resource path
|
791 | 39c34533 | pastith | * @param version the version number to restore
|
792 | 39c34533 | pastith | * @throws IOException if an I/O error occurs
|
793 | 39c34533 | pastith | */
|
794 | 39c34533 | pastith | private void restoreVersion(HttpServletRequest req, HttpServletResponse resp, String path, String version) throws IOException { |
795 | 2f1a60e0 | Dimitris Routsis | final User user = getUser(req);
|
796 | 39c34533 | pastith | User owner = getOwner(req); |
797 | 39c34533 | pastith | Object resource = null; |
798 | 39c34533 | pastith | try {
|
799 | 39c34533 | pastith | resource = getService().getResourceAtPath(owner.getId(), path, true);
|
800 | 39c34533 | pastith | } catch (ObjectNotFoundException e) {
|
801 | 39c34533 | pastith | resp.sendError(HttpServletResponse.SC_NOT_FOUND, path); |
802 | 39c34533 | pastith | return;
|
803 | 39c34533 | pastith | } catch (RpcException e) {
|
804 | 39c34533 | pastith | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path); |
805 | 39c34533 | pastith | return;
|
806 | 39c34533 | pastith | } |
807 | f7c44c33 | fstamatelopoulos | if (resource instanceof Folder) { |
808 | 39c34533 | pastith | resp.sendError(HttpServletResponse.SC_CONFLICT); |
809 | 39c34533 | pastith | return;
|
810 | 39c34533 | pastith | } |
811 | 39c34533 | pastith | |
812 | 39c34533 | pastith | try {
|
813 | f7c44c33 | fstamatelopoulos | final FileHeader file = (FileHeader) resource;
|
814 | 2f1a60e0 | Dimitris Routsis | final int oldVersion = Integer.parseInt(version); |
815 | 2f1a60e0 | Dimitris Routsis | |
816 | 2f1a60e0 | Dimitris Routsis | new TransactionHelper<Void>().tryExecute(new Callable<Void>() { |
817 | 2f1a60e0 | Dimitris Routsis | @Override
|
818 | 2f1a60e0 | Dimitris Routsis | public Void call() throws Exception { |
819 | 2f1a60e0 | Dimitris Routsis | getService().restoreVersion(user.getId(), file.getId(), oldVersion); |
820 | 2f1a60e0 | Dimitris Routsis | return null; |
821 | 2f1a60e0 | Dimitris Routsis | } |
822 | 2f1a60e0 | Dimitris Routsis | }); |
823 | 39c34533 | pastith | } catch (InsufficientPermissionsException e) {
|
824 | 39c34533 | pastith | resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); |
825 | 39c34533 | pastith | } catch (ObjectNotFoundException e) {
|
826 | 39c34533 | pastith | resp.sendError(HttpServletResponse.SC_NOT_FOUND, e.getMessage()); |
827 | 39c34533 | pastith | } catch (RpcException e) {
|
828 | 39c34533 | pastith | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path); |
829 | 39c34533 | pastith | } catch (GSSIOException e) {
|
830 | 39c34533 | pastith | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); |
831 | 39c34533 | pastith | } catch (QuotaExceededException e) {
|
832 | 39c34533 | pastith | resp.sendError(HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE, e.getMessage()); |
833 | 39c34533 | pastith | } catch (NumberFormatException e) { |
834 | 39c34533 | pastith | resp.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage()); |
835 | 2f1a60e0 | Dimitris Routsis | } catch (Exception e) { |
836 | 2f1a60e0 | Dimitris Routsis | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); |
837 | 39c34533 | pastith | } |
838 | 39c34533 | pastith | } |
839 | 39c34533 | pastith | |
840 | 39c34533 | pastith | /**
|
841 | e150a336 | pastith | * A method for handling multipart POST requests for uploading
|
842 | e150a336 | pastith | * files from browser-based JavaScript clients.
|
843 | e150a336 | pastith | *
|
844 | e150a336 | pastith | * @param request the HTTP request
|
845 | e150a336 | pastith | * @param response the HTTP response
|
846 | e150a336 | pastith | * @param path the resource path
|
847 | e150a336 | pastith | * @throws IOException in case an error occurs writing to the
|
848 | e150a336 | pastith | * response stream
|
849 | e150a336 | pastith | */
|
850 | e150a336 | pastith | private void handleMultipart(HttpServletRequest request, HttpServletResponse response, String path) throws IOException { |
851 | e150a336 | pastith | if (logger.isDebugEnabled())
|
852 | e150a336 | pastith | logger.debug("Multipart POST for resource: " + path);
|
853 | e150a336 | pastith | |
854 | e150a336 | pastith | User owner = getOwner(request); |
855 | e150a336 | pastith | boolean exists = true; |
856 | e150a336 | pastith | Object resource = null; |
857 | f7c44c33 | fstamatelopoulos | FileHeader file = null;
|
858 | e150a336 | pastith | try {
|
859 | e150a336 | pastith | resource = getService().getResourceAtPath(owner.getId(), path, false);
|
860 | e150a336 | pastith | } catch (ObjectNotFoundException e) {
|
861 | e150a336 | pastith | exists = false;
|
862 | e150a336 | pastith | } catch (RpcException e) {
|
863 | e150a336 | pastith | response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path); |
864 | e150a336 | pastith | return;
|
865 | e150a336 | pastith | } |
866 | e150a336 | pastith | |
867 | e150a336 | pastith | if (exists)
|
868 | f7c44c33 | fstamatelopoulos | if (resource instanceof FileHeader) { |
869 | f7c44c33 | fstamatelopoulos | file = (FileHeader) resource; |
870 | ebe40d2c | pastith | if (file.isDeleted()) {
|
871 | ebe40d2c | pastith | response.sendError(HttpServletResponse.SC_CONFLICT, file.getName() + " is in the trash");
|
872 | ebe40d2c | pastith | return;
|
873 | ebe40d2c | pastith | } |
874 | ebe40d2c | pastith | } else {
|
875 | e150a336 | pastith | response.sendError(HttpServletResponse.SC_CONFLICT, path + " is a folder");
|
876 | e150a336 | pastith | return;
|
877 | e150a336 | pastith | } |
878 | e150a336 | pastith | |
879 | e150a336 | pastith | Object parent;
|
880 | e150a336 | pastith | String parentPath = null; |
881 | e150a336 | pastith | try {
|
882 | e150a336 | pastith | parentPath = getParentPath(path); |
883 | e150a336 | pastith | parent = getService().getResourceAtPath(owner.getId(), parentPath, true);
|
884 | e150a336 | pastith | } catch (ObjectNotFoundException e) {
|
885 | e150a336 | pastith | response.sendError(HttpServletResponse.SC_NOT_FOUND, parentPath); |
886 | e150a336 | pastith | return;
|
887 | e150a336 | pastith | } catch (RpcException e) {
|
888 | e150a336 | pastith | response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path); |
889 | e150a336 | pastith | return;
|
890 | e150a336 | pastith | } |
891 | f7c44c33 | fstamatelopoulos | if (!(parent instanceof Folder)) { |
892 | e150a336 | pastith | response.sendError(HttpServletResponse.SC_CONFLICT); |
893 | e150a336 | pastith | return;
|
894 | e150a336 | pastith | } |
895 | f7c44c33 | fstamatelopoulos | final Folder folderLocal = (Folder) parent;
|
896 | 2f1a60e0 | Dimitris Routsis | final String fileName = getLastElement(path); |
897 | e150a336 | pastith | |
898 | 8b79a1c8 | Natasa Kapravelou | if (!isValidResourceName(fileName)) {
|
899 | 8b79a1c8 | Natasa Kapravelou | response.sendError(HttpServletResponse.SC_BAD_REQUEST); |
900 | 8b79a1c8 | Natasa Kapravelou | return;
|
901 | 8b79a1c8 | Natasa Kapravelou | } |
902 | 8b79a1c8 | Natasa Kapravelou | |
903 | e150a336 | pastith | FileItemIterator iter; |
904 | e150a336 | pastith | File uploadedFile = null; |
905 | e150a336 | pastith | try {
|
906 | e150a336 | pastith | // Create a new file upload handler.
|
907 | e150a336 | pastith | ServletFileUpload upload = new ServletFileUpload();
|
908 | e150a336 | pastith | StatusProgressListener progressListener = new StatusProgressListener(getService());
|
909 | e150a336 | pastith | upload.setProgressListener(progressListener); |
910 | e150a336 | pastith | iter = upload.getItemIterator(request); |
911 | bda7d76d | pastith | String dateParam = null; |
912 | bda7d76d | pastith | String auth = null; |
913 | e150a336 | pastith | while (iter.hasNext()) {
|
914 | e150a336 | pastith | FileItemStream item = iter.next(); |
915 | bda7d76d | pastith | String name = item.getFieldName();
|
916 | e150a336 | pastith | InputStream stream = item.openStream();
|
917 | bda7d76d | pastith | if (item.isFormField()) {
|
918 | bda7d76d | pastith | final String value = Streams.asString(stream); |
919 | bda7d76d | pastith | if (name.equals(DATE_PARAMETER))
|
920 | bda7d76d | pastith | dateParam = value; |
921 | bda7d76d | pastith | else if (name.equals(AUTHORIZATION_PARAMETER)) |
922 | bda7d76d | pastith | auth = value; |
923 | bda7d76d | pastith | |
924 | bda7d76d | pastith | if (logger.isDebugEnabled())
|
925 | bda7d76d | pastith | logger.debug(name + ":" + value);
|
926 | bda7d76d | pastith | } else {
|
927 | bda7d76d | pastith | // Fetch the timestamp used to guard against replay attacks.
|
928 | bda7d76d | pastith | if (dateParam == null) { |
929 | bda7d76d | pastith | response.sendError(HttpServletResponse.SC_FORBIDDEN, "No Date parameter");
|
930 | bda7d76d | pastith | return;
|
931 | bda7d76d | pastith | } |
932 | bda7d76d | pastith | |
933 | bda7d76d | pastith | long timestamp;
|
934 | bda7d76d | pastith | try {
|
935 | bda7d76d | pastith | timestamp = DateUtil.parseDate(dateParam).getTime(); |
936 | bda7d76d | pastith | } catch (DateParseException e) {
|
937 | bda7d76d | pastith | response.sendError(HttpServletResponse.SC_FORBIDDEN, e.getMessage()); |
938 | bda7d76d | pastith | return;
|
939 | bda7d76d | pastith | } |
940 | bda7d76d | pastith | if (!isTimeValid(timestamp)) {
|
941 | bda7d76d | pastith | response.sendError(HttpServletResponse.SC_FORBIDDEN); |
942 | bda7d76d | pastith | return;
|
943 | bda7d76d | pastith | } |
944 | bda7d76d | pastith | |
945 | bda7d76d | pastith | // Fetch the Authorization parameter and find the user specified in it.
|
946 | bda7d76d | pastith | if (auth == null) { |
947 | bda7d76d | pastith | response.sendError(HttpServletResponse.SC_FORBIDDEN, "No Authorization parameter");
|
948 | bda7d76d | pastith | return;
|
949 | bda7d76d | pastith | } |
950 | bda7d76d | pastith | String[] authParts = auth.split(" "); |
951 | bda7d76d | pastith | if (authParts.length != 2) { |
952 | bda7d76d | pastith | response.sendError(HttpServletResponse.SC_FORBIDDEN); |
953 | bda7d76d | pastith | return;
|
954 | bda7d76d | pastith | } |
955 | bda7d76d | pastith | String username = authParts[0]; |
956 | bda7d76d | pastith | String signature = authParts[1]; |
957 | bda7d76d | pastith | User user = null;
|
958 | bda7d76d | pastith | try {
|
959 | bda7d76d | pastith | user = getService().findUser(username); |
960 | bda7d76d | pastith | } catch (RpcException e) {
|
961 | bda7d76d | pastith | response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path); |
962 | bda7d76d | pastith | return;
|
963 | bda7d76d | pastith | } |
964 | bda7d76d | pastith | if (user == null) { |
965 | bda7d76d | pastith | response.sendError(HttpServletResponse.SC_FORBIDDEN); |
966 | bda7d76d | pastith | return;
|
967 | bda7d76d | pastith | } |
968 | bda7d76d | pastith | request.setAttribute(USER_ATTRIBUTE, user); |
969 | bda7d76d | pastith | |
970 | c961594d | pastith | // Remove the servlet path from the request URI.
|
971 | c961594d | pastith | String p = request.getRequestURI();
|
972 | c961594d | pastith | String servletPath = request.getContextPath() + request.getServletPath();
|
973 | c961594d | pastith | p = p.substring(servletPath.length()); |
974 | bda7d76d | pastith | // Validate the signature in the Authorization parameter.
|
975 | c961594d | pastith | String data = request.getMethod() + dateParam + p;
|
976 | bda7d76d | pastith | if (!isSignatureValid(signature, user, data)) {
|
977 | bda7d76d | pastith | response.sendError(HttpServletResponse.SC_FORBIDDEN); |
978 | bda7d76d | pastith | return;
|
979 | bda7d76d | pastith | } |
980 | bda7d76d | pastith | |
981 | e150a336 | pastith | progressListener.setUserId(user.getId()); |
982 | e150a336 | pastith | progressListener.setFilename(fileName); |
983 | 2f1a60e0 | Dimitris Routsis | final String contentType = item.getContentType(); |
984 | e150a336 | pastith | |
985 | e150a336 | pastith | try {
|
986 | e150a336 | pastith | uploadedFile = getService().uploadFile(stream, user.getId()); |
987 | e150a336 | pastith | } catch (IOException ex) { |
988 | e150a336 | pastith | throw new GSSIOException(ex, false); |
989 | e150a336 | pastith | } |
990 | f7c44c33 | fstamatelopoulos | FileHeader fileLocal = null;
|
991 | 2f1a60e0 | Dimitris Routsis | final File upf = uploadedFile; |
992 | f7c44c33 | fstamatelopoulos | final FileHeader f = file;
|
993 | 2f1a60e0 | Dimitris Routsis | final User u = user;
|
994 | e150a336 | pastith | if (file == null) |
995 | f7c44c33 | fstamatelopoulos | fileLocal = new TransactionHelper<FileHeader>().tryExecute(new Callable<FileHeader>() { |
996 | 2f1a60e0 | Dimitris Routsis | @Override
|
997 | f7c44c33 | fstamatelopoulos | public FileHeader call() throws Exception { |
998 | f7c44c33 | fstamatelopoulos | return getService().createFile(u.getId(), folderLocal.getId(), fileName, contentType, upf.getCanonicalFile().length(), upf.getAbsolutePath());
|
999 | 2f1a60e0 | Dimitris Routsis | } |
1000 | 2f1a60e0 | Dimitris Routsis | }); |
1001 | e150a336 | pastith | else
|
1002 | f7c44c33 | fstamatelopoulos | fileLocal = new TransactionHelper<FileHeader>().tryExecute(new Callable<FileHeader>() { |
1003 | 2f1a60e0 | Dimitris Routsis | @Override
|
1004 | f7c44c33 | fstamatelopoulos | public FileHeader call() throws Exception { |
1005 | 2f1a60e0 | Dimitris Routsis | return getService().updateFileContents(u.getId(), f.getId(), contentType, upf.getCanonicalFile().length(), upf.getAbsolutePath());
|
1006 | 2f1a60e0 | Dimitris Routsis | } |
1007 | 2f1a60e0 | Dimitris Routsis | }); |
1008 | f7c44c33 | fstamatelopoulos | updateAccounting(owner, new Date(), fileLocal.getCurrentBody().getFileSize()); |
1009 | 599c9fc4 | pastith | getService().removeFileUploadProgress(user.getId(), fileName); |
1010 | e150a336 | pastith | } |
1011 | e150a336 | pastith | } |
1012 | 2e7ca93c | pastith | // We can't return 204 here since GWT's onSubmitComplete won't fire.
|
1013 | 2e7ca93c | pastith | response.setContentType("text/html");
|
1014 | 2e7ca93c | pastith | response.getWriter().print("<pre></pre>");
|
1015 | e150a336 | pastith | } catch (FileUploadException e) {
|
1016 | e150a336 | pastith | String error = "Error while uploading file"; |
1017 | e150a336 | pastith | logger.error(error, e); |
1018 | e150a336 | pastith | response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, error); |
1019 | e150a336 | pastith | } catch (GSSIOException e) {
|
1020 | e150a336 | pastith | if (uploadedFile != null && uploadedFile.exists()) |
1021 | e150a336 | pastith | uploadedFile.delete(); |
1022 | e150a336 | pastith | String error = "Error while uploading file"; |
1023 | e150a336 | pastith | if (e.logAsError())
|
1024 | e150a336 | pastith | logger.error(error, e); |
1025 | e150a336 | pastith | else
|
1026 | e150a336 | pastith | logger.debug(error, e); |
1027 | e150a336 | pastith | response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, error); |
1028 | e150a336 | pastith | } catch (DuplicateNameException e) {
|
1029 | e150a336 | pastith | if (uploadedFile != null && uploadedFile.exists()) |
1030 | e150a336 | pastith | uploadedFile.delete(); |
1031 | e150a336 | pastith | String error = "The specified file name already exists in this folder"; |
1032 | e150a336 | pastith | logger.error(error, e); |
1033 | e150a336 | pastith | response.sendError(HttpServletResponse.SC_CONFLICT, error); |
1034 | e150a336 | pastith | |
1035 | e150a336 | pastith | } catch (InsufficientPermissionsException e) {
|
1036 | e150a336 | pastith | if (uploadedFile != null && uploadedFile.exists()) |
1037 | e150a336 | pastith | uploadedFile.delete(); |
1038 | e150a336 | pastith | String error = "You don't have the necessary permissions"; |
1039 | e150a336 | pastith | logger.error(error, e); |
1040 | e150a336 | pastith | response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, error); |
1041 | e150a336 | pastith | |
1042 | e150a336 | pastith | } catch (QuotaExceededException e) {
|
1043 | e150a336 | pastith | if (uploadedFile != null && uploadedFile.exists()) |
1044 | e150a336 | pastith | uploadedFile.delete(); |
1045 | e150a336 | pastith | String error = "Not enough free space available"; |
1046 | e150a336 | pastith | if (logger.isDebugEnabled())
|
1047 | e150a336 | pastith | logger.debug(error, e); |
1048 | e150a336 | pastith | response.sendError(HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE, error); |
1049 | e150a336 | pastith | |
1050 | e150a336 | pastith | } catch (ObjectNotFoundException e) {
|
1051 | e150a336 | pastith | if (uploadedFile != null && uploadedFile.exists()) |
1052 | e150a336 | pastith | uploadedFile.delete(); |
1053 | e150a336 | pastith | String error = "A specified object was not found"; |
1054 | e150a336 | pastith | logger.error(error, e); |
1055 | e150a336 | pastith | response.sendError(HttpServletResponse.SC_NOT_FOUND, error); |
1056 | e150a336 | pastith | } catch (RpcException e) {
|
1057 | e150a336 | pastith | if (uploadedFile != null && uploadedFile.exists()) |
1058 | e150a336 | pastith | uploadedFile.delete(); |
1059 | e150a336 | pastith | String error = "An error occurred while communicating with the service"; |
1060 | e150a336 | pastith | logger.error(error, e); |
1061 | e150a336 | pastith | response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, error); |
1062 | 2f1a60e0 | Dimitris Routsis | } catch (Exception e) { |
1063 | 2f1a60e0 | Dimitris Routsis | if (uploadedFile != null && uploadedFile.exists()) |
1064 | 2f1a60e0 | Dimitris Routsis | uploadedFile.delete(); |
1065 | 2f1a60e0 | Dimitris Routsis | String error = "An internal server error occurred"; |
1066 | 2f1a60e0 | Dimitris Routsis | logger.error(error, e); |
1067 | 2f1a60e0 | Dimitris Routsis | response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, error); |
1068 | e150a336 | pastith | } |
1069 | e150a336 | pastith | } |
1070 | e150a336 | pastith | |
1071 | e150a336 | pastith | /**
|
1072 | 14ad7326 | pastith | * Move the resource in the specified path to the specified destination.
|
1073 | 14ad7326 | pastith | *
|
1074 | 14ad7326 | pastith | * @param req the HTTP request
|
1075 | 14ad7326 | pastith | * @param resp the HTTP response
|
1076 | 14ad7326 | pastith | * @param path the path of the resource
|
1077 | 14ad7326 | pastith | * @param moveTo the destination of the move procedure
|
1078 | 14ad7326 | pastith | * @throws IOException if an input/output error occurs
|
1079 | 14ad7326 | pastith | */
|
1080 | 14ad7326 | pastith | private void moveResource(HttpServletRequest req, HttpServletResponse resp, String path, String moveTo) throws IOException { |
1081 | 2f1a60e0 | Dimitris Routsis | final User user = getUser(req);
|
1082 | 14ad7326 | pastith | User owner = getOwner(req); |
1083 | 14ad7326 | pastith | Object resource = null; |
1084 | 14ad7326 | pastith | try {
|
1085 | 68410d59 | pastith | resource = getService().getResourceAtPath(owner.getId(), path, true);
|
1086 | 14ad7326 | pastith | } catch (ObjectNotFoundException e) {
|
1087 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_NOT_FOUND, path); |
1088 | 14ad7326 | pastith | return;
|
1089 | 14ad7326 | pastith | } catch (RpcException e) {
|
1090 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path); |
1091 | 14ad7326 | pastith | return;
|
1092 | 14ad7326 | pastith | } |
1093 | 14ad7326 | pastith | |
1094 | 14ad7326 | pastith | String destination = null; |
1095 | 14ad7326 | pastith | User destOwner = null;
|
1096 | 14ad7326 | pastith | boolean exists = true; |
1097 | 14ad7326 | pastith | try {
|
1098 | 5e2b8ec6 | koutsoub | destination = getDestinationPath(req, encodePath(moveTo)); |
1099 | 5e2b8ec6 | koutsoub | destination = URLDecoder.decode(destination, "UTF-8"); |
1100 | 14ad7326 | pastith | destOwner = getDestinationOwner(req); |
1101 | 68410d59 | pastith | getService().getResourceAtPath(destOwner.getId(), destination, true);
|
1102 | 14ad7326 | pastith | } catch (ObjectNotFoundException e) {
|
1103 | 14ad7326 | pastith | exists = false;
|
1104 | 14ad7326 | pastith | } catch (URISyntaxException e) { |
1105 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage()); |
1106 | 14ad7326 | pastith | return;
|
1107 | 14ad7326 | pastith | } catch (RpcException e) {
|
1108 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, destination); |
1109 | 14ad7326 | pastith | return;
|
1110 | 14ad7326 | pastith | } |
1111 | 14ad7326 | pastith | if (exists) {
|
1112 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_CONFLICT, destination + " already exists");
|
1113 | 14ad7326 | pastith | return;
|
1114 | 14ad7326 | pastith | } |
1115 | 14ad7326 | pastith | |
1116 | 14ad7326 | pastith | try {
|
1117 | 2f1a60e0 | Dimitris Routsis | final User dOwner = destOwner;
|
1118 | 2f1a60e0 | Dimitris Routsis | final String dest = destination; |
1119 | f7c44c33 | fstamatelopoulos | if (resource instanceof Folder) { |
1120 | f7c44c33 | fstamatelopoulos | final Folder folderLocal = (Folder) resource;
|
1121 | 2f1a60e0 | Dimitris Routsis | new TransactionHelper<Void>().tryExecute(new Callable<Void>() { |
1122 | 2f1a60e0 | Dimitris Routsis | @Override
|
1123 | 2f1a60e0 | Dimitris Routsis | public Void call() throws Exception { |
1124 | f7c44c33 | fstamatelopoulos | getService().moveFolderToPath(user.getId(), dOwner.getId(), folderLocal.getId(), dest); |
1125 | 2f1a60e0 | Dimitris Routsis | return null; |
1126 | 2f1a60e0 | Dimitris Routsis | } |
1127 | 2f1a60e0 | Dimitris Routsis | }); |
1128 | 14ad7326 | pastith | } else {
|
1129 | f7c44c33 | fstamatelopoulos | final FileHeader fileLocal = (FileHeader) resource;
|
1130 | 2f1a60e0 | Dimitris Routsis | new TransactionHelper<Void>().tryExecute(new Callable<Void>() { |
1131 | 2f1a60e0 | Dimitris Routsis | @Override
|
1132 | 2f1a60e0 | Dimitris Routsis | public Void call() throws Exception { |
1133 | f7c44c33 | fstamatelopoulos | getService().moveFileToPath(user.getId(), dOwner.getId(), fileLocal.getId(), dest); |
1134 | 2f1a60e0 | Dimitris Routsis | return null; |
1135 | 2f1a60e0 | Dimitris Routsis | } |
1136 | 2f1a60e0 | Dimitris Routsis | }); |
1137 | 2f1a60e0 | Dimitris Routsis | |
1138 | 14ad7326 | pastith | } |
1139 | 14ad7326 | pastith | } catch (InsufficientPermissionsException e) {
|
1140 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); |
1141 | 14ad7326 | pastith | } catch (ObjectNotFoundException e) {
|
1142 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_NOT_FOUND, e.getMessage()); |
1143 | 14ad7326 | pastith | } catch (RpcException e) {
|
1144 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, destination); |
1145 | 14ad7326 | pastith | } catch (DuplicateNameException e) {
|
1146 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_CONFLICT, e.getMessage()); |
1147 | 14ad7326 | pastith | } catch (GSSIOException e) {
|
1148 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); |
1149 | 14ad7326 | pastith | } catch (QuotaExceededException e) {
|
1150 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE, e.getMessage()); |
1151 | 2f1a60e0 | Dimitris Routsis | } catch (Exception e) { |
1152 | 2f1a60e0 | Dimitris Routsis | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, destination); |
1153 | 14ad7326 | pastith | } |
1154 | 14ad7326 | pastith | } |
1155 | 14ad7326 | pastith | |
1156 | 14ad7326 | pastith | /**
|
1157 | 14ad7326 | pastith | * Copy the resource in the specified path to the specified destination.
|
1158 | 14ad7326 | pastith | *
|
1159 | 14ad7326 | pastith | * @param req the HTTP request
|
1160 | 14ad7326 | pastith | * @param resp the HTTP response
|
1161 | 14ad7326 | pastith | * @param path the path of the resource
|
1162 | 14ad7326 | pastith | * @param copyTo the destination of the copy procedure
|
1163 | 14ad7326 | pastith | * @throws IOException if an input/output error occurs
|
1164 | 14ad7326 | pastith | */
|
1165 | 14ad7326 | pastith | private void copyResource(HttpServletRequest req, HttpServletResponse resp, String path, String copyTo) throws IOException { |
1166 | 2f1a60e0 | Dimitris Routsis | final User user = getUser(req);
|
1167 | 14ad7326 | pastith | User owner = getOwner(req); |
1168 | 14ad7326 | pastith | Object resource = null; |
1169 | 14ad7326 | pastith | try {
|
1170 | 68410d59 | pastith | resource = getService().getResourceAtPath(owner.getId(), path, true);
|
1171 | 14ad7326 | pastith | } catch (ObjectNotFoundException e) {
|
1172 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_NOT_FOUND, path); |
1173 | 14ad7326 | pastith | return;
|
1174 | 14ad7326 | pastith | } catch (RpcException e) {
|
1175 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path); |
1176 | 14ad7326 | pastith | return;
|
1177 | 14ad7326 | pastith | } |
1178 | 14ad7326 | pastith | |
1179 | 14ad7326 | pastith | String destination = null; |
1180 | 14ad7326 | pastith | User destOwner = null;
|
1181 | 14ad7326 | pastith | boolean exists = true; |
1182 | 14ad7326 | pastith | try {
|
1183 | 4c44fdca | Dimitris Routsis | String destinationEncoded = getDestinationPath(req, encodePath(copyTo));
|
1184 | 4c44fdca | Dimitris Routsis | destination = URLDecoder.decode(destinationEncoded, "UTF-8"); |
1185 | 14ad7326 | pastith | destOwner = getDestinationOwner(req); |
1186 | 4c44fdca | Dimitris Routsis | getService().getResourceAtPath(destOwner.getId(), destinationEncoded, true);
|
1187 | 14ad7326 | pastith | } catch (ObjectNotFoundException e) {
|
1188 | 14ad7326 | pastith | exists = false;
|
1189 | 14ad7326 | pastith | } catch (URISyntaxException e) { |
1190 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage()); |
1191 | 14ad7326 | pastith | return;
|
1192 | 14ad7326 | pastith | } catch (RpcException e) {
|
1193 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, destination); |
1194 | 14ad7326 | pastith | return;
|
1195 | 14ad7326 | pastith | } |
1196 | 14ad7326 | pastith | if (exists) {
|
1197 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_CONFLICT, destination + " already exists");
|
1198 | 14ad7326 | pastith | return;
|
1199 | 14ad7326 | pastith | } |
1200 | 14ad7326 | pastith | |
1201 | 14ad7326 | pastith | try {
|
1202 | 2f1a60e0 | Dimitris Routsis | final User dOwner = destOwner;
|
1203 | 2f1a60e0 | Dimitris Routsis | final String dest = destination; |
1204 | f7c44c33 | fstamatelopoulos | if (resource instanceof Folder) { |
1205 | f7c44c33 | fstamatelopoulos | final Folder folderLocal = (Folder) resource;
|
1206 | 2f1a60e0 | Dimitris Routsis | new TransactionHelper<Void>().tryExecute(new Callable<Void>() { |
1207 | 2f1a60e0 | Dimitris Routsis | @Override
|
1208 | 2f1a60e0 | Dimitris Routsis | public Void call() throws Exception { |
1209 | f7c44c33 | fstamatelopoulos | getService().copyFolderStructureToPath(user.getId(), dOwner.getId(), folderLocal.getId(), dest); |
1210 | 2f1a60e0 | Dimitris Routsis | return null; |
1211 | 2f1a60e0 | Dimitris Routsis | } |
1212 | 2f1a60e0 | Dimitris Routsis | }); |
1213 | 14ad7326 | pastith | } else {
|
1214 | f7c44c33 | fstamatelopoulos | final FileHeader fileLocal = (FileHeader) resource;
|
1215 | 2f1a60e0 | Dimitris Routsis | new TransactionHelper<Void>().tryExecute(new Callable<Void>() { |
1216 | 2f1a60e0 | Dimitris Routsis | @Override
|
1217 | 2f1a60e0 | Dimitris Routsis | public Void call() throws Exception { |
1218 | f7c44c33 | fstamatelopoulos | getService().copyFileToPath(user.getId(), dOwner.getId(), fileLocal.getId(), dest); |
1219 | 2f1a60e0 | Dimitris Routsis | return null; |
1220 | 2f1a60e0 | Dimitris Routsis | } |
1221 | 2f1a60e0 | Dimitris Routsis | }); |
1222 | 14ad7326 | pastith | } |
1223 | 14ad7326 | pastith | } catch (InsufficientPermissionsException e) {
|
1224 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); |
1225 | 14ad7326 | pastith | } catch (ObjectNotFoundException e) {
|
1226 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_NOT_FOUND, e.getMessage()); |
1227 | 14ad7326 | pastith | } catch (RpcException e) {
|
1228 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, destination); |
1229 | 14ad7326 | pastith | } catch (DuplicateNameException e) {
|
1230 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_CONFLICT, e.getMessage()); |
1231 | 14ad7326 | pastith | } catch (GSSIOException e) {
|
1232 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); |
1233 | 14ad7326 | pastith | } catch (QuotaExceededException e) {
|
1234 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE, e.getMessage()); |
1235 | 2f1a60e0 | Dimitris Routsis | } catch (Exception e) { |
1236 | 2f1a60e0 | Dimitris Routsis | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, destination); |
1237 | 14ad7326 | pastith | } |
1238 | 14ad7326 | pastith | } |
1239 | 14ad7326 | pastith | |
1240 | 5e2b8ec6 | koutsoub | private String encodePath(String path) throws UnsupportedEncodingException{ |
1241 | 5e2b8ec6 | koutsoub | StringTokenizer str = new StringTokenizer(path, "/:", true); |
1242 | 5e2b8ec6 | koutsoub | String result = new String(); |
1243 | 5e2b8ec6 | koutsoub | while(str.hasMoreTokens()){
|
1244 | 5e2b8ec6 | koutsoub | String token = str.nextToken();
|
1245 | 5e2b8ec6 | koutsoub | if(!token.equals("/") && !token.equals(":")) |
1246 | 5e2b8ec6 | koutsoub | token = URLEncoder.encode(token,"UTF-8"); |
1247 | 5e2b8ec6 | koutsoub | result = result + token; |
1248 | 5e2b8ec6 | koutsoub | } |
1249 | 5e2b8ec6 | koutsoub | return result;
|
1250 | 5e2b8ec6 | koutsoub | } |
1251 | 14ad7326 | pastith | /**
|
1252 | 14ad7326 | pastith | * A helper method that extracts the relative resource path,
|
1253 | 14ad7326 | pastith | * after removing the 'files' namespace.
|
1254 | 4c44fdca | Dimitris Routsis | * The path returned is <i>not</i> URL-decoded.
|
1255 | 14ad7326 | pastith | *
|
1256 | 14ad7326 | pastith | * @param req the HTTP request
|
1257 | 14ad7326 | pastith | * @param path the specified path
|
1258 | 14ad7326 | pastith | * @return the path relative to the root folder
|
1259 | 14ad7326 | pastith | * @throws URISyntaxException
|
1260 | 14ad7326 | pastith | * @throws RpcException in case an error occurs while communicating
|
1261 | 14ad7326 | pastith | * with the backend
|
1262 | 4c44fdca | Dimitris Routsis | * @throws UnsupportedEncodingException
|
1263 | 14ad7326 | pastith | */
|
1264 | 4c44fdca | Dimitris Routsis | private String getDestinationPath(HttpServletRequest req, String path) throws URISyntaxException, RpcException, UnsupportedEncodingException { |
1265 | 14ad7326 | pastith | URI uri = new URI(path); |
1266 | 4c44fdca | Dimitris Routsis | String dest = uri.getRawPath();
|
1267 | 14ad7326 | pastith | // Remove the context path from the destination URI.
|
1268 | 14ad7326 | pastith | String contextPath = req.getContextPath();
|
1269 | 14ad7326 | pastith | if (!dest.startsWith(contextPath))
|
1270 | 14ad7326 | pastith | throw new URISyntaxException(dest, "Destination path does not start with " + contextPath); |
1271 | 14ad7326 | pastith | dest = dest.substring(contextPath.length()); |
1272 | 14ad7326 | pastith | // Remove the servlet path from the destination URI.
|
1273 | 14ad7326 | pastith | String servletPath = req.getServletPath();
|
1274 | 14ad7326 | pastith | if (!dest.startsWith(servletPath))
|
1275 | 14ad7326 | pastith | throw new URISyntaxException(dest, "Destination path does not start with " + servletPath); |
1276 | 14ad7326 | pastith | dest = dest.substring(servletPath.length()); |
1277 | 14ad7326 | pastith | // Strip the username part
|
1278 | 14ad7326 | pastith | if (dest.length() < 2) |
1279 | 14ad7326 | pastith | throw new URISyntaxException(dest, "No username in the destination URI"); |
1280 | 14ad7326 | pastith | int slash = dest.substring(1).indexOf('/'); |
1281 | 14ad7326 | pastith | if (slash == -1) |
1282 | 14ad7326 | pastith | throw new URISyntaxException(dest, "No username in the destination URI"); |
1283 | 4c44fdca | Dimitris Routsis | // Decode the user to get the proper characters (mainly the @)
|
1284 | 4c44fdca | Dimitris Routsis | String owner = URLDecoder.decode(dest.substring(1, slash + 1), "UTF-8"); |
1285 | 14ad7326 | pastith | User o; |
1286 | 14ad7326 | pastith | o = getService().findUser(owner); |
1287 | 14ad7326 | pastith | if (o == null) |
1288 | 14ad7326 | pastith | throw new URISyntaxException(dest, "User " + owner + " not found"); |
1289 | 14ad7326 | pastith | |
1290 | 14ad7326 | pastith | req.setAttribute(DESTINATION_OWNER_ATTRIBUTE, o); |
1291 | 14ad7326 | pastith | dest = dest.substring(slash + 1);
|
1292 | 14ad7326 | pastith | |
1293 | 14ad7326 | pastith | // Chop the resource namespace part
|
1294 | 14ad7326 | pastith | dest = dest.substring(RequestHandler.PATH_FILES.length()); |
1295 | 14ad7326 | pastith | |
1296 | 14ad7326 | pastith | dest = dest.endsWith("/")? dest: dest + '/'; |
1297 | 14ad7326 | pastith | return dest;
|
1298 | 14ad7326 | pastith | } |
1299 | 14ad7326 | pastith | |
1300 | 14ad7326 | pastith | /**
|
1301 | 14ad7326 | pastith | * Move the resource in the specified path to the trash bin.
|
1302 | 14ad7326 | pastith | *
|
1303 | 14ad7326 | pastith | * @param req the HTTP request
|
1304 | 14ad7326 | pastith | * @param resp the HTTP response
|
1305 | 14ad7326 | pastith | * @param path the path of the resource
|
1306 | 14ad7326 | pastith | * @throws IOException if an input/output error occurs
|
1307 | 14ad7326 | pastith | */
|
1308 | 14ad7326 | pastith | private void trashResource(HttpServletRequest req, HttpServletResponse resp, String path) throws IOException { |
1309 | 2f1a60e0 | Dimitris Routsis | final User user = getUser(req);
|
1310 | 14ad7326 | pastith | User owner = getOwner(req); |
1311 | 14ad7326 | pastith | Object resource = null; |
1312 | 14ad7326 | pastith | try {
|
1313 | 68410d59 | pastith | resource = getService().getResourceAtPath(owner.getId(), path, true);
|
1314 | 14ad7326 | pastith | } catch (ObjectNotFoundException e) {
|
1315 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_NOT_FOUND, path); |
1316 | 14ad7326 | pastith | return;
|
1317 | 14ad7326 | pastith | } catch (RpcException e) {
|
1318 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path); |
1319 | 14ad7326 | pastith | return;
|
1320 | 14ad7326 | pastith | } |
1321 | 14ad7326 | pastith | |
1322 | 14ad7326 | pastith | try {
|
1323 | f7c44c33 | fstamatelopoulos | if (resource instanceof Folder) { |
1324 | f7c44c33 | fstamatelopoulos | final Folder folderLocal = (Folder) resource;
|
1325 | 2f1a60e0 | Dimitris Routsis | new TransactionHelper<Void>().tryExecute(new Callable<Void>() { |
1326 | 2f1a60e0 | Dimitris Routsis | @Override
|
1327 | 2f1a60e0 | Dimitris Routsis | public Void call() throws Exception { |
1328 | f7c44c33 | fstamatelopoulos | getService().moveFolderToTrash(user.getId(), folderLocal.getId()); |
1329 | 2f1a60e0 | Dimitris Routsis | return null; |
1330 | 2f1a60e0 | Dimitris Routsis | } |
1331 | 2f1a60e0 | Dimitris Routsis | }); |
1332 | 14ad7326 | pastith | } else {
|
1333 | f7c44c33 | fstamatelopoulos | final FileHeader fileLocal = (FileHeader) resource;
|
1334 | 2f1a60e0 | Dimitris Routsis | new TransactionHelper<Void>().tryExecute(new Callable<Void>() { |
1335 | 2f1a60e0 | Dimitris Routsis | @Override
|
1336 | 2f1a60e0 | Dimitris Routsis | public Void call() throws Exception { |
1337 | f7c44c33 | fstamatelopoulos | getService().moveFileToTrash(user.getId(), fileLocal.getId()); |
1338 | 2f1a60e0 | Dimitris Routsis | return null; |
1339 | 2f1a60e0 | Dimitris Routsis | } |
1340 | 2f1a60e0 | Dimitris Routsis | }); |
1341 | 14ad7326 | pastith | } |
1342 | 14ad7326 | pastith | } catch (InsufficientPermissionsException e) {
|
1343 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); |
1344 | 14ad7326 | pastith | } catch (ObjectNotFoundException e) {
|
1345 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_NOT_FOUND, e.getMessage()); |
1346 | 14ad7326 | pastith | } catch (RpcException e) {
|
1347 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path); |
1348 | 2f1a60e0 | Dimitris Routsis | } catch (Exception e) { |
1349 | 2f1a60e0 | Dimitris Routsis | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path); |
1350 | 14ad7326 | pastith | } |
1351 | 14ad7326 | pastith | } |
1352 | 14ad7326 | pastith | |
1353 | 14ad7326 | pastith | /**
|
1354 | 14ad7326 | pastith | * Restore the resource in the specified path from the trash bin.
|
1355 | 14ad7326 | pastith | *
|
1356 | 14ad7326 | pastith | * @param req the HTTP request
|
1357 | 14ad7326 | pastith | * @param resp the HTTP response
|
1358 | 14ad7326 | pastith | * @param path the path of the resource
|
1359 | 14ad7326 | pastith | * @throws IOException if an input/output error occurs
|
1360 | 14ad7326 | pastith | */
|
1361 | 14ad7326 | pastith | private void restoreResource(HttpServletRequest req, HttpServletResponse resp, String path) throws IOException { |
1362 | 2f1a60e0 | Dimitris Routsis | final User user = getUser(req);
|
1363 | 14ad7326 | pastith | User owner = getOwner(req); |
1364 | 14ad7326 | pastith | Object resource = null; |
1365 | 14ad7326 | pastith | try {
|
1366 | e150a336 | pastith | resource = getService().getResourceAtPath(owner.getId(), path, false);
|
1367 | 14ad7326 | pastith | } catch (ObjectNotFoundException e) {
|
1368 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_NOT_FOUND, path); |
1369 | 14ad7326 | pastith | return;
|
1370 | 14ad7326 | pastith | } catch (RpcException e) {
|
1371 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path); |
1372 | 14ad7326 | pastith | return;
|
1373 | 14ad7326 | pastith | } |
1374 | 14ad7326 | pastith | |
1375 | 14ad7326 | pastith | try {
|
1376 | f7c44c33 | fstamatelopoulos | if (resource instanceof Folder) { |
1377 | f7c44c33 | fstamatelopoulos | final Folder folderLocal = (Folder) resource;
|
1378 | 2f1a60e0 | Dimitris Routsis | new TransactionHelper<Void>().tryExecute(new Callable<Void>() { |
1379 | 2f1a60e0 | Dimitris Routsis | @Override
|
1380 | 2f1a60e0 | Dimitris Routsis | public Void call() throws Exception { |
1381 | f7c44c33 | fstamatelopoulos | getService().removeFolderFromTrash(user.getId(), folderLocal.getId()); |
1382 | 2f1a60e0 | Dimitris Routsis | return null; |
1383 | 2f1a60e0 | Dimitris Routsis | } |
1384 | 2f1a60e0 | Dimitris Routsis | }); |
1385 | 14ad7326 | pastith | } else {
|
1386 | f7c44c33 | fstamatelopoulos | final FileHeader fileLocal = (FileHeader) resource;
|
1387 | 2f1a60e0 | Dimitris Routsis | new TransactionHelper<Void>().tryExecute(new Callable<Void>() { |
1388 | 2f1a60e0 | Dimitris Routsis | @Override
|
1389 | 2f1a60e0 | Dimitris Routsis | public Void call() throws Exception { |
1390 | f7c44c33 | fstamatelopoulos | getService().removeFileFromTrash(user.getId(), fileLocal.getId()); |
1391 | 2f1a60e0 | Dimitris Routsis | return null; |
1392 | 2f1a60e0 | Dimitris Routsis | } |
1393 | 2f1a60e0 | Dimitris Routsis | }); |
1394 | 14ad7326 | pastith | } |
1395 | 14ad7326 | pastith | } catch (InsufficientPermissionsException e) {
|
1396 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); |
1397 | 14ad7326 | pastith | } catch (ObjectNotFoundException e) {
|
1398 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_NOT_FOUND, e.getMessage()); |
1399 | 14ad7326 | pastith | } catch (RpcException e) {
|
1400 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path); |
1401 | 2f1a60e0 | Dimitris Routsis | } catch (Exception e) { |
1402 | 2f1a60e0 | Dimitris Routsis | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path); |
1403 | 14ad7326 | pastith | } |
1404 | 14ad7326 | pastith | } |
1405 | 14ad7326 | pastith | |
1406 | 14ad7326 | pastith | /**
|
1407 | 14ad7326 | pastith | * Update the resource in the specified path.
|
1408 | 14ad7326 | pastith | *
|
1409 | 14ad7326 | pastith | * @param req the HTTP request
|
1410 | 14ad7326 | pastith | * @param resp the HTTP response
|
1411 | 14ad7326 | pastith | * @param path the path of the resource
|
1412 | 14ad7326 | pastith | * @throws IOException if an input/output error occurs
|
1413 | 14ad7326 | pastith | */
|
1414 | 14ad7326 | pastith | private void updateResource(HttpServletRequest req, HttpServletResponse resp, String path) throws IOException { |
1415 | 77dcb3f1 | Panagiotis Astithas | final User user = getUser(req);
|
1416 | 14ad7326 | pastith | User owner = getOwner(req); |
1417 | 14ad7326 | pastith | Object resource = null; |
1418 | 9e6a28ed | Natasa Kapravelou | |
1419 | 14ad7326 | pastith | try {
|
1420 | 3d1b9329 | koutsoub | resource = getService().getResourceAtPath(owner.getId(), path, false);
|
1421 | 14ad7326 | pastith | } catch (ObjectNotFoundException e) {
|
1422 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_NOT_FOUND, path); |
1423 | 14ad7326 | pastith | return;
|
1424 | 14ad7326 | pastith | } catch (RpcException e) {
|
1425 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path); |
1426 | 14ad7326 | pastith | return;
|
1427 | 14ad7326 | pastith | } |
1428 | 14ad7326 | pastith | StringBuffer input = new StringBuffer(); |
1429 | 14ad7326 | pastith | JSONObject json = null;
|
1430 | a2c88d01 | Panagiotis Astithas | if (req.getContentType() != null && req.getContentType().startsWith("application/x-www-form-urlencoded")) |
1431 | f9e01fcb | Panagiotis Astithas | input.append(req.getParameter(RESOURCE_UPDATE_PARAMETER)); |
1432 | f9e01fcb | Panagiotis Astithas | else {
|
1433 | f9e01fcb | Panagiotis Astithas | // Assume application/json
|
1434 | f9e01fcb | Panagiotis Astithas | BufferedReader reader = new BufferedReader(new InputStreamReader(req.getInputStream(),"UTF-8")); |
1435 | f9e01fcb | Panagiotis Astithas | String line = null; |
1436 | f9e01fcb | Panagiotis Astithas | while ((line = reader.readLine()) != null) |
1437 | f9e01fcb | Panagiotis Astithas | input.append(line); |
1438 | f9e01fcb | Panagiotis Astithas | reader.close(); |
1439 | f9e01fcb | Panagiotis Astithas | } |
1440 | 14ad7326 | pastith | try {
|
1441 | 14ad7326 | pastith | json = new JSONObject(input.toString());
|
1442 | 14ad7326 | pastith | if (logger.isDebugEnabled())
|
1443 | 14ad7326 | pastith | logger.debug("JSON update: " + json);
|
1444 | f7c44c33 | fstamatelopoulos | if (resource instanceof Folder) { |
1445 | f7c44c33 | fstamatelopoulos | final Folder folderLocal = (Folder) resource;
|
1446 | 14ad7326 | pastith | String name = json.optString("name"); |
1447 | 891f51ce | Natasa Kapravelou | if (!isValidResourceName(name)) {
|
1448 | 891f51ce | Natasa Kapravelou | resp.sendError(HttpServletResponse.SC_BAD_REQUEST); |
1449 | 891f51ce | Natasa Kapravelou | return;
|
1450 | 891f51ce | Natasa Kapravelou | } |
1451 | ba5f9575 | Panagiotis Astithas | JSONArray permissions = json.optJSONArray("permissions");
|
1452 | f7c44c33 | fstamatelopoulos | Set<Permission> perms = null; |
1453 | ba5f9575 | Panagiotis Astithas | if (permissions != null) |
1454 | ba5f9575 | Panagiotis Astithas | perms = parsePermissions(user, permissions); |
1455 | 9e6a28ed | Natasa Kapravelou | Boolean readForAll = null; |
1456 | 9e6a28ed | Natasa Kapravelou | if (json.opt("readForAll") != null) |
1457 | 9e6a28ed | Natasa Kapravelou | readForAll = json.optBoolean("readForAll");
|
1458 | 9e6a28ed | Natasa Kapravelou | if (!name.isEmpty() || permissions != null || readForAll != null) { |
1459 | ba5f9575 | Panagiotis Astithas | final String fName = name.isEmpty()? null: name; |
1460 | 46397af3 | Panagiotis Astithas | final Boolean freadForAll = readForAll; |
1461 | f7c44c33 | fstamatelopoulos | final Set<Permission> fPerms = perms; |
1462 | f7c44c33 | fstamatelopoulos | Folder folderUpdated = new TransactionHelper<Folder>().tryExecute(new Callable<Folder>() { |
1463 | 77dcb3f1 | Panagiotis Astithas | @Override
|
1464 | f7c44c33 | fstamatelopoulos | public Folder call() throws Exception { |
1465 | f7c44c33 | fstamatelopoulos | return getService().updateFolder(user.getId(), folderLocal.getId(), fName, freadForAll, fPerms);
|
1466 | 77dcb3f1 | Panagiotis Astithas | } |
1467 | 77dcb3f1 | Panagiotis Astithas | |
1468 | 77dcb3f1 | Panagiotis Astithas | }); |
1469 | 425e3d5e | Panagiotis Astithas | resp.getWriter().println(getNewUrl(req, folderUpdated)); |
1470 | 5e2b8ec6 | koutsoub | } |
1471 | 14ad7326 | pastith | } else {
|
1472 | f7c44c33 | fstamatelopoulos | final FileHeader fileLocal = (FileHeader) resource;
|
1473 | 14ad7326 | pastith | String name = null; |
1474 | 14ad7326 | pastith | if (json.opt("name") != null) |
1475 | 14ad7326 | pastith | name = json.optString("name");
|
1476 | 9bee2fe5 | Natasa Kapravelou | if (name != null) |
1477 | 9bee2fe5 | Natasa Kapravelou | if (!isValidResourceName(name)) {
|
1478 | 9bee2fe5 | Natasa Kapravelou | resp.sendError(HttpServletResponse.SC_BAD_REQUEST); |
1479 | 9bee2fe5 | Natasa Kapravelou | return;
|
1480 | 9bee2fe5 | Natasa Kapravelou | } |
1481 | d114cfe2 | Panagiotis Astithas | Long modificationDate = null; |
1482 | d114cfe2 | Panagiotis Astithas | if (json.optLong("modificationDate") != 0) |
1483 | d114cfe2 | Panagiotis Astithas | modificationDate = json.optLong("modificationDate");
|
1484 | d74c0270 | Panagiotis Astithas | Boolean versioned = null; |
1485 | d74c0270 | Panagiotis Astithas | if (json.opt("versioned") != null) |
1486 | d74c0270 | Panagiotis Astithas | versioned = json.getBoolean("versioned");
|
1487 | 14ad7326 | pastith | JSONArray tagset = json.optJSONArray("tags");
|
1488 | 867d129b | Fotis Stamatelopoulos | String tags = null; |
1489 | 14ad7326 | pastith | StringBuffer t = new StringBuffer(); |
1490 | 14ad7326 | pastith | if (tagset != null) { |
1491 | 14ad7326 | pastith | for (int i = 0; i < tagset.length(); i++) |
1492 | 14ad7326 | pastith | t.append(tagset.getString(i) + ',');
|
1493 | 14ad7326 | pastith | tags = t.toString(); |
1494 | 14ad7326 | pastith | } |
1495 | 14ad7326 | pastith | JSONArray permissions = json.optJSONArray("permissions");
|
1496 | f7c44c33 | fstamatelopoulos | Set<Permission> perms = null; |
1497 | 14ad7326 | pastith | if (permissions != null) |
1498 | 14ad7326 | pastith | perms = parsePermissions(user, permissions); |
1499 | 14ad7326 | pastith | Boolean readForAll = null; |
1500 | 14ad7326 | pastith | if (json.opt("readForAll") != null) |
1501 | 14ad7326 | pastith | readForAll = json.optBoolean("readForAll");
|
1502 | d74c0270 | Panagiotis Astithas | if (name != null || tags != null || modificationDate != null |
1503 | d74c0270 | Panagiotis Astithas | || versioned != null || perms != null |
1504 | d74c0270 | Panagiotis Astithas | || readForAll != null) {
|
1505 | d74c0270 | Panagiotis Astithas | final String fName = name; |
1506 | d74c0270 | Panagiotis Astithas | final String fTags = tags; |
1507 | d74c0270 | Panagiotis Astithas | final Date mDate = modificationDate != null? new Date(modificationDate): null; |
1508 | d74c0270 | Panagiotis Astithas | final Boolean fVersioned = versioned; |
1509 | 77dcb3f1 | Panagiotis Astithas | final Boolean fReadForAll = readForAll; |
1510 | f7c44c33 | fstamatelopoulos | final Set<Permission> fPerms = perms; |
1511 | 77dcb3f1 | Panagiotis Astithas | new TransactionHelper<Object>().tryExecute(new Callable<Object>() { |
1512 | 77dcb3f1 | Panagiotis Astithas | @Override
|
1513 | 77dcb3f1 | Panagiotis Astithas | public Object call() throws Exception { |
1514 | f7c44c33 | fstamatelopoulos | getService().updateFile(user.getId(), fileLocal.getId(), |
1515 | d74c0270 | Panagiotis Astithas | fName, fTags, mDate, fVersioned, |
1516 | d74c0270 | Panagiotis Astithas | fReadForAll, fPerms); |
1517 | 77dcb3f1 | Panagiotis Astithas | return null; |
1518 | 77dcb3f1 | Panagiotis Astithas | } |
1519 | 77dcb3f1 | Panagiotis Astithas | |
1520 | 77dcb3f1 | Panagiotis Astithas | }); |
1521 | 14ad7326 | pastith | } |
1522 | 14ad7326 | pastith | } |
1523 | 14ad7326 | pastith | } catch (JSONException e) {
|
1524 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage()); |
1525 | 14ad7326 | pastith | } catch (InsufficientPermissionsException e) {
|
1526 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); |
1527 | 14ad7326 | pastith | } catch (ObjectNotFoundException e) {
|
1528 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_NOT_FOUND, e.getMessage()); |
1529 | 14ad7326 | pastith | } catch (DuplicateNameException e) {
|
1530 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_CONFLICT, e.getMessage()); |
1531 | 14ad7326 | pastith | } catch (RpcException e) {
|
1532 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path); |
1533 | 77dcb3f1 | Panagiotis Astithas | } catch (Exception e) { |
1534 | 77dcb3f1 | Panagiotis Astithas | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path); |
1535 | 77dcb3f1 | Panagiotis Astithas | return;
|
1536 | 14ad7326 | pastith | } |
1537 | 14ad7326 | pastith | } |
1538 | 14ad7326 | pastith | |
1539 | 14ad7326 | pastith | /**
|
1540 | 425e3d5e | Panagiotis Astithas | * Returns the new URL of an updated folder.
|
1541 | 425e3d5e | Panagiotis Astithas | */
|
1542 | f7c44c33 | fstamatelopoulos | private String getNewUrl(HttpServletRequest req, Folder folder) throws UnsupportedEncodingException { |
1543 | 8dca7586 | Panagiotis Astithas | String parentUrl = URLDecoder.decode(getContextPath(req, true),"UTF-8"); |
1544 | 8dca7586 | Panagiotis Astithas | String fpath = URLDecoder.decode(getRelativePath(req), "UTF-8"); |
1545 | 425e3d5e | Panagiotis Astithas | if (parentUrl.indexOf(fpath) != -1) |
1546 | 425e3d5e | Panagiotis Astithas | parentUrl = parentUrl.substring(0, parentUrl.indexOf(fpath));
|
1547 | 425e3d5e | Panagiotis Astithas | if(!parentUrl.endsWith("/")) |
1548 | 425e3d5e | Panagiotis Astithas | parentUrl = parentUrl+"/";
|
1549 | 425e3d5e | Panagiotis Astithas | parentUrl = parentUrl+folder.getOwner().getUsername()+PATH_FILES+folder.getPath(); |
1550 | 425e3d5e | Panagiotis Astithas | return parentUrl;
|
1551 | 425e3d5e | Panagiotis Astithas | } |
1552 | 425e3d5e | Panagiotis Astithas | |
1553 | 425e3d5e | Panagiotis Astithas | /**
|
1554 | 14ad7326 | pastith | * Helper method to convert a JSON array of permissions into a set of
|
1555 | f7c44c33 | fstamatelopoulos | * Permission objects.
|
1556 | 14ad7326 | pastith | *
|
1557 | 14ad7326 | pastith | * @param user the current user
|
1558 | 14ad7326 | pastith | * @param permissions the JSON array to parse
|
1559 | 14ad7326 | pastith | * @return the parsed set of permissions
|
1560 | 14ad7326 | pastith | * @throws JSONException if there was an error parsing the JSON object
|
1561 | 14ad7326 | pastith | * @throws RpcException if there was an error communicating with the EJB
|
1562 | 14ad7326 | pastith | * @throws ObjectNotFoundException if the user could not be found
|
1563 | 867d129b | Fotis Stamatelopoulos | * @throws UnsupportedEncodingException
|
1564 | 14ad7326 | pastith | */
|
1565 | f7c44c33 | fstamatelopoulos | private Set<Permission> parsePermissions(User user, JSONArray permissions) |
1566 | 867d129b | Fotis Stamatelopoulos | throws JSONException, RpcException, ObjectNotFoundException, UnsupportedEncodingException { |
1567 | 14ad7326 | pastith | if (permissions == null) |
1568 | 14ad7326 | pastith | return null; |
1569 | f7c44c33 | fstamatelopoulos | Set<Permission> perms = new HashSet<Permission>(); |
1570 | 14ad7326 | pastith | for (int i = 0; i < permissions.length(); i++) { |
1571 | 14ad7326 | pastith | JSONObject j = permissions.getJSONObject(i); |
1572 | f7c44c33 | fstamatelopoulos | Permission perm = new Permission(); |
1573 | 14ad7326 | pastith | perm.setModifyACL(j.optBoolean("modifyACL"));
|
1574 | 14ad7326 | pastith | perm.setRead(j.optBoolean("read"));
|
1575 | 14ad7326 | pastith | perm.setWrite(j.optBoolean("write"));
|
1576 | 14ad7326 | pastith | String permUser = j.optString("user"); |
1577 | 14ad7326 | pastith | if (!permUser.isEmpty()) {
|
1578 | 14ad7326 | pastith | User u = getService().findUser(permUser); |
1579 | 14ad7326 | pastith | if (u == null) |
1580 | 14ad7326 | pastith | throw new ObjectNotFoundException("User " + permUser + " not found"); |
1581 | f7c44c33 | fstamatelopoulos | perm.setUser(u); |
1582 | 14ad7326 | pastith | } |
1583 | 867d129b | Fotis Stamatelopoulos | // 31/8/2009: Add optional groupUri which takes priority if it exists
|
1584 | 867d129b | Fotis Stamatelopoulos | String permGroupUri = j.optString("groupUri"); |
1585 | 14ad7326 | pastith | String permGroup = j.optString("group"); |
1586 | 867d129b | Fotis Stamatelopoulos | if (!permGroupUri.isEmpty()) {
|
1587 | 867d129b | Fotis Stamatelopoulos | String[] names = permGroupUri.split("/"); |
1588 | 867d129b | Fotis Stamatelopoulos | String grp = URLDecoder.decode(names[names.length - 1], "UTF-8"); |
1589 | 867d129b | Fotis Stamatelopoulos | String usr = URLDecoder.decode(names[names.length - 3], "UTF-8"); |
1590 | 867d129b | Fotis Stamatelopoulos | User u = getService().findUser(usr); |
1591 | 867d129b | Fotis Stamatelopoulos | if (u == null) |
1592 | 867d129b | Fotis Stamatelopoulos | throw new ObjectNotFoundException("User " + permUser + " not found"); |
1593 | f7c44c33 | fstamatelopoulos | Group g = getService().getGroup(u.getId(), grp);
|
1594 | 867d129b | Fotis Stamatelopoulos | perm.setGroup(g); |
1595 | 867d129b | Fotis Stamatelopoulos | } |
1596 | 867d129b | Fotis Stamatelopoulos | else if (!permGroup.isEmpty()) { |
1597 | f7c44c33 | fstamatelopoulos | Group g = getService().getGroup(user.getId(), permGroup);
|
1598 | 14ad7326 | pastith | perm.setGroup(g); |
1599 | 14ad7326 | pastith | } |
1600 | 867d129b | Fotis Stamatelopoulos | if (permUser.isEmpty() && permGroupUri.isEmpty() && permGroup.isEmpty())
|
1601 | 14ad7326 | pastith | throw new JSONException("A permission must correspond to either a user or a group"); |
1602 | 14ad7326 | pastith | perms.add(perm); |
1603 | 14ad7326 | pastith | } |
1604 | 14ad7326 | pastith | return perms;
|
1605 | 14ad7326 | pastith | } |
1606 | 14ad7326 | pastith | |
1607 | 14ad7326 | pastith | /**
|
1608 | 14ad7326 | pastith | * Creates a new folder with the specified name under the folder in the provided path.
|
1609 | 14ad7326 | pastith | *
|
1610 | 14ad7326 | pastith | * @param req the HTTP request
|
1611 | 14ad7326 | pastith | * @param resp the HTTP response
|
1612 | 14ad7326 | pastith | * @param path the parent folder path
|
1613 | 14ad7326 | pastith | * @param folderName the name of the new folder
|
1614 | 14ad7326 | pastith | * @throws IOException if an input/output error occurs
|
1615 | 14ad7326 | pastith | */
|
1616 | 77dcb3f1 | Panagiotis Astithas | private void createFolder(HttpServletRequest req, HttpServletResponse resp, String path, final String folderName) throws IOException { |
1617 | 14ad7326 | pastith | if (logger.isDebugEnabled())
|
1618 | 14ad7326 | pastith | logger.debug("Creating folder " + folderName + " in '" + path); |
1619 | 14ad7326 | pastith | |
1620 | 77dcb3f1 | Panagiotis Astithas | final User user = getUser(req);
|
1621 | 14ad7326 | pastith | User owner = getOwner(req); |
1622 | 14ad7326 | pastith | boolean exists = true; |
1623 | 14ad7326 | pastith | try {
|
1624 | e150a336 | pastith | getService().getResourceAtPath(owner.getId(), path + folderName, false);
|
1625 | 14ad7326 | pastith | } catch (ObjectNotFoundException e) {
|
1626 | 14ad7326 | pastith | exists = false;
|
1627 | 14ad7326 | pastith | } catch (RpcException e) {
|
1628 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path + folderName); |
1629 | 14ad7326 | pastith | return;
|
1630 | 14ad7326 | pastith | } |
1631 | 14ad7326 | pastith | |
1632 | 14ad7326 | pastith | if (exists) {
|
1633 | 14ad7326 | pastith | resp.addHeader("Allow", METHOD_GET + ", " + METHOD_DELETE + |
1634 | 14ad7326 | pastith | ", " + METHOD_HEAD);
|
1635 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); |
1636 | 14ad7326 | pastith | return;
|
1637 | 14ad7326 | pastith | } |
1638 | 14ad7326 | pastith | |
1639 | 14ad7326 | pastith | Object parent;
|
1640 | 14ad7326 | pastith | try {
|
1641 | 68410d59 | pastith | parent = getService().getResourceAtPath(owner.getId(), path, true);
|
1642 | 14ad7326 | pastith | } catch (ObjectNotFoundException e) {
|
1643 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_CONFLICT); |
1644 | 14ad7326 | pastith | return;
|
1645 | 14ad7326 | pastith | } catch (RpcException e) {
|
1646 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path + folderName); |
1647 | 14ad7326 | pastith | return;
|
1648 | 14ad7326 | pastith | } |
1649 | 14ad7326 | pastith | try {
|
1650 | f7c44c33 | fstamatelopoulos | if (parent instanceof Folder) { |
1651 | f7c44c33 | fstamatelopoulos | final Folder folderLocal = (Folder) parent;
|
1652 | f7c44c33 | fstamatelopoulos | Folder newFolder = new TransactionHelper<Folder>().tryExecute(new Callable<Folder>() { |
1653 | 77dcb3f1 | Panagiotis Astithas | @Override
|
1654 | f7c44c33 | fstamatelopoulos | public Folder call() throws Exception { |
1655 | f7c44c33 | fstamatelopoulos | return getService().createFolder(user.getId(), folderLocal.getId(), folderName);
|
1656 | 77dcb3f1 | Panagiotis Astithas | } |
1657 | 77dcb3f1 | Panagiotis Astithas | |
1658 | 77dcb3f1 | Panagiotis Astithas | }); |
1659 | a0dde818 | Panagiotis Astithas | String newResource = getApiRoot() + newFolder.getURI();
|
1660 | 14ad7326 | pastith | resp.setHeader("Location", newResource);
|
1661 | 14ad7326 | pastith | resp.setContentType("text/plain");
|
1662 | 14ad7326 | pastith | PrintWriter out = resp.getWriter();
|
1663 | 14ad7326 | pastith | out.println(newResource); |
1664 | 14ad7326 | pastith | } else {
|
1665 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); |
1666 | 14ad7326 | pastith | return;
|
1667 | 14ad7326 | pastith | } |
1668 | 14ad7326 | pastith | } catch (DuplicateNameException e) {
|
1669 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_CONFLICT); |
1670 | 14ad7326 | pastith | return;
|
1671 | 14ad7326 | pastith | } catch (InsufficientPermissionsException e) {
|
1672 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); |
1673 | 14ad7326 | pastith | return;
|
1674 | 14ad7326 | pastith | } catch (ObjectNotFoundException e) {
|
1675 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_CONFLICT); |
1676 | 14ad7326 | pastith | return;
|
1677 | 14ad7326 | pastith | } catch (RpcException e) {
|
1678 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path + folderName); |
1679 | 14ad7326 | pastith | return;
|
1680 | 77dcb3f1 | Panagiotis Astithas | } catch (Exception e) { |
1681 | 77dcb3f1 | Panagiotis Astithas | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path); |
1682 | 77dcb3f1 | Panagiotis Astithas | return;
|
1683 | 14ad7326 | pastith | } |
1684 | 14ad7326 | pastith | resp.setStatus(HttpServletResponse.SC_CREATED); |
1685 | 14ad7326 | pastith | } |
1686 | 14ad7326 | pastith | |
1687 | 14ad7326 | pastith | /**
|
1688 | 14ad7326 | pastith | * @param req
|
1689 | 14ad7326 | pastith | * @param resp
|
1690 | 14ad7326 | pastith | * @throws IOException
|
1691 | 14ad7326 | pastith | * @throws FileNotFoundException
|
1692 | 14ad7326 | pastith | */
|
1693 | 14ad7326 | pastith | void putResource(HttpServletRequest req, HttpServletResponse resp) throws IOException, FileNotFoundException { |
1694 | 14ad7326 | pastith | String path = getInnerPath(req, PATH_FILES);
|
1695 | f0c744b4 | Panagiotis Astithas | try {
|
1696 | f0c744b4 | Panagiotis Astithas | path = URLDecoder.decode(path, "UTF-8"); |
1697 | f0c744b4 | Panagiotis Astithas | } catch (IllegalArgumentException e) { |
1698 | f0c744b4 | Panagiotis Astithas | resp.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage()); |
1699 | f0c744b4 | Panagiotis Astithas | return;
|
1700 | f0c744b4 | Panagiotis Astithas | } |
1701 | 14ad7326 | pastith | if (logger.isDebugEnabled())
|
1702 | 14ad7326 | pastith | logger.debug("Updating resource: " + path);
|
1703 | 14ad7326 | pastith | |
1704 | 204107fb | Panagiotis Astithas | final User user = getUser(req);
|
1705 | 14ad7326 | pastith | User owner = getOwner(req); |
1706 | 14ad7326 | pastith | boolean exists = true; |
1707 | 14ad7326 | pastith | Object resource = null; |
1708 | f7c44c33 | fstamatelopoulos | FileHeader fileLocal = null;
|
1709 | 14ad7326 | pastith | try {
|
1710 | e150a336 | pastith | resource = getService().getResourceAtPath(owner.getId(), path, false);
|
1711 | 14ad7326 | pastith | } catch (ObjectNotFoundException e) {
|
1712 | 14ad7326 | pastith | exists = false;
|
1713 | 14ad7326 | pastith | } catch (RpcException e) {
|
1714 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path); |
1715 | 14ad7326 | pastith | return;
|
1716 | 14ad7326 | pastith | } |
1717 | 14ad7326 | pastith | |
1718 | 14ad7326 | pastith | if (exists)
|
1719 | f7c44c33 | fstamatelopoulos | if (resource instanceof FileHeader) |
1720 | f7c44c33 | fstamatelopoulos | fileLocal = (FileHeader) resource; |
1721 | 14ad7326 | pastith | else {
|
1722 | e150a336 | pastith | resp.sendError(HttpServletResponse.SC_CONFLICT, path + " is a folder");
|
1723 | 14ad7326 | pastith | return;
|
1724 | 14ad7326 | pastith | } |
1725 | 14ad7326 | pastith | boolean result = true; |
1726 | 14ad7326 | pastith | |
1727 | 14ad7326 | pastith | // Temporary content file used to support partial PUT.
|
1728 | 14ad7326 | pastith | File contentFile = null; |
1729 | 14ad7326 | pastith | |
1730 | 14ad7326 | pastith | Range range = parseContentRange(req, resp); |
1731 | 14ad7326 | pastith | |
1732 | 14ad7326 | pastith | InputStream resourceInputStream = null; |
1733 | 14ad7326 | pastith | |
1734 | 14ad7326 | pastith | // Append data specified in ranges to existing content for this
|
1735 | 14ad7326 | pastith | // resource - create a temporary file on the local filesystem to
|
1736 | 14ad7326 | pastith | // perform this operation.
|
1737 | 14ad7326 | pastith | // Assume just one range is specified for now
|
1738 | 14ad7326 | pastith | if (range != null) { |
1739 | 14ad7326 | pastith | try {
|
1740 | 14ad7326 | pastith | contentFile = executePartialPut(req, range, path); |
1741 | 14ad7326 | pastith | } catch (RpcException e) {
|
1742 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path); |
1743 | 14ad7326 | pastith | return;
|
1744 | 14ad7326 | pastith | } catch (ObjectNotFoundException e) {
|
1745 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_CONFLICT); |
1746 | 14ad7326 | pastith | return;
|
1747 | 14ad7326 | pastith | } catch (InsufficientPermissionsException e) {
|
1748 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); |
1749 | 14ad7326 | pastith | return;
|
1750 | 14ad7326 | pastith | } |
1751 | 14ad7326 | pastith | resourceInputStream = new FileInputStream(contentFile); |
1752 | 14ad7326 | pastith | } else
|
1753 | 14ad7326 | pastith | resourceInputStream = req.getInputStream(); |
1754 | 14ad7326 | pastith | |
1755 | 14ad7326 | pastith | try {
|
1756 | f7c44c33 | fstamatelopoulos | Folder folderLocal = null;
|
1757 | 68410d59 | pastith | Object parent = getService().getResourceAtPath(owner.getId(), getParentPath(path), true); |
1758 | f7c44c33 | fstamatelopoulos | if (!(parent instanceof Folder)) { |
1759 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_CONFLICT); |
1760 | 14ad7326 | pastith | return;
|
1761 | 14ad7326 | pastith | } |
1762 | f7c44c33 | fstamatelopoulos | folderLocal = (Folder) parent; |
1763 | 204107fb | Panagiotis Astithas | final String name = getLastElement(path); |
1764 | 204107fb | Panagiotis Astithas | final String mimeType = context.getMimeType(name); |
1765 | b13aae04 | pastith | File uploadedFile = null; |
1766 | b13aae04 | pastith | try {
|
1767 | b13aae04 | pastith | uploadedFile = getService().uploadFile(resourceInputStream, user.getId()); |
1768 | b13aae04 | pastith | } catch (IOException ex) { |
1769 | b13aae04 | pastith | throw new GSSIOException(ex, false); |
1770 | b13aae04 | pastith | } |
1771 | f7c44c33 | fstamatelopoulos | FileHeader fileTemp = null;
|
1772 | 2f1a60e0 | Dimitris Routsis | final File uploadedf = uploadedFile; |
1773 | f7c44c33 | fstamatelopoulos | final Folder parentf = folderLocal;
|
1774 | f7c44c33 | fstamatelopoulos | final FileHeader f = fileLocal;
|
1775 | 14ad7326 | pastith | if (exists)
|
1776 | f7c44c33 | fstamatelopoulos | fileTemp = new TransactionHelper<FileHeader>().tryExecute(new Callable<FileHeader>() { |
1777 | 2f1a60e0 | Dimitris Routsis | @Override
|
1778 | f7c44c33 | fstamatelopoulos | public FileHeader call() throws Exception { |
1779 | 2f1a60e0 | Dimitris Routsis | return getService().updateFileContents(user.getId(), f.getId(), mimeType, uploadedf.getCanonicalFile().length(), uploadedf.getAbsolutePath());
|
1780 | 2f1a60e0 | Dimitris Routsis | } |
1781 | 2f1a60e0 | Dimitris Routsis | }); |
1782 | 2f1a60e0 | Dimitris Routsis | else
|
1783 | f7c44c33 | fstamatelopoulos | fileTemp = new TransactionHelper<FileHeader>().tryExecute(new Callable<FileHeader>() { |
1784 | 204107fb | Panagiotis Astithas | @Override
|
1785 | f7c44c33 | fstamatelopoulos | public FileHeader call() throws Exception { |
1786 | 4d737770 | Fotis Stamatelopoulos | return getService().createFile(user.getId(), parentf.getId(), name, mimeType, uploadedf.getCanonicalFile().length(), uploadedf.getAbsolutePath());
|
1787 | 204107fb | Panagiotis Astithas | } |
1788 | 204107fb | Panagiotis Astithas | |
1789 | 204107fb | Panagiotis Astithas | }); |
1790 | f7c44c33 | fstamatelopoulos | updateAccounting(owner, new Date(), fileTemp.getCurrentBody().getFileSize()); |
1791 | f7c44c33 | fstamatelopoulos | getService().removeFileUploadProgress(user.getId(), fileTemp.getName()); |
1792 | 14ad7326 | pastith | } catch(ObjectNotFoundException e) {
|
1793 | 14ad7326 | pastith | result = false;
|
1794 | 14ad7326 | pastith | } catch (RpcException e) {
|
1795 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path); |
1796 | 14ad7326 | pastith | return;
|
1797 | 14ad7326 | pastith | } catch (IOException e) { |
1798 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path); |
1799 | 14ad7326 | pastith | return;
|
1800 | 14ad7326 | pastith | } catch (GSSIOException e) {
|
1801 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path); |
1802 | 14ad7326 | pastith | return;
|
1803 | 14ad7326 | pastith | } catch (DuplicateNameException e) {
|
1804 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_CONFLICT); |
1805 | 14ad7326 | pastith | return;
|
1806 | 14ad7326 | pastith | } catch (InsufficientPermissionsException e) {
|
1807 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); |
1808 | 14ad7326 | pastith | return;
|
1809 | 14ad7326 | pastith | } catch (QuotaExceededException e) {
|
1810 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE, e.getMessage()); |
1811 | 14ad7326 | pastith | return;
|
1812 | 204107fb | Panagiotis Astithas | } catch (Exception e) { |
1813 | 204107fb | Panagiotis Astithas | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path); |
1814 | 204107fb | Panagiotis Astithas | return;
|
1815 | 14ad7326 | pastith | } |
1816 | 14ad7326 | pastith | |
1817 | 14ad7326 | pastith | if (result) {
|
1818 | 14ad7326 | pastith | if (exists)
|
1819 | 14ad7326 | pastith | resp.setStatus(HttpServletResponse.SC_NO_CONTENT); |
1820 | 14ad7326 | pastith | else
|
1821 | 14ad7326 | pastith | resp.setStatus(HttpServletResponse.SC_CREATED); |
1822 | 14ad7326 | pastith | } else
|
1823 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_CONFLICT); |
1824 | 14ad7326 | pastith | } |
1825 | 14ad7326 | pastith | |
1826 | 14ad7326 | pastith | /**
|
1827 | 14ad7326 | pastith | * Delete a resource.
|
1828 | 14ad7326 | pastith | *
|
1829 | 14ad7326 | pastith | * @param req The servlet request we are processing
|
1830 | 14ad7326 | pastith | * @param resp The servlet response we are processing
|
1831 | 14ad7326 | pastith | * @throws IOException if the response cannot be sent
|
1832 | 14ad7326 | pastith | */
|
1833 | 14ad7326 | pastith | void deleteResource(HttpServletRequest req, HttpServletResponse resp) throws IOException { |
1834 | 14ad7326 | pastith | String path = getInnerPath(req, PATH_FILES);
|
1835 | 14ad7326 | pastith | if (logger.isDebugEnabled())
|
1836 | 14ad7326 | pastith | logger.debug("Deleting resource '" + path);
|
1837 | 5e2b8ec6 | koutsoub | path = URLDecoder.decode(path, "UTF-8"); |
1838 | 2f1a60e0 | Dimitris Routsis | final User user = getUser(req);
|
1839 | 14ad7326 | pastith | User owner = getOwner(req); |
1840 | 14ad7326 | pastith | boolean exists = true; |
1841 | 14ad7326 | pastith | Object object = null; |
1842 | 14ad7326 | pastith | try {
|
1843 | e150a336 | pastith | object = getService().getResourceAtPath(owner.getId(), path, false);
|
1844 | 14ad7326 | pastith | } catch (ObjectNotFoundException e) {
|
1845 | 14ad7326 | pastith | exists = false;
|
1846 | 14ad7326 | pastith | } catch (RpcException e) {
|
1847 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); |
1848 | 14ad7326 | pastith | return;
|
1849 | 14ad7326 | pastith | } |
1850 | 14ad7326 | pastith | |
1851 | 14ad7326 | pastith | if (!exists) {
|
1852 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_NOT_FOUND); |
1853 | 14ad7326 | pastith | return;
|
1854 | 14ad7326 | pastith | } |
1855 | 14ad7326 | pastith | |
1856 | f7c44c33 | fstamatelopoulos | Folder folderLocal = null;
|
1857 | f7c44c33 | fstamatelopoulos | FileHeader fileLocal = null;
|
1858 | f7c44c33 | fstamatelopoulos | if (object instanceof Folder) |
1859 | f7c44c33 | fstamatelopoulos | folderLocal = (Folder) object; |
1860 | 14ad7326 | pastith | else
|
1861 | f7c44c33 | fstamatelopoulos | fileLocal = (FileHeader) object; |
1862 | 14ad7326 | pastith | |
1863 | f7c44c33 | fstamatelopoulos | if (fileLocal != null) |
1864 | 14ad7326 | pastith | try {
|
1865 | f7c44c33 | fstamatelopoulos | final FileHeader f = fileLocal;
|
1866 | 2f1a60e0 | Dimitris Routsis | new TransactionHelper<Void>().tryExecute(new Callable<Void>() { |
1867 | 2f1a60e0 | Dimitris Routsis | @Override
|
1868 | 2f1a60e0 | Dimitris Routsis | public Void call() throws Exception { |
1869 | 2f1a60e0 | Dimitris Routsis | getService().deleteFile(user.getId(), f.getId()); |
1870 | 2f1a60e0 | Dimitris Routsis | return null; |
1871 | 2f1a60e0 | Dimitris Routsis | } |
1872 | 2f1a60e0 | Dimitris Routsis | }); |
1873 | 14ad7326 | pastith | } catch (InsufficientPermissionsException e) {
|
1874 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); |
1875 | 14ad7326 | pastith | return;
|
1876 | 14ad7326 | pastith | } catch (ObjectNotFoundException e) {
|
1877 | 14ad7326 | pastith | // Although we had already found the object, it was
|
1878 | 14ad7326 | pastith | // probably deleted from another thread.
|
1879 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_NOT_FOUND); |
1880 | 14ad7326 | pastith | return;
|
1881 | 14ad7326 | pastith | } catch (RpcException e) {
|
1882 | 14ad7326 | pastith | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); |
1883 | 14ad7326 | pastith | return;
|
1884 | 2f1a60e0 | Dimitris Routsis | } catch (Exception e) { |
1885 | 2f1a60e0 | Dimitris Routsis | resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); |
1886 | 2f1a60e0 | Dimitris Routsis | return;
|
1887 | 14ad7326 | pastith | } |
1888 | f7c44c33 | fstamatelopoulos | else if (folderLocal != null) |
1889 | 14ad7326 | pastith | try {
|
1890 | f7c44c33 | fstamatelopoulos | final Folder fo = folderLocal;
|
1891 | 2f1a60e0 | Dimitris Routsis | new TransactionHelper<Void>().tryExecute(new Callable<Void>() { |
1892 | 2f1a60e0 | Dimitris Routsis | @Override
|
1893 | 2f1a60e0 | Dimitris Routsis | public Void call() throws Exception { |
1894 | 2f1a60e0 | Dimitris Routsis | getService().deleteFolder(user.getId(), fo.getId()); |
1895 | 2f1a60e0 | Dimitris Routsis | return null; |
1896 | 2f1a60e0 | Dimitris Routsis | } |
1897 | 2f1a60e0 | Dimitris Routsis | }); |
1898 | 14ad7326 | pastith | } catch (InsufficientPermissionsException e) {
|
1899 | 14ad7326 | pastith | resp.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED); |
1900 | 14ad7326 | pastith | return;
|
1901 | 14ad7326 | pastith | } catch (ObjectNotFoundException e) {
|
1902 | 14ad7326 | pastith | resp.setStatus(HttpServletResponse.SC_NOT_FOUND); |
1903 | 14ad7326 | pastith | return;
|
1904 | 14ad7326 | pastith | } catch (RpcException e) {
|
1905 | 14ad7326 | pastith | resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); |
1906 | 14ad7326 | pastith | return;
|
1907 | 2f1a60e0 | Dimitris Routsis | } catch (Exception e) { |
1908 | 2f1a60e0 | Dimitris Routsis | resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); |
1909 | 2f1a60e0 | Dimitris Routsis | return;
|
1910 | 14ad7326 | pastith | } |
1911 | 14ad7326 | pastith | resp.setStatus(HttpServletResponse.SC_NO_CONTENT); |
1912 | 14ad7326 | pastith | return;
|
1913 | 14ad7326 | pastith | } |
1914 | 14ad7326 | pastith | |
1915 | 14ad7326 | pastith | /**
|
1916 | 14ad7326 | pastith | * Return an InputStream to a JSON representation of the contents
|
1917 | 14ad7326 | pastith | * of this directory.
|
1918 | 14ad7326 | pastith | *
|
1919 | 14ad7326 | pastith | * @param user the user that made the request
|
1920 | 14ad7326 | pastith | * @param folder the specified directory
|
1921 | 14ad7326 | pastith | * @return an input stream with the rendered contents
|
1922 | 14ad7326 | pastith | * @throws IOException if the response cannot be sent
|
1923 | 14ad7326 | pastith | * @throws ServletException
|
1924 | 14ad7326 | pastith | * @throws InsufficientPermissionsException if the user does not have
|
1925 | 14ad7326 | pastith | * the necessary privileges to read the directory
|
1926 | 14ad7326 | pastith | */
|
1927 | f7c44c33 | fstamatelopoulos | private InputStream renderJson(User user, Folder folder) throws IOException, |
1928 | 14ad7326 | pastith | ServletException, InsufficientPermissionsException { |
1929 | a3c09df3 | Giannis Koutsoubos | try {
|
1930 | a3c09df3 | Giannis Koutsoubos | folder = getService().expandFolder(folder); |
1931 | a3c09df3 | Giannis Koutsoubos | } catch (ObjectNotFoundException e1) {
|
1932 | a3c09df3 | Giannis Koutsoubos | // TODO Auto-generated catch block
|
1933 | a3c09df3 | Giannis Koutsoubos | e1.printStackTrace(); |
1934 | a3c09df3 | Giannis Koutsoubos | } catch (RpcException e1) {
|
1935 | a3c09df3 | Giannis Koutsoubos | // TODO Auto-generated catch block
|
1936 | a3c09df3 | Giannis Koutsoubos | e1.printStackTrace(); |
1937 | a3c09df3 | Giannis Koutsoubos | } |
1938 | 14ad7326 | pastith | JSONObject json = new JSONObject();
|
1939 | 14ad7326 | pastith | try {
|
1940 | 08c62ec7 | pastith | json.put("name", folder.getName()).
|
1941 | 47d800f9 | pastith | put("owner", folder.getOwner().getUsername()).
|
1942 | 14ad7326 | pastith | put("createdBy", folder.getAuditInfo().getCreatedBy().getUsername()).
|
1943 | 14ad7326 | pastith | put("creationDate", folder.getAuditInfo().getCreationDate().getTime()).
|
1944 | 9e6a28ed | Natasa Kapravelou | put("deleted", folder.isDeleted()).
|
1945 | 16b54aa8 | koutsoub | put("shared", folder.getShared()).
|
1946 | 9e6a28ed | Natasa Kapravelou | put("readForAll", folder.isReadForAll());
|
1947 | 9e6a28ed | Natasa Kapravelou | |
1948 | 77f75ac4 | pastith | if (folder.getAuditInfo().getModifiedBy() != null) |
1949 | 77f75ac4 | pastith | json.put("modifiedBy", folder.getAuditInfo().getModifiedBy().getUsername()).
|
1950 | 77f75ac4 | pastith | put("modificationDate", folder.getAuditInfo().getModificationDate().getTime());
|
1951 | 8cc77d04 | pastith | if (folder.getParent() != null) { |
1952 | 8cc77d04 | pastith | JSONObject j = new JSONObject();
|
1953 | 865f1d02 | pastith | j.put("uri", getApiRoot() + folder.getParent().getURI());
|
1954 | 8cc77d04 | pastith | j.put("name", folder.getParent().getName());
|
1955 | 8cc77d04 | pastith | json.put("parent", j);
|
1956 | d6ba3052 | koutsoub | } |
1957 | f7abcd5a | pastith | List<JSONObject> subfolders = new ArrayList<JSONObject>(); |
1958 | f7c44c33 | fstamatelopoulos | for (Folder f: folder.getSubfolders())
|
1959 | f7abcd5a | pastith | if (!f.isDeleted()) {
|
1960 | f7abcd5a | pastith | JSONObject j = new JSONObject();
|
1961 | f7abcd5a | pastith | j.put("name", f.getName()).
|
1962 | 086c7250 | koutsoub | put("uri", getApiRoot() + f.getURI()).
|
1963 | 086c7250 | koutsoub | put("shared", f.getShared());
|
1964 | f7abcd5a | pastith | subfolders.add(j); |
1965 | f7abcd5a | pastith | } |
1966 | f7abcd5a | pastith | json.put("folders", subfolders);
|
1967 | f7abcd5a | pastith | List<JSONObject> files = new ArrayList<JSONObject>(); |
1968 | f7c44c33 | fstamatelopoulos | List<FileHeader> fileHeaders = getService().getFiles(user.getId(), folder.getId(), false); |
1969 | f7c44c33 | fstamatelopoulos | for (FileHeader f: fileHeaders) {
|
1970 | f7abcd5a | pastith | JSONObject j = new JSONObject();
|
1971 | f7abcd5a | pastith | j.put("name", f.getName()).
|
1972 | 3f2e14a0 | pastith | put("owner", f.getOwner().getUsername()).
|
1973 | f7abcd5a | pastith | put("deleted", f.isDeleted()).
|
1974 | f7c44c33 | fstamatelopoulos | put("version", f.getCurrentBody().getVersion()).
|
1975 | f7c44c33 | fstamatelopoulos | put("content", f.getCurrentBody().getMimeType()).
|
1976 | f7c44c33 | fstamatelopoulos | put("size", f.getCurrentBody().getFileSize()).
|
1977 | 16b54aa8 | koutsoub | put("shared", f.getShared()).
|
1978 | 16b54aa8 | koutsoub | put("versioned",f.isVersioned()).
|
1979 | f7abcd5a | pastith | put("creationDate", f.getAuditInfo().getCreationDate().getTime()).
|
1980 | d6ba3052 | koutsoub | put("path", f.getFolder().getPath()).
|
1981 | 2b90ab8a | pastith | put("uri", getApiRoot() + f.getURI());
|
1982 | eee18108 | pastith | if (f.getAuditInfo().getModificationDate() != null) |
1983 | eee18108 | pastith | j.put("modificationDate", f.getAuditInfo().getModificationDate().getTime());
|
1984 | f7abcd5a | pastith | files.add(j); |
1985 | f7abcd5a | pastith | } |
1986 | 14ad7326 | pastith | json.put("files", files);
|
1987 | f7c44c33 | fstamatelopoulos | Set<Permission> perms = getService().getFolderPermissions(user.getId(), folder.getId()); |
1988 | 14ad7326 | pastith | json.put("permissions", renderJson(perms));
|
1989 | 14ad7326 | pastith | } catch (JSONException e) {
|
1990 | 14ad7326 | pastith | throw new ServletException(e); |
1991 | 14ad7326 | pastith | } catch (ObjectNotFoundException e) {
|
1992 | 14ad7326 | pastith | throw new ServletException(e); |
1993 | 14ad7326 | pastith | } catch (RpcException e) {
|
1994 | 14ad7326 | pastith | throw new ServletException(e); |
1995 | 14ad7326 | pastith | } |
1996 | 14ad7326 | pastith | |
1997 | 14ad7326 | pastith | // Prepare a writer to a buffered area
|
1998 | 14ad7326 | pastith | ByteArrayOutputStream stream = new ByteArrayOutputStream(); |
1999 | 14ad7326 | pastith | OutputStreamWriter osWriter = new OutputStreamWriter(stream, "UTF8"); |
2000 | 14ad7326 | pastith | PrintWriter writer = new PrintWriter(osWriter); |
2001 | 14ad7326 | pastith | |
2002 | 14ad7326 | pastith | // Return an input stream to the underlying bytes
|
2003 | 14ad7326 | pastith | writer.write(json.toString()); |
2004 | 14ad7326 | pastith | writer.flush(); |
2005 | 14ad7326 | pastith | return new ByteArrayInputStream(stream.toByteArray()); |
2006 | 14ad7326 | pastith | } |
2007 | 14ad7326 | pastith | |
2008 | 14ad7326 | pastith | /**
|
2009 | 14ad7326 | pastith | * Return a String with a JSON representation of the metadata
|
2010 | 77f75ac4 | pastith | * of the specified folder.
|
2011 | 77f75ac4 | pastith | * @throws RpcException
|
2012 | 77f75ac4 | pastith | * @throws InsufficientPermissionsException
|
2013 | 77f75ac4 | pastith | * @throws ObjectNotFoundException
|
2014 | 77f75ac4 | pastith | */
|
2015 | f7c44c33 | fstamatelopoulos | private String renderJsonMetadata(User user, Folder folder) |
2016 | 77f75ac4 | pastith | throws ServletException, InsufficientPermissionsException {
|
2017 | 77f75ac4 | pastith | // Check if the user has read permission.
|
2018 | 77f75ac4 | pastith | try {
|
2019 | 77f75ac4 | pastith | if (!getService().canReadFolder(user.getId(), folder.getId()))
|
2020 | 77f75ac4 | pastith | throw new InsufficientPermissionsException(); |
2021 | 77f75ac4 | pastith | } catch (ObjectNotFoundException e) {
|
2022 | 77f75ac4 | pastith | throw new ServletException(e); |
2023 | 77f75ac4 | pastith | } catch (RpcException e) {
|
2024 | 77f75ac4 | pastith | throw new ServletException(e); |
2025 | 77f75ac4 | pastith | } |
2026 | 77f75ac4 | pastith | |
2027 | 77f75ac4 | pastith | JSONObject json = new JSONObject();
|
2028 | 77f75ac4 | pastith | try {
|
2029 | c031299f | Christos V. Stathis | json.put("name", URLEncoder.encode(folder.getName(), "UTF-8")). |
2030 | 77f75ac4 | pastith | put("owner", folder.getOwner().getUsername()).
|
2031 | 77f75ac4 | pastith | put("createdBy", folder.getAuditInfo().getCreatedBy().getUsername()).
|
2032 | 77f75ac4 | pastith | put("creationDate", folder.getAuditInfo().getCreationDate().getTime()).
|
2033 | 77f75ac4 | pastith | put("deleted", folder.isDeleted());
|
2034 | 77f75ac4 | pastith | if (folder.getAuditInfo().getModifiedBy() != null) |
2035 | 77f75ac4 | pastith | json.put("modifiedBy", folder.getAuditInfo().getModifiedBy().getUsername()).
|
2036 | 77f75ac4 | pastith | put("modificationDate", folder.getAuditInfo().getModificationDate().getTime());
|
2037 | 77f75ac4 | pastith | } catch (JSONException e) {
|
2038 | 77f75ac4 | pastith | throw new ServletException(e); |
2039 | 77f75ac4 | pastith | } |
2040 | c031299f | Christos V. Stathis | catch (UnsupportedEncodingException e) { |
2041 | c031299f | Christos V. Stathis | throw new ServletException(e); |
2042 | c031299f | Christos V. Stathis | } |
2043 | c031299f | Christos V. Stathis | return json.toString();
|
2044 | 77f75ac4 | pastith | } |
2045 | 77f75ac4 | pastith | |
2046 | 77f75ac4 | pastith | /**
|
2047 | 77f75ac4 | pastith | * Return a String with a JSON representation of the metadata
|
2048 | 14ad7326 | pastith | * of the specified file. If an old file body is provided, then
|
2049 | 14ad7326 | pastith | * the metadata of that particular version will be returned.
|
2050 | 14ad7326 | pastith | *
|
2051 | 14ad7326 | pastith | * @param user the user that made the request
|
2052 | 14ad7326 | pastith | * @param file the specified file header
|
2053 | 14ad7326 | pastith | * @param oldBody the version number
|
2054 | 14ad7326 | pastith | * @return the JSON-encoded file
|
2055 | 14ad7326 | pastith | * @throws ServletException
|
2056 | 14ad7326 | pastith | * @throws InsufficientPermissionsException if the user does not have
|
2057 | 14ad7326 | pastith | * the necessary privileges to read the directory
|
2058 | 14ad7326 | pastith | */
|
2059 | f7c44c33 | fstamatelopoulos | private String renderJson(User user, FileHeader file, FileBody oldBody) |
2060 | 3a90e4f3 | pastith | throws ServletException, InsufficientPermissionsException {
|
2061 | 14ad7326 | pastith | JSONObject json = new JSONObject();
|
2062 | 14ad7326 | pastith | try {
|
2063 | a3c09df3 | Giannis Koutsoubos | file=getService().expandFile(file); |
2064 | 8cc77d04 | pastith | // Need to encode file name in order to properly display it in the web client.
|
2065 | 5e2b8ec6 | koutsoub | json.put("name", URLEncoder.encode(file.getName(),"UTF-8")). |
2066 | 47d800f9 | pastith | put("owner", file.getOwner().getUsername()).
|
2067 | 47d800f9 | pastith | put("versioned", file.isVersioned()).
|
2068 | f7c44c33 | fstamatelopoulos | put("version", oldBody != null ? oldBody.getVersion() : file.getCurrentBody().getVersion()). |
2069 | 47d800f9 | pastith | put("readForAll", file.isReadForAll()).
|
2070 | 16b54aa8 | koutsoub | put("shared", file.getShared()).
|
2071 | f7c44c33 | fstamatelopoulos | put("tags", renderJson(file.getFileTagsAsStrings())).
|
2072 | 2b90ab8a | pastith | put("path", file.getFolder().getPath()).
|
2073 | 865f1d02 | pastith | put("uri", getApiRoot() + file.getURI()).
|
2074 | 14ad7326 | pastith | put("deleted", file.isDeleted());
|
2075 | 8cc77d04 | pastith | JSONObject j = new JSONObject();
|
2076 | 865f1d02 | pastith | j.put("uri", getApiRoot() + file.getFolder().getURI()).
|
2077 | 8cc77d04 | pastith | put("name", URLEncoder.encode(file.getFolder().getName(),"UTF-8")); |
2078 | 8cc77d04 | pastith | json.put("folder", j);
|
2079 | 14ad7326 | pastith | if (oldBody != null) |
2080 | 14ad7326 | pastith | json.put("createdBy", oldBody.getAuditInfo().getCreatedBy().getUsername()).
|
2081 | 14ad7326 | pastith | put("creationDate", oldBody.getAuditInfo().getCreationDate().getTime()).
|
2082 | 14ad7326 | pastith | put("modifiedBy", oldBody.getAuditInfo().getModifiedBy().getUsername()).
|
2083 | 2d40bbc6 | pastith | put("modificationDate", oldBody.getAuditInfo().getModificationDate().getTime()).
|
2084 | 0e4865ee | pastith | put("content", oldBody.getMimeType()).
|
2085 | 2d40bbc6 | pastith | put("size", oldBody.getFileSize());
|
2086 | 14ad7326 | pastith | else
|
2087 | 14ad7326 | pastith | json.put("createdBy", file.getAuditInfo().getCreatedBy().getUsername()).
|
2088 | 14ad7326 | pastith | put("creationDate", file.getAuditInfo().getCreationDate().getTime()).
|
2089 | 14ad7326 | pastith | put("modifiedBy", file.getAuditInfo().getModifiedBy().getUsername()).
|
2090 | 2d40bbc6 | pastith | put("modificationDate", file.getAuditInfo().getModificationDate().getTime()).
|
2091 | f7c44c33 | fstamatelopoulos | put("content", file.getCurrentBody().getMimeType()).
|
2092 | f7c44c33 | fstamatelopoulos | put("size", file.getCurrentBody().getFileSize());
|
2093 | f7c44c33 | fstamatelopoulos | Set<Permission> perms = getService().getFilePermissions(user.getId(), file.getId()); |
2094 | 14ad7326 | pastith | json.put("permissions", renderJson(perms));
|
2095 | 14ad7326 | pastith | } catch (JSONException e) {
|
2096 | 14ad7326 | pastith | throw new ServletException(e); |
2097 | 14ad7326 | pastith | } catch (ObjectNotFoundException e) {
|
2098 | 14ad7326 | pastith | throw new ServletException(e); |
2099 | 14ad7326 | pastith | } catch (RpcException e) {
|
2100 | 14ad7326 | pastith | throw new ServletException(e); |
2101 | 3a90e4f3 | pastith | } catch (UnsupportedEncodingException e) { |
2102 | 3a90e4f3 | pastith | throw new ServletException(e); |
2103 | 14ad7326 | pastith | } |
2104 | 14ad7326 | pastith | |
2105 | 14ad7326 | pastith | return json.toString();
|
2106 | 14ad7326 | pastith | } |
2107 | 14ad7326 | pastith | |
2108 | 14ad7326 | pastith | /**
|
2109 | 14ad7326 | pastith | * Return a String with a JSON representation of the
|
2110 | 14ad7326 | pastith | * specified set of permissions.
|
2111 | 14ad7326 | pastith | *
|
2112 | 14ad7326 | pastith | * @param permissions the set of permissions
|
2113 | 14ad7326 | pastith | * @return the JSON-encoded object
|
2114 | 14ad7326 | pastith | * @throws JSONException
|
2115 | fc5ef2cc | droutsis | * @throws UnsupportedEncodingException
|
2116 | 14ad7326 | pastith | */
|
2117 | f7c44c33 | fstamatelopoulos | private JSONArray renderJson(Set<Permission> permissions) throws JSONException, UnsupportedEncodingException { |
2118 | 14ad7326 | pastith | JSONArray perms = new JSONArray();
|
2119 | f7c44c33 | fstamatelopoulos | for (Permission p: permissions) { |
2120 | 14ad7326 | pastith | JSONObject permission = new JSONObject();
|
2121 | 14ad7326 | pastith | permission.put("read", p.hasRead()).put("write", p.hasWrite()).put("modifyACL", p.hasModifyACL()); |
2122 | 14ad7326 | pastith | if (p.getUser() != null) |
2123 | 14ad7326 | pastith | permission.put("user", p.getUser().getUsername());
|
2124 | 867d129b | Fotis Stamatelopoulos | if (p.getGroup() != null) { |
2125 | f7c44c33 | fstamatelopoulos | Group group = p.getGroup();
|
2126 | 867d129b | Fotis Stamatelopoulos | permission.put("groupUri", getApiRoot() + group.getOwner().getUsername() + PATH_GROUPS + "/" + URLEncoder.encode(group.getName(),"UTF-8")); |
2127 | fc5ef2cc | droutsis | permission.put("group", URLEncoder.encode(p.getGroup().getName(),"UTF-8")); |
2128 | 867d129b | Fotis Stamatelopoulos | } |
2129 | 14ad7326 | pastith | perms.put(permission); |
2130 | 14ad7326 | pastith | } |
2131 | 14ad7326 | pastith | return perms;
|
2132 | 14ad7326 | pastith | } |
2133 | 14ad7326 | pastith | |
2134 | 14ad7326 | pastith | /**
|
2135 | fc5ef2cc | droutsis | * Return a String with a JSON representation of the
|
2136 | fc5ef2cc | droutsis | * specified collection of tags.
|
2137 | fc5ef2cc | droutsis | *
|
2138 | fc5ef2cc | droutsis | * @param tags the collection of tags
|
2139 | fc5ef2cc | droutsis | * @return the JSON-encoded object
|
2140 | fc5ef2cc | droutsis | * @throws JSONException
|
2141 | fc5ef2cc | droutsis | * @throws UnsupportedEncodingException
|
2142 | fc5ef2cc | droutsis | */
|
2143 | fc5ef2cc | droutsis | private JSONArray renderJson(Collection<String> tags) throws JSONException, UnsupportedEncodingException { |
2144 | fc5ef2cc | droutsis | JSONArray tagArray = new JSONArray();
|
2145 | fc5ef2cc | droutsis | for (String t: tags) |
2146 | fc5ef2cc | droutsis | tagArray.put(URLEncoder.encode(t,"UTF-8")); |
2147 | fc5ef2cc | droutsis | return tagArray;
|
2148 | fc5ef2cc | droutsis | } |
2149 | fc5ef2cc | droutsis | |
2150 | fc5ef2cc | droutsis | /**
|
2151 | 14ad7326 | pastith | * Retrieves the user who owns the destination namespace, for a
|
2152 | 14ad7326 | pastith | * copy or move request.
|
2153 | 14ad7326 | pastith | *
|
2154 | 14ad7326 | pastith | * @param req the HTTP request
|
2155 | 14ad7326 | pastith | * @return the owner of the namespace
|
2156 | 14ad7326 | pastith | */
|
2157 | 14ad7326 | pastith | protected User getDestinationOwner(HttpServletRequest req) {
|
2158 | 14ad7326 | pastith | return (User) req.getAttribute(DESTINATION_OWNER_ATTRIBUTE);
|
2159 | 14ad7326 | pastith | } |
2160 | e150a336 | pastith | |
2161 | e150a336 | pastith | /**
|
2162 | e150a336 | pastith | * A helper inner class for updating the progress status of a file upload.
|
2163 | e150a336 | pastith | *
|
2164 | e150a336 | pastith | * @author kman
|
2165 | e150a336 | pastith | */
|
2166 | e150a336 | pastith | public static class StatusProgressListener implements ProgressListener { |
2167 | e150a336 | pastith | private int percentLogged = 0; |
2168 | e150a336 | pastith | private long bytesTransferred = 0; |
2169 | e150a336 | pastith | |
2170 | e150a336 | pastith | private long fileSize = -100; |
2171 | e150a336 | pastith | |
2172 | e150a336 | pastith | private Long userId; |
2173 | e150a336 | pastith | |
2174 | e150a336 | pastith | private String filename; |
2175 | e150a336 | pastith | |
2176 | e150a336 | pastith | private ExternalAPI service;
|
2177 | e150a336 | pastith | |
2178 | e150a336 | pastith | public StatusProgressListener(ExternalAPI aService) {
|
2179 | e150a336 | pastith | service = aService; |
2180 | e150a336 | pastith | } |
2181 | e150a336 | pastith | |
2182 | e150a336 | pastith | /**
|
2183 | e150a336 | pastith | * Modify the userId.
|
2184 | e150a336 | pastith | *
|
2185 | e150a336 | pastith | * @param aUserId the userId to set
|
2186 | e150a336 | pastith | */
|
2187 | e150a336 | pastith | public void setUserId(Long aUserId) { |
2188 | e150a336 | pastith | userId = aUserId; |
2189 | e150a336 | pastith | } |
2190 | e150a336 | pastith | |
2191 | e150a336 | pastith | /**
|
2192 | e150a336 | pastith | * Modify the filename.
|
2193 | e150a336 | pastith | *
|
2194 | e150a336 | pastith | * @param aFilename the filename to set
|
2195 | e150a336 | pastith | */
|
2196 | e150a336 | pastith | public void setFilename(String aFilename) { |
2197 | e150a336 | pastith | filename = aFilename; |
2198 | e150a336 | pastith | } |
2199 | e150a336 | pastith | |
2200 | 023f6f1e | Panagiotis Astithas | @Override
|
2201 | e150a336 | pastith | public void update(long bytesRead, long contentLength, int items) { |
2202 | e150a336 | pastith | //monitoring per percent of bytes uploaded
|
2203 | e150a336 | pastith | bytesTransferred = bytesRead; |
2204 | e150a336 | pastith | if (fileSize != contentLength)
|
2205 | e150a336 | pastith | fileSize = contentLength; |
2206 | e150a336 | pastith | int percent = new Long(bytesTransferred * 100 / fileSize).intValue(); |
2207 | e150a336 | pastith | if (percent < 5 || percent % TRACK_PROGRESS_PERCENT == 0 ) |
2208 | bb9093fe | Christos V. Stathis | if (percent != percentLogged){
|
2209 | bb9093fe | Christos V. Stathis | percentLogged = percent; |
2210 | e150a336 | pastith | try {
|
2211 | e150a336 | pastith | if (userId != null && filename != null) |
2212 | e150a336 | pastith | service.createFileUploadProgress(userId, filename, bytesTransferred, fileSize); |
2213 | e150a336 | pastith | } catch (ObjectNotFoundException e) {
|
2214 | e150a336 | pastith | // Swallow the exception since it is going to be caught
|
2215 | e150a336 | pastith | // by previously called methods
|
2216 | e150a336 | pastith | } |
2217 | bb9093fe | Christos V. Stathis | } |
2218 | e150a336 | pastith | } |
2219 | e150a336 | pastith | } |
2220 | 51ad539e | Natasa Kapravelou | |
2221 | 31e19588 | Natasa Kapravelou | /**
|
2222 | 31e19588 | Natasa Kapravelou | * Return an InputStream to an HTML representation of the contents of this
|
2223 | 31e19588 | Natasa Kapravelou | * directory.
|
2224 | 31e19588 | Natasa Kapravelou | *
|
2225 | 31e19588 | Natasa Kapravelou | * @param contextPath Context path to which our internal paths are relative
|
2226 | 51ad539e | Natasa Kapravelou | * @param path the requested path to the resource
|
2227 | 31e19588 | Natasa Kapravelou | * @param folder the specified directory
|
2228 | 51ad539e | Natasa Kapravelou | * @param user the specified user
|
2229 | 31e19588 | Natasa Kapravelou | * @return an input stream with the rendered contents
|
2230 | 31e19588 | Natasa Kapravelou | * @throws IOException
|
2231 | 31e19588 | Natasa Kapravelou | * @throws ServletException
|
2232 | 31e19588 | Natasa Kapravelou | */
|
2233 | f7c44c33 | fstamatelopoulos | private InputStream renderHtml(String contextPath, String path, Folder folder, User user) |
2234 | 51ad539e | Natasa Kapravelou | throws IOException, ServletException { |
2235 | 31e19588 | Natasa Kapravelou | String name = folder.getName();
|
2236 | 31e19588 | Natasa Kapravelou | // Prepare a writer to a buffered area
|
2237 | 31e19588 | Natasa Kapravelou | ByteArrayOutputStream stream = new ByteArrayOutputStream(); |
2238 | 31e19588 | Natasa Kapravelou | OutputStreamWriter osWriter = new OutputStreamWriter(stream, "UTF8"); |
2239 | 31e19588 | Natasa Kapravelou | PrintWriter writer = new PrintWriter(osWriter); |
2240 | 31e19588 | Natasa Kapravelou | StringBuffer sb = new StringBuffer(); |
2241 | 31e19588 | Natasa Kapravelou | // rewriteUrl(contextPath) is expensive. cache result for later reuse
|
2242 | 31e19588 | Natasa Kapravelou | String rewrittenContextPath = rewriteUrl(contextPath);
|
2243 | 31e19588 | Natasa Kapravelou | // Render the page header
|
2244 | 31e19588 | Natasa Kapravelou | sb.append("<html>\r\n");
|
2245 | 31e19588 | Natasa Kapravelou | sb.append("<head>\r\n");
|
2246 | 31e19588 | Natasa Kapravelou | sb.append("<title>");
|
2247 | 31e19588 | Natasa Kapravelou | sb.append("Index of " + name);
|
2248 | 31e19588 | Natasa Kapravelou | sb.append("</title>\r\n");
|
2249 | 31e19588 | Natasa Kapravelou | sb.append("<STYLE><!--");
|
2250 | 31e19588 | Natasa Kapravelou | sb.append(GSS_CSS); |
2251 | 31e19588 | Natasa Kapravelou | sb.append("--></STYLE> ");
|
2252 | 31e19588 | Natasa Kapravelou | sb.append("</head>\r\n");
|
2253 | 31e19588 | Natasa Kapravelou | sb.append("<body>");
|
2254 | 31e19588 | Natasa Kapravelou | sb.append("<h1>");
|
2255 | 31e19588 | Natasa Kapravelou | sb.append("Index of " + name);
|
2256 | 31e19588 | Natasa Kapravelou | |
2257 | 31e19588 | Natasa Kapravelou | // Render the link to our parent (if required)
|
2258 | 51ad539e | Natasa Kapravelou | String parentDirectory = path;
|
2259 | 31e19588 | Natasa Kapravelou | if (parentDirectory.endsWith("/")) |
2260 | 31e19588 | Natasa Kapravelou | parentDirectory = parentDirectory.substring(0, parentDirectory.length() - 1); |
2261 | 31e19588 | Natasa Kapravelou | int slash = parentDirectory.lastIndexOf('/'); |
2262 | 31e19588 | Natasa Kapravelou | if (slash >= 0) { |
2263 | 51ad539e | Natasa Kapravelou | String parent = path.substring(0, slash); |
2264 | 8e471ce5 | Natasa Kapravelou | sb.append(" - <a href=\"");
|
2265 | 8e471ce5 | Natasa Kapravelou | sb.append(rewrittenContextPath); |
2266 | 51ad539e | Natasa Kapravelou | if (parent.equals("")) |
2267 | 51ad539e | Natasa Kapravelou | parent = "/";
|
2268 | 51ad539e | Natasa Kapravelou | sb.append(parent); |
2269 | 51ad539e | Natasa Kapravelou | if (!parent.endsWith("/")) |
2270 | 51ad539e | Natasa Kapravelou | sb.append("/");
|
2271 | 8e471ce5 | Natasa Kapravelou | sb.append("\">");
|
2272 | 8e471ce5 | Natasa Kapravelou | sb.append("<b>");
|
2273 | 51ad539e | Natasa Kapravelou | sb.append("Up To " + parent);
|
2274 | 8e471ce5 | Natasa Kapravelou | sb.append("</b>");
|
2275 | 8e471ce5 | Natasa Kapravelou | sb.append("</a>");
|
2276 | 31e19588 | Natasa Kapravelou | } |
2277 | 31e19588 | Natasa Kapravelou | |
2278 | 31e19588 | Natasa Kapravelou | sb.append("</h1>");
|
2279 | 31e19588 | Natasa Kapravelou | sb.append("<HR size=\"1\" noshade=\"noshade\">");
|
2280 | 31e19588 | Natasa Kapravelou | |
2281 | 31e19588 | Natasa Kapravelou | sb.append("<table width=\"100%\" cellspacing=\"0\"" + " cellpadding=\"5\" align=\"center\">\r\n"); |
2282 | 31e19588 | Natasa Kapravelou | |
2283 | 31e19588 | Natasa Kapravelou | // Render the column headings
|
2284 | 31e19588 | Natasa Kapravelou | sb.append("<tr>\r\n");
|
2285 | 31e19588 | Natasa Kapravelou | sb.append("<td align=\"left\"><font size=\"+1\"><strong>");
|
2286 | 31e19588 | Natasa Kapravelou | sb.append("Name");
|
2287 | 31e19588 | Natasa Kapravelou | sb.append("</strong></font></td>\r\n");
|
2288 | 31e19588 | Natasa Kapravelou | sb.append("<td align=\"center\"><font size=\"+1\"><strong>");
|
2289 | 31e19588 | Natasa Kapravelou | sb.append("Size");
|
2290 | 31e19588 | Natasa Kapravelou | sb.append("</strong></font></td>\r\n");
|
2291 | 31e19588 | Natasa Kapravelou | sb.append("<td align=\"right\"><font size=\"+1\"><strong>");
|
2292 | 31e19588 | Natasa Kapravelou | sb.append("Last modified");
|
2293 | 31e19588 | Natasa Kapravelou | sb.append("</strong></font></td>\r\n");
|
2294 | 31e19588 | Natasa Kapravelou | sb.append("</tr>");
|
2295 | 31e19588 | Natasa Kapravelou | // Render the directory entries within this directory
|
2296 | 31e19588 | Natasa Kapravelou | boolean shade = false; |
2297 | 31e19588 | Natasa Kapravelou | Iterator iter = folder.getSubfolders().iterator();
|
2298 | 31e19588 | Natasa Kapravelou | while (iter.hasNext()) {
|
2299 | f7c44c33 | fstamatelopoulos | Folder subf = (Folder) iter.next(); |
2300 | 51ad539e | Natasa Kapravelou | if(subf.isReadForAll() && !subf.isDeleted()){
|
2301 | 8e471ce5 | Natasa Kapravelou | String resourceName = subf.getName();
|
2302 | 8e471ce5 | Natasa Kapravelou | if (resourceName.equalsIgnoreCase("WEB-INF") || resourceName.equalsIgnoreCase("META-INF")) |
2303 | 8e471ce5 | Natasa Kapravelou | continue;
|
2304 | 31e19588 | Natasa Kapravelou | |
2305 | 8e471ce5 | Natasa Kapravelou | sb.append("<tr");
|
2306 | 8e471ce5 | Natasa Kapravelou | if (shade)
|
2307 | 8e471ce5 | Natasa Kapravelou | sb.append(" bgcolor=\"#eeeeee\"");
|
2308 | 8e471ce5 | Natasa Kapravelou | sb.append(">\r\n");
|
2309 | 8e471ce5 | Natasa Kapravelou | shade = !shade; |
2310 | 51ad539e | Natasa Kapravelou | |
2311 | 8e471ce5 | Natasa Kapravelou | sb.append("<td align=\"left\"> \r\n");
|
2312 | 8e471ce5 | Natasa Kapravelou | sb.append("<a href=\"");
|
2313 | 51ad539e | Natasa Kapravelou | sb.append(rewrittenContextPath+path); |
2314 | 51ad539e | Natasa Kapravelou | sb.append(rewriteUrl(resourceName)); |
2315 | 8e471ce5 | Natasa Kapravelou | sb.append("/");
|
2316 | 8e471ce5 | Natasa Kapravelou | sb.append("\"><tt>");
|
2317 | 8e471ce5 | Natasa Kapravelou | sb.append(RequestUtil.filter(resourceName)); |
2318 | 8e471ce5 | Natasa Kapravelou | sb.append("/");
|
2319 | 8e471ce5 | Natasa Kapravelou | sb.append("</tt></a></td>\r\n");
|
2320 | 31e19588 | Natasa Kapravelou | |
2321 | 8e471ce5 | Natasa Kapravelou | sb.append("<td align=\"right\"><tt>");
|
2322 | 8e471ce5 | Natasa Kapravelou | sb.append(" ");
|
2323 | 8e471ce5 | Natasa Kapravelou | sb.append("</tt></td>\r\n");
|
2324 | 51ad539e | Natasa Kapravelou | |
2325 | 8e471ce5 | Natasa Kapravelou | sb.append("<td align=\"right\"><tt>");
|
2326 | 8e471ce5 | Natasa Kapravelou | sb.append(getLastModifiedHttp(folder.getAuditInfo())); |
2327 | 8e471ce5 | Natasa Kapravelou | sb.append("</tt></td>\r\n");
|
2328 | 31e19588 | Natasa Kapravelou | |
2329 | 8e471ce5 | Natasa Kapravelou | sb.append("</tr>\r\n");
|
2330 | 51ad539e | Natasa Kapravelou | |
2331 | 51ad539e | Natasa Kapravelou | } |
2332 | 31e19588 | Natasa Kapravelou | } |
2333 | f7c44c33 | fstamatelopoulos | List<FileHeader> files;
|
2334 | 31e19588 | Natasa Kapravelou | try {
|
2335 | 31e19588 | Natasa Kapravelou | files = getService().getFiles(user.getId(), folder.getId(), true);
|
2336 | 31e19588 | Natasa Kapravelou | } catch (ObjectNotFoundException e) {
|
2337 | 31e19588 | Natasa Kapravelou | throw new ServletException(e.getMessage()); |
2338 | 31e19588 | Natasa Kapravelou | } catch (InsufficientPermissionsException e) {
|
2339 | 31e19588 | Natasa Kapravelou | throw new ServletException(e.getMessage()); |
2340 | 31e19588 | Natasa Kapravelou | } catch (RpcException e) {
|
2341 | 31e19588 | Natasa Kapravelou | throw new ServletException(e.getMessage()); |
2342 | 31e19588 | Natasa Kapravelou | } |
2343 | f7c44c33 | fstamatelopoulos | for (FileHeader file : files)
|
2344 | 51ad539e | Natasa Kapravelou | //Display only file resources that are marked as public and are not deleted
|
2345 | 51ad539e | Natasa Kapravelou | if(file.isReadForAll() && !file.isDeleted()){
|
2346 | f9bd859c | Natasa Kapravelou | String resourceName = file.getName();
|
2347 | f9bd859c | Natasa Kapravelou | if (resourceName.equalsIgnoreCase("WEB-INF") || resourceName.equalsIgnoreCase("META-INF")) |
2348 | f9bd859c | Natasa Kapravelou | continue;
|
2349 | 51ad539e | Natasa Kapravelou | |
2350 | f9bd859c | Natasa Kapravelou | sb.append("<tr");
|
2351 | f9bd859c | Natasa Kapravelou | if (shade)
|
2352 | f9bd859c | Natasa Kapravelou | sb.append(" bgcolor=\"#eeeeee\"");
|
2353 | f9bd859c | Natasa Kapravelou | sb.append(">\r\n");
|
2354 | f9bd859c | Natasa Kapravelou | shade = !shade; |
2355 | f9bd859c | Natasa Kapravelou | |
2356 | f9bd859c | Natasa Kapravelou | sb.append("<td align=\"left\"> \r\n");
|
2357 | f9bd859c | Natasa Kapravelou | sb.append("<a href=\"");
|
2358 | 51ad539e | Natasa Kapravelou | sb.append(rewrittenContextPath + path); |
2359 | 51ad539e | Natasa Kapravelou | sb.append(rewriteUrl(resourceName)); |
2360 | f9bd859c | Natasa Kapravelou | sb.append("\"><tt>");
|
2361 | f9bd859c | Natasa Kapravelou | sb.append(RequestUtil.filter(resourceName)); |
2362 | f9bd859c | Natasa Kapravelou | sb.append("</tt></a></td>\r\n");
|
2363 | f9bd859c | Natasa Kapravelou | |
2364 | f9bd859c | Natasa Kapravelou | sb.append("<td align=\"right\"><tt>");
|
2365 | f7c44c33 | fstamatelopoulos | sb.append(renderSize(file.getCurrentBody().getFileSize())); |
2366 | f9bd859c | Natasa Kapravelou | sb.append("</tt></td>\r\n");
|
2367 | f9bd859c | Natasa Kapravelou | |
2368 | f9bd859c | Natasa Kapravelou | sb.append("<td align=\"right\"><tt>");
|
2369 | f9bd859c | Natasa Kapravelou | sb.append(getLastModifiedHttp(file.getAuditInfo())); |
2370 | f9bd859c | Natasa Kapravelou | sb.append("</tt></td>\r\n");
|
2371 | f9bd859c | Natasa Kapravelou | |
2372 | f9bd859c | Natasa Kapravelou | sb.append("</tr>\r\n");
|
2373 | f9bd859c | Natasa Kapravelou | } |
2374 | 31e19588 | Natasa Kapravelou | |
2375 | 31e19588 | Natasa Kapravelou | // Render the page footer
|
2376 | 31e19588 | Natasa Kapravelou | sb.append("</table>\r\n");
|
2377 | 31e19588 | Natasa Kapravelou | |
2378 | 31e19588 | Natasa Kapravelou | sb.append("<HR size=\"1\" noshade=\"noshade\">");
|
2379 | 31e19588 | Natasa Kapravelou | sb.append("</body>\r\n");
|
2380 | 31e19588 | Natasa Kapravelou | sb.append("</html>\r\n");
|
2381 | 31e19588 | Natasa Kapravelou | |
2382 | 31e19588 | Natasa Kapravelou | // Return an input stream to the underlying bytes
|
2383 | 31e19588 | Natasa Kapravelou | writer.write(sb.toString()); |
2384 | 31e19588 | Natasa Kapravelou | writer.flush(); |
2385 | 31e19588 | Natasa Kapravelou | return new ByteArrayInputStream(stream.toByteArray()); |
2386 | 31e19588 | Natasa Kapravelou | |
2387 | 31e19588 | Natasa Kapravelou | } |
2388 | 14ad7326 | pastith | } |