httpbasicconnection.java
来自「很棒的web服务器源代码」· Java 代码 · 共 443 行
JAVA
443 行
// HttpBasicConnection.java// $Id: HttpBasicConnection.java,v 1.24 2004/02/11 15:25:18 ylafon Exp $// (c) COPYRIGHT MIT and INRIA, 1996.// Please first read the full copyright statement in file COPYRIGHT.htmlpackage org.w3c.www.protocol.http;import java.lang.reflect.Method;import java.lang.reflect.InvocationTargetException;import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.io.PrintStream;import java.net.InetAddress;import java.net.Socket;import org.w3c.www.mime.MimeParser;import org.w3c.www.mime.MimeParserFactory;import org.w3c.www.http.HttpStreamObserver;class HttpBasicConnection extends HttpConnection implements HttpStreamObserver{ private static final boolean debug = false; static Method sock_m = null; static { try { Class c = java.net.Socket.class; sock_m = c.getMethod("isClosed", null); } catch (NoSuchMethodException ex) { // not using a recent jdk... sock_m = null; } } // A small class that start a thread to create a socket // while the original thread waits only for some amount of time // and indicate the other thread (if not finished) that the newly // created socket can be destroyed if it took too long. private class TimedSocket implements Runnable { Socket _sock = null; InetAddress _inetaddr = null; int _port = 0; boolean _ok = true; IOException _ioex = null; public synchronized Socket getSocket(InetAddress inetaddr, int port) throws IOException { _inetaddr = inetaddr; _port = port; Thread t = new Thread(this); t.start(); try { t.join(connect_timeout); } catch (InterruptedException iex){ _ok = false; if (_sock != null) { try { _sock.close(); } catch (IOException ioex) {}; _sock = null; } } if (_sock != null) { return _sock; } _ok = false; // should we interrupt the other thread here? if (_ioex != null) { throw _ioex; } else { throw new IOException("Connect timed out"); } } public void run() { Socket s = null; try { s = new Socket(inetaddr, port); } catch (IOException ex) { _ioex = ex; } if (_ok) { _sock = s; } else { try { if (s != null) { s.close(); } } catch (IOException ioex) {}; } } } /** * The physical socket underlying the connection. */ private Socket socket = null; /** * The MIME parser to read input from the connection. */ MimeParser parser = null; /** * THe socket output stream, when available. */ OutputStream output = null; /** * The socket input stream when available. */ InputStream input = null; /** * The MimeParser factory to use to create Reply instances. */ MimeParserFactory reply_factory = null; /** * The thread that owns the connection, for checking assertions. */ Thread th = null; /** * The target INET address of this connection. */ InetAddress inetaddr = null; /** * The target port number for this connection. */ int port = -1; /** * The Timout on the underlying socket */ int timeout = 300000; /** * The Connection timeout for the underlying socket */ int connect_timeout = 1000; /** * All connections are associated with a uniq identifier, for debugging. */ protected int id = -1; /** * if a close is needed at the end of the connection (ie: on a * Connection: close client or server side */ protected boolean closeOnEOF = false; protected synchronized void setCloseOnEOF(boolean doit) { closeOnEOF = doit; } /** * Print this connection into a String. * @return A String containing the external representation for the * connection. */ public String toString() { return inetaddr + ":" + port +"["+id+"]"; } /** * The entity stream we observe has reached its end. * Notify the server that it can now reuse the connection safely for some * other pending requests. * @param in The stream that has reached its end of file. */ public synchronized void notifyEOF(InputStream in) { markIdle(closeOnEOF); } /** * The entity stream we were to observe refuse to be observed. * The connection will not be reusable, so we should detach it from the * managing server, without closing it, since the entity reader will * close it itself. * @param in The stream that has been closed. */ public synchronized void notifyFailure(InputStream in) { markIdle(true); } /** * The entity stream we observe has been closed. * After making sure the entire entity has been read, we can safely hand * out the connection to the server, for later reuse. * @param in The stream that has been closed. */ public synchronized void notifyClose(InputStream in) { boolean _close = false; try { if (in.available() > 0) { _close = true; }// try {// byte buffer[] = new byte[1024];// while (in.read(buffer) >= 0) {// } } catch (IOException ex) { _close = true; } finally { markIdle(_close); } } /** * Close this connection to terminate it. * This method will only close the streams, and free all the data * structures that it keeps. */ public synchronized void close() { close(false); } /** * Close this connection to terminate it. * This method will only close the streams, and free all the data * structures that it keeps. */ private synchronized void close(boolean force) { if ( socket != null || force) { // Close the socket: try { if (socket != null) { socket.close(); } } catch (IOException ex) { } socket = null; // Mark all data as invalid: output = null; input = null; parser = null; cached = false; th = null; // Mark that connection as dead: ((HttpBasicServer) server).deleteConnection(this); } } /** * Mark this connection as being used. * The server, which keeps track of idle connections, has decided to use * this connection to run some request. Mark this connection as used * and unregister it from the server's list of idle connections. * <p>Some assumptions are checked before handing out the connection * for use, which can throw an RuntimeException. * @return A boolean, <strong>true</strong> if the connection can be used * or reused, <strong>false</strong> otherwise (the connection was detected * idle, and destroy itself). * @exception RuntimeException If the connection is in an invalid state. */ public boolean markUsed() { cached = false; if ( debug ) System.out.println(this+ " used !"); if ( th != null ) throw new RuntimeException(this+" already used by "+th); th = Thread.currentThread(); if ( socket != null ) { cached = true; if (sock_m != null) { try { // check if socket is good using jdk1.4 feature // would be faster to do it natively... Boolean b = (Boolean) sock_m.invoke(socket, null); if (debug) { System.out.println("Socket is closed? "+b); } if (b.booleanValue()) { try { socket.close(); } catch (IOException ieox) {} socket = null; } } catch (InvocationTargetException ex) { if (debug) ex.printStackTrace(); // weird, let's close it socket = null; } catch (IllegalAccessException ex) { // weird also here :) if (debug) ex.printStackTrace(); socket = null; } catch (Exception fex) { socket = null; } } } // damn... jdk1.4 is not behaving as it should :( if ( socket == null ) { try { TimedSocket ts = new TimedSocket(); socket = ts.getSocket(inetaddr, port); socket.setSoTimeout(timeout); output = new BufferedOutputStream(socket.getOutputStream()); input = new BufferedInputStream(socket.getInputStream()); parser = new MimeParser(input, reply_factory); cached = false; } catch (Throwable ex) { if (debug) { ex.printStackTrace(); } // Close that connection (cleanup): close(true); return false; } } return true; } /** * The connection is now idle again. * Mark the connection as idle, and register it to the server's list of * idle connection (if this connection can be reused). If the connection * cannot be reused, detach it from the server and forget about it (the * caller will close it by closing the entity stream). * @param close Should this connection be physically closed (it is not * reusable), or should we try to keep track of it for later reuse. * @exception RuntimeException If the connection is in an invalid state. */ public void markIdle(boolean close) { // Has this connection already been marked idle ? synchronized (this) { if ( th == null ) return; if ( debug ) System.out.println(this+" idle !"+close); // Check consistency: // if ( Thread.currentThread() != th ) // throw new RuntimeException(this + // " th mismatch " + // th + // "/" + // Thread.currentThread()); // Ok, mark idle for good: th = null; } if ( close ) { if ( debug ) System.out.println(this+" closing !"); close(); } else { // Notify the server that a new connection is available: ((HttpBasicServer) server).registerConnection(this); } } /** * Some data available on input, while writing to the server. * This callback gets called when the client is emitting data to the * server and the server has sent us something before we actually sent * all our bytes. * <p>Take any appropriate action. */ public void notifyInputAvailable(InputStream in) { return; } /** * Get the MIME parser to read from this connection. * All access to the connection's input stream should go through the MIME * parser to ensure buffering coherency. * @return A MimeParser instance suitable to parse the reply input stream. * @exception RuntimeException If the connection was not connected. */ public MimeParser getParser() { if ( parser == null ) throw new RuntimeException("getParser while disconnected."); return parser; } /** * Get the connection output stream. * @return The output stream to send data on this connection. * @exception RuntimeException If the connection was not previously opened. */ public OutputStream getOutputStream() { if ( output == null ) throw new RuntimeException("getOutputStream while disconnected."); return output; } /** * Create a new connection. * To be used only by HttpServer instances. */ HttpBasicConnection(HttpServer server , int id , InetAddress addr , int port , int timeout , MimeParserFactory reply_factory) throws IOException { this(server, id, addr, port, timeout, 1000, reply_factory); } /** * Create a new connection. * To be used only by HttpServer instances. */ HttpBasicConnection(HttpServer server , int id , InetAddress addr , int port , int timeout , int connect_timeout , MimeParserFactory reply_factory) throws IOException { this.server = server; this.inetaddr = addr; this.port = port; this.id = id; this.timeout = timeout; this.connect_timeout = connect_timeout; this.reply_factory = reply_factory; }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?