1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package com.xpn.xwiki.web

File TempResourceAction.java

 

Coverage histogram

../../../../img/srcFileCovDistChart10.png
0% of files have more coverage

Code metrics

10
45
5
1
211
110
14
0.31
9
5
2.8

Classes

Class Line # Actions
TempResourceAction 65 45 0% 14 4
0.9333333493.3%
 

Contributing tests

This file is covered by 9 tests. .

Source view

1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    * Lesser General Public License for more details.
14    *
15    * You should have received a copy of the GNU Lesser General Public
16    * License along with this software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20    package com.xpn.xwiki.web;
21   
22    import java.io.File;
23    import java.io.IOException;
24    import java.io.UnsupportedEncodingException;
25    import java.net.URI;
26    import java.net.URLDecoder;
27    import java.net.URLEncoder;
28    import java.util.ArrayList;
29    import java.util.List;
30    import java.util.regex.Matcher;
31    import java.util.regex.Pattern;
32   
33    import org.apache.commons.io.FileUtils;
34    import org.apache.commons.io.IOUtils;
35    import org.apache.commons.lang3.StringUtils;
36    import org.apache.tika.Tika;
37    import org.apache.tika.mime.MimeTypes;
38    import org.slf4j.Logger;
39    import org.slf4j.LoggerFactory;
40    import org.xwiki.environment.Environment;
41   
42    import com.xpn.xwiki.XWikiContext;
43    import com.xpn.xwiki.XWikiException;
44    import com.xpn.xwiki.util.Util;
45   
46    /**
47    * Action responsible for downloading temporary resources created by various modules. The temporary resource is put in
48    * the temporary directory in a directory named "temp" and in subdirectories "(module)/(wiki)/(space)/(page)/(file)"
49    * where:
50    * <ul>
51    * <li>(module): it's the 3rd path segment in the request URL (format: {code .../temp/1/2/3/4})</li>
52    * <li>(wiki): the name of the current wiki (extracted from the URL too)</li>
53    * <li>(space): it's the 1st path segment in the request URL (format: {code .../temp/1/2/3/4})</li>
54    * <li>(page): it's the 2nd path segment in the request URL (format: {code .../temp/1/2/3/4})</li>
55    * <li>(file): it's the 4th path segment in the request URL (format: {code .../temp/1/2/3/4})</li>
56    * </ul>
57    * For example if the URL is {@code http://localhost:8080/xwiki/bin/temp/Main/WebHome/test/test.png} then the resource
58    * will be fetched from {@code TMPDIR/temp/test/xwiki/Main/WebHome/test.png}.
59    *
60    * @version $Id: 6f3f1396fe8ad908af3af0d696cb7d6b9005de51 $
61    * @since 2.4M1
62    * @deprecated Use the "tmp" resource reference handler instead since 8.3
63    */
64    @Deprecated
 
