http 服务器 java_Java实现Http服务器(四)

(1)HTTPServer的监听启动

sun.net.httpserver.ServerImpl类中启动了Socket监听,ServerImpl的内部类Dispatch类启动了Http服务器的监听

/* 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 (terminating && exchanges == 0) {

finished = true;

}

SocketChannel chan = c.getChannel();

LeftOverInputStream is = t.getOriginalInputStream();

if (!is.isEOF()) {

t.close = true;

}

if (t.close || idleConnections.size() >= MAX_IDLE_CONNECTIONS) {

c.close();

allConnections.remove (c);

} else {

if (is.isDataBuffered()) {

/* don't re-enable the interestops, just handle it */

handle (c.getChannel(), c);

} else {

/* re-enable interestops */

SelectionKey key = c.getSelectionKey();

if (key.isValid()) {

key.interestOps (

key.interestOps()|SelectionKey.OP_READ

);

}

c.time = getTime() + IDLE_INTERVAL;

idleConnections.add (c);

}

}

}

} catch (IOException e) {

logger.log (

Level.FINER, "Dispatcher (1)", e

);

c.close();

}

}

public void run() {

while (!finished) {

try {

/* process the events list first */

while (resultSize() > 0) {

Event r;

synchronized (lolock) {

r = events.remove(0);

handleEvent (r);

}

}

selector.select(1000);

/* process the selected list now */

Set selected = selector.selectedKeys();

Iterator iter = selected.iterator();

while (iter.hasNext()) {

SelectionKey key = iter.next();

iter.remove ();

if (key.equals (listenerKey)) {

if (terminating) {

continue;

}

SocketChannel chan = schan.accept();

if (chan == null) {

continue; /* cancel something ? */

}

chan.configureBlocking (false);

SelectionKey newkey = chan.register (selector, SelectionKey.OP_READ);

HttpConnection c = new HttpConnection ();

c.selectionKey = newkey;

c.setChannel (chan);

newkey.attach (c);

allConnections.add (c);

} else {

try {

if (key.isReadable()) {

boolean closed;

SocketChannel chan = (SocketChannel)key.channel();

HttpConnection conn = (HttpConnection)key.attachment();

// interestOps will be restored at end of read

key.interestOps (0);

handle (chan, conn);

} else {

assert false;

}

} catch (IOException e) {

HttpConnection conn = (HttpConnection)key.attachment();

logger.log (

Level.FINER, "Dispatcher (2)", e

);

conn.close();

}

}

}

} catch (CancelledKeyException e) {

logger.log (Level.FINER, "Dispatcher (3)", e);

} catch (IOException e) {

logger.log (Level.FINER, "Dispatcher (4)", e);

} catch (Exception e) {

logger.log (Level.FINER, "Dispatcher (7)", e);

}

}

}

public void handle (SocketChannel chan, HttpConnection conn)

throws IOException

{

try {

Exchange t = new Exchange (chan, protocol, conn);

executor.execute (t);

} catch (HttpError e1) {

logger.log (Level.FINER, "Dispatcher (5)", e1);

conn.close();

} catch (IOException e) {

logger.log (Level.FINER, "Dispatcher (6)", e);

conn.close();

}

}

}

static boolean debug = ServerConfig.debugEnabled ();

static synchronized void dprint (String s) {

if (debug) {

System.out.println (s);

}

}

static synchronized void dprint (Exception e) {

if (debug) {

System.out.println (e);

e.printStackTrace();

}

}

Logger getLogger () {

return logger;

}

该类的初始化在sun.net.httpserver.ServerImpl的构造方法当中

ServerImpl (HttpServer wrapper, String protocol, InetSocketAddress addr, int backlog) throws IOException {

this.protocol = protocol;

this.wrapper = wrapper;

this.logger = Logger.getLogger ("com.sun.net.httpserver");

https = protocol.equalsIgnoreCase ("https");

this.address = addr;

contexts = new ContextList();

schan = ServerSocketChannel.open();

if (addr != null) {

ServerSocket socket = schan.socket();

socket.bind (addr, backlog);

bound = true;

}

selector = Selector.open ();

schan.configureBlocking (false);

listenerKey = schan.register (selector, SelectionKey.OP_ACCEPT);

dispatcher = new Dispatcher();

idleConnections = Collections.synchronizedSet (new HashSet());

allConnections = Collections.synchronizedSet (new HashSet());

time = System.currentTimeMillis();

timer = new Timer ("server-timer", true);

timer.schedule (new ServerTimerTask(), CLOCK_TICK, CLOCK_TICK);

events = new LinkedList();

logger.config ("HttpServer created "+protocol+" "+ addr);

}

