/* * Zed Attack Proxy (ZAP) and its related class files. * * ZAP is an HTTP/HTTPS proxy for assessing web application security. * * Copyright 2013 The ZAP Development team * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.parosproxy.paros.core.scanner; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * * @author andy */ public class MultipartParam { private final List<String> headers = new ArrayList<>(); private String name; private String fileName; private String content; /** * * @param headerline * @throws java.io.IOException */ public void addHeader(String headerline) throws IOException { headers.add(headerline); if (headerline.toLowerCase().startsWith("content-disposition:")) { // Parse the content-disposition line extractDispositionInfo(headerline); } } /** * * @return */ public String getContent() { return content; } /** * * @param value */ public void setContent(String value) { this.content = value; } /** * * @return */ public List<String> getHeaders() { return headers; } /** * * @return */ public String getName() { return name; } /** * * @return */ public String getFileName() { return fileName; } /** * * @return */ @Override public String toString() { StringBuilder result = new StringBuilder(); for (String header : headers) { result.append(header); result.append("\r\n"); } result.append("\r\n"); result.append(content); result.append("\r\n"); return result.toString(); } /** * Extracts and returns disposition info from a line, as a * <code>String<code> * array with elements: disposition, name, filename. * * @exception IOException if the line is malformatted. */ private void extractDispositionInfo(String line) throws IOException { // Convert the line to a lowercase string without the ending \r\n // Keep the original line for error messages and for variable names. String origline = line; line = origline.toLowerCase(); // Get the content disposition, should be "form-data" int start = line.indexOf("content-disposition: "); int end = line.indexOf(";"); if (start == -1 || end == -1) { throw new IOException("Content disposition corrupt: " + origline); } String disposition = line.substring(start + 21, end).trim(); if (!disposition.equals("form-data")) { throw new IOException("Invalid content disposition: " + disposition); } // Get the field name start = line.indexOf("name=\"", end); // start at last semicolon end = line.indexOf("\"", start + 7); // skip name=\" int startOffset = 6; if (start == -1 || end == -1) { // Some browsers like lynx don't surround with "" // Thanks to Deon van der Merwe, dvdm@truteq.co.za, for noticing start = line.indexOf("name=", end); end = line.indexOf(";", start + 6); if (start == -1) { throw new IOException("Content disposition corrupt: " + origline); } else if (end == -1) { end = line.length(); } startOffset = 5; // without quotes we have one fewer char to skip } name = origline.substring(start + startOffset, end); // Get the filename, if given String filename = null; String origname = null; start = line.indexOf("filename=\"", end + 2); // start after name end = line.indexOf("\"", start + 10); // skip filename=\" if (start != -1 && end != -1) { // note the != filename = origline.substring(start + 10, end); origname = filename; // The filename may contain a full path. Cut to just the filename. int slash = Math.max(filename.lastIndexOf('/'), filename.lastIndexOf('\\')); if (slash > -1) { filename = filename.substring(slash + 1); // past last slash } } fileName = filename; } /** * Extracts and returns the content type from a line, or null if the line * was empty. * * @return content type, or null if line was empty. * @exception IOException if the line is malformatted. */ private static String extractContentType(String line) throws IOException { // Convert the line to a lowercase string line = line.toLowerCase(); // Get the content type, if any // Note that Opera at least puts extra info after the type, so handle // that. For example: Content-Type: text/plain; name="foo" // Thanks to Leon Poyyayil, leon.poyyayil@trivadis.com, for noticing this. int end = line.indexOf(";"); if (end == -1) { end = line.length(); } return line.substring(13, end).trim(); // "content-type:" is 13 } }