package context.arch.comm.protocol; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException; import java.util.logging.Level; import java.util.logging.Logger; import java.io.BufferedReader; import java.io.StringReader; import java.io.InputStreamReader; import java.io.BufferedOutputStream; import java.io.OutputStream; import java.io.DataOutputStream; import java.io.IOException; import context.arch.comm.CommunicationsClient; import context.arch.comm.CommunicationsObject; import context.arch.comm.DataObject; /** * This class subclasses TCPClientSocket, creating and sending HTTP requests. * It implements the CommunicationsClient interface * * @see context.arch.comm.protocol.TCPClientSocket * @see context.arch.comm.CommunicationsClient */ public class HTTPClientSocket extends TCPClientSocket implements CommunicationsClient { private static final Logger LOGGER = Logger.getLogger(HTTPClientSocket.class.getName()); static {LOGGER.setLevel(Level.WARNING);} // this should be set in a configuration file /** * Debug flag. Set to true to see debug messages. */ public static boolean DEBUG = false; /** * The protocol being used is HTTP */ public static final String PROTOCOL = "HTTP"; /** * HTTP GET request type */ public static final String GET = "GET"; /** * HTTP POST request type */ public static final String POST = "POST"; /** * Default port to use is 5555 */ public static final int DEFAULT_PORT = 5555; @SuppressWarnings("unused") private CommunicationsObject commObject; /** * Basic constructor for HTTPClientSocket that calls TCPClientSocket * * @param object Handle of the generic instantiating communications object * @see #DEFAULT_PORT * @see context.arch.comm.protocol.TCPClientSocket */ public HTTPClientSocket(CommunicationsObject object) { super(DEFAULT_PORT); commObject = object; portNumber = DEFAULT_PORT; } /** * Constructor for HTTPClientSocket that calls TCPClientSocket with the * given port * * @param object Handle of the generic instantiating communications object * @param server Hostname of the remote server to connect to * @param port Port to use to receive communications on * @see context.arch.comm.protocol.TCPServerSocket */ public HTTPClientSocket(CommunicationsObject object, String server, Integer port) { super(server, port.intValue()); commObject = object; } /** * This method adds the HTTP protocol for a POST request * (POST is the default) * * @param content The request to send * @return socket for the connection */ public String addRequestProtocol(String data, String url) throws ProtocolException { return addRequestProtocol (data, url, POST); } /** * Method that adds the HTTP protocol to a request message * * @param data Request message to add HTTP protocol to * @param url Tag/URL to add to message * @return the request with the HTTP protocol added * @exception context.arch.comm.protocol.ProtocolException if the protocol * can not be added */ public String addRequestProtocol(String data, String url, String type) throws ProtocolException { int xmlLen = data.length(); String eol = "\r\n"; StringBuffer text = new StringBuffer(); String thisMachine; try { // get our machine name InetAddress thisInet = InetAddress.getLocalHost(); thisMachine = thisInet.getHostName(); } catch (UnknownHostException e) { thisMachine = "localhost"; } xmlLen += 2*eol.length(); // add length of end of lines at the end if (type.equals (POST)) { text.append(POST + " " + url + " HTTP/1.0" + eol); } else { text.append (GET + " " + url + " HTTP/1.0" + eol); } text.append("User-Agent: Context Client" + eol); text.append("Host: " + thisMachine + eol); if (type.equals (POST)) { text.append("Content-Type: text/xml" + eol); text.append("Content-Length: " + xmlLen + eol); text.append(eol); text.append(data + eol); } text.append(eol); //commObject.println("\nHTTPClientSocket : addRequestProtocol\n" + " CONTENT:\n" + text.toString()); return text.toString(); } /** * Method that strips away the HTTP protocol from a reply message * * @param socket Socket on which reply is coming from * @return the reply with the HTTP protocol stripped away * @exception context.arch.comm.protocol.ProtocolException if the protocol * can not be stripped away */ public RequestData stripReplyProtocol(Socket data) throws ProtocolException { BufferedReader bufferedReader = null; try { bufferedReader = new BufferedReader(new InputStreamReader(data.getInputStream())); String get = bufferedReader.readLine(); if (get == null) { // may be because port is open, but in the midst of being shut down by the OS, or used by something else unrelated to the toolkit return null; } // StringTokenizer tokenizer = new StringTokenizer(get); int bytesRead = 0; int bytesReadThisTime = 0; char [] tempdata; String marker = "content-length:"; while (get != null && !get.toLowerCase().startsWith(marker)) { get = bufferedReader.readLine(); //System.out.println("BaseObject get = " + get + ": " + (get == null)); } // get may be null in later lines...don't know why, maybe when there is no network connectivity if (get == null) { return null; } int length = 0; try { length = new Integer(get.substring(marker.length()).trim()).intValue(); } catch (NumberFormatException nfe) { System.out.println("RequestServerSocket run error: "+nfe); throw new ProtocolException(); } if (DEBUG) { System.out.println ("Content-Length is: " + length); } while (!(get.trim().equals(""))) { get = bufferedReader.readLine(); } char[] postdata = new char[length]; tempdata = new char [length]; while (bytesRead < length) { if (bufferedReader.ready()){ int ix = bytesRead; // index to current end of tempdata bytesReadThisTime = bufferedReader.read(postdata, 0, length); // DS: check we've read what we should bytesRead += bytesReadThisTime; if (DEBUG) { System.out.println ("read " + bytesReadThisTime + " more bytes, "+bytesRead); } for (int i = 0; (i < bytesReadThisTime) && (ix + i < length); i++) { tempdata[ix + i] = postdata[i]; } postdata = new char[length]; } } String readerData = new String(tempdata); //if (DEBUG) commObject.println("\nHTTPClientSocket : stripReplyProtocol :" + readerData); StringReader sreader = new StringReader(readerData); return new RequestData(RequestData.DECODE,null,sreader); } catch (IOException ioe) { System.out.println("HTTPClientSocket stripReplyProtocol IOException: "+ioe); throw new ProtocolException(); } catch (Exception e) { // DS, 9/1/98: catch all (the request failed) e.printStackTrace (); System.out.println("HTTPClientSocket stripReplyProtocol Exception: "+e); throw new ProtocolException(); } } /** * This method generates an error message if a request can't * be handled properly, to the point where a contextual error message * can still be sent as the reply. CURRENTLY RETURNS EMPTY DATAOBJECT - * NEEDS WORK (AKD). * * @return error message in the form of a DataObject * @see #getFatalMessage() */ public DataObject getErrorMessage() { return new DataObject(); } /** * This method generates an fatal message if a request can't * be handled properly, to the point where no contextual error message * can be sent as the reply. CURRENTLY RETURNS EMPTY STRING - * NEEDS WORK (AKD). * * @return fatal error message * @see #getErrorMessage() */ public String getFatalMessage() { return new String(""); } /** * This method sends a request to a remote server * * @param content The request to send * @return socket for the connection */ public Socket sendRequest(String content) throws IOException{ OutputStream rawOut = null; String requestToSend = content; //if (content == null) // throw new RPCException("No XML content set for request"); if (DEBUG) { //System.out.println("HTTPClientSocket <sendRequest> about to create socket " + remoteServer + " " + portNumber); System.out.println("HTTPClientSocket <sendRequest> CONTENT is:\n" + requestToSend); } Socket socket = null; try { socket = new Socket(remoteServer, portNumber); } catch (Exception e) { LOGGER.info("HTTPClientSocket <sendRequest> While creating socket in sendRequest (remoteServer = " + remoteServer + ", portNumber = " + portNumber + "): " + e); /* * Socket may be closed because this is trying to connect to an old subscriber (read from a .log file) * but the subscriber no longer exists */ } if (socket != null){ try { rawOut = socket.getOutputStream(); } catch (Exception e) { System.out.println ("While getting OutputStream in sendRequest: " + e); } if (rawOut != null){ BufferedOutputStream buffOut = new BufferedOutputStream(rawOut); DataOutputStream out = new DataOutputStream(buffOut); try { out.writeBytes(content); out.flush(); } catch (Exception e) { System.out.println ("While creating socket in sendRequest: " + e); } } } return socket; } /** * Method to get the communications protocol being used * * @return communications protocol being used * @see #PROTOCOL */ public String getProtocol() { return PROTOCOL; } public String toString(){ return "HTTP client socket port=" + this.portNumber + " - protocol=" + this.getProtocol () + " - server=" + this.getServer (); } }