随后在sun.net.httpserver.ServerImpl类的start方法当中,作为线程被启动

public void start () {

if (!bound || started || finished) {

throw new IllegalStateException ("server in wrong state");

}

if (executor == null) {

executor = new DefaultExecutor();

}

Thread t = new Thread (dispatcher);

started = true;

t.start();

}

import com.sun.net.httpserver.HttpServer;

private HttpServer httpServer = null;

public final void init() throws IOException

{

this.executor = Executors.newCachedThreadPool();

final InetSocketAddress sa = new InetSocketAddress("0.0.0.0", 8080);

this.httpServer = HttpServer.create(sa, 0);

this.httpServer.setExecutor(this.executor);

this.httpServer.createContext("/", new HttpServerHandler());

this.httpServer.start();

}

上面是使用JDK内置HttpServer的方法。

在第二篇文章中介绍过返回的默认对象是

sun.net.httpserver.HttpServerImpl对象,该对象是com.sun.net.httpserver.HttpServer对象的子类

public class HttpServerImpl extends HttpServer {

ServerImpl server;

HttpServerImpl () throws IOException {

this (new InetSocketAddress(80), 0);

}

HttpServerImpl (

InetSocketAddress addr, int backlog

) throws IOException {

server = new ServerImpl (this, "http", addr, backlog);

}

.............................................

}

该对象又是ServerImpl对象的外观类,提供了HttpServer的方法,封装了ServerImpl自身的各种方法实现

最终在应用中调用this.httpserver.start()

本质上调用的就是sun.net.httpserver.ServerImpl对象的start()方法

---------------------------------------------------------------------------------------------------------------------------------------

下面分析下Dispatcher类中run方法的监听过程

public void run() {

//server的关闭标志,在调用httpserver.stop()方法后--->即ServerImpl类的stop()方法,设置finished为true(初始化为false)

while (!finished) {

try {

/* process the events list first */

//由于支持HTTP1.1的原因,在一次发送数据结束之后,并不是立即关闭连接和socket,而是将发送完成作为一个事件传递过来,根据上下文决定是否关闭连接

while (resultSize() > 0) {

Event r;

synchronized (lolock) {

r = events.remove(0);

handleEvent (r);

}

}

selector.select(1000);

/* process the selected list now */

Set selected = selector.selectedKeys();

Iterator iter = selected.iterator();

while (iter.hasNext()) {

SelectionKey key = iter.next();

iter.remove ();

if (key.equals (listenerKey)) {

if (terminating) {

continue;

}

SocketChannel chan = schan.accept();

if (chan == null) {

continue; /* cancel something ? */

}

chan.configureBlocking (false);

SelectionKey newkey = chan.register (selector, SelectionKey.OP_READ);

HttpConnection c = new HttpConnection ();

c.selectionKey = newkey;

c.setChannel (chan);

newkey.attach (c);

allConnections.add (c);

} else {

try {

if (key.isReadable()) {

boolean closed;

SocketChannel chan = (SocketChannel)key.channel();

HttpConnection conn = (HttpConnection)key.attachment();

// interestOps will be restored at end of read

key.interestOps (0);

handle (chan, conn);

} else {

assert false;

}

} catch (IOException e) {

HttpConnection conn = (HttpConnection)key.attachment();

logger.log (

Level.FINER, "Dispatcher (2)", e

);

conn.close();

}

}

}

} catch (CancelledKeyException e) {

logger.log (Level.FINER, "Dispatcher (3)", e);

} catch (IOException e) {

logger.log (Level.FINER, "Dispatcher (4)", e);

} catch (Exception e) {

logger.log (Level.FINER, "Dispatcher (7)", e);

}

}

}

设置请求处理器的方法

public HttpContextImpl createContext (String path, HttpHandler handler) {

return server.createContext (path, handler);

}