65    public class TempResourceAction extends XWikiAction
66    {
67    /**
68    * URI pattern for this action.
69    */
70    public static final Pattern URI_PATTERN = Pattern.compile(".*?/temp/([^/]*+)/([^/]*+)/([^/]*+)/(.*+)");
71   
72    /**
73    * The path separator.
74    */
75    private static final String PATH_SEPARATOR = "/";
76   
77    /**
78    * The URL encoding.
79    */
80    private static final String URL_ENCODING = "UTF-8";
81   
82    /**
83    * Logging support.
84    */
85    private static final Logger LOGGER = LoggerFactory.getLogger(TempResourceAction.class);
86   
87    /**
88    * Used for detecting mime-types of files.
89    */
90    private Tika tika = new Tika();
91   
92    /**
93    * Used to find the temporary dir.
94    */
95    private Environment environment = Utils.getComponent(Environment.class);
96   
 
97  10 toggle @Override
98    public String render(XWikiContext context) throws XWikiException
99    {
100  10 XWikiRequest request = context.getRequest();
101  10 XWikiResponse response = context.getResponse();
102  10 String uri = request.getRequestURI();
103   
104    // Locate the temporary file.
105  10 File tempFile = getTemporaryFile(uri, context);
106  10 if (null == tempFile) {
107  1 throw new XWikiException(XWikiException.MODULE_XWIKI_APP, XWikiException.ERROR_XWIKI_APP_URL_EXCEPTION,
108    "Invalid temporary resource URL");
109    }
110   
111    // Write temporary file into response.
112  9 response.setDateHeader("Last-Modified", tempFile.lastModified());
113  9 String contentType = MimeTypes.OCTET_STREAM;
114  9 try {
115  9 contentType = this.tika.detect(tempFile);
116    } catch (IOException ex) {
117  0 LOGGER.warn(
118    String.format("Unable to determine mime type for temporary resource [%s]", tempFile.getAbsolutePath()),
119    ex);
120    }
121  9 response.setContentType(contentType);
122  9 if ("1".equals(request.getParameter("force-download"))) {
123  1 String fileName = StringUtils.defaultIfBlank(request.getParameter("force-filename"), tempFile.getName());
124  1 fileName = Util.encodeURI(fileName, context).replaceAll("\\+", "%20");
125  1 response.addHeader("Content-disposition", "attachment; filename*=utf-8''" + fileName);
126    }
127  9 try {
128  9 response.setContentLength((int) tempFile.length());
129  9 IOUtils.copy(FileUtils.openInputStream(tempFile), response.getOutputStream());
130    } catch (IOException e) {
131  0 throw new XWikiException(XWikiException.MODULE_XWIKI_APP,
132    XWikiException.ERROR_XWIKI_APP_SEND_RESPONSE_EXCEPTION, "Exception while sending response", e);
133    }
134  9 return null;
135    }
136   
137    /**
138    * Returns the temporary file corresponding to the specified URI.
139    *
140    * @param uri request URI.
141    * @param context xwiki context.
142    * @return temporary file corresponding to the specified URI or null if no such file can be located.
143    */
 
144  16 toggle protected File getTemporaryFile(String uri, XWikiContext context)
145    {
146  16 Matcher matcher = URI_PATTERN.matcher(uri);
147  16 File result = null;
148  16 if (matcher.find()) {
149  15 List<String> pathSegments = new ArrayList<String>();
150    // Add all the path segments.
151  15 pathSegments.add("temp");
152    // temp/module
153  15 pathSegments.add(withMinimalURLEncoding(matcher.group(3)));
154    // temp/module/wiki
155  15 pathSegments.add(encodeURLPathSegment(context.getWikiId()));
156    // temp/module/wiki/space
157  15 pathSegments.add(withMinimalURLEncoding(matcher.group(1)));
158    // temp/module/wiki/space/page
159  15 pathSegments.add(withMinimalURLEncoding(matcher.group(2)));
160    // Save the path prefix before adding the file path to be able to check if the file path tries to get out of
161    // the parent folder (e.g. using '/../').
162  15 String prefix = StringUtils.join(pathSegments, PATH_SEPARATOR);
163    // temp/module/wiki/space/page/path/to/file.tmp
164  15 for (String filePathSegment : matcher.group(4).split(PATH_SEPARATOR)) {
165  18 pathSegments.add(withMinimalURLEncoding(filePathSegment));
166    }
167  15 String path = URI.create(StringUtils.join(pathSegments, PATH_SEPARATOR)).normalize().toString();
168  15 if (path.startsWith(prefix)) {
169  14 result = new File(this.environment.getTemporaryDirectory(), path);
170  14 result = result.exists() ? result : null;
171    }
172    }
173  16 return result;
174    }
175   
176    /**
177    * Keeps only minimal URL encoding. Currently, XWiki's URL factory over encodes the URLs in order to protect them
178    * from XWiki 1.0 syntax parser.
179    * <p>
180    * This method also ensures that the path to the temporary file is fully encoded (has the canonical form) even if
181    * the URL used to access the file is partially decoded (which can happen for instance when XWiki is behind Apache's
182    * {@code mode_proxy} with {@code nocanon} option disabled).
183    *
184    * @param encodedPathSegment an encoded URL path segment
185    * @return the given string with minimal URL encoding
186    */
 
187  63 toggle private String withMinimalURLEncoding(String encodedPathSegment)
188    {
189  63 return encodeURLPathSegment(decodeURLPathSegment(encodedPathSegment));
190    }
191   
 
192  78 toggle private String encodeURLPathSegment(String segment)
193    {
194  78 try {
195  78 return URLEncoder.encode(segment, URL_ENCODING);
196    } catch (UnsupportedEncodingException e) {
197    // This should never happen.
198  0 return segment;
199    }
200    }
201   
 
202  63 toggle private String decodeURLPathSegment(String encodedSegment)
203    {
204  63 try {
205  63 return URLDecoder.decode(encodedSegment, URL_ENCODING);
206    } catch (UnsupportedEncodingException e) {
207    // This should never happen.
208  0 return encodedSegment;
209    }
210    }
211    }