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

File Utils.java

 

Coverage histogram

../../../../img/srcFileCovDistChart6.png
69% of files have more coverage

Code metrics

90
247
35
1
923
502
110
0.45
7.06
35
3.14

Classes

Class Line # Actions
Utils 57 247 0% 110 180
0.51612951.6%
 

Contributing tests

This file is covered by 435 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.IOException;
23    import java.io.InputStream;
24    import java.io.UnsupportedEncodingException;
25    import java.lang.reflect.Type;
26    import java.net.URL;
27    import java.util.Collections;
28    import java.util.Date;
29    import java.util.HashMap;
30    import java.util.List;
31    import java.util.Map;
32    import java.util.Map.Entry;
33   
34    import javax.inject.Provider;
35    import javax.servlet.http.HttpServletRequest;
36    import javax.servlet.http.HttpServletResponse;
37   
38    import org.apache.commons.fileupload.FileItem;
39    import org.apache.commons.io.IOUtils;
40    import org.apache.commons.lang3.BooleanUtils;
41    import org.apache.commons.lang3.RandomStringUtils;
42    import org.apache.commons.lang3.StringUtils;
43    import org.apache.commons.lang3.exception.ExceptionUtils;
44    import org.apache.struts.upload.MultipartRequestWrapper;
45    import org.slf4j.Logger;
46    import org.slf4j.LoggerFactory;
47    import org.xwiki.component.manager.ComponentLookupException;
48    import org.xwiki.component.manager.ComponentManager;
49    import org.xwiki.xml.XMLUtils;
50   
51    import com.xpn.xwiki.XWiki;
52    import com.xpn.xwiki.XWikiContext;
53    import com.xpn.xwiki.XWikiException;
54    import com.xpn.xwiki.plugin.fileupload.FileUploadPlugin;
55    import com.xpn.xwiki.util.Util;
56   
 