public synchronized HttpContextImpl createContext (String path) {

if (path == null) {

throw new NullPointerException ("null path parameter");

}

HttpContextImpl context = new HttpContextImpl (protocol, path, null, this);

contexts.add (context);

logger.config ("context created: " + path);

return context;

}

HttpContextImpl类的介绍

/**

* HttpContext represents a mapping between a protocol (http or https) together with a root URI path

* to a {@link HttpHandler} which is invoked to handle requests destined

* for the protocol/path on the associated HttpServer.

*

* HttpContext instances are created by {@link HttpServer#createContext(String,String,HttpHandler,Object)}

*

*/

contexts对象是  private ContextList contexts;

是ServerImpl的成员变量

该类提供了URL和处理该URL的Handler的映射,可以看到,最多支持50个URL的处理。

add(HttpContextImpl ctx)方法增加映射对象

findContext(String protocol,String path) 返回相应请求的HttpContextImpl对象

下面可以看一下find的过程(坚持最长匹配 比如/guowuxin/hello  /guowuxin 这是两个映射  则当/guowuxin 请求来的时候将使用前者的映射,貌似很没有礼貌)

坚持最长匹配也是没有使用map的原因

(1)判断protocol (HTTP1.0 HTTP1.1)

(2)exact变量要求是否是全匹配亦或者是开头(startsWith) 默认 我们看到run方法中默认的是开头匹配

package sun.net.httpserver;

import java.util.*;

import com.sun.net.httpserver.*;

import com.sun.net.httpserver.spi.*;

class ContextList {

final static int MAX_CONTEXTS = 50;

LinkedList list = new LinkedList();

public synchronized void add (HttpContextImpl ctx) {

assert ctx.getPath() != null;

list.add (ctx);

}

public synchronized int size () {

return list.size();

}

/* initially contexts are located only by protocol:path.

* Context with longest prefix matches (currently case-sensitive)

*/

synchronized HttpContextImpl findContext (String protocol, String path) {

return findContext (protocol, path, false);

}

synchronized HttpContextImpl findContext (String protocol, String path, boolean exact) {

protocol = protocol.toLowerCase();

String longest = "";

HttpContextImpl lc = null;

for (HttpContextImpl ctx: list) {

if (!ctx.getProtocol().equals(protocol)) {

continue;

}

String cpath = ctx.getPath();

if (exact && !cpath.equals (path)) {

continue;

} else if (!exact && !path.startsWith(cpath)) {

continue;

}

if (cpath.length() > longest.length()) {

longest = cpath;

lc = ctx;

}

}

return lc;

}

public synchronized void remove (String protocol, String path)

throws IllegalArgumentException

{

HttpContextImpl ctx = findContext (protocol, path, true);

if (ctx == null) {

throw new IllegalArgumentException ("cannot remove element from list");

}

list.remove (ctx);

}

public synchronized void remove (HttpContextImpl context)

throws IllegalArgumentException

{

for (HttpContextImpl ctx: list) {

if (ctx.equals (context)) {

list.remove (ctx);

return;

}

}

throw new IllegalArgumentException ("no such context in list");

}

}

-------------------------------------------------------------------------------------------------------------------------------------------------

下面重点分析下server端的HttpConnection的复用(在HTTP1.1协议下,TCP连接在发送完数据之后不会断开)

exchange.getResponseBody().close();

这里就要先介绍下,我们的请求处理器HttpHandler接口

package com.sun.net.httpserver;

import java.io.IOException;

/**

* A handler which is invoked to process HTTP exchanges. Each

* HTTP exchange is handled by one of these handlers.

* @since 1.6

*/

public interface HttpHandler {

/**

* Handle the given request and generate an appropriate response.

* See {@link HttpExchange} for a description of the steps

* involved in handling an exchange.

* @param exchange the exchange containing the request from the

* client and used to send the response

* @throws NullPointerException if exchange is null

*/

public abstract void handle (HttpExchange exchange) throws IOException;

}

该接口的实现类用于处理相应的url请求,其中参数HttpExchange类如其名,作用就是接收输入参数,返回输出信息,就是用来交换Http消息的一个工具接口。

下面是它的一个实现类,也是一个外观类,包装了ExchangeImpl类,提供了HttpExchange接口的方法,封装了ExchangeImpl类的方法。

