001 /* 002 * LAPIS lightweight structured text processing system 003 * 004 * Copyright (C) 1998-2002 Carnegie Mellon University, 005 * Copyright (C) 2003 Massachusetts Institute of Technology. 006 * All rights reserved. 007 * 008 * This library is free software; you can redistribute it 009 * and/or modify it under the terms of the GNU General 010 * Public License as published by the Free Software 011 * Foundation, version 2. 012 * 013 * LAPIS homepage: http://graphics.lcs.mit.edu/lapis/ 014 */ 015 016 package lapisx.net; 017 018 import java.net.*; 019 import java.io.*; 020 import java.util.*; 021 import java.lang.reflect.*; 022 023 // FIX: support multipart/form-data as well 024 public class FormURL { 025 String method; 026 URL action; 027 URL url; 028 String queryString; 029 Vector queryVector; 030 031 /** 032 * Create a query using a given method (get or post) and query data. 033 * @param method "get" or "post" (case-insensitive). 034 * @param url URL to send query to. Must be http: 035 * @param query Name/value pairs to simulate submitting a form. Names and values may be arbitrary objects; this method uses toString() to convert them to strings, then URL-encodes them before sending to the web server. Pass null if no form data is desired. 036 */ 037 public FormURL (String method, URL url, Vector query) { 038 this (method, url, (query != null) ? encodeQuery (query) : null); 039 queryVector = query; 040 } 041 042 /** 043 * Open a URL using a given method (get or post) and query data. 044 * @param method "get" or "post" (case-insensitive). 045 * @param url URL to open. Must be http: 046 * @param query URL-encoded name/value pairs, or null if no query desired 047 */ 048 public FormURL (String method, URL url, String query) { 049 this.method = method; 050 this.action = url; 051 this.url = url; 052 this.queryString = (query != null) ? query : ""; 053 054 if (method == null || "get".equalsIgnoreCase (method)) { 055 try { 056 this.url = new URL (URLUtil.getServiceURL (url) + "?" + query); 057 } catch (MalformedURLException e) { 058 throw new RuntimeException (e.toString ());// shouldn't happen 059 } 060 } 061 } 062 063 // FIX: constructor from a String (assuming GET), or String + method 064 065 public String getMethod () { 066 return method; 067 } 068 069 public URL getAction () { 070 return url; 071 } 072 073 public URL getURL () { 074 return url; 075 } 076 077 public String getQueryString () { 078 return queryString; 079 } 080 081 // FIX: write decodeQuery, so that this can work even when 082 // FormURL is constructed from a string, not a hash 083 public Vector getQueryVector () { 084 return queryVector; 085 } 086 087 public String toString () { 088 return url.toString (); 089 } 090 091 /** 092 * Open a connection ready to submit query and retrieve its results. 093 * @return URLConnection (set up for connection but not yet connected) 094 */ 095 public URLConnection openConnection () throws IOException { 096 if (!"http".equals (url.getProtocol ())) 097 throw new IOException ("query URL must be http:"); 098 099 URLConnection conn = url.openConnection (); 100 101 // handle POST method 102 if ("post".equalsIgnoreCase (method)) { 103 conn.setDoOutput (true); 104 conn.setUseCaches (false); 105 conn.setRequestProperty ("Content-type", 106 "application/x-www-form-urlencoded"); 107 conn.setRequestProperty ("Content-length", String.valueOf (queryString.length())); 108 109 // commence request 110 PrintWriter out = null; 111 try { 112 out = new PrintWriter (new OutputStreamWriter 113 (conn.getOutputStream ())); 114 // System.err.println ("Sending by POST:\n" + queryString + "\ndone"); 115 out.print (queryString); 116 out.flush (); 117 } finally { 118 if (out != null) 119 out.close (); 120 } 121 } 122 123 return conn; 124 } 125 126 /** 127 * URL-encode a sequence of name-value pairs. 128 * @param query Name/value pairs to encode; even indexes are names, odd indexes are values 129 * @return String of URL-encoded name/value pairs 130 */ 131 public static String encodeQuery (Vector query) { 132 StringBuffer result = new StringBuffer (); 133 134 for (int i = 0, n = query.size (); i < n; i+=2) { 135 String name = (String)query.elementAt (i); 136 String value = (String)query.elementAt (i+1); 137 138 if (result.length () > 0) 139 result.append ('&'); 140 141 result.append (ENCODER.encode (name)); 142 result.append ('='); 143 result.append (ENCODER.encode (value)); 144 } 145 return result.toString (); 146 } 147 148 // 149 // The following craziness calls the deprecated URLEncoder.encode(string) 150 // only when we have to, in Java 1.2 and 1.3. In Java 1.4 and later, 151 // we call the preferred URLEncoder.encode(string, character-encoding). 152 // 153 private static Encoder ENCODER; 154 155 private interface Encoder { 156 public String encode (String s); 157 } 158 159 /** 160 * Wrapper for deprecated Java 1.2/1.3 URLEncoder.encode(). 161 */ 162 private static class Encoder2 implements Encoder { 163 Class cls; 164 Method method; 165 public Encoder2 () throws Exception { 166 cls = Class.forName ("java.net.URLEncoder"); 167 method = cls.getMethod ("encode", new Class[] {String.class}); 168 } 169 public String encode (String s) { 170 try { 171 return (String) method.invoke (cls, new Object[] {s}); 172 } catch (Exception e) { 173 throw new RuntimeException (e.toString ()); 174 } 175 } 176 } 177 178 /** 179 * Wrapper for preferred Java 1.4 & later URLEncoder.encode(). 180 */ 181 private static class Encoder4 implements Encoder { 182 Class cls; 183 Method method; 184 public Encoder4 () throws Exception { 185 cls = Class.forName ("java.net.URLEncoder"); 186 method = cls.getMethod ("encode", 187 new Class[] {String.class, String.class}); 188 } 189 public String encode (String s) { 190 try { 191 return (String) method.invoke (cls, new Object[] {s, "UTF-8"}); 192 } catch (Exception e) { 193 throw new RuntimeException (e.toString ()); 194 } 195 } 196 } 197 198 /** 199 * Determine which version of Java is running and 200 * set ENCODER appropriately. 201 */ 202 static { 203 String javaVersion = System.getProperty ("java.version"); 204 try { 205 if (javaVersion.startsWith ("1.2") 206 || javaVersion.startsWith ("1.3")) 207 ENCODER = new Encoder2 (); 208 else 209 ENCODER = new Encoder4 (); 210 } catch (Exception e) { 211 throw new RuntimeException (e.toString ()); 212 } 213 } 214 }