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 + -
显示快捷键?