package sun.net.httpserver;

import java.io.*;

import java.nio.*;

import java.nio.channels.*;

import java.net.*;

import javax.net.ssl.*;

import java.util.*;

import sun.net.www.MessageHeader;

import com.sun.net.httpserver.*;

import com.sun.net.httpserver.spi.*;

class HttpExchangeImpl extends HttpExchange {

ExchangeImpl impl;

HttpExchangeImpl (ExchangeImpl impl) {

this.impl = impl;

}

public Headers getRequestHeaders () {

return impl.getRequestHeaders();

}

public Headers getResponseHeaders () {

return impl.getResponseHeaders();

}

public URI getRequestURI () {

return impl.getRequestURI();

}

public String getRequestMethod (){

return impl.getRequestMethod();

}

public HttpContextImpl getHttpContext (){

return impl.getHttpContext();

}

public void close () {

impl.close();

}

public InputStream getRequestBody () {

return impl.getRequestBody();

}

public int getResponseCode () {

return impl.getResponseCode();

}

public OutputStream getResponseBody () {

return impl.getResponseBody();

}

public void sendResponseHeaders (int rCode, long contentLen)

throws IOException

{

impl.sendResponseHeaders (rCode, contentLen);

}

public InetSocketAddress getRemoteAddress (){

return impl.getRemoteAddress();

}

public InetSocketAddress getLocalAddress (){

return impl.getLocalAddress();

}

public String getProtocol (){

return impl.getProtocol();

}

public Object getAttribute (String name) {

return impl.getAttribute (name);

}

public void setAttribute (String name, Object value) {

impl.setAttribute (name, value);

}

public void setStreams (InputStream i, OutputStream o) {

impl.setStreams (i, o);

}

public HttpPrincipal getPrincipal () {

return impl.getPrincipal();

}

ExchangeImpl getExchangeImpl () {

return impl;

}

}

下面是sun.net.httpserver包中ExchangeImpl类的实现,该类中保存了TCP连接输入输出流的引用,

package sun.net.httpserver;

import java.io.*;

import java.nio.*;

import java.nio.channels.*;

import java.net.*;

import javax.net.ssl.*;

import java.util.*;

import java.text.*;

import sun.net.www.MessageHeader;

import com.sun.net.httpserver.*;

import com.sun.net.httpserver.spi.*;

