Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.  Oracle designates this
   * particular file as subject to the "Classpath" exception as provided
   * by Oracle in the LICENSE file that accompanied this code.
  *
  * This code 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
  * version 2 for more details (a copy is included in the LICENSE file that
  * accompanied this code).
  *
  * You should have received a copy of the GNU General Public License version
  * 2 along with this work; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
 
 package koncept.http.sun.net.httpserver;
 
 import java.net.URI;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
 
 
Provides implementation for both HTTP and HTTPS
 
 class ServerImpl implements TimeSourceConfigurableServer {
 	
 	public static final ConfigurationOption FILTER_ORDER = new ConfigurationOption("server.filter.order""system-first""system-last");
 
     private String protocol;
     private boolean https;
     private Executor executor;
     private HttpsConfigurator httpsConfig;
     private SSLContext sslContext;
     private ContextList contexts;
     private InetSocketAddress address;
     private ServerSocketChannel schan;
     private Selector selector;
     private SelectionKey listenerKey;
     private Set<HttpConnectionidleConnections;
     private Set<HttpConnectionallConnections;
     /* following two are used to keep track of the times
      * when a connection/request is first received
      * and when we start to send the response
      */
     private Set<HttpConnectionreqConnections;
     private Set<HttpConnectionrspConnections;
     private List<Eventevents;
     private Object lolock = new Object();
    private volatile boolean finished = false;
    private volatile boolean terminating = false;
    private boolean bound = false;
    private boolean started = false;
    private volatile long time;  /* current time */
    private volatile long subticks = 0;
    private volatile long ticks/* number of clock ticks since server started */
    private HttpServer wrapper;
    final static int CLOCK_TICK = ServerConfig.getClockTick();
    final static long IDLE_INTERVAL = ServerConfig.getIdleInterval();
    final static int MAX_IDLE_CONNECTIONS = ServerConfig.getMaxIdleConnections();
    final static long TIMER_MILLIS = ServerConfig.getTimerMillis ();
    final static long MAX_REQ_TIME=getTimeMillis(ServerConfig.getMaxReqTime());
    final static long MAX_RSP_TIME=getTimeMillis(ServerConfig.getMaxRspTime());
    final static boolean timer1Enabled =  != -1 ||  != -1;
    private Timer timertimer1;
    private Logger logger;
    ServerImpl (
        HttpServer wrapperString protocolInetSocketAddress addrint backlog
    ) throws IOException {
    	.put("");
        this. = protocol;
        this. = wrapper;
        this. = Logger.getLogger ("com.sun.net.httpserver");
        ServerConfig.checkLegacyProperties ();
         = protocol.equalsIgnoreCase ("https");
        this. = addr;
         = new ContextList();
         = ServerSocketChannel.open();
        if (addr != null) {
            ServerSocket socket = .socket();
            socket.bind (addrbacklog);
             = true;
        }
         = Selector.open ();
        .configureBlocking (false);
         = new Dispatcher();
         = Collections.synchronizedSet (new HashSet<HttpConnection>());
         = Collections.synchronizedSet (new HashSet<HttpConnection>());
         = Collections.synchronizedSet (new HashSet<HttpConnection>());
         = Collections.synchronizedSet (new HashSet<HttpConnection>());
         = System.currentTimeMillis();
         = new Timer ("server-timer"true);
        .schedule (new ServerTimerTask(), );
        if () {
             = new Timer ("server-timer1"true);
            .schedule (new ServerTimerTask1(),,);
            .config ("HttpServer timer1 enabled period in ms:  "+);
            .config ("MAX_REQ_TIME:  "+);
            .config ("MAX_RSP_TIME:  "+);
        }
         = new LinkedList<Event>();
        .config ("HttpServer created "+protocol+" "addr);
    }
    public void bind (InetSocketAddress addrint backlogthrows IOException {
        if () {
            throw new BindException ("HttpServer already bound");
        }
        if (addr == null) {
            throw new NullPointerException ("null address");
        }
        ServerSocket socket = .socket();
        socket.bind (addrbacklog);
         = true;
    }
    public void start () {
        if (! ||  || ) {
            throw new IllegalStateException ("server in wrong state");
        }
        if ( == null) {
             = new DefaultExecutor();
        }
        Thread t = new Thread ();
         = true;
        t.start();
    }
    public void setExecutor (Executor executor) {
        if () {
            throw new IllegalStateException ("server already started");
        }
        this. = executor;
    }
    private static class DefaultExecutor implements Executor {
        public void execute (Runnable task) {
            task.run();
        }
    }
    public Executor getExecutor () {
        return ;
    }
    public void setHttpsConfigurator (HttpsConfigurator config) {
        if (config == null) {
            throw new NullPointerException ("null HttpsConfigurator");
        }
        if () {
            throw new IllegalStateException ("server already started");
        }
        this. = config;
         = config.getSSLContext();
    }
        return ;
    }
    public void stop (int delay) {
        if (delay < 0) {
            throw new IllegalArgumentException ("negative delay parameter");
        }
         = true;
        try { .close(); } catch (IOException e) {}
        .wakeup();
        long latest = System.currentTimeMillis() + delay * 1000;
        while (System.currentTimeMillis() < latest) {
            delay();
            if () {
                break;
            }
        }
         = true;
        .wakeup();
        synchronized () {
            for (HttpConnection c : ) {
                c.close();
            }
        }
        .clear();
        .clear();
        .cancel();
        if () {
            .cancel();
        }
    }
    public synchronized HttpContextImpl createContext (String pathHttpHandler handler) {
        if (handler == null || path == null) {
            throw new NullPointerException ("null handler, or path parameter");
        }
        HttpContextImpl context = new HttpContextImpl (pathhandlerthis);
        .add (context);
        .config ("context created: " + path);
        return context;
    }
    public synchronized HttpContextImpl createContext (String path) {
        if (path == null) {
            throw new NullPointerException ("null path parameter");
        }
        HttpContextImpl context = new HttpContextImpl (pathnullthis);
        .add (context);
        .config ("context created: " + path);
        return context;
    }
    public synchronized void removeContext (String paththrows IllegalArgumentException {
        if (path == null) {
            throw new NullPointerException ("null path parameter");
        }
        .remove (path);
        .config ("context removed: " + path);
    }
    public synchronized void removeContext (HttpContext contextthrows IllegalArgumentException {
        if (!(context instanceof HttpContextImpl)) {
            throw new IllegalArgumentException ("wrong HttpContext type");
        }
        .remove ((HttpContextImpl)context);
        .config ("context removed: " + context.getPath());
    }
    public InetSocketAddress getAddress() {
    }
    Selector getSelector () {
        return ;
    }
    void addEvent (Event r) {
        synchronized () {
            .add (r);
            .wakeup();
        }
    }
    /* main server listener task */
    class Dispatcher implements Runnable {
        private void handleEvent (Event r) {
            ExchangeImpl t = r.exchange;
            HttpConnection c = t.getConnection();
            try {
                if (r instanceof WriteFinishedEvent) {
                    int exchanges = endExchange();
                    if ( && exchanges == 0) {
                         = true;
                    }
                    responseCompleted (c);
                    LeftOverInputStream is = t.getOriginalInputStream();
                    if (!is.isEOF()) {
                        t.close = true;
                    }
                    if (t.close || .size() >= ) {
                        c.close();
                        .remove (c);
                    } else {
                        if (is.isDataBuffered()) {
                            /* don't re-enable the interestops, just handle it */
                            requestStarted (c);
                            handle (c.getChannel(), c);
                        } else {
                            .add (c);
                        }
                    }
                }
            } catch (IOException e) {
                .log (
                    ."Dispatcher (1)"e
                );
                c.close();
            }
        }
        final LinkedList<HttpConnectionconnsToRegister =
                new LinkedList<HttpConnection>();
        void reRegister (HttpConnection c) {
            /* re-register with selector */
            try {
                SocketChannel chan = c.getChannel();
                chan.configureBlocking (false);
                SelectionKey key = chan.register (.);
                key.attach (c);
                c.selectionKey = key;
                c.time = getTime() + ;
                .add (c);
            } catch (IOException e) {
                dprint(e);
                .log(."Dispatcher(8)"e);
                c.close();
            }
        }
        public void run() {
            while (!) {
                try {
                    ListIterator<HttpConnectionli =
                        .listIterator();
                    for (HttpConnection c : ) {
                        reRegister(c);
                    }
                    .clear();
                    List<Eventlist = null;
                    .select(1000);
                    synchronized () {
                        if (.size() > 0) {
                            list = ;
                             = new LinkedList<Event>();
                        }
                    }
                    if (list != null) {
                        for (Event rlist) {
                            handleEvent (r);
                        }
                    }
                    /* process the selected list now  */
                    Set<SelectionKeyselected = .selectedKeys();
                    Iterator<SelectionKeyiter = selected.iterator();
                    while (iter.hasNext()) {
                        SelectionKey key = iter.next();
                        iter.remove ();
                        if (key.equals ()) {
                            if () {
                                continue;
                            }
                            SocketChannel chan = .accept();
                            if (chan == null) {
                                continue/* cancel something ? */
                            }
                            chan.configureBlocking (false);
                            SelectionKey newkey = chan.register (.);
                            HttpConnection c = new HttpConnection ();
                            c.selectionKey = newkey;
                            c.setChannel (chan);
                            newkey.attach (c);
                            requestStarted (c);
                            .add (c);
                        } else {
                            try {
                                if (key.isReadable()) {
                                    boolean closed;
                                    SocketChannel chan = (SocketChannel)key.channel();
                                    HttpConnection conn = (HttpConnection)key.attachment();
                                    key.cancel();
                                    chan.configureBlocking (true);
                                    if (.remove(conn)) {
                                        // was an idle connection so add it
                                        // to reqConnections set.
                                        requestStarted (conn);
                                    }
                                    handle (chanconn);
                                } else {
                                    assert false;
                                }
                            } catch (CancelledKeyException e) {
                                handleException(keynull);
                            } catch (IOException e) {
                                handleException(keye);
                            }
                        }
                    }
                    // call the selector just to process the cancelled keys
                    .selectNow();
                } catch (IOException e) {
                    .log (."Dispatcher (4)"e);
                } catch (Exception e) {
                    e.printStackTrace();
                    .log (."Dispatcher (7)"e);
                }
            }
        }
        private void handleException (SelectionKey keyException e) {
            HttpConnection conn = (HttpConnection)key.attachment();
            if (e != null) {
                .log (."Dispatcher (2)"e);
            }
            closeConnection(conn);
        }
        public void handle (SocketChannel chanHttpConnection conn)
        throws IOException
        {
            try {
                Exchange t = new Exchange (chanconn);
                .execute (t);
            } catch (HttpError e1) {
                .log (."Dispatcher (4)"e1);
                closeConnection(conn);
            } catch (IOException e) {
                .log (."Dispatcher (5)"e);
                closeConnection(conn);
            }
        }
    }
    static boolean debug = ServerConfig.debugEnabled ();
    static synchronized void dprint (String s) {
        if () {
            ..println (s);
        }
    }
    static synchronized void dprint (Exception e) {
        if () {
            ..println (e);
            e.printStackTrace();
        }
    }
    Logger getLogger () {
        return ;
    }
    private void closeConnection(HttpConnection conn) {
        conn.close();
        .remove(conn);
        switch (conn.getState()) {
        case :
            .remove(conn);
            break;
        case :
            .remove(conn);
            break;
        case :
            .remove(conn);
            break;
        }
        assert !.remove(conn);
        assert !.remove(conn);
        assert !.remove(conn);
    }
        /* per exchange task */
    class Exchange implements Runnable {
    	
        SocketChannel chan;
        HttpConnection connection;
        HttpContextImpl context;
        InputStream rawin;
        OutputStream rawout;
        String protocol;
        ExchangeImpl tx;
        HttpContextImpl ctx;
        boolean rejected = false;
        Exchange (SocketChannel chanString protocolHttpConnection connthrows IOException {
            this. = chan;
            this. = conn;
            this. = protocol;
        }
        public void run () {
            /* context will be null for new connections */
             = .getHttpContext();
            boolean newconnection;
            SSLEngine engine = null;
            String requestLine = null;
            SSLStreams sslStreams = null;
            try {
                if ( != null ) {
                    this. = .getInputStream();
                    this. = .getRawOutputStream();
                    newconnection = false;
                } else {
                    /* figure out what kind of connection this is */
                    newconnection = true;
                    if () {
                        if ( == null) {
                            .warning ("SSL connection received. No https contxt created");
                            throw new HttpError ("No SSL context established");
                        }
                        sslStreams = new SSLStreams (ServerImpl.this);
                         = sslStreams.getInputStream();
                         = sslStreams.getOutputStream();
                        engine = sslStreams.getSSLEngine();
                        . = sslStreams;
                    } else {
                         = new BufferedInputStream(
                            new Request.ReadStream (
                                ServerImpl.this
                        ));
                         = new Request.WriteStream (
                            ServerImpl.this
                        );
                    }
                    . = ;
                    . = ;
                }
                Request req = new Request ();
                requestLine = req.requestLine();
                if (requestLine == null) {
                    /* connection closed */
                    closeConnection();
                    return;
                }
                int space = requestLine.indexOf (' ');
                if (space == -1) {
                    reject (.,
                            requestLine"Bad request line");
                    return;
                }
                String method = requestLine.substring (0, space);
                int start = space+1;
                space = requestLine.indexOf(' 'start);
                if (space == -1) {
                    reject (.,
                            requestLine"Bad request line");
                    return;
                }
                String uriStr = requestLine.substring (startspace);
                URI uri = new URI (uriStr);
                start = space+1;
                String version = requestLine.substring (start);
                Headers headers = req.headers();
                String s = headers.getFirst ("Transfer-encoding");
                long clen = 0L;
                if (s !=null && s.equalsIgnoreCase ("chunked")) {
                    clen = -1L;
                } else {
                    s = headers.getFirst ("Content-Length");
                    if (s != null) {
                        clen = Long.parseLong(s);
                    }
                    if (clen == 0) {
                        requestCompleted ();
                    }
                }
                 = .findContext (uri.getPath());
                if ( == null) {
                    reject (.,
                            requestLine"No context found for request");
                    return;
                }
                .setContext ();
                if (.getHandler() == null) {
                    reject (.,
                            requestLine"No handler for context");
                    return;
                }
                 = new ExchangeImpl (
                    methodurireqclen
                );
                String chdr = headers.getFirst("Connection");
                Headers rheaders = .getResponseHeaders();
                if (chdr != null && chdr.equalsIgnoreCase ("close")) {
                    . = true;
                }
                if (version.equalsIgnoreCase ("http/1.0")) {
                    . = true;
                    if (chdr == null) {
                        . = true;
                        rheaders.set ("Connection""close");
                    } else if (chdr.equalsIgnoreCase ("keep-alive")) {
                        rheaders.set ("Connection""keep-alive");
                        int idle=(int)ServerConfig.getIdleInterval()/1000;
                        int max=(int)ServerConfig.getMaxIdleConnections();
                        String val = "timeout="+idle+", max="+max;
                        rheaders.set ("Keep-Alive"val);
                    }
                }
                if (newconnection) {
                    .setParameters (
                        enginesslStreams,
                        
                    );
                }
                /* check if client sent an Expect 100 Continue.
                 * In that case, need to send an interim response.
                 * In future API may be modified to allow app to
                 * be involved in this process.
                 */
                String exp = headers.getFirst("Expect");
                if (exp != null && exp.equalsIgnoreCase ("100-continue")) {
                    logReply (100, requestLinenull);
                    sendReply (
                        .falsenull
                    );
                }
                /* uf is the list of filters seen/set by the user.
                 * sf is the list of filters established internally
                 * and which are not visible to the user. uc and sc
                 * are the corresponding Filter.Chains.
                 * They are linked together by a LinkHandler
                 * so that they can both be invoked in one call.
                 */
                
                String filterOrder = .get();
                boolean systemFirst = filterOrder.equals("system-first");
                
                List<Filtersf = .getSystemFilters();
                List<Filteruf = .getFilters();
                Filter.Chain chain;
                if (systemFirst) {
                	Filter.Chain uc = new Filter.Chain(uf.getHandler());
                	Filter.Chain sc = new Filter.Chain(sfnew LinkHandler (uc));
                	chain = sc;
                } else {
                	Filter.Chain sc = new Filter.Chain(sf.getHandler());
                    Filter.Chain uc = new Filter.Chain(ufnew LinkHandler (sc));
                    chain = uc;
                }
                /* set up the two stream references */
                .getRequestBody();
                .getResponseBody();
                if () {
                    chain.doFilter (new HttpsExchangeImpl ());
                } else {
                	chain.doFilter (new HttpExchangeImpl ());
                }
            } catch (IOException e1) {
                .log (."ServerImpl.Exchange (1)"e1);
                closeConnection();
            } catch (NumberFormatException e3) {
                reject (.,
                        requestLine"NumberFormatException thrown");
            } catch (URISyntaxException e) {
                reject (.,
                        requestLine"URISyntaxException thrown");
            } catch (Exception e4) {
                .log (."ServerImpl.Exchange (2)"e4);
                closeConnection();
            }
        }
        /* used to link to 2 or more Filter.Chains together */
        class LinkHandler implements HttpHandler {
            Filter.Chain nextChain;
            LinkHandler (Filter.Chain nextChain) {
                this. = nextChain;
            }
            public void handle (HttpExchange exchangethrows IOException {
                .doFilter (exchange);
            }
        }
        void reject (int codeString requestStrString message) {
             = true;
            logReply (coderequestStrmessage);
            sendReply (
                codefalse"<h1>"+code+Code.msg(code)+"</h1>"+message
            );
            closeConnection();
        }
        void sendReply (
            int codeboolean closeNowString text)
        {
            try {
                StringBuilder builder = new StringBuilder (512);
                builder.append ("HTTP/1.1 ")
                    .append (code).append (Code.msg(code)).append ("\r\n");
                if (text != null && text.length() != 0) {
                    builder.append ("Content-Length: ")
                        .append (text.length()).append ("\r\n")
                        .append ("Content-Type: text/html\r\n");
                } else {
                    builder.append ("Content-Length: 0\r\n");
                    text = "";
                }
                if (closeNow) {
                    builder.append ("Connection: close\r\n");
                }
                builder.append ("\r\n").append (text);
                String s = builder.toString();
                byte[] b = s.getBytes("ISO8859_1");
                .write (b);
                .flush();
                if (closeNow) {
                    closeConnection();
                }
            } catch (IOException e) {
                .log (."ServerImpl.sendReply"e);
                closeConnection();
            }
        }
    }
    void logReply (int codeString requestStrString text) {
        if (!.isLoggable(.)) {
            return;
        }
        if (text == null) {
            text = "";
        }
        String r;
        if (requestStr.length() > 80) {
           r = requestStr.substring (0, 80) + "<TRUNCATED>";
        } else {
           r = requestStr;
        }
        String message = r + " [" + code + " " +
                    Code.msg(code) + "] ("+text+")";
        .fine (message);
    }
    long getTicks() {
        return ;
    }
    public long getTime() {
        return ;
    }
    void delay () {
        Thread.yield();
        try {
            Thread.sleep (200);
        } catch (InterruptedException e) {}
    }
    private int exchangeCount = 0;
    synchronized void startExchange () {
         ++;
    }
    synchronized int endExchange () {
         --;
        assert  >= 0;
        return ;
    }
    HttpServer getWrapper () {
        return ;
    }
    void requestStarted (HttpConnection c) {
        c.creationTime = getTime();
        c.setState (.);
        .add (c);
    }
    // called after a request has been completely read
    // by the server. This stops the timer which would
    // close the connection if the request doesn't arrive
    // quickly enough. It then starts the timer
    // that ensures the client reads the response in a timely
    // fashion.
    void requestCompleted (HttpConnection c) {
        assert c.getState() == .;
        .remove (c);
        c.rspStartedTime = getTime();
        .add (c);
        c.setState (.);
    }
    // called after response has been sent
    void responseCompleted (HttpConnection c) {
        assert c.getState() == .;
        .remove (c);
        c.setState (.);
    }

    
TimerTask run every CLOCK_TICK ms
    class ServerTimerTask extends TimerTask {
        public void run () {
            LinkedList<HttpConnectiontoClose = new LinkedList<HttpConnection>();
             = System.currentTimeMillis();
             ++;
            synchronized () {
                for (HttpConnection c : ) {
                    if (c.time <= ) {
                        toClose.add (c);
                    }
                }
                for (HttpConnection c : toClose) {
                    .remove (c);
                    .remove (c);
                    c.close();
                }
            }
        }
    }
    class ServerTimerTask1 extends TimerTask {
        // runs every TIMER_MILLIS
        public void run () {
            LinkedList<HttpConnectiontoClose = new LinkedList<HttpConnection>();
             = System.currentTimeMillis();
            synchronized () {
                if ( != -1) {
                    for (HttpConnection c : ) {
                        if (c.creationTime +  +  <= ) {
                            toClose.add (c);
                        }
                    }
                    for (HttpConnection c : toClose) {
                        .log (."closing: no request: " + c);
                        .remove (c);
                        .remove (c);
                        c.close();
                    }
                }
            }
            toClose = new LinkedList<HttpConnection>();
            synchronized () {
                if ( != -1) {
                    for (HttpConnection c : ) {
                        if (c.rspStartedTime +  + <= ) {
                            toClose.add (c);
                        }
                    }
                    for (HttpConnection c : toClose) {
                        .log (."closing: no response: " + c);
                        .remove (c);
                        .remove (c);
                        c.close();
                    }
                }
            }
        }
    }
    void logStackTrace (String s) {
        .finest (s);
        StringBuilder b = new StringBuilder ();
        StackTraceElement[] e = Thread.currentThread().getStackTrace();
        for (int i=0; i<e.lengthi++) {
            b.append (e[i].toString()).append("\n");
        }
        .finest (b.toString());
    }
    static long getTimeMillis(long secs) {
        if (secs == -1) {
            return -1;
        } else {
            return secs * 1000;
        }
    }
    
    @Override
    public Map<ConfigurationOptionStringoptions() {
    	return ;
    }
    
    @Override
    public void resetOptionsToDefaults() {
    	ConfigurationOption.set(."exchange");
    	ConfigurationOption.set("system-first");
    }
    
    @Override
    public void resetOptionsToJVMStandard() {
    	ConfigurationOption.set(."context");
    	ConfigurationOption.set("system-last");
    }