diff --git a/core/java/src/net/i2p/util/EepPost.java b/core/java/src/net/i2p/util/EepPost.java new file mode 100644 index 0000000000000000000000000000000000000000..e938493419ab8d6b29cdec5eaa150d72e3eaa4e8 --- /dev/null +++ b/core/java/src/net/i2p/util/EepPost.java @@ -0,0 +1,189 @@ +package net.i2p.util; + +import java.io.*; +import java.net.*; +import java.util.*; +import net.i2p.I2PAppContext; + +/** + * Simple helper for uploading files and such via HTTP POST (rfc 1867) + * + */ +public class EepPost { + public static void main(String args[]) { + EepPost e = new EepPost(); + Map fields = new HashMap(); + fields.put("key", "value"); + fields.put("key1", "value1"); + fields.put("key2", "value2"); + fields.put("blogpost0", new File("/home/i2p/1.snd")); + fields.put("blogpost1", new File("/home/i2p/2.snd")); + fields.put("blogpost2", new File("/home/i2p/2.snd")); + fields.put("blogpost3", new File("/home/i2p/2.snd")); + fields.put("blogpost4", new File("/home/i2p/2.snd")); + fields.put("blogpost5", new File("/home/i2p/2.snd")); + e.postFiles("http://localhost:7653/import.jsp", null, -1, fields, null); + //e.postFiles("http://localhost/cgi-bin/read.pl", null, -1, fields, null); + //e.postFiles("http://localhost:2001/import.jsp", null, -1, fields, null); + } + /** + * Submit an HTTP POST to the given URL (using the proxy if specified), + * uploading the given fields. If the field's value is a File object, then + * that file is uploaded, and if the field's value is a String object, the + * value is posted for that particular field. Multiple values for one + * field name is not currently supported. + * + */ + public void postFiles(String url, String proxyHost, int proxyPort, Map fields, Runnable onCompletion) { + I2PThread postThread = new I2PThread(new Runner(url, proxyHost, proxyPort, fields, onCompletion)); + postThread.start(); + } + + private class Runner implements Runnable { + private String _url; + private String _proxyHost; + private int _proxyPort; + private Map _fields; + private Runnable _onCompletion; + public Runner(String url, String proxy, int port, Map fields, Runnable onCompletion) { + _url = url; + _proxyHost = proxy; + _proxyPort = port; + _fields = fields; + _onCompletion = onCompletion; + } + public void run() { + try { + URL u = new URL(_url); + String h = u.getHost(); + int p = u.getPort(); + if (p <= 0) + p = 80; + String path = u.getPath(); + + boolean isProxy = true; + if ( (_proxyHost == null) || (_proxyPort <= 0) ) { + isProxy = false; + _proxyHost = h; + _proxyPort = p; + } + + Socket s = new Socket(_proxyHost, _proxyPort); + OutputStream out = s.getOutputStream(); + String sep = getSeparator(); + long length = calcContentLength(sep, _fields); + String header = getHeader(isProxy, path, h, p, sep, length); + System.out.println("Header: \n" + header); + out.write(header.getBytes()); + out.flush(); + if (false) { + out.write(("--" + sep + "\ncontent-disposition: form-data; name=\"field1\"\n\nStuff goes here\n--" + sep + "--\n").getBytes()); + } else { + sendFields(out, sep, _fields); + } + out.flush(); + BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream())); + String line = null; + while ( (line = in.readLine()) != null) + System.out.println("recv: [" + line + "]"); + out.close(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (_onCompletion != null) + _onCompletion.run(); + } + } + } + + private long calcContentLength(String sep, Map fields) { + long len = 0; + for (Iterator iter = fields.keySet().iterator(); iter.hasNext(); ) { + String key = (String)iter.next(); + Object val = fields.get(key); + if (val instanceof File) { + File f = (File)val; + len += ("--" + sep + "\nContent-Disposition: form-data; name=\"" + key + "\"; filename=\"" + f.getName() + "\"\n").length(); + //len += ("Content-length: " + f.length() + "\n").length(); + len += ("Content-Type: application/octet-stream\n\n").length(); + len += f.length(); + len += 1; // nl + } else { + len += ("--" + sep + "\nContent-Disposition: form-data; name=\"" + key + "\"\n\n").length(); + len += val.toString().length(); + len += 1; // nl + } + } + len += 2 + sep.length() + 2; + //len += 2; + return len; + } + private void sendFields(OutputStream out, String separator, Map fields) throws IOException { + for (Iterator iter = fields.keySet().iterator(); iter.hasNext(); ) { + String field = (String)iter.next(); + Object val = fields.get(field); + if (val instanceof File) + sendFile(out, separator, field, (File)val); + else + sendField(out, separator, field, val.toString()); + } + out.write(("--" + separator + "--\n").getBytes()); + } + + private void sendFile(OutputStream out, String separator, String field, File file) throws IOException { + long len = file.length(); + out.write(("--" + separator + "\n").getBytes()); + out.write(("Content-Disposition: form-data; name=\"" + field + "\"; filename=\"" + file.getName() + "\"\n").getBytes()); + //out.write(("Content-length: " + len + "\n").getBytes()); + out.write(("Content-Type: application/octet-stream\n\n").getBytes()); + FileInputStream in = new FileInputStream(file); + byte buf[] = new byte[1024]; + int read = -1; + while ( (read = in.read(buf)) != -1) + out.write(buf, 0, read); + out.write("\n".getBytes()); + in.close(); + } + + private void sendField(OutputStream out, String separator, String field, String val) throws IOException { + out.write(("--" + separator + "\n").getBytes()); + out.write(("Content-Disposition: form-data; name=\"" + field + "\"\n\n").getBytes()); + out.write(val.getBytes()); + out.write("\n".getBytes()); + } + + private String getHeader(boolean isProxy, String path, String host, int port, String separator, long length) { + StringBuffer buf = new StringBuffer(512); + buf.append("POST "); + if (isProxy) { + buf.append("http://").append(host); + if (port != 80) + buf.append(":").append(port); + } + buf.append(path); + buf.append(" HTTP/1.1\n"); + buf.append("Host: ").append(host); + if (port != 80) + buf.append(":").append(port); + buf.append("\n"); + buf.append("Connection: close\n"); + buf.append("Content-length: ").append(length).append("\n"); + buf.append("Content-type: multipart/form-data, boundary=").append(separator); + buf.append("\n"); + buf.append("\n"); + return buf.toString(); + } + + private String getSeparator() { + if (false) + return "ABCDEFG"; + if (false) + return "------------------------" + new java.util.Random().nextLong(); + byte separator[] = new byte[32]; // 2^-128 chance of this being a problem + I2PAppContext.getGlobalContext().random().nextBytes(separator); + StringBuffer sep = new StringBuffer(48); + for (int i = 0; i < separator.length; i++) + sep.append((char)((int)'a' + (int)(separator[i]&0x0F))).append((char)((int)'a' + (int)((separator[i] >>> 4) & 0x0F))); + return sep.toString(); + } +}