class ExchangeImpl {

Headers reqHdrs, rspHdrs;

Request req;

String method;

URI uri;

HttpConnection connection;

int reqContentLen;

long rspContentLen;

/* raw streams which access the socket directly */

InputStream ris;

OutputStream ros;

Thread thread;

/* close the underlying connection when this exchange finished */

boolean close;

boolean closed;

boolean http10 = false;

/* for formatting the Date: header */

static TimeZone tz;

static DateFormat df;

static {

String pattern = "EEE, dd MMM yyyy HH:mm:ss zzz";

tz = TimeZone.getTimeZone ("GMT");

df = new SimpleDateFormat (pattern, Locale.US);

df.setTimeZone (tz);

}

/* streams which take care of the HTTP protocol framing

* and are passed up to higher layers

*/

InputStream uis;

OutputStream uos;

LeftOverInputStream uis_orig; // uis may have be a user supplied wrapper

PlaceholderOutputStream uos_orig;

boolean sentHeaders; /* true after response headers sent */

Map attributes;

int rcode = -1;

HttpPrincipal principal;

ServerImpl server;

ExchangeImpl (

String m, URI u, Request req, int len, HttpConnection connection

) throws IOException {

this.req = req;

this.reqHdrs = req.headers();

this.rspHdrs = new Headers();

this.method = m;

this.uri = u;

this.connection = connection;

this.reqContentLen = len;

/* ros only used for headers, body written directly to stream */

this.ros = req.outputStream();

this.ris = req.inputStream();

server = getServerImpl();

server.startExchange();

}

public Headers getRequestHeaders () {

return new UnmodifiableHeaders (reqHdrs);

}

public Headers getResponseHeaders () {

return rspHdrs;

}

public URI getRequestURI () {

return uri;

}

public String getRequestMethod (){

return method;

}

public HttpContextImpl getHttpContext (){

return connection.getHttpContext();

}

public void close () {

if (closed) {

return;

}

closed = true;

/* close the underlying connection if,

* a) the streams not set up yet, no response can be sent, or

* b) if the wrapper output stream is not set up, or

* c) if the close of the input/outpu stream fails

*/

try {

if (uis_orig == null || uos == null) {

connection.close();

return;

}

if (!uos_orig.isWrapped()) {

connection.close();

return;

}

if (!uis_orig.isClosed()) {

uis_orig.close();

}

uos.close();

} catch (IOException e) {

connection.close();

}

}

public InputStream getRequestBody () {

if (uis != null) {

return uis;

}

if (reqContentLen == -1) {

uis_orig = new ChunkedInputStream (this, ris);

uis = uis_orig;

} else {

uis_orig = new FixedLengthInputStream (this, ris, reqContentLen);

uis = uis_orig;

}

return uis;

}

LeftOverInputStream getOriginalInputStream () {

return uis_orig;

}

public int getResponseCode () {

return rcode;

}

public OutputStream getResponseBody () {

/* TODO. Change spec to remove restriction below. Filters

* cannot work with this restriction

*

* if (!sentHeaders) {

* throw new IllegalStateException ("headers not sent");

* }

*/

if (uos == null) {

uos_orig = new PlaceholderOutputStream (null);

uos = uos_orig;

}

return uos;

}

/* returns the place holder stream, which is the stream

* returned from the 1st call to getResponseBody()

* The "real" ouputstream is then placed inside this

*/

PlaceholderOutputStream getPlaceholderResponseBody () {

getResponseBody();

return uos_orig;

}

public void sendResponseHeaders (int rCode, long contentLen)

throws IOException

{

if (sentHeaders) {

throw new IOException ("headers already sent");

}

this.rcode = rCode;

String statusLine = "HTTP/1.1 "+rCode+Code.msg(rCode)+"\r\n";

OutputStream tmpout = new BufferedOutputStream (ros);

PlaceholderOutputStream o = getPlaceholderResponseBody();

tmpout.write (bytes(statusLine, 0), 0, statusLine.length());

boolean noContentToSend = false; // assume there is content

rspHdrs.set ("Date", df.format (new Date()));

if (contentLen == 0) {

if (http10) {

o.setWrappedStream (new UndefLengthOutputStream (this, ros));

close = true;

} else {

rspHdrs.set ("Transfer-encoding", "chunked");

o.setWrappedStream (new ChunkedOutputStream (this, ros));

}

} else {

if (contentLen == -1) {

noContentToSend = true;

contentLen = 0;

}

/* content len might already be set, eg to implement HEAD resp */

if (rspHdrs.getFirst ("Content-length") == null) {

rspHdrs.set ("Content-length", Long.toString(contentLen));

}

o.setWrappedStream (new FixedLengthOutputStream (this, ros, contentLen));

}

write (rspHdrs, tmpout);

this.rspContentLen = contentLen;

tmpout.flush() ;

tmpout = null;

sentHeaders = true;

if (noContentToSend) {

WriteFinishedEvent e = new WriteFinishedEvent (this);

server.addEvent (e);

closed = true;

}

server.logReply (rCode, req.requestLine(), null);

}

void write (Headers map, OutputStream os) throws IOException {

Set>> entries = map.entrySet();

for (Map.Entry> entry : entries) {

String key = entry.getKey();

byte[] buf;

List values = entry.getValue();

for (String val : values) {

int i = key.length();

buf = bytes (key, 2);

buf[i++] = ':';

buf[i++] = ' ';

os.write (buf, 0, i);

buf = bytes (val, 2);

i = val.length();

buf[i++] = '\r';

buf[i++] = '\n';

os.write (buf, 0, i);

}

}

os.write ('\r');

os.write ('\n');

}

private byte[] rspbuf = new byte [128]; // used by bytes()

/**

* convert string to byte[], using rspbuf

* Make sure that at least "extra" bytes are free at end

* of rspbuf. Reallocate rspbuf if not big enough.

* caller must check return value to see if rspbuf moved

*/

private byte[] bytes (String s, int extra) {

int slen = s.length();

if (slen+extra > rspbuf.length) {

int diff = slen + extra - rspbuf.length;

rspbuf = new byte [2* (rspbuf.length + diff)];

}

char c[] = s.toCharArray();

for (int i=0; i

rspbuf[i] = (byte)c[i];

}

return rspbuf;

}

public InetSocketAddress getRemoteAddress (){

Socket s = connection.getChannel().socket();

InetAddress ia = s.getInetAddress();

int port = s.getPort();

return new InetSocketAddress (ia, port);

}

public InetSocketAddress getLocalAddress (){

Socket s = connection.getChannel().socket();

InetAddress ia = s.getLocalAddress();

int port = s.getLocalPort();

return new InetSocketAddress (ia, port);

}

public String getProtocol (){

String reqline = req.requestLine();

int index = reqline.lastIndexOf (' ');

return reqline.substring (index+1);

}

public SSLSession getSSLSession () {

SSLEngine e = connection.getSSLEngine();

if (e == null) {

return null;

}

return e.getSession();

}

public Object getAttribute (String name) {

if (name == null) {

throw new NullPointerException ("null name parameter");

}

if (attributes == null) {

attributes = getHttpContext().getAttributes();

}

return attributes.get (name);

}

public void setAttribute (String name, Object value) {

if (name == null) {

throw new NullPointerException ("null name parameter");

}

if (attributes == null) {

attributes = getHttpContext().getAttributes();

}

attributes.put (name, value);

}

public void setStreams (InputStream i, OutputStream o) {

assert uis != null;

if (i != null) {

uis = i;

}

if (o != null) {

uos = o;

}

}

/**

* PP

*/

HttpConnection getConnection () {

return connection;

}

ServerImpl getServerImpl () {

return getHttpContext().getServerImpl();

}

public HttpPrincipal getPrincipal () {

return principal;

}

void setPrincipal (HttpPrincipal principal) {

this.principal = principal;

}

static ExchangeImpl get (HttpExchange t) {

if (t instanceof HttpExchangeImpl) {

return ((HttpExchangeImpl)t).getExchangeImpl();

} else {

assert t instanceof HttpsExchangeImpl;

return ((HttpsExchangeImpl)t).getExchangeImpl();

}

}

}

