/* * Encog(tm) Core v3.4 - Java Version * http://www.heatonresearch.com/encog/ * https://github.com/encog/encog-java-core * Copyright 2008-2016 Heaton Research, Inc. * * 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. * * For more information on Heaton Research copyrights, licenses * and trademarks visit: * http://www.heatonresearch.com/copyright */ package org.encog.util.http; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.net.URLConnection; import java.net.URLEncoder; import java.util.HashMap; import java.util.Map; import java.util.Random; import java.util.StringTokenizer; import org.encog.bot.BotError; /** * This class is used to construct responses to HTML forms. The class supports * both standard HTML forms, as well as multipart forms. */ public class FormUtility { /** * The charset to use for URL encoding. Per URL coding spec, this value * should always be UTF-8. */ public static final String ENCODE = "UTF-8"; /** * The size of the read buffer. */ public static final int BUFFER_SIZE = 8192; /** * The length of random string to create for multipart. */ public static final int RANDOM_LENGTH = 36; /** * A Java random number generator. */ private static Random random = new Random(); /** * Encode the specified string. This encodes all special characters. * * @param str * The string to encode. * @return The encoded string. */ private static String encode(final String str) { try { return URLEncoder.encode(str, FormUtility.ENCODE); } catch (final UnsupportedEncodingException e) { return str; } } /** * Generate a boundary for a multipart form. * * @return The boundary. */ public static String getBoundary() { return "---------------------------" + FormUtility.randomString() + FormUtility.randomString() + FormUtility.randomString(); } /** * Parse a URL query string. Return a map of all of the name value pairs. * * @param form * The query string to parse. * @return A map of name-value pairs. */ public static Map<String, String> parse(final String form) { final Map<String, String> result = new HashMap<String, String>(); final StringTokenizer tok = new StringTokenizer(form, "&"); while (tok.hasMoreTokens()) { final String str = tok.nextToken(); final StringTokenizer tok2 = new StringTokenizer(str, "="); if (!tok2.hasMoreTokens()) { continue; } String left = tok2.nextToken(); if (!tok2.hasMoreTokens()) { left = FormUtility.encode(left); result.put(left, null); continue; } String right = tok2.nextToken(); right = FormUtility.encode(right); result.put(left, right); } return result; } /** * Generate a random string, of a specified length. This is used to generate * the multipart boundary. * * @return A random string. */ protected static String randomString() { return Long.toString(FormUtility.random.nextLong(), FormUtility.RANDOM_LENGTH); } /** * The boundary used for a multipart post. This field is null if this is not * a multipart form and has a value if this is a multipart form. */ private final String boundary; /** * The stream to output the encoded form to. */ private final OutputStream os; /** * Keep track of if we're on the first form element. */ private boolean first; /** * Prepare to access either a regular, or multipart, form. * * @param os * The stream to output to. * @param boundary * The boundary to be used, or null if this is not a multipart * form. */ public FormUtility(final OutputStream os, final String boundary) { this.os = os; this.boundary = boundary; this.first = true; } /** * Add a file to a multipart form. * * @param name * The field name. * @param file * The file to attach. */ public void add(final String name, final File file) { try { if (this.boundary != null) { boundary(); writeName(name); write("; filename=\""); write(file.getName()); write("\""); newline(); write("Content-Type: "); String type = URLConnection.guessContentTypeFromName(file .getName()); if (type == null) { type = "application/octet-stream"; } writeln(type); newline(); final byte[] buf = new byte[FormUtility.BUFFER_SIZE]; int nread; final InputStream in = new FileInputStream(file); while ((nread = in.read(buf, 0, buf.length)) >= 0) { this.os.write(buf, 0, nread); } newline(); } } catch (final IOException e) { throw new BotError(e); } } /** * Add a regular text field to either a regular or multipart form. * * @param name * The name of the field. * @param value * The value of the field. */ public void add(final String name, final String value) { if (this.boundary != null) { boundary(); writeName(name); newline(); newline(); writeln(value); } else { if (!this.first) { write("&"); } write(FormUtility.encode(name)); write("="); write(FormUtility.encode(value)); } this.first = false; } /** * Generate a multipart form boundary. * */ private void boundary() { write("--"); write(this.boundary); } /** * Complete the building of the form. * */ public void complete() { try { if (this.boundary != null) { boundary(); writeln("--"); this.os.flush(); } } catch (final IOException e) { throw (new BotError(e)); } } /** * Create a new line by displaying a carriage return and linefeed. * */ private void newline() { write("\r\n"); } /** * Write the specified string, without a carriage return and line feed. * * @param str * The String to write. */ private void write(final String str) { try { this.os.write(str.getBytes()); } catch (final IOException e) { throw new BotError(e); } } /** * Write a string, with a carriage return and linefeed. * * @param str * The string to write. */ protected void writeln(final String str) { write(str); newline(); } /** * Write the name element for a multipart post. * * @param name * The name of the field. */ private void writeName(final String name) { newline(); write("Content-Disposition: form-data; name=\""); write(name); write("\""); } }