Barracuda: Updated HttpRequester
Shawn Wilson <[email protected]>
| Newsgroups | gmane.comp.java.enhydra.barracuda.general |
|---|---|
| Organization | ATMReports.com |
| Message-ID | <[email protected]> |
Folks, I have made some updates to the org.enhydra.barracuda.plankton.http.HttpRequester class to support the use of cookies between server and client. This also involved the creation of a new org.enhydra.barracuda.plankton.http.Cookie class to represent an HTTP cookie. I have attached these files to this email, so if someone thinks this update may be useful they can use it themselves or a committer can commit it to the barracuda tree or whatever you guys feel you want to do with it. Thanks! -shawn -- ==================================== Shawn Wilson [[email protected]] Software Developer, ATMReports.com PH: 877-327-0873, FAX: 406-294-5806 ====================================
Cookie.java
(text/plain, 5.5 KB)
/* * Enhydra Java Application Server Project * * The contents of this file are subject to the Enhydra Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License on * the Enhydra web site (http://www.enhydra.org/). * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific terms governing rights and limitations * under the License. * * The Initial Developer of the Enhydra Application Server is Lutris * Technologies, Inc. The Enhydra Application Server and portions created * by Lutris Technologies, Inc. are Copyright Lutris Technologies, Inc. * All Rights Reserved. * * Contributor(s): * * $Id: HttpRequester.java,v 1.1 2002/11/02 19:15:53 cryd0221 Exp $ */ package org.enhydra.barracuda.plankton.http; import java.text.*; import java.util.*; //saw_112602.1 - added /** * Basic representation of an HTTP 'cookie'. * See http://wp.netscape.com/newsref/std/cookie_spec.html for more * information about cookies. * * @author [email protected] */ public class Cookie { protected static final DateFormat df = new SimpleDateFormat("EEE, dd-MMM-yyyy HH:mm:ss zzz"); protected String name; protected String value; protected Date expires; protected String domain; protected String path; protected boolean secure; /** * Construct a cookie from a single 'Set-Cookie' header value string from the server. * * @throws ParseException if the string cannot be parsed into a valid cookie */ public Cookie(String str) throws ParseException { StringTokenizer st = new StringTokenizer(str, ";"); int length = 0; // to keep track of position for ParseExceptions String str1 = st.nextToken(); length += str1.length(); str1 = str1.trim(); int index = str1.indexOf('='); if(index < 0) throw new ParseException("Missing name=value pair", 0); else if(index == 0) throw new ParseException("Missing name for name=value pair", 0); else if(index == str1.length()) throw new ParseException("Missing value for name=value pair", 0); else { name = str1.substring(0, index); value = str1.substring(index+1); } while(st.hasMoreTokens()) { str1 = st.nextToken(); String str2 = str1.trim(); if(str2.startsWith("expires=")) { try { expires = df.parse(str2.substring(8)); } catch(ParseException e) { ParseException ee = new ParseException("Invalid date format for 'expires' option", length+8); ee.initCause(e); throw ee; } } else if(str2.startsWith("domain=")) { domain = str2.substring(7); } else if(str2.startsWith("path=")) { path = str2.substring(5); } else if(str2.equals("secure")) { secure = true; } else { throw new ParseException("Unrecognized option: "+str2, length); } length += 1+str1.length(); // (+1 for the semicolon delimiter) } } /** * Construct a minimal cookie. * Every cookie must have at least a name and value. * * @throws NullPointerException is name or value is <code>null</code>. */ public Cookie(String name, String value) { this(name, value, (Date)null, null, null, false); } /** * Construct a cookie with the given values. * Every cookie must have at least a name and value. * * @param expires must be in the format defined in the cookie specification * * @throws NullPointerException is name or value is <code>null</code>. * @throws ParseException if the 'expires' parameter is not in the correct format. */ public Cookie(String name, String value, String expires, String domain, String path, boolean secure) throws ParseException { this(name, value, (df==null ? null : df.parse(expires)), domain, path, secure); } /** * Construct a cookie with the given values. * Every cookie must have at least a name and value. * * @throws NullPointerException is name or value is <code>null</code>. */ public Cookie(String name, String value, Date expires, String domain, String path, boolean secure) { if(name == null || value == null) throw new NullPointerException("Neither 'name' nor 'value' may be null"); this.name = name; this.value = value; this.expires = expires; this.domain = domain; this.path = path; this.secure = secure; } public String getName() { return name; } public String getValue() { return value; } public Date getExpires() { return expires; } public String getDomain() { return domain; } public String getPath() { return path; } public boolean isSecure() { return secure; } public String toString() { StringBuffer sb = new StringBuffer(name+"="+value); if(expires != null) sb.append("; expires=").append(df.format(expires)); if(domain != null) sb.append("; domain=").append(domain); if(path != null) sb.append("; path=").append(path); if(secure) sb.append("; secure"); return sb.toString(); } };
HttpRequester.java
(text/plain, 22.6 KB)
/*
* Enhydra Java Application Server Project
*
* The contents of this file are subject to the Enhydra Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License on
* the Enhydra web site (http://www.enhydra.org/).
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific terms governing rights and limitations
* under the License.
*
* The Initial Developer of the Enhydra Application Server is Lutris
* Technologies, Inc. The Enhydra Application Server and portions created
* by Lutris Technologies, Inc. are Copyright Lutris Technologies, Inc.
* All Rights Reserved.
*
* Contributor(s):
*
* $Id: HttpRequester.java,v 1.1 2002/11/02 19:15:53 cryd0221 Exp $
*/
package org.enhydra.barracuda.plankton.http;
import java.io.*;
import java.net.*;
import java.text.*;
import java.util.*;
import org.enhydra.barracuda.plankton.data.Base64;
/**
* This class encapsulates access to/from a URL via
* both POST and GET methods. To use, simply set the
* URL, the method (POST/GET), and the params. If you're
* using get, the params are optional (they can be included
* as part of the URL). Also note that you can pass a
* username and password if you need to do basic authentication
*
* Refer to the source for this class (main method) to see an example of
* how you would use this class for both POST and GET methods:
*/
public class HttpRequester {
public static final String POST = "POST";
public static final String GET = "GET";
protected URL url = null;
protected String method = GET;
protected Map props = null;
protected HttpOutputWriter outputWriter = null;
protected String user = null;
protected String password = null;
protected boolean authenticate = false;
protected boolean acceptCookies = true; //saw_112602.1
protected List cookies = null; //saw_112602.1
protected OutputStream outStream = null;
protected InputStream inStream = null;
protected BufferedReader in = null;
/**
* Set the Request. This is a convenience method to encapsulate
* calls to setUrl, setMethod, and setParams all in one fell swoop.
*
* @param url the URL we wish to access
* @param method the method we wish to use (either GET or POST)
* @param props the Map contains our key-value URL parameter pairs.
* If the value is a Set, the resulting URL will contain a key-value
* mapping for each entry in the Set.
* @throws MalformedURLException
*/
public void setRequest(String iurl, String imethod, Map iprops) throws MalformedURLException {
setRequest(iurl, imethod, iprops, null);
}
/**
* Set the Request. This is a convenience method to encapsulate
* calls to setUrl, setMethod, and setParams all in one fell swoop.
*
* @param url the URL we wish to access
* @param method the method we wish to use (either GET or POST)
* @param props the Map contains our key-value URL parameter pairs.
* If the value is a Set, the resulting URL will contain a key-value
* mapping for each entry in the Set.
* @throws MalformedURLException
*/
public void setRequest(URL iurl, String imethod, Map iprops) throws MalformedURLException {
setRequest(iurl, imethod, iprops, null);
}
/**
* Set the Request. This is a convenience method to encapsulate
* calls to setUrl, setMethod, and setParams all in one fell swoop.
*
* @param url the URL we wish to access
* @param method the method we wish to use (either GET or POST)
* @param props the Map contains our key-value URL parameter pairs.
* If the value is a Set, the resulting URL will contain a key-value
* mapping for each entry in the Set.
* @param outputWriter the HttpOutputWriter we wish to write to
* @throws MalformedURLException
*/
public void setRequest(String iurl, String imethod, Map iprops, HttpOutputWriter ioutputWriter) throws MalformedURLException {
setRequest(iurl, imethod, iprops, null, null, null);
}
/**
* Set the Request. This is a convenience method to encapsulate
* calls to setUrl, setMethod, and setParams all in one fell swoop.
*
* @param url the URL we wish to access
* @param method the method we wish to use (either GET or POST)
* @param props the Map contains our key-value URL parameter pairs.
* If the value is a Set, the resulting URL will contain a key-value
* mapping for each entry in the Set.
* @param outputWriter the HttpOutputWriter we wish to write to
* @throws MalformedURLException
*/
public void setRequest(URL iurl, String imethod, Map iprops, HttpOutputWriter ioutputWriter) throws MalformedURLException {
setRequest(iurl, imethod, iprops, null, null, null);
}
/**
* Set the Request. This is a convenience method to encapsulate
* calls to setUrl, setMethod, and setParams all in one fell swoop.
*
* @param url the URL we wish to access
* @param method the method we wish to use (either GET or POST)
* @param props the Map contains our key-value URL parameter pairs.
* If the value is a Set, the resulting URL will contain a key-value
* mapping for each entry in the Set.
* @param user the user named required to connect
* @param password the password named required to connect
* @param outputWriter the HttpOutputWriter we wish to write to
* @throws MalformedURLException
*/
public void setRequest(String iurl, String imethod, Map iprops, String iuser, String ipwd, HttpOutputWriter ioutputWriter) throws MalformedURLException {
if (iurl!=null) setUrl(iurl);
if (imethod!=null) setMethod(imethod);
if (iprops!=null) setParams(iprops);
if (iuser!=null) setUser(iuser);
if (ipwd!=null) setPassword(ipwd);
if (ioutputWriter!=null) setOutputWriter(ioutputWriter);
}
/**
* Set the Request. This is a convenience method to encapsulate
* calls to setUrl, setMethod, and setParams all in one fell swoop.
*
* @param url the URL we wish to access
* @param method the method we wish to use (either GET or POST)
* @param props the Map contains our key-value URL parameter pairs.
* If the value is a Set, the resulting URL will contain a key-value
* mapping for each entry in the Set.
* @param user the user named required to connect
* @param password the password named required to connect
* @param outputWriter the HttpOutputWriter we wish to write to
* @throws MalformedURLException
*/
public void setRequest (URL iurl, String imethod, Map iprops, String iuser, String ipwd, HttpOutputWriter ioutputWriter) throws MalformedURLException {
if (iurl!=null) setUrl(iurl);
if (imethod!=null) setMethod(imethod);
if (iprops!=null) setParams(iprops);
if (iuser!=null) setUser(iuser);
if (ipwd!=null) setPassword(ipwd);
if (ioutputWriter!=null) setOutputWriter(ioutputWriter);
}
/**
* Set the URL we wish to access
*
* @param url the URL we wish to access
* @throws MalformedURLException
*/
public void setUrl (String iurl) throws MalformedURLException {
//if we're setting it back to null, otherwise, create the url
//which represents the servlet which will do the generation
if (iurl==null) url = null;
else setUrl (new URL (iurl));
}
/**
* Set the URL we wish to access
*
* @param url the URL we wish to access
*/
public void setUrl (URL iurl) {
url = iurl;
}
/**
* Get the URL for the HttpRequest object
*
* @return the URL behind this request
*/
public URL getUrl () {
return url;
}
/**
* Set the method we wish to use. Valid values are either GET
* or POST. Default is GET.
*
* @param method the method we wish to use (either GET or POST)
*/
public void setMethod (String imethod) {
if (imethod.toUpperCase().equals(POST)) method = POST;
else method = GET;
}
/**
* Get the method we're using for this HttpRequest object
*
* @return the method we're using (either GET or POST)
*/
public String getMethod () {
return method;
}
/**
* Set the parmeters we wish to pass to the URL as name-value pairs.
* If you are using the POST method, it will look for properties in
* here. If you are using the get method, you can manually pass the
* properties as part of the URL string, and just ignore this method.
*
* @param props the Map contains our key-value URL parameter pairs.
* If the value is a Set, the resulting URL will contain a key-value
* mapping for each entry in the Set.
*/
public void setParams (Map iprops) {
props = iprops;
}
/**
* Return the HashMap object for this HttpRequest. If the map is null (ie.
* because you are using the GET method), we attempt to look for the
* properties in the actual URL string and build a HashMap from that.
*
* @return a Map containing all the parameters for this HttpRequest
*/
public Map getParams () {
//if someone asks for the param map and its null, try
//and build it based on the actual URL string
if (props==null) {
//avoid the obvious errs
if (url==null) return null;
//build the HashMap
props = HttpConverter.cvtURLStringToMap (url.toString(), "&");
}
//return the HashMap
return props;
}
/**
* Set the user (if we need to authenticate in order to make the connection)
*
* @param user the user name
*/
public void setUser(String iuser) {
user = iuser;
authenticate = (user!=null);
}
/**
* Get the user name
*
* @return the user name
*/
public String getUser() {
return user;
}
/**
* Set the password (if we need to authenticate in order to make the connection)
*
* @param password the password
*/
public void setPassword(String ipassword) {
password = ipassword;
authenticate = (password!=null);
}
/**
* Get the password
*
* @return the password
*/
protected String getPassword() {
return password;
}
//saw_112602.1 - begin
/**
* Set whether or not to accept cookies from the server.
* The default is <code>true</code>.
*
* Setting this value to <code>false</code> after cookies
* have already been obtained does not clear the current
* cookies, it simply will not accept any new cookies.
*
* @see #clearCookies()
*/
public void setAcceptCookies(boolean accept) {
this.acceptCookies = accept;
}
/**
* Determine whether or not we are accepting cookies.
*/
public boolean getAcceptCookies() {
return acceptCookies;
}
/**
* Return a list of cookies this client is sending to the server
*
* @return a list of {@link Cookie cookies}, or <code>null</code> if
* the server has not set any cookies in the client
*
* @see Cookie
*/
public List getCookies() {
return cookies;
}
/**
* Clear any cookies this client knows about.
*/
public void clearCookies() {
cookies = null;
}
//saw_112602.1 - end
/**
* Set the output writer to be used for posting data
*
* @param ioutputWriter the HttpOutputWriter
*/
public void setOutputWriter (HttpOutputWriter ioutputWriter) {
outputWriter = ioutputWriter;
}
/**
* Return the output writer. If none is set, the default will be used.
*
* @return the HttpOutputWriter
*/
public HttpOutputWriter getOutputWriter () {
//if someone asks for the output writer and its null,
//return the default
if (outputWriter==null) {
return new DefaultOutputWriter ();
} else
return outputWriter;
}
/**
* Connect to the URL
*
* @throws ConnectException
* @throws IOException
*/
public void connect() throws ConnectException, IOException {
//pre-launch checks
if (url==null) throw new ConnectException ("Invalid URL. URL can not be NULL");
if (method!=POST && method!=GET) throw new ConnectException ("Invalid Method. Method must be either POST or GET");
URLConnection conn;
//POST
if (method==POST) {
//open the connection and set output & input to true
conn = url.openConnection();
conn.setDoOutput(true);
conn.setDoInput(true);
//Set up an authorization header with our credentials (this chunk of
//code stolen from org.apache.catalina.ant.AbstractCatalinaTask;
//thanks to Craig R. McClanahan [[email protected]] for pointing
//me to this example)
if (authenticate) {
String input = user + ":" + password;
String output = new String(Base64.encode(input.getBytes()));
conn.setRequestProperty("Authorization", "Basic " + output);
}
//write the key values to the stream
outStream = conn.getOutputStream();
getOutputWriter().writeOutput(outStream);
//GET
} else {
//first see if we have a param structure...if so, build a URL String.
if (props!=null) {
//figure out what the current URL is and strip off any parameters
String newUrl = getUrl().toString();
int pos = newUrl.indexOf("?");
if (pos>0) newUrl = newUrl.substring(0,pos);
//now run through the map and build a new url string
setUrl(newUrl+"?"+ HttpConverter.cvtMapToURLString(props, "&"));
newUrl = getUrl().toString();
if (newUrl.endsWith("?")) setUrl(newUrl.substring(0,newUrl.length()-1));
//now set the url and set the params object back to null so we don't
//need to rebuild the URL string again
setParams(null);
}
//open the connection and set input to true
conn = url.openConnection();
conn.setDoInput(true);
//Set up an authorization header with our credentials (this chunk of
//code stolen from org.apache.catalina.ant.AbstractCatalinaTask;
//thanks to Craig R. McClanahan [[email protected]] for pointing
//me to this example)
if (authenticate) {
String input = user + ":" + password;
String output = new String(Base64.encode(input.getBytes()));
conn.setRequestProperty("Authorization", "Basic " + output);
}
}
//saw_112602.1 - begin
//do we have cookies to send?
if(cookies != null) {
//NOTE: this implementation of cookie support is very basic and
//does not completely follow spec. Specifically, cookie expiration
//is not checked and a single repeated cookie is not ordered by
//the path specifications.
StringBuffer sb = new StringBuffer();
Iterator it = cookies.iterator();
while(it.hasNext()) {
Cookie cookie = (Cookie)it.next();
if(cookie.getDomain() == null || url.getHost().toLowerCase().endsWith(cookie.getDomain().toLowerCase())) {
if(cookie.getPath() == null || url.getPath().startsWith(cookie.getPath())) {
if(!cookie.isSecure() || url.getProtocol().equalsIgnoreCase("https")) {
sb.append(cookie.getName()).append('=').append(cookie.getValue()).append("; ");
} else {
//System.out.println("Ignoring cookie for secure transmission");
}
} else {
//System.out.println("Ignoring cookie for different path: "+cookie.getPath());
}
} else {
//System.out.println("Ignoring cookie for different domain: "+cookie.getDomain());
}
}
if(sb.length() > 0) {
//System.out.println("Sending header Cookie: "+sb.toString());
conn.setRequestProperty("Cookie", sb.toString());
}
}
//now open an input stream to read the response
inStream = conn.getInputStream();
in = new BufferedReader(new InputStreamReader(inStream));
//are we accepting cookies, and did the server send any back?
List scookies = (List)conn.getHeaderFields().get("Set-Cookie");
if(acceptCookies && scookies != null) {
cookies = new ArrayList(scookies.size());
//System.out.println("Got cookie header(s) from server:");
Iterator it = scookies.iterator();
while(it.hasNext()) {
String cookieStr = (String)it.next();
//System.out.println(" --> " + cookieStr);
try {
Cookie cookie = new Cookie(cookieStr);
//System.out.println(" COOKIE: "+cookie);
cookies.add(cookie);
} catch(ParseException e) {
e.printStackTrace();
}
}
}
//saw_112602.1 - end
}
/**
* Read responses from the URL
*
* @return a String representation of what we got back
* @throws ConnectException
* @throws IOException
*/
public String readLine() throws ConnectException, IOException {
//pre-launch checks
if (in==null) throw new ConnectException ("Connection is not active");
//get the line
String inputLine = in.readLine();
//if its null, auto disconnect
if (inputLine==null) disconnect();
//now return the String
return inputLine;
}
/**
* Get the underlying output stream
*
* @return the output stream
* @throws ConnectException
*/
public OutputStream getOutputStream() throws ConnectException {
//pre-launch checks
if (outStream==null) throw new ConnectException ("Connection is not active");
//return the input stream
return outStream;
}
/**
* Get the underlying input stream
*
* @return the input stream
* @throws ConnectException
*/
public InputStream getInputStream() throws ConnectException {
//pre-launch checks
if (inStream==null) throw new ConnectException ("Connection is not active");
//return the input stream
return inStream;
}
/**
* Disconnect from the URL. You really only need to call this
* if you terminate the readLine process on your end. if
* readLine() encounters a null value, it assumes input is
* complete and automatically calls this method.
*/
public void disconnect() {
if (outStream!=null) try {outStream.close();} catch (IOException ioe) {}
outStream = null;
if (in!=null) try {in.close();} catch (IOException ioe) {}
in = null;
if (inStream!=null) try {inStream.close();} catch (IOException ioe) {}
inStream = null;
}
/**
* This inner class provides the default mechanism to write to an output stream
*/
class DefaultOutputWriter implements HttpOutputWriter {
public void writeOutput(OutputStream outputStream) throws IOException {
System.out.println ("Using default HttpOutputWriter to POST data");
PrintWriter out = new PrintWriter(outputStream);
try {
String paramStr = HttpConverter.cvtMapToURLString(props, "&");
if (paramStr!=null && paramStr.trim().length()>0) out.print (paramStr);
System.out.println ("Data posted!");
} finally {
out.close();
outputStream.close();
}
}
}
public static void main(String[] args) {
//sample GET
try {
HttpRequester hr = new HttpRequester();
// String urlStr = "http://localhost:8080/manager/list"; //connect to Tomcat manager app
// String paramStr = "";
String urlStr = "http://localhost:8080/manager/reload?path=/examples"; //connect to Tomcat manager app
String paramStr = null;
Map props = null;
if (paramStr!=null) HttpConverter.cvtURLStringToMap (paramStr, "&");
hr.setRequest(urlStr, HttpRequester.GET, props, "admin", "123123", null);
hr.connect();
String inputLine;
while ((inputLine = hr.readLine()) != null) {
System.out.println(inputLine);
}
hr.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
/*
//sample POST
try {
HttpRequester hr = new HttpRequester();
String urlStr = "http://localhost:8010/EventHandler6/rocks.examples.ex1.TestEvent.event";
String paramStr = "parm1=foo&parm2=blah&parm2=boo";
Map props = HttpConverter.cvtURLStringToMap (paramStr, "&");
hr.setRequest (urlStr, HttpRequester.POST, props);
hr.connect();
String inputLine;
while ((inputLine = hr.readLine()) != null) {
System.out.println(inputLine);
}
hr.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
*/
//sample cookie support check - saw_112602.1
try {
HttpRequester hr = new HttpRequester();
hr.setRequest("http://www.psycinfo.com/cookie/set-cookie.cfm", HttpRequester.GET, null);
hr.connect();
String inputLine;
while ((inputLine = hr.readLine()) != null) {
System.out.println(inputLine);
}
hr.disconnect();
hr.setRequest("http://www.psycinfo.com/cookie/check-cookie.cfm", HttpRequester.GET, null);
hr.connect();
while ((inputLine = hr.readLine()) != null) {
System.out.println(inputLine);
}
hr.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
}