/**

* An OutputStream which wraps another stream

* which is supplied either at creation time, or sometime later.

* If a caller/user tries to write to this stream before

* the wrapped stream has been provided, then an IOException will

* be thrown.

*/

class PlaceholderOutputStream extends java.io.OutputStream {

OutputStream wrapped;

PlaceholderOutputStream (OutputStream os) {

wrapped = os;

}

void setWrappedStream (OutputStream os) {

wrapped = os;

}

boolean isWrapped () {

return wrapped != null;

}

private void checkWrap () throws IOException {

if (wrapped == null) {

throw new IOException ("response headers not sent yet");

}

}

public void write(int b) throws IOException {

checkWrap();

wrapped.write (b);

}

public void write(byte b[]) throws IOException {

checkWrap();

wrapped.write (b);

}

public void write(byte b[], int off, int len) throws IOException {

checkWrap();

wrapped.write (b, off, len);

}

public void flush() throws IOException {

checkWrap();

wrapped.flush();

}

public void close() throws IOException {

checkWrap();

wrapped.close();

}

}

下面是一个输出流的装饰类

package sun.net.httpserver;

import java.io.*;

import com.sun.net.httpserver.*;

import com.sun.net.httpserver.spi.*;

/**

* a (filter) input stream which can tell us if bytes are "left over"

* on the underlying stream which can be read (without blocking)

* on another instance of this class.

*

* The class can also report if all bytes "expected" to be read

* were read, by the time close() was called. In that case,

* bytes may be drained to consume them (by calling drain() ).

*

* isEOF() returns true, when all expected bytes have been read

*/

