diff options
Diffstat (limited to 'base/util/src/com/netscape/cmsutil/http')
9 files changed, 985 insertions, 0 deletions
diff --git a/base/util/src/com/netscape/cmsutil/http/ConnectAsync.java b/base/util/src/com/netscape/cmsutil/http/ConnectAsync.java new file mode 100644 index 000000000..ca230ca21 --- /dev/null +++ b/base/util/src/com/netscape/cmsutil/http/ConnectAsync.java @@ -0,0 +1,46 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmsutil.http; + +import java.net.SocketException; + +import com.netscape.cmsutil.net.ISocketFactory; + +public class ConnectAsync extends Thread { + String host = null; + int port = 0; + ISocketFactory obj = null; + + public ConnectAsync(ISocketFactory sock, String host, int port) { + super(); + this.host = host; + this.port = port; + this.obj = sock; + setName("ConnectAsync"); + } + + public void run() { + try { + obj.makeSocket(host, port); + } catch (SocketException e) { + // Stop throwing exception + } catch (Exception e) { + // Stop throwing exception + } + } +} diff --git a/base/util/src/com/netscape/cmsutil/http/Http.java b/base/util/src/com/netscape/cmsutil/http/Http.java new file mode 100644 index 000000000..2cda7fd12 --- /dev/null +++ b/base/util/src/com/netscape/cmsutil/http/Http.java @@ -0,0 +1,31 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmsutil.http; + +public class Http { + public static final String HttpVers = "HTTP/1.0"; + + public static final String Vers1_0 = "HTTP/1.0"; + public static final String Vers1_1 = "HTTP/1.1"; + public static final String CRLF = "\r\n"; + + public static final char CR = '\r'; + public static final char LF = '\n'; + public static final char SP = ' '; + +} diff --git a/base/util/src/com/netscape/cmsutil/http/HttpClient.java b/base/util/src/com/netscape/cmsutil/http/HttpClient.java new file mode 100644 index 000000000..438c70c23 --- /dev/null +++ b/base/util/src/com/netscape/cmsutil/http/HttpClient.java @@ -0,0 +1,217 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmsutil.http; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.net.Socket; + +import org.mozilla.jss.ssl.SSLCertificateApprovalCallback; + +import com.netscape.cmsutil.net.ISocketFactory; + +/** + * basic http client. + * not optimized for performance. + * handles only string content. + */ +public class HttpClient { + protected ISocketFactory mFactory = null; + + protected Socket mSocket = null; + protected InputStream mInputStream = null; + protected OutputStream mOutputStream = null; + + protected InputStreamReader mInputStreamReader = null; + protected OutputStreamWriter mOutputStreamWriter = null; + protected BufferedReader mBufferedReader = null; + protected SSLCertificateApprovalCallback mCertApprovalCallback = null; + protected boolean mConnected = false; + + public HttpClient() { + } + + public HttpClient(ISocketFactory factory) { + mFactory = factory; + } + + public HttpClient(ISocketFactory factory, SSLCertificateApprovalCallback certApprovalCallback) { + mFactory = factory; + mCertApprovalCallback = certApprovalCallback; + } + + public void connect(String host, int port) + throws IOException { + if (mFactory != null) { + if (mCertApprovalCallback == null) { + mSocket = mFactory.makeSocket(host, port); + } else { + mSocket = mFactory.makeSocket(host, port, mCertApprovalCallback, null); + } + } else { + mSocket = new Socket(host, port); + } + + if (mSocket == null) { + IOException e = new IOException("Couldn't make connection"); + + throw e; + } + + mInputStream = mSocket.getInputStream(); + mOutputStream = mSocket.getOutputStream(); + mInputStreamReader = new InputStreamReader(mInputStream, "UTF8"); + mBufferedReader = new BufferedReader(mInputStreamReader); + mOutputStreamWriter = new OutputStreamWriter(mOutputStream, "UTF8"); + mConnected = true; + } + + // Inserted by beomsuk + public void connect(String host, int port, int timeout) + throws IOException { + if (mFactory != null) { + mSocket = mFactory.makeSocket(host, port, timeout); + } else { + mSocket = new Socket(host, port); + } + + if (mSocket == null) { + IOException e = new IOException("Couldn't make connection"); + + throw e; + } + + mInputStream = mSocket.getInputStream(); + mOutputStream = mSocket.getOutputStream(); + mInputStreamReader = new InputStreamReader(mInputStream, "UTF8"); + mBufferedReader = new BufferedReader(mInputStreamReader); + mOutputStreamWriter = new OutputStreamWriter(mOutputStream, "UTF8"); + mConnected = true; + } + + // Insert end + public boolean connected() { + return mConnected; + } + + /** + * Sends a request to http server. + * Returns a http response. + */ + public HttpResponse send(HttpRequest request) + throws IOException { + HttpResponse resp = new HttpResponse(); + + if (mOutputStream == null) + throw new IOException("Output stream not initialized"); + request.write(mOutputStreamWriter); + try { + resp.parse(mBufferedReader); + } catch (IOException e) { + // XXX should we disconnect in all cases ? + disconnect(); + throw e; + } + disconnect(); + return resp; + } + + public void disconnect() + throws IOException { + mSocket.close(); + mInputStream = null; + mOutputStream = null; + mConnected = false; + } + + public InputStream getInputStream() { + return mInputStream; + } + + public OutputStream getOutputStream() { + return mOutputStream; + } + + public BufferedReader getBufferedReader() { + return mBufferedReader; + } + + public InputStreamReader getInputStreamReader() { + return mInputStreamReader; + } + + public OutputStreamWriter getOutputStreamWriter() { + return mOutputStreamWriter; + } + + public Socket getSocket() { + return mSocket; + } + + /** + * unit test + */ + public static void main(String args[]) + throws Exception { + HttpClient c = new HttpClient(); + HttpRequest req = new HttpRequest(); + HttpResponse resp = null; + + System.out.println("connecting to " + args[0] + " " + args[1]); + c.connect(args[0], Integer.parseInt(args[1])); + + req.setMethod("GET"); + req.setURI(args[2]); + if (args.length >= 4) + req.setHeader("Connection", args[3]); + resp = c.send(req); + + System.out.println("version " + resp.getHttpVers()); + System.out.println("status code " + resp.getStatusCode()); + System.out.println("reason " + resp.getReasonPhrase()); + System.out.println("content " + resp.getContent()); + + //String lenstr = resp.getHeader("Content-Length"); + //System.out.println("content len is "+lenstr); + //int length = Integer.parseInt(lenstr); + //char[] content = new char[length]; + //c.mBufferedReader.read(content, 0, content.length); + //System.out.println(content); + + if (args.length >= 4 && args[3].equalsIgnoreCase("keep-alive")) { + for (int i = 0; i < 2; i++) { + if (i == 1) + req.setHeader("Connection", "Close"); + resp = c.send(req); + System.out.println("version " + resp.getHttpVers()); + System.out.println("status code " + resp.getStatusCode()); + System.out.println("reason " + resp.getReasonPhrase()); + System.out.println("content " + resp.getContent()); + //len = Integer.parseInt(resp.getHeader("Content-Length")); + //System.out.println("content len is "+len); + //msgbody = new char[len]; + //c.mBufferedReader.read(msgbody, 0, len); + //System.out.println(content); + } + } + } +} diff --git a/base/util/src/com/netscape/cmsutil/http/HttpEofException.java b/base/util/src/com/netscape/cmsutil/http/HttpEofException.java new file mode 100644 index 000000000..824b9ea2a --- /dev/null +++ b/base/util/src/com/netscape/cmsutil/http/HttpEofException.java @@ -0,0 +1,35 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmsutil.http; + +import java.io.IOException; + +public class HttpEofException extends IOException { + /** + * + */ + private static final long serialVersionUID = 433303354049669059L; + + public HttpEofException() { + super(); + } + + public HttpEofException(String msg) { + super(msg); + } +} diff --git a/base/util/src/com/netscape/cmsutil/http/HttpMessage.java b/base/util/src/com/netscape/cmsutil/http/HttpMessage.java new file mode 100644 index 000000000..badec5930 --- /dev/null +++ b/base/util/src/com/netscape/cmsutil/http/HttpMessage.java @@ -0,0 +1,163 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmsutil.http; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.util.Enumeration; +import java.util.Hashtable; + +/** + * Basic HTTP Message, excluding message body. + * Not optimized for performance. + * Set fields or parse from input. + */ +public class HttpMessage { + protected String mLine = null; // request or response line. + protected Hashtable<String, String> mHeaders = null; + protected String mContent = null; // arbitrary content chars assumed. + + /** + * Instantiate a HttpResponse for write to http client. + */ + public HttpMessage() { + mHeaders = new Hashtable<String, String>(); + } + + /** + * Set a header field. <br> + * Content-length is automatically set on write.<br> + * If value spans multiple lines must be in proper http format for + * multiple lines. + */ + public void setHeader(String name, String value) { + if (mHeaders == null) + mHeaders = new Hashtable<String, String>(); + mHeaders.put(name.toLowerCase(), value); + } + + /** + * get a header + */ + public String getHeader(String name) { + return (String) mHeaders.get(name.toLowerCase()); + } + + /** + * write http headers + * does not support values of more than one line + */ + public void writeHeaders(OutputStreamWriter writer) + throws IOException { + if (mHeaders != null) { + Enumeration<String> keys = mHeaders.keys(); + String header, value; + + while (keys.hasMoreElements()) { + header = keys.nextElement(); + value = mHeaders.get(header); + writer.write(header + ":" + value + Http.CRLF); + } + } + writer.write(Http.CRLF); // end with CRLF line. + } + + /** + * read http headers. + * does not support values of more than one line or multivalue headers. + */ + public void readHeaders(BufferedReader reader) + throws IOException { + mHeaders = new Hashtable<String, String>(); + + int colon; + String line, key, value; + + while (true) { + line = reader.readLine(); + if (line == null || line.equals("")) + break; + colon = line.indexOf(':'); + if (colon == -1) { + mHeaders = null; + throw new HttpProtocolException("Bad Http header format"); + } + key = line.substring(0, colon); + value = line.substring(colon + 1); + mHeaders.put(key.toLowerCase(), value.trim()); + } + } + + public void write(OutputStreamWriter writer) + throws IOException { + writer.write(mLine + Http.CRLF); + writeHeaders(writer); + writer.flush(); + if (mContent != null) { + writer.write(mContent); + } + writer.flush(); + } + + public void parse(BufferedReader reader) + throws IOException { + String line = reader.readLine(); + + // if (line == null) { + // throw new HttpEofException("End of stream reached"); + // } + if (line.equals("")) { + throw new HttpProtocolException("Bad Http req/resp line " + line); + } + mLine = line; + readHeaders(reader); + + // won't work if content length is not set. + String lenstr = mHeaders.get("content-length"); + + if (lenstr != null) { + int len = Integer.parseInt(lenstr); + char[] cbuf = new char[len]; + int done = reader.read(cbuf, 0, cbuf.length); + int total = done; + + while (done >= 0 && total < len) { + done = reader.read(cbuf, total, len - total); + total += done; + } + + mContent = new String(cbuf); + } + } + + public void reset() { + mLine = null; + mHeaders = null; + mContent = null; + } + + public void setContent(String content) { + mContent = content; + } + + public String getContent() { + return mContent; + } + +} diff --git a/base/util/src/com/netscape/cmsutil/http/HttpProtocolException.java b/base/util/src/com/netscape/cmsutil/http/HttpProtocolException.java new file mode 100644 index 000000000..b5ceb1d7f --- /dev/null +++ b/base/util/src/com/netscape/cmsutil/http/HttpProtocolException.java @@ -0,0 +1,35 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmsutil.http; + +import java.io.IOException; + +public class HttpProtocolException extends IOException { + /** + * + */ + private static final long serialVersionUID = -953002842302351684L; + + public HttpProtocolException() { + super(); + } + + public HttpProtocolException(String msg) { + super(msg); + } +} diff --git a/base/util/src/com/netscape/cmsutil/http/HttpRequest.java b/base/util/src/com/netscape/cmsutil/http/HttpRequest.java new file mode 100644 index 000000000..9024dabf0 --- /dev/null +++ b/base/util/src/com/netscape/cmsutil/http/HttpRequest.java @@ -0,0 +1,137 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmsutil.http; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.OutputStreamWriter; + +/** + * Basic HTTP Request. not optimized for performance. + * Set fields or parse from input. + * Handles text content. + */ +public class HttpRequest extends HttpMessage { + public static final String GET = "GET"; + public static final String POST = "POST"; + public static final String HEAD = "HEAD"; + + protected String mMethod = null; + protected String mURI = null; + protected String mHttpVers = null; + + /** + * Instantiate a HttpResponse for write to http client. + */ + public HttpRequest() { + super(); + } + + /** + * set set request method. + */ + public void setMethod(String method) + throws HttpProtocolException { + if (!method.equals(GET) && !method.equals(HEAD) && + !method.equals(POST)) + throw new HttpProtocolException("No such method " + method); + mMethod = method; + } + + /** + * set reason phrase. + */ + public void setURI(String uri) { + mURI = uri; + } + + /** + * write request to the http client + */ + public void write(OutputStreamWriter writer) + throws IOException { + if (mMethod == null || mURI == null) { + HttpProtocolException e = new HttpProtocolException( + "Http request method or uri not initialized"); + + //e.printStackTrace(); + throw e; + } + + mLine = mMethod + " " + mURI + " " + Http.HttpVers; + super.write(writer); + } + + /** + * parse a http request from a http client + */ + public void parse(BufferedReader reader) + throws IOException { + super.parse(reader); + + int method = mLine.indexOf(Http.SP); + + mMethod = mLine.substring(0, method); + if (!mMethod.equals(GET) && !mMethod.equals(POST) && + !mMethod.equals(HEAD)) { + reset(); + throw new HttpProtocolException("Bad Http request method"); + } + + int uri = mLine.lastIndexOf(Http.SP); + + mURI = mLine.substring(method + 1, uri); + + mHttpVers = mLine.substring(uri + 1); + if (!mHttpVers.equals("")) { + if (!mHttpVers.equals(Http.Vers1_0) && + !mHttpVers.equals(Http.Vers1_1)) { + reset(); + throw new HttpProtocolException("Bad Http version in request"); + } + } + } + + public void reset() { + mMethod = null; + mURI = null; + mHttpVers = null; + super.reset(); + } + + /** + * get method + */ + public String getMethod() { + return mMethod; + } + + /** + * get reason phrase + */ + public String getURI() { + return mURI; + } + + /** + * get http version + */ + public String getHttpVers() { + return mHttpVers; + } +} diff --git a/base/util/src/com/netscape/cmsutil/http/HttpResponse.java b/base/util/src/com/netscape/cmsutil/http/HttpResponse.java new file mode 100644 index 000000000..7ac7e2f69 --- /dev/null +++ b/base/util/src/com/netscape/cmsutil/http/HttpResponse.java @@ -0,0 +1,139 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmsutil.http; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.OutputStreamWriter; + +/** + * Basic HTTP Response. + * Set fields or parse from input. + * Handles only text content. + */ +public class HttpResponse extends HttpMessage { + protected String mStatusCode = null; + protected String mReasonPhrase = null; + protected String mHttpVers = null; + + /** + * Instantiate a HttpResponse for write to http client. + */ + public HttpResponse() { + super(); + } + + /** + * set status code of response + */ + public void setStatusCode(int code) { + mStatusCode = String.valueOf(code); + } + + /** + * set reason phrase. + */ + public void setReasonPhrase(String phrase) { + mReasonPhrase = phrase; + } + + /** + * get status code + */ + public String getStatusCode() { + return mStatusCode; + } + + /** + * get reason phrase + */ + public String getReasonPhrase() { + return mReasonPhrase; + } + + /** + * write the response out to the http client + */ + public void write(OutputStreamWriter writer) + throws IOException { + if (mStatusCode == null) { + throw new HttpProtocolException("status code not set in response"); + } + // write status-line + mLine = Http.HttpVers + " " + mStatusCode + " "; + if (mReasonPhrase != null) + mLine += mReasonPhrase; + mLine += Http.CRLF; + super.write(writer); + } + + /** + * parse a http response from a http server + */ + public void parse(BufferedReader reader) + throws IOException { + mHttpVers = null; + mStatusCode = null; + mReasonPhrase = null; + + super.parse(reader); + + int httpvers = mLine.indexOf(' '); + + if (httpvers == -1) { + reset(); + throw new HttpProtocolException("no Http version in response"); + } + mHttpVers = mLine.substring(0, httpvers); + if (!mHttpVers.equals(Http.Vers1_0) && + !mHttpVers.equals(Http.Vers1_1)) { + reset(); + throw new HttpProtocolException("Bad Http version in response"); + } + + int code = mLine.indexOf(' ', httpvers + 1); + + if (code == -1) { + reset(); + throw new HttpProtocolException("no status code in response"); + } + mStatusCode = mLine.substring(httpvers + 1, code); + try { + Integer.parseInt(mStatusCode); + } catch (NumberFormatException e) { + reset(); + throw new HttpProtocolException("Bad status code in response"); + } + + mReasonPhrase = mLine.substring(code + 1); + } + + public void reset() { + mStatusCode = null; + mHttpVers = null; + mReasonPhrase = null; + super.reset(); + } + + /** + * get http version + */ + public String getHttpVers() { + return mHttpVers; + } +} diff --git a/base/util/src/com/netscape/cmsutil/http/JssSSLSocketFactory.java b/base/util/src/com/netscape/cmsutil/http/JssSSLSocketFactory.java new file mode 100644 index 000000000..c2013a5d2 --- /dev/null +++ b/base/util/src/com/netscape/cmsutil/http/JssSSLSocketFactory.java @@ -0,0 +1,182 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmsutil.http; + +import java.io.IOException; +import java.net.Socket; +import java.net.SocketException; +import java.net.UnknownHostException; + +import org.mozilla.jss.CryptoManager; +import org.mozilla.jss.ssl.SSLCertificateApprovalCallback; +import org.mozilla.jss.ssl.SSLClientCertificateSelectionCallback; +import org.mozilla.jss.ssl.SSLHandshakeCompletedEvent; +import org.mozilla.jss.ssl.SSLHandshakeCompletedListener; +import org.mozilla.jss.ssl.SSLSocket; + +import com.netscape.cmsutil.net.ISocketFactory; + +/** + * Uses NSS ssl socket. + * + * @version $Revision$ $Date$ + */ +public class JssSSLSocketFactory implements ISocketFactory { + private String mClientAuthCertNickname = null; + private SSLSocket s = null; + + public JssSSLSocketFactory() { + } + + public JssSSLSocketFactory(String certNickname) { + mClientAuthCertNickname = certNickname; + } + + // XXX remove these static SSL cipher suite initializations later on. + static final int cipherSuites[] = { + SSLSocket.SSL3_RSA_WITH_RC4_128_MD5, + SSLSocket.SSL3_RSA_WITH_3DES_EDE_CBC_SHA, + SSLSocket.SSL3_RSA_WITH_DES_CBC_SHA, + SSLSocket.SSL3_RSA_EXPORT_WITH_RC4_40_MD5, + SSLSocket.SSL3_RSA_EXPORT_WITH_RC2_CBC_40_MD5, + SSLSocket.SSL3_RSA_WITH_NULL_MD5, + SSLSocket.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + SSLSocket.TLS_RSA_WITH_AES_128_CBC_SHA, + SSLSocket.TLS_RSA_WITH_AES_256_CBC_SHA, + SSLSocket.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, + SSLSocket.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + //SSLSocket.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, + //SSLSocket.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + //SSLSocket.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + SSLSocket.TLS_DHE_DSS_WITH_AES_128_CBC_SHA, + SSLSocket.TLS_DHE_DSS_WITH_AES_256_CBC_SHA, + SSLSocket.TLS_DHE_RSA_WITH_AES_128_CBC_SHA, + SSLSocket.TLS_DHE_RSA_WITH_AES_256_CBC_SHA, + 0 + }; + + static { + int i; + + for (i = SSLSocket.SSL2_RC4_128_WITH_MD5; i <= SSLSocket.SSL2_RC2_128_CBC_EXPORT40_WITH_MD5; ++i) { + try { + SSLSocket.setCipherPreferenceDefault(i, false); + } catch (SocketException e) { + } + } + + //skip SSL_EN_IDEA_128_EDE3_CBC_WITH_MD5 + for (i = SSLSocket.SSL2_DES_64_CBC_WITH_MD5; i <= SSLSocket.SSL2_DES_192_EDE3_CBC_WITH_MD5; ++i) { + try { + SSLSocket.setCipherPreferenceDefault(i, false); + } catch (SocketException e) { + } + } + for (i = 0; cipherSuites[i] != 0; ++i) { + try { + SSLSocket.setCipherPreferenceDefault(cipherSuites[i], true); + } catch (SocketException e) { + } + } + } + + public Socket makeSocket(String host, int port) + throws IOException, UnknownHostException { + return makeSocket(host, port, null, null); + } + + public Socket makeSocket(String host, int port, + SSLCertificateApprovalCallback certApprovalCallback, + SSLClientCertificateSelectionCallback clientCertCallback) + throws IOException, UnknownHostException { + + try { + s = new SSLSocket(host, port, null, 0, certApprovalCallback, + clientCertCallback); + for (int i = 0; cipherSuites[i] != 0; ++i) { + try { + SSLSocket.setCipherPreferenceDefault(cipherSuites[i], true); + } catch (SocketException e) { + } + } + + s.setUseClientMode(true); + s.enableSSL2(false); + //TODO Do we rally want to set the default each time? + SSLSocket.enableSSL2Default(false); + s.enableV2CompatibleHello(false); + + SSLHandshakeCompletedListener listener = null; + + listener = new ClientHandshakeCB(this); + s.addHandshakeCompletedListener(listener); + + if (mClientAuthCertNickname != null) { + // 052799 setClientCertNickname does not + // report error if the nickName is invalid. + // So we check this ourself using + // findCertByNickname + CryptoManager.getInstance().findCertByNickname(mClientAuthCertNickname); + + s.setClientCertNickname(mClientAuthCertNickname); + } + s.forceHandshake(); + } catch (org.mozilla.jss.crypto.ObjectNotFoundException e) { + throw new IOException(e.toString()); + } catch (org.mozilla.jss.crypto.TokenException e) { + throw new IOException(e.toString()); + } catch (UnknownHostException e) { + throw e; + } catch (IOException e) { + throw e; + } catch (Exception e) { + throw new IOException(e.toString()); + } + return s; + } + + public Socket makeSocket(String host, int port, int timeout) + throws IOException, UnknownHostException { + Thread t = new ConnectAsync(this, host, port); + + t.start(); + try { + t.join(1000 * timeout); + } catch (InterruptedException e) { + } + + if (t.isAlive()) { + } + + return s; + } + + public void log(int level, String msg) { + } + + class ClientHandshakeCB implements SSLHandshakeCompletedListener { + Object sc; + + public ClientHandshakeCB(Object sc) { + this.sc = sc; + } + + public void handshakeCompleted(SSLHandshakeCompletedEvent event) { + } + } +} |