diff options
Diffstat (limited to 'java/src/com')
-rw-r--r-- | java/src/com/memberwebs/httpauth/HttpAuthConnection.java | 689 |
1 files changed, 391 insertions, 298 deletions
diff --git a/java/src/com/memberwebs/httpauth/HttpAuthConnection.java b/java/src/com/memberwebs/httpauth/HttpAuthConnection.java index 823209c..8a8029c 100644 --- a/java/src/com/memberwebs/httpauth/HttpAuthConnection.java +++ b/java/src/com/memberwebs/httpauth/HttpAuthConnection.java @@ -6,16 +6,16 @@ * modification, are permitted provided that the following conditions * are met: * - * * Redistributions of source code must retain the above - * copyright notice, this list of conditions and the - * following disclaimer. - * * Redistributions in binary form must reproduce the - * above copyright notice, this list of conditions and - * the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * * The names of contributors to this software may not be - * used to endorse or promote products derived from this - * software without specific prior written permission. + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the + * above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * * The names of contributors to this software may not be + * used to endorse or promote products derived from this + * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT @@ -43,6 +43,7 @@ import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.Writer; +import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketException; @@ -56,293 +57,385 @@ import java.util.Map; * @author Stef Walter */ public class HttpAuthConnection - implements HttpAuthConnectionSource + implements HttpAuthConnectionSource { - /** - * The option to set the authenticaton handler. - */ - public static final String OPT_HANDLER = "Handler"; - - /** - * The option to set the digest domains. - */ - public static final String OPT_DOMAIN = "Domain"; - - private Writer m_output; - private BufferedReader m_input; - private Socket m_socket; - private boolean m_checkedout; - - /** - * Connects to the HttpAuth daemon at the given address and port. The - * appropriate handler is set. - * - * @param hostname The address where the HttpAuth daemon is running. - * @param port The TCP port for the HttpAuth daemon. - * @param handler The HttpAuth handler to use. - */ - public void open(String hostname, int port, String handler) - throws IOException, HttpAuthException - { - HashMap options = new HashMap(); - options.put(OPT_HANDLER, handler); - open(hostname, port, options); - } - - /** - * Connects to the HttpAuth daemon at the given address and port. Various - * options (including the handler) can be set. - * - * @param hostname The address where the HttpAuth daemon is running. - * @param port The TCP port for the HttpAuth daemon. - * @param options The HttpAuth options to use. This must include {@link #OPT_HANDLER}. - */ - public void open(String hostname, int port, Map options) - throws IOException, HttpAuthException - { - synchronized(this) - { - close(); - - m_socket = new Socket(); - m_socket.connect(new InetSocketAddress(hostname, port), 60000); - - m_input = new BufferedReader(new InputStreamReader(m_socket.getInputStream())); - m_output = new OutputStreamWriter(m_socket.getOutputStream()); - - // Okay now read the version number - Response ver = readResponse(100); - if(!ver.details.trim().equals("HTTPAUTH/1.0")) - throw new HttpAuthException("httpauthd speaking wrong version of protocol: " + ver.details); - - // Set any options as necessary - Iterator it = options.keySet().iterator(); - while(it.hasNext()) - { - String name = (String)it.next(); - String value = (String)options.get(name); - - // Set the options request - sendLine("SET " + name + " " + value); - - // This throws an exception if we don't get the right response - readResponse(202); - } - } - } - - /** - * Closes the connection to the HttpAuth daemon. - */ - public void close() - throws IOException - { - synchronized(this) - { - if(m_socket != null && m_output != null) - { - try - { - sendLine("QUIT"); - } - catch(IOException e) - { - } - } - - if(m_output != null) - { - m_output.close(); - m_output = null; - } - - if(m_input != null) - { - m_input.close(); - m_input = null; - } - - if(m_socket != null) - { - m_socket.close(); - m_socket = null; - } - } - } - - /** - * Checks whether we're connected to the HttpAuth daemon. - */ - public boolean isConnected() - { - return m_socket != null && m_socket.isConnected() - && m_input != null && m_output != null; - } - - /** - * Sends a command string to the HttpAuth daemon. - * - * @param string The command to send. - */ - public void sendLine(String string) - throws IOException - { - synchronized(this) - { - m_output.write(string + "\n"); - m_output.flush(); - } - } - - /** - * Reads a response line from the HttpAuth daemon. - * - * @return The response line. - */ - public String readLine() - throws IOException - { - synchronized(this) - { - return m_input.readLine(); - } - } - - /* --------------------------------------------------------------------------- - * HttpAuthConnectionSource - * - * This is a simple implementation which allows a single connection - * to be used in leu of a connection pool. - */ - - /** - * Treats this single connection as a pool. Checks out the current - * connection. Use {@link HttpAuthConnectionPool} instead. - * @return The connection. - */ - public HttpAuthConnection getOpenConnection() - throws HttpAuthException - { - synchronized(this) - { - if(!isConnected() && !m_checkedout) - return null; - - m_checkedout = true; - return this; - } - } - - /** - * Treats this single connection as a pool. Checks in the current - * connection. Use {@link HttpAuthConnectionPool} instead. - * @param conn The connection. - */ - public void doneWithConnection(HttpAuthConnection conn) - throws HttpAuthException - { - synchronized(this) - { - m_checkedout = false; - } - } - - // ----------------------------------------------------------------------------- - // Helper functions - - protected Response readResponse(int expected) - throws HttpAuthException, IOException - { - Response resp = new Response(); - String line = readLine(); - - if(line == null) - throw new SocketException("Broken Pipe: unexpected end of data from httpauthd"); - - String word = parseWord(line); - line = line.substring(word.length()); - word = word.trim(); - - try - { - int code = Integer.parseInt(word, 10); - if(code < 100 || code > 599) - throw new NumberFormatException(); - - resp.code = code; - } - catch(NumberFormatException e) - { - throw new HttpAuthException("httpauth protocol error. invalid code received: " + word); - } - - if(expected != 0 && resp.code != expected) - throw new HttpAuthException("httpauth protocol error. expected code '" + expected + "' and got: " + resp.code); - - if(resp.code == 200) - { - word = parseWord(line); - line = line.substring(word.length()).trim(); - word = word.trim(); - - try - { - int code = Integer.parseInt(word, 10); - if(code < 100 || code > 599) - throw new NumberFormatException(); - - resp.ccode = code; - } - catch(NumberFormatException e) - { - throw new HttpAuthException("httpauth protocol error. invalid code received: " + word); - } - } - - if(line.length() > 0) - resp.details = line; - - return resp; - } - - protected String parseWord(String line) - { - int start = -1; - int end; - char ch; - - while(true) - { - if(++start >= line.length()) - return ""; - - ch = line.charAt(start); - if(ch != ' ' && ch != '\t') - break; - } - - end = start - 1; - - while(true) - { - if(++end >= line.length()) - break; - - ch = line.charAt(end); - if(ch == ' ' || ch == '\t') - break; - } - - if(end == -1) - return ""; - - return line.substring(0, end); - } - - class Response - { - int code; - int ccode; - String details; - }; + /** + * The option to set the authenticaton handler. + */ + public static final String OPT_HANDLER = "Handler"; + + /** + * The option to set the digest domains. + */ + public static final String OPT_DOMAIN = "Domain"; + + private Writer m_output; + private BufferedReader m_input; + private Socket m_socket; + private boolean m_checkedout; + private boolean m_isPristine = true; + + /** + * Connects to the HttpAuth daemon at the given address and port. The + * appropriate handler is set. + * + * @param address The address where the HttpAuth daemon is running. + * @param port The TCP port for the HttpAuth daemon. + * @param handler The HttpAuth handler to use. + */ + public void open(InetAddress address, int port, String handler) + throws IOException, HttpAuthException + { + HashMap options = new HashMap(); + options.put(OPT_HANDLER, handler); + open(address, port, options); + } + + /** + * Connects to the HttpAuth daemon at the given address and port. The + * appropriate handler is set. + * + * @param hostname The address where the HttpAuth daemon is running. + * @param port The TCP port for the HttpAuth daemon. + * @param handler The HttpAuth handler to use. + */ + public void open(String hostname, int port, String handler) + throws IOException, HttpAuthException + { + HashMap options = new HashMap(); + options.put(OPT_HANDLER, handler); + open(InetAddress.getByName(hostname), port, options); + } + + /** + * Connects to the HttpAuth daemon at the given address and port. Various + * options (including the handler) can be set. + * + * @param hostname The address where the HttpAuth daemon is running. + * @param port The TCP port for the HttpAuth daemon. + * @param options The HttpAuth options to use. This must include {@link #OPT_HANDLER}. + */ + public void open(String hostname, int port, Map options) + throws IOException, HttpAuthException + { + open(InetAddress.getByName(hostname), port, options); + } + + /** + * Connects to the HttpAuth daemon at the given address and port. Various + * options (including the handler) can be set. + * + * @param address The address where the HttpAuth daemon is running. + * @param port The TCP port for the HttpAuth daemon. + * @param options The HttpAuth options to use. This must include {@link #OPT_HANDLER}. + */ + public void open(InetAddress address, int port, Map options) + throws IOException, HttpAuthException + { + synchronized(this) + { + try + { + close(); + + m_isPristine = true; + m_socket = new Socket(); + m_socket.connect(new InetSocketAddress(address, port), 60000); + + m_input = new BufferedReader(new InputStreamReader(m_socket.getInputStream())); + m_output = new OutputStreamWriter(m_socket.getOutputStream()); + + // Okay now read the version number + Response ver = readResponse(100); + if(!ver.details.trim().equals("HTTPAUTH/1.0")) + throw new HttpAuthException("httpauthd speaking wrong version of protocol: " + ver.details); + + // Set any options as necessary + Iterator it = options.keySet().iterator(); + while(it.hasNext()) + { + String name = (String)it.next(); + String value = (String)options.get(name); + + // Set the options request + sendLine("SET " + name + " " + value); + + // This throws an exception if we don't get the right response + readResponse(202); + } + } + catch(HttpAuthException ex) + { + m_isPristine = false; + throw ex; + } + catch(IOException ex) + { + m_isPristine = false; + throw ex; + } + } + } + + /** + * Closes the connection to the HttpAuth daemon. + */ + public void close() + throws IOException + { + synchronized(this) + { + if(m_socket != null && m_output != null) + { + try + { + sendLine("QUIT"); + } + catch(IOException e) + { + m_isPristine = false; + } + } + + try + { + if(m_output != null) + { + m_output.close(); + m_output = null; + } + + if(m_input != null) + { + m_input.close(); + m_input = null; + } + + if(m_socket != null) + { + m_socket.close(); + m_socket = null; + } + } + catch(IOException ex) + { + m_isPristine = false; + throw ex; + } + } + } + + /** + * Checks whether we're connected to the HttpAuth daemon. + */ + public boolean isConnected() + { + return m_socket != null && m_socket.isConnected() && + m_input != null && m_output != null; + } + + /** + * Checks whether the connection has had errors. + */ + public boolean isPristine() + { + return m_isPristine; + } + + + /** + * Sends a command string to the HttpAuth daemon. + * + * @param string The command to send. + */ + public void sendLine(String string) + throws IOException + { + synchronized(this) + { + try + { + m_output.write(string + "\n"); + m_output.flush(); + } + catch(IOException ex) + { + m_isPristine = false; + throw ex; + } + } + } + + /** + * Reads a response line from the HttpAuth daemon. + * + * @return The response line. + */ + public String readLine() + throws IOException + { + synchronized(this) + { + try + { + return m_input.readLine(); + } + catch(IOException ex) + { + m_isPristine = false; + throw ex; + } + } + } + + /* --------------------------------------------------------------------------- + * HttpAuthConnectionSource + * + * This is a simple implementation which allows a single connection + * to be used in leu of a connection pool. + */ + + /** + * Treats this single connection as a pool. Checks out the current + * connection. Use {@link HttpAuthConnectionPool} instead. + * @return The connection. + */ + public HttpAuthConnection getOpenConnection() + throws HttpAuthException + { + synchronized(this) + { + if(!isConnected() && !m_checkedout) + return null; + + m_checkedout = true; + return this; + } + } + + /** + * Treats this single connection as a pool. Checks in the current + * connection. Use {@link HttpAuthConnectionPool} instead. + * @param conn The connection. + */ + public void doneWithConnection(HttpAuthConnection conn) + throws HttpAuthException + { + synchronized(this) + { + m_checkedout = false; + } + } + + // ----------------------------------------------------------------------------- + // Helper functions + + protected Response readResponse(int expected) + throws HttpAuthException, IOException + { + try + { + Response resp = new Response(); + String line = readLine(); + + if(line == null) + throw new SocketException("Broken Pipe: unexpected end of data from httpauthd"); + + String word = parseWord(line); + line = line.substring(word.length()); + word = word.trim(); + + try + { + int code = Integer.parseInt(word, 10); + if(code < 100 || code > 599) + throw new NumberFormatException(); + + resp.code = code; + } + catch(NumberFormatException e) + { + throw new HttpAuthException("httpauth protocol error. invalid code received: " + word); + } + + if(expected != 0 && resp.code != expected) + throw new HttpAuthException("httpauth protocol error. expected code '" + expected + "' and got: " + resp.code); + + if(resp.code == 200) + { + word = parseWord(line); + line = line.substring(word.length()).trim(); + word = word.trim(); + + try + { + int code = Integer.parseInt(word, 10); + if(code < 100 || code > 599) + throw new NumberFormatException(); + + resp.ccode = code; + } + catch(NumberFormatException e) + { + throw new HttpAuthException("httpauth protocol error. invalid code received: " + word); + } + } + + if(line.length() > 0) + resp.details = line; + + return resp; + } + catch(HttpAuthException ex) + { + m_isPristine = false; + throw ex; + } + catch(IOException ex) + { + m_isPristine = false; + throw ex; + } + } + + protected String parseWord(String line) + { + int start = -1; + int end; + char ch; + + while(true) + { + if(++start >= line.length()) + return ""; + + ch = line.charAt(start); + if(ch != ' ' && ch != '\t') + break; + } + + end = start - 1; + + while(true) + { + if(++end >= line.length()) + break; + + ch = line.charAt(end); + if(ch == ' ' || ch == '\t') + break; + } + + if(end == -1) + return ""; + + return line.substring(0, end); + } + + class Response + { + int code; + int ccode; + String details; + }; } |