abstract class LeftOverInputStream extends FilterInputStream {

ExchangeImpl t;

ServerImpl server;

protected boolean closed = false;

protected boolean eof = false;

byte[] one = new byte [1];

public LeftOverInputStream (ExchangeImpl t, InputStream src) {

super (src);

this.t = t;

this.server = t.getServerImpl();

}

/**

* if bytes are left over buffered on *the UNDERLYING* stream

*/

public boolean isDataBuffered () throws IOException {

assert eof;

return super.available() > 0;

}

public void close () throws IOException {

if (closed) {

return;

}

closed = true;

if (!eof) {

eof = drain (ServerConfig.getDrainAmount());

}

}

public boolean isClosed () {

return closed;

}

public boolean isEOF () {

return eof;

}

protected abstract int readImpl (byte[]b, int off, int len) throws IOException;

public synchronized int read () throws IOException {

if (closed) {

throw new IOException ("Stream is closed");

}

int c = readImpl (one, 0, 1);

if (c == -1 || c == 0) {

return c;

} else {

return one[0] & 0xFF;

}

}

public synchronized int read (byte[]b, int off, int len) throws IOException {

if (closed) {

throw new IOException ("Stream is closed");

}

return readImpl (b, off, len);

}

/**

* read and discard up to l bytes or "eof" occurs,

* (whichever is first). Then return true if the stream

* is at eof (ie. all bytes were read) or false if not

* (still bytes to be read)

*/

public boolean drain (long l) throws IOException {

int bufSize = 2048;

byte[] db = new byte [bufSize];

while (l > 0) {

long len = readImpl (db, 0, bufSize);

if (len == -1) {

eof = true;

return true;

} else {

l = l - len;

}

}

return false;

}

}

package sun.net.httpserver;

import java.io.*;

import javax.net.ssl.*;

import java.nio.channels.*;

import java.util.logging.Logger;

import com.sun.net.httpserver.*;

import com.sun.net.httpserver.spi.*;

/**

* encapsulates all the connection specific state for a HTTP/S connection

* one of these is hung from the selector attachment and is used to locate

* everything from that.

*/

class HttpConnection {

HttpContextImpl context;

SSLEngine engine;

SSLContext sslContext;

SSLStreams sslStreams;

/* high level streams returned to application */

InputStream i;

/* low level stream that sits directly over channel */

InputStream raw;

OutputStream rawout;

SocketChannel chan;

SelectionKey selectionKey;

String protocol;

long time;

int remaining;

boolean closed = false;

Logger logger;

public String toString() {

String s = null;

if (chan != null) {

s = chan.toString();

}

return s;

}

HttpConnection () {

}

void setChannel (SocketChannel c) {

chan = c;

}

void setContext (HttpContextImpl ctx) {

context = ctx;

}

void setParameters (

InputStream in, OutputStream rawout, SocketChannel chan,

SSLEngine engine, SSLStreams sslStreams, SSLContext sslContext, String protocol,

HttpContextImpl context, InputStream raw

)

{

this.context = context;

this.i = in;

this.rawout = rawout;

this.raw = raw;

this.protocol = protocol;

this.engine = engine;

this.chan = chan;

this.sslContext = sslContext;

this.sslStreams = sslStreams;

this.logger = context.getLogger();

}

SocketChannel getChannel () {

return chan;

}

synchronized void close () {

if (closed) {

return;

}

closed = true;

if (logger != null && chan != null) {

logger.finest ("Closing connection: " + chan.toString());

}

if (!chan.isOpen()) {

ServerImpl.dprint ("Channel already closed");

return;

}

try {

/* need to ensure temporary selectors are closed */

if (raw != null) {

raw.close();

}

} catch (IOException e) {

ServerImpl.dprint (e);

}

try {

if (rawout != null) {

rawout.close();

}

} catch (IOException e) {

ServerImpl.dprint (e);

}

try {

if (sslStreams != null) {

sslStreams.close();

}

} catch (IOException e) {

ServerImpl.dprint (e);

}

try {

chan.close();

} catch (IOException e) {

ServerImpl.dprint (e);

}

}

/* remaining is the number of bytes left on the lowest level inputstream

* after the exchange is finished

*/

void setRemaining (int r) {

remaining = r;

}

int getRemaining () {

return remaining;

}

SelectionKey getSelectionKey () {

return selectionKey;

}

InputStream getInputStream () {

return i;

}

OutputStream getRawOutputStream () {

return rawout;

}

String getProtocol () {

return protocol;

}

SSLEngine getSSLEngine () {

return engine;

}

SSLContext getSSLContext () {

return sslContext;

}

HttpContextImpl getHttpContext () {

return context;

}

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值