@Override public void write(final String fileName) throws IOException { File target = new File(fileName); if (!target.isAbsolute()) { if (config.getLocation().isEmpty()) { target = new File(servletContext.getDeployment().getDeploymentInfo().getTempDir(), fileName); } else { target = new File(config.getLocation(), fileName); } } if (!formValue.getFile().renameTo(target)) { // maybe different filesystem FileUtils.copyFile(formValue.getFile(), target); } }
/** * Parse, if necessary, the multipart stream. * * @throws IOException * @throws ServletException */ protected void parse() throws IOException, ServletException { // have we already parsed the input? if (_parts != null) return; // initialize long total = 0; // keep running total of size of bytes read from input and throw an exception if exceeds // MultipartConfigElement._maxRequestSize _parts = new MultiMap(); // if its not a multipart request, don't parse it if (_contentType == null || !_contentType.startsWith("multipart/form-data")) return; // sort out the location to which to write the files if (_config.getLocation() == null) _tmpDir = _contextTmpDir; else if ("".equals(_config.getLocation())) _tmpDir = _contextTmpDir; else { File f = new File(_config.getLocation()); if (f.isAbsolute()) _tmpDir = f; else _tmpDir = new File(_contextTmpDir, _config.getLocation()); } if (!_tmpDir.exists()) _tmpDir.mkdirs(); String contentTypeBoundary = ""; if (_contentType.indexOf("boundary=") >= 0) contentTypeBoundary = QuotedStringTokenizer.unquote( value(_contentType.substring(_contentType.indexOf("boundary="))).trim()); String boundary = "--" + contentTypeBoundary; byte[] byteBoundary = (boundary + "--").getBytes(StringUtil.__ISO_8859_1); // Get first boundary String line = ((ReadLineInputStream) _in).readLine(); if (line == null) throw new IOException("Missing content for multipart request"); boolean badFormatLogged = false; line = line.trim(); while (line != null && !line.equals(boundary)) { if (!badFormatLogged) { LOG.warn("Badly formatted multipart request"); badFormatLogged = true; } line = ((ReadLineInputStream) _in).readLine(); line = (line == null ? line : line.trim()); } if (line == null) throw new IOException("Missing initial multi part boundary"); // Read each part boolean lastPart = false; String contentDisposition = null; String contentType = null; String contentTransferEncoding = null; outer: while (!lastPart) { MultiMap headers = new MultiMap(); while (true) { line = ((ReadLineInputStream) _in).readLine(); // No more input if (line == null) break outer; // end of headers: if ("".equals(line)) break; total += line.length(); if (_config.getMaxRequestSize() > 0 && total > _config.getMaxRequestSize()) throw new IllegalStateException( "Request exceeds maxRequestSize (" + _config.getMaxRequestSize() + ")"); // get content-disposition and content-type int c = line.indexOf(':', 0); if (c > 0) { String key = line.substring(0, c).trim().toLowerCase(Locale.ENGLISH); String value = line.substring(c + 1, line.length()).trim(); headers.put(key, value); if (key.equalsIgnoreCase("content-disposition")) contentDisposition = value; if (key.equalsIgnoreCase("content-type")) contentType = value; if (key.equals("content-transfer-encoding")) contentTransferEncoding = value; } } // Extract content-disposition boolean form_data = false; if (contentDisposition == null) { throw new IOException("Missing content-disposition"); } QuotedStringTokenizer tok = new QuotedStringTokenizer(contentDisposition, ";", false, true); String name = null; String filename = null; while (tok.hasMoreTokens()) { String t = tok.nextToken().trim(); String tl = t.toLowerCase(Locale.ENGLISH); if (t.startsWith("form-data")) form_data = true; else if (tl.startsWith("name=")) name = value(t); else if (tl.startsWith("filename=")) filename = filenameValue(t); } // Check disposition if (!form_data) { continue; } // It is valid for reset and submit buttons to have an empty name. // If no name is supplied, the browser skips sending the info for that field. // However, if you supply the empty string as the name, the browser sends the // field, with name as the empty string. So, only continue this loop if we // have not yet seen a name field. if (name == null) { continue; } if ("base64".equalsIgnoreCase(contentTransferEncoding)) { _in = new Base64InputStream(_in); } else if ("quoted-printable".equalsIgnoreCase(contentTransferEncoding)) { _in = new FilterInputStream(_in) { @Override public int read() throws IOException { int c = in.read(); if (c >= 0 && c == '=') { int hi = in.read(); int lo = in.read(); if (hi < 0 || lo < 0) { throw new IOException("Unexpected end to quoted-printable byte"); } char[] chars = new char[] {(char) hi, (char) lo}; c = Integer.parseInt(new String(chars), 16); } return c; } }; } // Have a new Part MultiPart part = new MultiPart(name, filename); part.setHeaders(headers); part.setContentType(contentType); _parts.add(name, part); part.open(); try { int state = -2; int c; boolean cr = false; boolean lf = false; // loop for all lines while (true) { int b = 0; while ((c = (state != -2) ? state : _in.read()) != -1) { total++; if (_config.getMaxRequestSize() > 0 && total > _config.getMaxRequestSize()) throw new IllegalStateException( "Request exceeds maxRequestSize (" + _config.getMaxRequestSize() + ")"); state = -2; // look for CR and/or LF if (c == 13 || c == 10) { if (c == 13) { _in.mark(1); int tmp = _in.read(); if (tmp != 10) _in.reset(); else state = tmp; } break; } // look for boundary if (b >= 0 && b < byteBoundary.length && c == byteBoundary[b]) b++; else { // this is not a boundary if (cr) part.write(13); if (lf) part.write(10); cr = lf = false; if (b > 0) part.write(byteBoundary, 0, b); b = -1; part.write(c); } } // check partial boundary if ((b > 0 && b < byteBoundary.length - 2) || (b == byteBoundary.length - 1)) { if (cr) part.write(13); if (lf) part.write(10); cr = lf = false; part.write(byteBoundary, 0, b); b = -1; } // boundary match if (b > 0 || c == -1) { if (b == byteBoundary.length) lastPart = true; if (state == 10) state = -2; break; } // handle CR LF if (cr) part.write(13); if (lf) part.write(10); cr = (c == 13); lf = (c == 10 || state == 10); if (state == 10) state = -2; } } finally { part.close(); } } if (!lastPart) throw new IOException("Incomplete parts"); }