diff options
Diffstat (limited to 'bundles/org.eclipse.wst.wsi/src/org/eclipse/wst/wsi/internal/core/monitor/SocketHandler.java')
-rw-r--r-- | bundles/org.eclipse.wst.wsi/src/org/eclipse/wst/wsi/internal/core/monitor/SocketHandler.java | 963 |
1 files changed, 0 insertions, 963 deletions
diff --git a/bundles/org.eclipse.wst.wsi/src/org/eclipse/wst/wsi/internal/core/monitor/SocketHandler.java b/bundles/org.eclipse.wst.wsi/src/org/eclipse/wst/wsi/internal/core/monitor/SocketHandler.java deleted file mode 100644 index 8a38a2645..000000000 --- a/bundles/org.eclipse.wst.wsi/src/org/eclipse/wst/wsi/internal/core/monitor/SocketHandler.java +++ /dev/null @@ -1,963 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2002-2003 IBM Corporation, Beacon Information Technology Inc. and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM - Initial API and implementation - * BeaconIT - Initial API and implementation - *******************************************************************************/ -package org.eclipse.wst.wsi.internal.core.monitor; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InterruptedIOException; -import java.io.OutputStream; -import java.io.UnsupportedEncodingException; -import java.net.Socket; - -import org.eclipse.wst.wsi.internal.core.WSIConstants; -import org.eclipse.wst.wsi.internal.core.WSIException; -import org.eclipse.wst.wsi.internal.core.log.MessageEntry; -import org.eclipse.wst.wsi.internal.core.util.Utils; - -/** - * Socket Handler. - * - * @author Peter Brittenham (peterbr@us.ibm.com) - * @version 1.0.1 - */ -public class SocketHandler extends Thread -{ - protected SocketConnection socketConnection; - protected SocketHandler pairedSocketHandler; - protected String connectionType; - protected int conversationID; - protected String targetHost; - protected int readTimeoutSeconds; - - protected Socket inSocket; - protected Socket outSocket; - protected InputStream inputStream = null; - protected OutputStream outputStream = null; - - protected boolean verbose = false; - - protected boolean readTimedOut = false; - - // I18N: 2003.02.26 modified by K.Nakagome@BeaconIT - private String mimeCharset = null; - private String xmlEncoding = null; - - protected static final String CRLF = "\r\n"; - - protected static final String HTTP_100_CONTINUE = - "100 Continue".toUpperCase(); - protected static final String CHUNKED = - "Transfer-Encoding: chunked".toUpperCase(); - protected static final String CHUNKED_WITH_QUOTES = - "Transfer-Encoding: \"chunked\"".toUpperCase(); - protected static final String CONTENT_LENGTH = - "Content-Length:".toUpperCase(); - - /** - * Create socket handler. - * @param socketConnection socket connection. - * @param connectionType connection type. - * @param conversationID conversation id. - * @param targetHost target host. - * @param inSocket in socket. - * @param outSocket out socket. - * @param readTimeoutSeconds read timeout seconds. - */ - public SocketHandler( - SocketConnection socketConnection, - String connectionType, - int conversationID, - String targetHost, - Socket inSocket, - Socket outSocket, - int readTimeoutSeconds) - { - this.socketConnection = socketConnection; - this.connectionType = connectionType; - this.conversationID = conversationID; - this.targetHost = targetHost; - this.inSocket = inSocket; - this.outSocket = outSocket; - this.readTimeoutSeconds = readTimeoutSeconds; - - // ADD: - verbose = - socketConnection.getMonitor().getMonitorConfig().getVerboseOption(); - - start(); - } - - /** - * Set paired socket handler. - * @param pairedSocketHandler paired socket handler. - */ - public void setPairedSocketHandler(SocketHandler pairedSocketHandler) - { - this.pairedSocketHandler = pairedSocketHandler; - } - - /** - * Send the data from the input socket to the output socket. - */ - public void run() - { - int readLen; - String readMsg; - MessageContext messageContext = null; - - // Create read buffer - byte[] readBuffer = new byte[4096]; - - try - { - // Get the input and output streams - this.inputStream = this.inSocket.getInputStream(); - this.outputStream = this.outSocket.getOutputStream(); - - // Process while the connection is active - // (NOTE: there might be more than 1 message per connection) - boolean connectionActive = true; - while (connectionActive) - { - // Reset all data - readLen = 0; - messageContext = new MessageContext(); - - // Read until message is complete - boolean messageComplete = false; - while (!messageComplete) - { - try - { - // DEBUG: - debug("run", "Read data from the input stream."); - - // Read data from the input stream - readLen = inputStream.read(readBuffer, 0, readBuffer.length); - - // Reset read timeout flag - readTimedOut = false; - - // DEBUG: - debug("run", "readLen: " + readLen); - - if (readLen == -1) - { - connectionActive = false; - messageComplete = true; - } - - // If data was read, then check for 100 continue - else if (readLen > 0) - { - // If this is the first data that was read, then get the timestamp - if (messageContext.timestamp == null) - messageContext.timestamp = Utils.getTimestamp(); - - if (connectionType.equals(MessageEntry.TYPE_REQUEST)) - { - byte[] toHost = - new String( - socketConnection.redirect.getToHost() - + ":" - + socketConnection.redirect.getToPort()) - .getBytes(); - - String message = new String(readBuffer, 0, readLen); - - int index = message.indexOf(CRLF + "Host: "); - if (index > -1) - { - index += 8; - int secondPart = message.indexOf(CRLF, index); - - // Write the data to the output stream and then go format it - write(this.outputStream, readBuffer, 0, index); - write(this.outputStream, toHost, 0, toHost.length); - write( - this.outputStream, - readBuffer, - secondPart, - readLen - secondPart); - } - else - { - // Write the data to the output stream and then go format it - write(this.outputStream, readBuffer, 0, readLen); - } - } - else - { - // Write the data to the output stream and then go format it - write(this.outputStream, readBuffer, 0, readLen); - } - - // DEBUG: - if (verbose) - { - String bufferString = new String(readBuffer, 0, readLen); - debug("run", "buffer as string: [" + bufferString + "]"); - if (bufferString.length() <= 50) - debug( - "run", - "buffer as hexstring: [" - + Utils.toHexString(bufferString) - + "]"); - else - debug( - "run", - "buffer as hexstring: [" - + Utils.toHexString(bufferString.substring(0, 50)) - + " ...]"); - } - - // See if this part of the buffer contains the BOM - if (messageContext.bom == 0) - { - messageContext.bom = getBOM(readBuffer); - } - - // DEBUG - debug("run", "bom: " + messageContext.bom); - - String encoding; - - try - { - encoding = getEncoding(); - readMsg = - new String( - readBuffer, - 0, - readLen, - Utils.getJavaEncoding(encoding)); - setEncoding(readMsg); - if (!encoding.equals(getEncoding())) - { - encoding = getEncoding(); - readMsg = - new String( - readBuffer, - 0, - readLen, - Utils.getJavaEncoding(encoding)); - } - } - - catch (UnsupportedEncodingException uee) - { - debug("run", "EXCEPTION (3): " + uee.toString()); - throw new RuntimeException(uee.toString()); - } - - // Set encoding in the message context - messageContext.encoding = encoding; - - // DEBUG - debug("run", "encoding: " + messageContext.encoding); - - // Process message - messageContext = processMessage(readLen, readMsg, messageContext); - } - - // If message is complete, then log it and reset buffer - if ((isMessageComplete(messageContext)) - || ((readLen == -1) && (messageContext.messageBuffer.length() > 0))) - { - // Log message - logMessage(messageContext); - - // Set message complete - messageComplete = true; - } - } - - catch (InterruptedIOException ie) - { - // Set read timeout flag - readTimedOut = true; - - debug("run", "InterruptedIOException: " + ie.toString()); - - // If the read is not done, then shutdown - if (pairedSocketHandler != null - && pairedSocketHandler.isReadWaiting() - && pairedSocketHandler.isReadTimedOut()) - { - // DEBUG: - debug("run", "read timed out on both sockets"); - - // If there is data in the message buffer and it is complete, then log it - if ((isMessageComplete(messageContext)) - || (messageContext.messageBuffer.length() > 0)) - { - // Log message - logMessage(messageContext); - } - - // Set message complete - connectionActive = false; - messageComplete = true; - } - } - - catch (Exception e2) - { - // DEBUG: - debug( - "run", - "EXCEPTION (2): " - + e2.toString() - + "\n" - + Utils.getExceptionDetails(e2)); - //e2.printStackTrace(); - - // If there is data in the message buffer and it is complete, then log it - if ((isMessageComplete(messageContext)) - || (messageContext.messageBuffer.length() > 0)) - { - // Log message - logMessage(messageContext); - } - - // Set message complete - connectionActive = false; - messageComplete = true; - } - } - } - } - - catch (Exception e) - { - // DEBUG: - debug( - "run", - "EXCEPTION (1): " - + e.getMessage() - + "\n" - + Utils.getExceptionDetails(e)); - //e.printStackTrace(); - } - - catch (Error err) - { - // DEBUG: - debug("run", "ERROR: " + err.getMessage()); - //err.printStackTrace(); - } - - finally - { - shutdown(); - socketConnection.wakeUp(); - } - } - - /** - * Process the message. - */ - private MessageContext processMessage( - int readLen, - String readMsg, - MessageContext inMessageContext) - throws WSIException - { - boolean continueRead = false; - - // Initialize message context - MessageContext messageContext = inMessageContext; - - // Get message buffer and chunked data from message context - StringBuffer messageBuffer = messageContext.messageBuffer; - ChunkedData chunkedData = messageContext.chunkedData; - - // If all we received was the header with 100 continue, then ignore it - if ((readMsg.toUpperCase().indexOf(HTTP_100_CONTINUE) != -1) - && (readLen >= 25)) - { - // DEBUG: - debug("processMessage", "Ignore HTTP 100 Continue."); - - // Find the end of the HTTP 100 message - int index = Utils.getFirstCRLFCRLF(readMsg); - - // If there is only the HTTP 100 message, then just ignore it - if (index == readMsg.length()) - continueRead = true; - - // Otherwise remove the HTTP 100 message and continue - else - readMsg = readMsg.substring(index); - } - - // ADD: What if a bypassed message contains another message after it? - if (!continueRead && bypassMessage(readMsg)) - { - // DEBUG: - debug( - "processMessage", - "Do not log message as defined in the monitor spec, but it will be sent."); - - continueRead = true; - } - - if (!continueRead) - { - int index = 0; - - // If there is chunked data, then get the length - if ((readMsg.toUpperCase().indexOf(CHUNKED) != -1) - || (readMsg.toUpperCase().indexOf(CHUNKED_WITH_QUOTES) != -1)) - { - // DEBUG: - debug("processMessage", "Processing chunked data..."); - - // Get the location of the first CFLF - if ((index = readMsg.indexOf(CRLF + CRLF)) == -1) - { - throw new WSIException("Could not locate end of HTTP header."); - } - - // Include the CRLF+CRLF in the index - index += 4; - - // DEBUG: - debug( - "processMessage", - "Add header before decoding chunked data: [" - + readMsg.substring(0, index) - + "]"); - - // Add HTTP header to buffer - messageBuffer.append(readMsg.substring(0, index)); - - // If there is no more data (i.e. header only), then just indicate that there is more chunked data - if (readMsg.length() == index) - { - chunkedData = new ChunkedData(this, true); - - // DEBUG: - debug( - "processMessage", - "There is chunk data, but none in this part of the message."); - } - - // Determine if the remainder of the data is complete (i.e. ends with [0][CRLF][Optional Footer][CRLF]) - else - { - // Create chunked data object - chunkedData = new ChunkedData(this, readMsg.substring(index)); - - if (!chunkedData.isMoreChunkedData()) - { - chunkedData.decodeAndAddDataToBuffer(messageBuffer); - } - } - } - - else if (chunkedData != null && chunkedData.isMoreChunkedData()) - { - // DEBUG: - debug("processMessage", "Processing MORE chunked data..."); - - // Add data - chunkedData.addData(readMsg); - - // Decode data - if (!chunkedData.isMoreChunkedData()) - { - chunkedData.decodeAndAddDataToBuffer(messageBuffer); - } - } - - // Else just append the data to the buffer - else - { - // DEBUG: - debug( - "processMessage", - "Add data to message entry buffer: [" + readMsg + "]"); - - messageBuffer.append(readMsg); - } - } - - // Set updated message buffer and chunked data in message context - messageContext.messageBuffer = messageBuffer; - messageContext.chunkedData = chunkedData; - - // Return message context - return messageContext; - } - - /** - * Shutdown input socket and close input stream. - * @param inSocket in socket. - * @param inputStream input stream. - */ - protected void stopInput(Socket inSocket, InputStream inputStream) - { - try - { - // If there is a input socket, then shutdown the input - if (inSocket != null) - { - inSocket.shutdownInput(); - } - - // If there is an input stream then close it - if (inputStream != null) - { - inputStream.close(); - } - } - catch (Exception e) - { - // Ignore since we are stopping everything - } - - inputStream = null; - } - - /** - * Shutdown output socket and close output stream. - * @param outSocket out socket. - * @param outputStream output stream. - */ - protected void stopOutput(Socket outSocket, OutputStream outputStream) - { - try - { - // If there is an output stream, then flush it - if (outputStream != null) - { - outputStream.flush(); - } - - // If there is a input socket, then shutdown the input - if (outSocket != null) - { - outSocket.shutdownOutput(); - } - - // If there is an output stream then close it - if (outputStream != null) - { - outputStream.close(); - } - } - - catch (Exception e) - { - // Ignore since we are stopping everything - } - - outputStream = null; - } - - /** - * Shutdown handler. - */ - public void shutdown() - { - // Stop both the input and output - stopInput(this.inSocket, this.inputStream); - stopOutput(this.outSocket, this.outputStream); - } - - /** - * Display debug messages. - */ - void debug(String method, String message) - { - debug("SocketHandler", method, message); - } - - /** - * Display debug messages. - */ - void debug(String className, String method, String message) - { - if (verbose) - print(className, method, message); - } - - /** - * Display messages. - */ - void print(String className, String method, String message) - { - System.out.println( - "[" - + Thread.currentThread().getName() - + "] [" - + className - + "." - + method - + "] [" - + this.connectionType - + "] " - + message); - } - - /** - * Write data. - */ - private void write( - OutputStream outputStream, - byte[] buffer, - int start, - int length) - throws IOException - { - if (outputStream == null) - { - // DEBUG: - debug("write", "Could not write buffer because output stream is null."); - } - else - { - // DEBUG: - debug("write", "buffer: [" + new String(buffer, start, length) + "]"); - - outputStream.write(buffer, start, length); - } - } - - /** - * Check if message is complete. - * - * @param messageContext - */ - private boolean isMessageComplete(MessageContext messageContext) - throws WSIException - { - int index, index2, contentLen; - boolean messageComplete = false; - - boolean moreChunkedData = messageContext.chunkedData.isMoreChunkedData(); - - String message = messageContext.messageBuffer.toString(); - - // Find the first CRLF + CRLF which marks the end of the HTTP header - String httpHeader; - index = Utils.getFirstCRLFCRLF(message); - if (index == -1) - httpHeader = message; - else - httpHeader = message.substring(0, index); - - // If chunked data, then complete only if there is no more data - if (((httpHeader.toUpperCase().indexOf(CHUNKED) != -1) - || (httpHeader.toUpperCase().indexOf(CHUNKED_WITH_QUOTES) != -1)) - && (!moreChunkedData)) - { - debug( - "isMessageComplete", - "HTTP header indicates chunked data and there is no more chunked data"); - messageComplete = true; - } - - // Check for content length - else if ((index = httpHeader.toUpperCase().indexOf(CONTENT_LENGTH)) == -1) - { - debug("isMessageComplete", "HTTP header does not contain content length"); - - // Should not have complete POST header without content length - if (httpHeader.startsWith("POST")) - { - if (httpHeader.endsWith(CRLF + CRLF)) - { - throw new WSIException("Could not locate content-length in HTTP POST header."); - } - - messageComplete = false; - } - - // This could be a GET, so see if the the complete header has been received - else if ( - httpHeader.startsWith("GET") - && (message.length() == httpHeader.length() - && message.endsWith(CRLF + CRLF))) - { - messageComplete = true; - } - - else - { - messageComplete = false; - } - } - - // If there is content length, then see if the entire message has been received - else if ((index = httpHeader.toUpperCase().indexOf(CONTENT_LENGTH)) != -1) - { - // Find end of content length value - index2 = httpHeader.indexOf(CRLF, index); - - debug("isMessageComplete", "CRLF: " + Utils.toHexString(CRLF)); - debug( - "isMessageComplete", - "httpHeader/index: " + Utils.toHexString(httpHeader.substring(index))); - - // Get content length - contentLen = - Integer - .decode( - httpHeader.substring(index + CONTENT_LENGTH.length() + 1, index2)) - .intValue(); - - // DEBUG: - debug("isMessageComplete", "contentLen: " + contentLen); - - // Find the first CRLF + CRLF which marks the end of the HTTP header - index = Utils.getFirstCRLFCRLF(message); - - // DEBUG: - debug( - "isMessageComplete", - "actual received message length: " + (message.length() - (index))); - - // If content length is equal to actual message content length, then message is complete - if (contentLen == message.length() - index) - { - messageComplete = true; - - // DEBUG: - debug( - "isMessageComplete", - "contentLen = actual received message length."); - } - } - - // Message is not complete - else - { - messageComplete = false; - } - - // DEBUG: - debug("isMessageComplete", "messageComplete: " + messageComplete); - - return messageComplete; - } - - /** - * Log message. - * - * @param messageBuffer - */ - private void logMessage(MessageContext messageContext) throws WSIException - { - // Determine sender and receiver host/port - String senderHostAndPort, receiverHostAndPort; - - // Request - if (connectionType.equals(MessageEntry.TYPE_REQUEST)) - { - senderHostAndPort = - inSocket.getInetAddress().getHostAddress() + ":" + inSocket.getPort(); - receiverHostAndPort = targetHost + ":" + outSocket.getPort(); - } - - // Response - else - { - senderHostAndPort = targetHost + ":" + inSocket.getPort(); - receiverHostAndPort = - outSocket.getInetAddress().getHostAddress() + ":" + outSocket.getPort(); - } - - // Create message entry - this.socketConnection.logMessage( - conversationID, - this.connectionType, - messageContext.timestamp, - senderHostAndPort, - receiverHostAndPort, - messageContext.messageBuffer, - messageContext.bom, - messageContext.encoding); - } - - /** - * Check for HTTP messages that should not be logged. - */ - private boolean bypassMessage(String message) - { - boolean bypass = false; - if ((message.startsWith("CONNECT")) - || (message.startsWith("TRACE")) - || (message.startsWith("DELETE")) - || (message.startsWith("OPTIONS")) - || (message.startsWith("HEAD"))) - { - bypass = true; - } - - return bypass; - } - - // I18N: 2003.02.26 modified by K.Nakagome@BeaconIT - /** - * Set Encoding Parameters - * @param messageFragment String of a HTTP message fragment. - * @author K.Nakagome@BeaconIT Japan SIG - */ - private void setEncoding(String messageFragment) - { - if (mimeCharset == null || mimeCharset.length() == 0) - { - mimeCharset = Utils.getHTTPCharset(messageFragment); - } - if (xmlEncoding == null || xmlEncoding.length() == 0) - { - xmlEncoding = Utils.getXMLEncoding(messageFragment); - } - return; - } - - // I18N: 2003.02.26 modified by K.Nakagome@BeaconIT - /** - * Get Encoding Parameter - * @return Character encoding of HTTP message. - * @author K.Nakagome@BeaconIT Japan SIG - */ - private String getEncoding() - { - String encoding = WSIConstants.DEFAULT_XML_ENCODING; - if (mimeCharset != null && mimeCharset.length() > 0) - { - encoding = mimeCharset; - } - if (xmlEncoding != null && xmlEncoding.length() > 0) - { - encoding = xmlEncoding; - } - return encoding; - } - - /** - * Get the Byte Order Mark from the message (if there is one). - */ - private int getBOM(byte[] message) - { - int bom = 0; - - byte FF = (byte) 0xFF; - byte FE = (byte) 0xFE; - byte EF = (byte) 0xEF; - byte BB = (byte) 0xBB; - byte BF = (byte) 0xBF; - - // Search through the byte array for CRLF+CRLF. This will mark the end of the header. - int i = Utils.getFirstCRLFCRLF(message, 0); - if (i != -1) - { - // DEBUG: - debug( - "getBOM", - "message[i]: " - + message[i] - + ", message[i+1]: " - + message[i+1]); - - // Check for UTF-8 BOM - if (((i + 2) < message.length) - && message[i] == EF - && message[i+1] == BB - && message[i+2] == BF) - { - bom = 0xEFBBBF; - } - // Check for UTF-16 big-endian BOM - else if ( - ((i+1) < message.length) - && message[i] == FE - && message[i + 1] == FF) - { - bom = 0xFEFF; - } - // Check for UTF-16 little-endian BOM - else if ( - ((i+1) < message.length) - && message[i] == FF - && message[i+1] == FE) - { - bom = 0xFFFE; - } - // ADD: Do we need to check for other BOMs - } - return bom; - } - - /** - * Determine if the read is still waiting for data. - */ - boolean isReadWaiting() - { - boolean readWaiting = false; - - try - { - // DEBUG: - debug( - "isReadWaiting", - "inSocket.getInputStream().available(): " - + inSocket.getInputStream().available()); - - if (inSocket.getInputStream().available() == 0) - { - readWaiting = true; - } - } - - catch (IOException ioe) - { - } - - return readWaiting; - } - - /** - * Get read timed out flag. - */ - boolean isReadTimedOut() - { - return this.readTimedOut; - } - - /** - * Message context contains information about the message that is being processed. - */ - class MessageContext - { - StringBuffer messageBuffer; - ChunkedData chunkedData; - String timestamp; - int bom; - String encoding; - - /** - * Create new message context. - */ - MessageContext() - { - messageBuffer = new StringBuffer(); - chunkedData = new ChunkedData(); - timestamp = null; - bom = 0; - encoding = WSIConstants.DEFAULT_XML_ENCODING; - } - } -} |