57    public class Utils
58    {
59    protected static final Logger LOGGER = LoggerFactory.getLogger(Utils.class);
60   
61    /** A key that is used for placing a map of replaced (for protection) strings in the context. */
62    private static final String PLACEHOLDERS_CONTEXT_KEY = Utils.class.getCanonicalName() + "_placeholders";
63   
64    /** Whether placeholders are enabled or not. */
65    private static final String PLACEHOLDERS_ENABLED_CONTEXT_KEY = Utils.class.getCanonicalName()
66    + "_placeholders_enabled";
67   
68    /**
69    * The component manager used by {@link #getComponent(Class)} and {@link #getComponent(Class, String)}. It is useful
70    * for any non component code that need to initialize/access components.
71    */
72    private static ComponentManager rootComponentManager;
73   
74    /**
75    * Generate the response by parsing a velocity template and printing the result to the {@link XWikiResponse
76    * Response}. This is the main entry point to the View part of the XWiki MVC architecture.
77    *
78    * @param template The name of the template to parse, without the {@code .vm} prefix. The template will be searched
79    * in the usual places: current XWikiSkins object, attachment of the current skin document, current skin
80    * folder, baseskin folder, /templates/ folder.
81    * @param context the current context
82    * @throws XWikiException when the response cannot be written to the client (for example when the client canceled
83    * the request, thus closing the socket)
84    * @see XWiki#parseTemplate(String, XWikiContext)
85    */
 
86  163 toggle public static void parseTemplate(String template, XWikiContext context) throws XWikiException
87    {
88  163 parseTemplate(template, true, context);
89    }
90   
91    /**
92    * Generate the response by parsing a velocity template and (optionally) printing the result to the
93    * {@link XWikiResponse Response}.
94    *
95    * @param template The name of the template to parse, without the {@code .vm} prefix. The template will be searched
96    * in the usual places: current XWikiSkins object, attachment of the current skin document, current skin
97    * folder, baseskin folder, /templates/ folder.
98    * @param write Whether the generated response should be written to the client or not. If {@code false}, only the
99    * needed headers are generated, suitable for implementing a HEAD response.
100    * @param context the current context
101    * @throws XWikiException when the response cannot be written to the client (for example when the client canceled
102    * the request, thus closing the socket)
103    * @see XWiki#parseTemplate(String, XWikiContext)
104    */
 
105  6953 toggle public static void parseTemplate(String template, boolean write, XWikiContext context) throws XWikiException
106    {
107  6953 XWikiResponse response = context.getResponse();
108   
109    // If a Redirect has already been sent then don't process the template since it means and we shouldn't write
110    // anymore to the servlet output stream!
111    // See: http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletResponse.html#sendRedirect(String)
112    // "After using this method, the response should be considered to be committed and should not be written
113    // to."
114  6952 if ((response instanceof XWikiServletResponse)
115    && ((XWikiServletResponse) response).getStatus() == HttpServletResponse.SC_FOUND) {
116  60 return;
117    }
118   
119    // Set content-type and encoding (this can be changed later by pages themselves)
120  6892 response.setContentType("text/html; charset=" + context.getWiki().getEncoding());
121   
122  6893 String action = context.getAction();
123  6893 long cacheSetting = context.getWiki().getXWikiPreferenceAsLong("headers_nocache", -1, context);
124  6893 if (cacheSetting == -1) {
125  6893 cacheSetting = context.getWiki().ParamAsLong("xwiki.httpheaders.cache", -1);
126    }
127  6893 if (cacheSetting == -1) {
128  6893 cacheSetting = 1;
129    }
130  6893 if ((!"download".equals(action)) && (!"skin".equals(action))) {
131  6892 if (context.getResponse() instanceof XWikiServletResponse) {
132    // Add a last modified to tell when the page was last updated
133  6892 if (context.getWiki().getXWikiPreferenceAsLong("headers_lastmodified", 0, context) != 0) {
134  0 if (context.getDoc() != null) {
135  0 response.setDateHeader("Last-Modified", context.getDoc().getDate().getTime());
136    }
137    }
138    // Set a nocache to make sure the page is reloaded after an edit
139  6892 if (cacheSetting == 1) {
140  6892 response.setHeader("Pragma", "no-cache");
141  6892 response.setHeader("Cache-Control", "no-cache");
142  0 } else if (cacheSetting == 2) {
143  0 response.setHeader("Pragma", "no-cache");
144  0 response.setHeader("Cache-Control", "max-age=0, no-cache, no-store");
145  0 } else if (cacheSetting == 3) {
146  0 response.setHeader("Cache-Control", "private");
147  0 } else if (cacheSetting == 4) {
148  0 response.setHeader("Cache-Control", "public");
149    }
150   
151    // Set an expires in one month
152  6892 long expires = context.getWiki().getXWikiPreferenceAsLong("headers_expires", -1, context);
153  6892 if (expires == -1) {
154  6892 response.setDateHeader("Expires", -1);
155  0 } else if (expires != 0) {
156  0 response.setDateHeader("Expires", (new Date()).getTime() + 30 * 24 * 3600 * 1000L);
157    }
158    }
159    }
160   
161  6893 if (("download".equals(action)) || ("skin".equals(action))) {
162    // Set a nocache to make sure these files are not cached by proxies
163  1 if (cacheSetting == 1 || cacheSetting == 2) {
164  1 response.setHeader("Cache-Control", "no-cache");
165    }
166    }
167   
168  6893 context.getWiki().getPluginManager().beginParsing(context);
169    // This class allows various components in the rendering chain to use placeholders for some fragile data. For
170    // example, the URL generated for the image macro should not be further rendered, as it might get broken by wiki
171    // filters. For this to work, keep a map of [used placeholders -> values] in the context, and replace them when
172    // the content is fully rendered. The rendering code can use Utils.createPlaceholder.
173    // Initialize the placeholder map
174  6893 enablePlaceholders(context);
175  6893 String content = "";
176  6893 try {
177    // Note: This line below can change the state of the response. For example a vm file can have a call to
178    // sendRedirect. In this case we need to be careful to not write to the output stream since it's already
179    // been committed. This is why we do a check below before calling response.getOutputStream().write().
180  6893 content = context.getWiki().evaluateTemplate(template + ".vm", context);
181    // Replace all placeholders with the protected values
182  6893 content = replacePlaceholders(content, context);
183  6893 disablePlaceholders(context);
184  6893 content = context.getWiki().getPluginManager().endParsing(content.trim(), context);
185    } catch (IOException e) {
186  0 LOGGER.debug("IOException while evaluating template [{}] from /templates/", template, e);
187   
188    // get Error template "This template does not exist
189  0 try {
190  0 content = context.getWiki().evaluateTemplate("templatedoesnotexist.vm", context);
191  0 content = content.trim();
192    } catch (IOException ex) {
193    // Cannot write output, can't do anything else
194    }
195    }
196   
197  6893 if (!context.isFinished()) {
198  6889 if (context.getResponse() instanceof XWikiServletResponse) {
199    // Set the content length to the number of bytes, not the
200    // string length, so as to handle multi-byte encodings
201  6891 try {
202  6891 response.setContentLength(content.getBytes(context.getWiki().getEncoding()).length);
203    } catch (UnsupportedEncodingException e) {
204  0 e.printStackTrace();
205    }
206    }
207   
208    // We only write if the caller has asked.
209    // We also make sure to verify that there hasn't been a call to sendRedirect before since it would mean the
210    // response has already been written to and we shouldn't try to write in it.
211  6889 if (write
212    && ((response instanceof XWikiServletResponse) && ((XWikiServletResponse) response).getStatus() != HttpServletResponse.SC_FOUND)) {
213  6837 try {
214  6837 try {
215  6839 response.getOutputStream().write(content.getBytes(context.getWiki().getEncoding()));
216    } catch (IllegalStateException ex) {
217  0 response.getWriter().write(content);
218    }
219    } catch (IOException e) {
220  1 throw new XWikiException(XWikiException.MODULE_XWIKI_APP,
221    XWikiException.ERROR_XWIKI_APP_SEND_RESPONSE_EXCEPTION, "Exception while sending response", e);
222    }
223    }
224    }
225   
226  6891 try {
227  6887 response.getOutputStream().flush();
228    } catch (Throwable ex) {
229  0 try {
230  0 response.getWriter().flush();
231    } catch (Throwable ex2) {
232    }
233    }
234    }
235   
236    /**
237    * Retrieve the URL to which the client should be redirected after the successful completion of the requested
238    * action. This is taken from the {@code xredirect} parameter in the query string. If this parameter is not set, or
239    * is set to an empty value, return the default redirect specified as the second argument.
240    *
241    * @param request the current request
242    * @param defaultRedirect the default value to use if no {@code xredirect} parameter is present
243    * @return the destination URL, as specified in the {@code xredirect} parameter, or the specified default URL
244    */
 
245  40 toggle public static String getRedirect(XWikiRequest request, String defaultRedirect)
246    {
247  40 String redirect = request.getParameter("xredirect");
248  40 if (StringUtils.isBlank(redirect)) {
249  16 redirect = defaultRedirect;
250    }
251   
252  40 return redirect;
253    }
254   
255    /**
256    * Retrieve the URL to which the client should be redirected after the successful completion of the requested
257    * action. This is taken from the {@code xredirect} parameter in the query string. If this parameter is not set, or
258    * is set to an empty value, compose an URL back to the current document, using the specified action and query
259    * string, and return it.
260    *
261    * @param action the XWiki action to use for composing the default redirect URL ({@code view}, {@code edit}, etc)
262    * @param queryString the query parameters to append to the fallback URL
263    * @param context the current context
264    * @return the destination URL, as specified in the {@code xredirect} parameter, or computed using the current
265    * document and the specified action and query string
266    */
 
267  164 toggle public static String getRedirect(String action, String queryString, XWikiContext context)
268    {
269  164 return getRedirect(action, queryString, "xredirect");
270    }
271   
272    /**
273    * Retrieve the URL to which the client should be redirected after the successful completion of the requested
274    * action. If any of the specified {@code redirectParameters} (in order) is present in the query string, it is
275    * returned as the redirect destination. If none of the parameters is set, compose an URL back to the current
276    * document using the specified action and query string, and return it.
277    *
278    * @param action the XWiki action to use for composing the default redirect URL ({@code view}, {@code edit}, etc)
279    * @param queryString the query parameters to append to the fallback URL
280    * @param redirectParameters list of request parameters to look for as the redirect destination; each of the
281    * parameters is tried in the order they are passed, and the first one set to a non-empty value is
282    * returned, if any
283    * @return the destination URL, as specified in one of the {@code redirectParameters}, or computed using the current
284    * document and the specified action and query string
285    */
 
286  179 toggle public static String getRedirect(String action, String queryString, String... redirectParameters)
287    {
288  179 XWikiContext context = getContext();
289  179 XWikiRequest request = context.getRequest();
290  179 String redirect = null;
291  179 for (String p : redirectParameters) {
292  194 redirect = request.getParameter(p);
293  194 if (StringUtils.isNotEmpty(redirect)) {
294  16 break;
295    }
296    }
297   
298  179 if (StringUtils.isEmpty(redirect)) {
299  163 redirect = context.getDoc().getURL(action, queryString, true, context);
300    }
301   
302  179 return redirect;
303    }
304   
305    /**
306    * Retrieve the URL to which the client should be redirected after the successful completion of the requested
307    * action. This is taken from the {@code xredirect} parameter in the query string. If this parameter is not set, or
308    * is set to an empty value, compose an URL back to the current document, using the specified action, and return it.
309    *
310    * @param action the XWiki action to use for composing the default redirect URL ({@code view}, {@code edit}, etc)
311    * @param context the current context
312    * @return the destination URL, as specified in the {@code xredirect} parameter, or computed using the current
313    * document and the specified action
314    */
 
315  149 toggle public static String getRedirect(String action, XWikiContext context)
316    {
317  149 return getRedirect(action, null, context);
318    }
319   
320    /**
321    * Retrieve the name of the velocity template which should be used to generate the response. This is taken from the
322    * {@code xpage} parameter in the query string. If this parameter is not set, or is set to an empty value, return
323    * the provided default name.
324    *
325    * @param request the current request
326    * @param defaultpage the default value to use if no {@code xpage} parameter is set
327    * @return the name of the requested template, as specified in the {@code xpage} parameter, or the specified default
328    * template
329    */
 
330  6948 toggle public static String getPage(XWikiRequest request, String defaultpage)
331    {
332  6948 String page = request.getParameter("xpage");
333  6948 if (StringUtils.isEmpty(page)) {
334  6375 page = defaultpage;
335    }
336   
337  6948 return page;
338    }
339   
340    /**
341    * Get the name of an uploaded file, corresponding to the specified form field.
342    *
343    * @param filelist the list of uploaded files, computed by the FileUpload plugin
344    * @param name the name of the form field
345    * @return the original name of the file, if the specified field name does correspond to an uploaded file, or
346    * {@code null} otherwise
347    */
 
348  0 toggle public static String getFileName(List<FileItem> filelist, String name)
349    {
350  0 for (FileItem item : filelist) {
351  0 if (name.equals(item.getFieldName())) {
352  0 return item.getName();
353    }
354    }
355   
356  0 return null;
357    }
358   
359    /**
360    * Get the content of an uploaded file, corresponding to the specified form field.
361    *
362    * @param filelist the list of uploaded files, computed by the FileUpload plugin
363    * @param name the name of the form field
364    * @return the content of the file, if the specified field name does correspond to an uploaded file, or {@code null}
365    * otherwise
366    * @throws XWikiException if the file cannot be read due to an underlying I/O exception
367    */
 
368  0 toggle public static byte[] getContent(List<FileItem> filelist, String name) throws XWikiException
369    {
370  0 for (FileItem item : filelist) {
371  0 if (name.equals(item.getFieldName())) {
372  0 byte[] data = new byte[(int) item.getSize()];
373  0 InputStream fileis = null;
374  0 try {
375  0 fileis = item.getInputStream();
376  0 fileis.read(data);
377    } catch (IOException e) {
378  0 throw new XWikiException(XWikiException.MODULE_XWIKI_APP,
379    XWikiException.ERROR_XWIKI_APP_UPLOAD_FILE_EXCEPTION,
380    "Exception while reading uploaded parsed file", e);
381    } finally {
382  0 IOUtils.closeQuietly(fileis);
383    }
384   
385  0 return data;
386    }
387    }
388   
389  0 return null;
390    }
391   
 
392  11440 toggle public static XWikiContext prepareContext(String action, XWikiRequest request, XWikiResponse response,
393    XWikiEngineContext engine_context) throws XWikiException
394    {
395  11442 XWikiContext context = new XWikiContext();
396  11427 String dbname = "xwiki";
397  11409 URL url = XWiki.getRequestURL(request);
398  11449 context.setURL(url);
399   
400  11437 context.setEngineContext(engine_context);
401  11445 context.setRequest(request);
402  11431 context.setResponse(response);
403  11438 context.setAction(action);
404  11436 context.setWikiId(dbname);
405   
406  11430 int mode = 0;
407  11427 if (request instanceof XWikiServletRequest) {
408  11419 mode = XWikiContext.MODE_SERVLET;
409    }
410  11425 context.setMode(mode);
411   
412  11427 return context;
413    }
414   
415    /**
416    * Parse the request parameters from the specified String using the specified encoding. <strong>IMPLEMENTATION
417    * NOTE</strong>: URL decoding is performed individually on the parsed name and value elements, rather than on the
418    * entire query string ahead of time, to properly deal with the case where the name or value includes an encoded
419    * {@code =} or {@code &} character that would otherwise be interpreted as a delimiter.
420    * <p>
421    * Code borrowed from Apache Tomcat 5.0
422    *
423    * @param data input string containing request parameters
424    * @param encoding the encoding to use for transforming bytes into characters
425    * @throws IllegalArgumentException if the data is malformed
426    */
 
427  0 toggle public static Map<String, String[]> parseParameters(String data, String encoding)
428    throws UnsupportedEncodingException
429    {
430  0 if (!StringUtils.isEmpty(data)) {
431    // use the specified encoding to extract bytes out of the
432    // given string so that the encoding is not lost. If an
433    // encoding is not specified, let it use platform default
434  0 byte[] bytes = null;
435  0 try {
436  0 if (encoding == null) {
437  0 bytes = data.getBytes();
438    } else {
439  0 bytes = data.getBytes(encoding);
440    }
441    } catch (UnsupportedEncodingException uee) {
442    }
443   
444  0 return parseParameters(bytes, encoding);
445    }
446   
447  0 return Collections.emptyMap();
448    }
449   
450    /**
451    * Parse the request parameters from the specified byte array using the specified encoding. <strong>IMPLEMENTATION
452    * NOTE</strong>: URL decoding is performed individually on the parsed name and value elements, rather than on the
453    * entire query string ahead of time, to properly deal with the case where the name or value includes an encoded
454    * {@code =} or {@code &} character that would otherwise be interpreted as a delimiter.
455    * <p>
456    * NOTE: byte array data is modified by this method. Caller beware.
457    * <p>
458    * Code borrowed from Apache Tomcat 5.0
459    *
460    * @param data input byte array containing request parameters
461    * @param encoding Encoding to use for converting hex
462    * @throws UnsupportedEncodingException if the data is malformed
463    */
 
464  0 toggle public static Map<String, String[]> parseParameters(byte[] data, String encoding)
465    throws UnsupportedEncodingException
466    {
467  0 Map<String, String[]> map = new HashMap<String, String[]>();
468   
469  0 if (data != null && data.length > 0) {
470  0 int ix = 0;
471  0 int ox = 0;
472  0 String key = null;
473  0 String value = null;
474  0 while (ix < data.length) {
475  0 byte c = data[ix++];
476  0 switch ((char) c) {
477  0 case '&':
478  0 value = new String(data, 0, ox, encoding);
479  0 if (key != null) {
480  0 putMapEntry(map, key, value);
481  0 key = null;
482    }
483  0 ox = 0;
484  0 break;
485  0 case '=':
486  0 if (key == null) {
487  0 key = new String(data, 0, ox, encoding);
488  0 ox = 0;
489    } else {
490  0 data[ox++] = c;
491    }
492  0 break;
493  0 case '+':
494  0 data[ox++] = (byte) ' ';
495  0 break;
496  0 case '%':
497  0 data[ox++] = (byte) ((convertHexDigit(data[ix++]) << 4) + convertHexDigit(data[ix++]));
498  0 break;
499  0 default:
500  0 data[ox++] = c;
501    }
502    }
503    // The last value does not end in '&'. So save it now.
504  0 if (key != null) {
505  0 value = new String(data, 0, ox, encoding);
506  0 putMapEntry(map, key, value);
507    }
508    }
509   
510  0 return map;
511    }
512   
513    /**
514    * Convert a byte character value to the corresponding hexidecimal digit value.
515    * <p>
516    * Code borrowed from Apache Tomcat 5.0
517    * </p>
518    *
519    * @param b the character value byte
520    */
 
521  0 toggle private static byte convertHexDigit(byte b)
522    {
523  0 if ((b >= '0') && (b <= '9')) {
524  0 return (byte) (b - '0');
525    }
526  0 if ((b >= 'a') && (b <= 'f')) {
527  0 return (byte) (b - 'a' + 10);
528    }
529  0 if ((b >= 'A') && (b <= 'F')) {
530  0 return (byte) (b - 'A' + 10);
531    }
532   
533  0 return 0;
534    }
535   
536    /**
537    * Put name-value pair in map. When an entry for {@code name} already exist, add the new value to the array of
538    * values.
539    * <p>
540    * Code borrowed from Apache Tomcat 5.0
541    * </p>
542    *
543    * @param map the map that is being constructed
544    * @param name the name of the parameter
545    * @param value the value of the parameter
546    */
 
547  0 toggle private static void putMapEntry(Map<String, String[]> map, String name, String value)
548    {
549  0 String[] newValues = null;
550  0 String[] oldValues = map.get(name);
551  0 if (oldValues == null) {
552  0 newValues = new String[] {value};
553    } else {
554  0 newValues = new String[oldValues.length + 1];
555  0 System.arraycopy(oldValues, 0, newValues, 0, oldValues.length);
556  0 newValues[oldValues.length] = value;
557    }
558  0 map.put(name, newValues);
559    }
560   
561    /**
562    * Escapes the XML special characters in a <code>String</code> using numerical XML entities.
563    *
564    * @param value the text to escape, may be null
565    * @return a new escaped <code>String</code>, <code>null</code> if null input
566    * @deprecated starting with 2.7 use {@link XMLUtils#escape(Object) $services.xml.escape(content)}
567    */
 
568  0 toggle @Deprecated
569    public static String formEncode(String value)
570    {
571  0 return XMLUtils.escape(value);
572    }
573   
 
574  0 toggle public static String SQLFilter(String text)
575    {
576  0 try {
577  0 return text.replaceAll("'", "''");
578    } catch (Exception e) {
579  0 return text;
580    }
581    }
582   
583    /**
584    * @deprecated replaced by {@link com.xpn.xwiki.util.Util#encodeURI(String, XWikiContext)} since 1.3M2
585    */
 
586  0 toggle @Deprecated
587    public static String encode(String text, XWikiContext context)
588    {
589  0 return Util.encodeURI(text, context);
590    }
591   
592    /**
593    * @deprecated replaced by {@link com.xpn.xwiki.util.Util#decodeURI(String, XWikiContext)} since 1.3M2
594    */
 
595  0 toggle @Deprecated
596    public static String decode(String text, XWikiContext context)
597    {
598  0 return Util.decodeURI(text, context);
599    }
600   
601    /**
602    * Process a multi-part request, extracting all the uploaded files.
603    *
604    * @param request the current request to process
605    * @param context the current context
606    * @return the instance of the {@link FileUploadPlugin} used to parse the uploaded files
607    */
 
608  9511 toggle public static FileUploadPlugin handleMultipart(HttpServletRequest request, XWikiContext context)
609    {
610  9509 FileUploadPlugin fileupload = null;
611  9507 try {
612  9509 if (request instanceof MultipartRequestWrapper) {
613  10 fileupload = new FileUploadPlugin("fileupload", "fileupload", context);
614  10 context.put("fileuploadplugin", fileupload);