History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/net/httpserver (27 of 18352 files). Show all

Unified · Split

27 files
  1. java/pkg/sun/net/httpserver/AuthFilter.java +86 −0
  2. java/pkg/sun/net/httpserver/ChunkedInputStream.java +176 −0
  3. java/pkg/sun/net/httpserver/ChunkedOutputStream.java +163 −0
  4. java/pkg/sun/net/httpserver/Code.java +109 −0
  5. java/pkg/sun/net/httpserver/ContextList.java +97 −0
  6. java/pkg/sun/net/httpserver/DefaultHttpServerProvider.java +41 −0
  7. java/pkg/sun/net/httpserver/Event.java +46 −0
  8. java/pkg/sun/net/httpserver/ExchangeImpl.java +456 −0
  9. java/pkg/sun/net/httpserver/FixedLengthInputStream.java +82 −0
  10. java/pkg/sun/net/httpserver/FixedLengthOutputStream.java +104 −0
  11. java/pkg/sun/net/httpserver/HttpConnection.java +196 −0
  12. java/pkg/sun/net/httpserver/HttpContextImpl.java +152 −0
  13. java/pkg/sun/net/httpserver/HttpError.java +37 −0
  14. java/pkg/sun/net/httpserver/HttpExchangeImpl.java +120 −0
  15. java/pkg/sun/net/httpserver/HttpServerImpl.java +92 −0
  16. java/pkg/sun/net/httpserver/HttpsExchangeImpl.java +124 −0
  17. java/pkg/sun/net/httpserver/HttpsServerImpl.java +100 −0
  18. java/pkg/sun/net/httpserver/LeftOverInputStream.java +122 −0
  19. java/pkg/sun/net/httpserver/Request.java +402 −0
  20. java/pkg/sun/net/httpserver/SSLStreams.java +662 −0
  21. java/pkg/sun/net/httpserver/ServerConfig.java +175 −0
  22. java/pkg/sun/net/httpserver/ServerImpl.java +870 −0
  23. java/pkg/sun/net/httpserver/StreamClosedException.java +32 −0
  24. java/pkg/sun/net/httpserver/TimeSource.java +30 −0
  25. java/pkg/sun/net/httpserver/UndefLengthOutputStream.java +81 −0
  26. java/pkg/sun/net/httpserver/UnmodifiableHeaders.java +101 −0
  27. java/pkg/sun/net/httpserver/mkfile +33 −0
java/pkg/sun/net/httpserver/AuthFilter.java+86−0
@@ -0,0 +1,86 @@
1+/*
2+ * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package sun.net.httpserver;
27+
28+import com.sun.net.httpserver.*;
29+import java.io.*;
30+import java.nio.*;
31+import java.nio.channels.*;
32+import sun.net.www.MessageHeader;
33+import java.util.*;
34+import javax.security.auth.*;
35+import javax.security.auth.callback.*;
36+import javax.security.auth.login.*;
37+
38+public class AuthFilter extends Filter {
39+
40+ private Authenticator authenticator;
41+
42+ public AuthFilter (Authenticator authenticator) {
43+ this.authenticator = authenticator;
44+ }
45+
46+ public String description () {
47+ return "Authentication filter";
48+ }
49+
50+ public void setAuthenticator (Authenticator a) {
51+ authenticator = a;
52+ }
53+
54+ public void consumeInput (HttpExchange t) throws IOException {
55+ InputStream i = t.getRequestBody();
56+ byte[] b = new byte [4096];
57+ while (i.read (b) != -1);
58+ i.close ();
59+ }
60+
61+ /**
62+ * The filter's implementation, which is invoked by the server
63+ */
64+ public void doFilter (HttpExchange t, Filter.Chain chain) throws IOException
65+ {
66+ if (authenticator != null) {
67+ Authenticator.Result r = authenticator.authenticate (t);
68+ if (r instanceof Authenticator.Success) {
69+ Authenticator.Success s = (Authenticator.Success)r;
70+ ExchangeImpl e = ExchangeImpl.get (t);
71+ e.setPrincipal (s.getPrincipal());
72+ chain.doFilter (t);
73+ } else if (r instanceof Authenticator.Retry) {
74+ Authenticator.Retry ry = (Authenticator.Retry)r;
75+ consumeInput (t);
76+ t.sendResponseHeaders (ry.getResponseCode(), -1);
77+ } else if (r instanceof Authenticator.Failure) {
78+ Authenticator.Failure f = (Authenticator.Failure)r;
79+ consumeInput (t);
80+ t.sendResponseHeaders (f.getResponseCode(), -1);
81+ }
82+ } else {
83+ chain.doFilter (t);
84+ }
85+ }
86+}
java/pkg/sun/net/httpserver/ChunkedInputStream.java+176−0
@@ -0,0 +1,176 @@
1+/*
2+ * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package sun.net.httpserver;
27+
28+import java.io.*;
29+import java.net.*;
30+import com.sun.net.httpserver.*;
31+import com.sun.net.httpserver.spi.*;
32+
33+class ChunkedInputStream extends LeftOverInputStream {
34+ ChunkedInputStream (ExchangeImpl t, InputStream src) {
35+ super (t, src);
36+ }
37+
38+ private int remaining;
39+
40+ /* true when a chunk header needs to be read */
41+
42+ private boolean needToReadHeader = true;
43+
44+ static char CR = '\r';
45+ static char LF = '\n';
46+
47+ private int numeric (char[] arr, int nchars) throws IOException {
48+ assert arr.length >= nchars;
49+ int len = 0;
50+ for (int i=0; i<nchars; i++) {
51+ char c = arr[i];
52+ int val=0;
53+ if (c>='0' && c <='9') {
54+ val = c - '0';
55+ } else if (c>='a' && c<= 'f') {
56+ val = c - 'a' + 10;
57+ } else if (c>='A' && c<= 'F') {
58+ val = c - 'A' + 10;
59+ } else {
60+ throw new IOException ("invalid chunk length");
61+ }
62+ len = len * 16 + val;
63+ }
64+ return len;
65+ }
66+
67+ /* read the chunk header line and return the chunk length
68+ * any chunk extensions are ignored
69+ */
70+ private int readChunkHeader () throws IOException {
71+ boolean gotCR = false;
72+ int c;
73+ char[] len_arr = new char [16];
74+ int len_size = 0;
75+ boolean end_of_len = false;
76+
77+ while ((c=in.read())!= -1) {
78+ char ch = (char) c;
79+ if (len_size == len_arr.length -1) {
80+ throw new IOException ("invalid chunk header");
81+ }
82+ if (gotCR) {
83+ if (ch == LF) {
84+ int l = numeric (len_arr, len_size);
85+ return l;
86+ } else {
87+ gotCR = false;
88+ }
89+ if (!end_of_len) {
90+ len_arr[len_size++] = ch;
91+ }
92+ } else {
93+ if (ch == CR) {
94+ gotCR = true;
95+ } else if (ch == ';') {
96+ end_of_len = true;
97+ } else if (!end_of_len) {
98+ len_arr[len_size++] = ch;
99+ }
100+ }
101+ }
102+ throw new IOException ("end of stream reading chunk header");
103+ }
104+
105+ protected int readImpl (byte[]b, int off, int len) throws IOException {
106+ if (eof) {
107+ return -1;
108+ }
109+ if (needToReadHeader) {
110+ remaining = readChunkHeader();
111+ if (remaining == 0) {
112+ eof = true;
113+ consumeCRLF();
114+ t.getServerImpl().requestCompleted (t.getConnection());
115+ return -1;
116+ }
117+ needToReadHeader = false;
118+ }
119+ if (len > remaining) {
120+ len = remaining;
121+ }
122+ int n = in.read(b, off, len);
123+ if (n > -1) {
124+ remaining -= n;
125+ }
126+ if (remaining == 0) {
127+ needToReadHeader = true;
128+ consumeCRLF();
129+ }
130+ return n;
131+ }
132+
133+ private void consumeCRLF () throws IOException {
134+ char c;
135+ c = (char)in.read(); /* CR */
136+ if (c != CR) {
137+ throw new IOException ("invalid chunk end");
138+ }
139+ c = (char)in.read(); /* LF */
140+ if (c != LF) {
141+ throw new IOException ("invalid chunk end");
142+ }
143+ }
144+
145+ /**
146+ * returns the number of bytes available to read in the current chunk
147+ * which may be less than the real amount, but we'll live with that
148+ * limitation for the moment. It only affects potential efficiency
149+ * rather than correctness.
150+ */
151+ public int available () throws IOException {
152+ if (eof || closed) {
153+ return 0;
154+ }
155+ int n = in.available();
156+ return n > remaining? remaining: n;
157+ }
158+
159+ /* called after the stream is closed to see if bytes
160+ * have been read from the underlying channel
161+ * and buffered internally
162+ */
163+ public boolean isDataBuffered () throws IOException {
164+ assert eof;
165+ return in.available() > 0;
166+ }
167+
168+ public boolean markSupported () {return false;}
169+
170+ public void mark (int l) {
171+ }
172+
173+ public void reset () throws IOException {
174+ throw new IOException ("mark/reset not supported");
175+ }
176+}
java/pkg/sun/net/httpserver/ChunkedOutputStream.java+163−0
@@ -0,0 +1,163 @@
1+/*
2+ * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package sun.net.httpserver;
27+
28+import java.io.*;
29+import java.net.*;
30+import com.sun.net.httpserver.*;
31+import com.sun.net.httpserver.spi.*;
32+
33+/**
34+ * a class which allows the caller to write an arbitrary
35+ * number of bytes to an underlying stream.
36+ * normal close() does not close the underlying stream
37+ *
38+ * This class is buffered.
39+ *
40+ * Each chunk is written in one go as :-
41+ * abcd\r\nxxxxxxxxxxxxxx\r\n
42+ *
43+ * abcd is the chunk-size, and xxx is the chunk data
44+ * If the length is less than 4 chars (in size) then the buffer
45+ * is written with an offset.
46+ * Final chunk is:
47+ * 0\r\n\r\n
48+ */
49+
50+class ChunkedOutputStream extends FilterOutputStream
51+{
52+ private boolean closed = false;
53+ /* max. amount of user data per chunk */
54+ final static int CHUNK_SIZE = 4096;
55+ /* allow 4 bytes for chunk-size plus 4 for CRLFs */
56+ final static int OFFSET = 6; /* initial <=4 bytes for len + CRLF */
57+ private int pos = OFFSET;
58+ private int count = 0;
59+ private byte[] buf = new byte [CHUNK_SIZE+OFFSET+2];
60+ ExchangeImpl t;
61+
62+ ChunkedOutputStream (ExchangeImpl t, OutputStream src) {
63+ super (src);
64+ this.t = t;
65+ }
66+
67+ public void write (int b) throws IOException {
68+ if (closed) {
69+ throw new StreamClosedException ();
70+ }
71+ buf [pos++] = (byte)b;
72+ count ++;
73+ if (count == CHUNK_SIZE) {
74+ writeChunk();
75+ }
76+ assert count < CHUNK_SIZE;
77+ }
78+
79+ public void write (byte[]b, int off, int len) throws IOException {
80+ if (closed) {
81+ throw new StreamClosedException ();
82+ }
83+ int remain = CHUNK_SIZE - count;
84+ if (len > remain) {
85+ System.arraycopy (b,off,buf,pos,remain);
86+ count = CHUNK_SIZE;
87+ writeChunk();
88+ len -= remain;
89+ off += remain;
90+ while (len >= CHUNK_SIZE) {
91+ System.arraycopy (b,off,buf,OFFSET,CHUNK_SIZE);
92+ len -= CHUNK_SIZE;
93+ off += CHUNK_SIZE;
94+ count = CHUNK_SIZE;
95+ writeChunk();
96+ }
97+ }
98+ if (len > 0) {
99+ System.arraycopy (b,off,buf,pos,len);
100+ count += len;
101+ pos += len;
102+ }
103+ if (count == CHUNK_SIZE) {
104+ writeChunk();
105+ }
106+ }
107+
108+ /**
109+ * write out a chunk , and reset the pointers
110+ * chunk does not have to be CHUNK_SIZE bytes
111+ * count must == number of user bytes (<= CHUNK_SIZE)
112+ */
113+ private void writeChunk () throws IOException {
114+ char[] c = Integer.toHexString (count).toCharArray();
115+ int clen = c.length;
116+ int startByte = 4 - clen;
117+ int i;
118+ for (i=0; i<clen; i++) {
119+ buf[startByte+i] = (byte)c[i];
120+ }
121+ buf[startByte + (i++)] = '\r';
122+ buf[startByte + (i++)] = '\n';
123+ buf[startByte + (i++) + count] = '\r';
124+ buf[startByte + (i++) + count] = '\n';
125+ out.write (buf, startByte, i+count);
126+ count = 0;
127+ pos = OFFSET;
128+ }
129+
130+ public void close () throws IOException {
131+ if (closed) {
132+ return;
133+ }
134+ flush();
135+ try {
136+ /* write an empty chunk */
137+ writeChunk();
138+ out.flush();
139+ LeftOverInputStream is = t.getOriginalInputStream();
140+ if (!is.isClosed()) {
141+ is.close();
142+ }
143+ /* some clients close the connection before empty chunk is sent */
144+ } catch (IOException e) {
145+
146+ } finally {
147+ closed = true;
148+ }
149+
150+ WriteFinishedEvent e = new WriteFinishedEvent (t);
151+ t.getHttpContext().getServerImpl().addEvent (e);
152+ }
153+
154+ public void flush () throws IOException {
155+ if (closed) {
156+ throw new StreamClosedException ();
157+ }
158+ if (count > 0) {
159+ writeChunk();
160+ }
161+ out.flush();
162+ }
163+}
java/pkg/sun/net/httpserver/Code.java+109−0
@@ -0,0 +1,109 @@
1+/*
2+ * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package sun.net.httpserver;
27+
28+class Code {
29+
30+ public static final int HTTP_CONTINUE = 100;
31+ public static final int HTTP_OK = 200;
32+ public static final int HTTP_CREATED = 201;
33+ public static final int HTTP_ACCEPTED = 202;
34+ public static final int HTTP_NOT_AUTHORITATIVE = 203;
35+ public static final int HTTP_NO_CONTENT = 204;
36+ public static final int HTTP_RESET = 205;
37+ public static final int HTTP_PARTIAL = 206;
38+ public static final int HTTP_MULT_CHOICE = 300;
39+ public static final int HTTP_MOVED_PERM = 301;
40+ public static final int HTTP_MOVED_TEMP = 302;
41+ public static final int HTTP_SEE_OTHER = 303;
42+ public static final int HTTP_NOT_MODIFIED = 304;
43+ public static final int HTTP_USE_PROXY = 305;
44+ public static final int HTTP_BAD_REQUEST = 400;
45+ public static final int HTTP_UNAUTHORIZED = 401;
46+ public static final int HTTP_PAYMENT_REQUIRED = 402;
47+ public static final int HTTP_FORBIDDEN = 403;
48+ public static final int HTTP_NOT_FOUND = 404;
49+ public static final int HTTP_BAD_METHOD = 405;
50+ public static final int HTTP_NOT_ACCEPTABLE = 406;
51+ public static final int HTTP_PROXY_AUTH = 407;
52+ public static final int HTTP_CLIENT_TIMEOUT = 408;
53+ public static final int HTTP_CONFLICT = 409;
54+ public static final int HTTP_GONE = 410;
55+ public static final int HTTP_LENGTH_REQUIRED = 411;
56+ public static final int HTTP_PRECON_FAILED = 412;
57+ public static final int HTTP_ENTITY_TOO_LARGE = 413;
58+ public static final int HTTP_REQ_TOO_LONG = 414;
59+ public static final int HTTP_UNSUPPORTED_TYPE = 415;
60+ public static final int HTTP_INTERNAL_ERROR = 500;
61+ public static final int HTTP_NOT_IMPLEMENTED = 501;
62+ public static final int HTTP_BAD_GATEWAY = 502;
63+ public static final int HTTP_UNAVAILABLE = 503;
64+ public static final int HTTP_GATEWAY_TIMEOUT = 504;
65+ public static final int HTTP_VERSION = 505;
66+
67+ static String msg (int code) {
68+
69+ switch (code) {
70+ case HTTP_OK: return " OK";
71+ case HTTP_CONTINUE: return " Continue";
72+ case HTTP_CREATED: return " Created";
73+ case HTTP_ACCEPTED: return " Accepted";
74+ case HTTP_NOT_AUTHORITATIVE: return " Non-Authoritative Information";
75+ case HTTP_NO_CONTENT: return " No Content";
76+ case HTTP_RESET: return " Reset Content";
77+ case HTTP_PARTIAL: return " Partial Content";
78+ case HTTP_MULT_CHOICE: return " Multiple Choices";
79+ case HTTP_MOVED_PERM: return " Moved Permanently";
80+ case HTTP_MOVED_TEMP: return " Temporary Redirect";
81+ case HTTP_SEE_OTHER: return " See Other";
82+ case HTTP_NOT_MODIFIED: return " Not Modified";
83+ case HTTP_USE_PROXY: return " Use Proxy";
84+ case HTTP_BAD_REQUEST: return " Bad Request";
85+ case HTTP_UNAUTHORIZED: return " Unauthorized" ;
86+ case HTTP_PAYMENT_REQUIRED: return " Payment Required";
87+ case HTTP_FORBIDDEN: return " Forbidden";
88+ case HTTP_NOT_FOUND: return " Not Found";
89+ case HTTP_BAD_METHOD: return " Method Not Allowed";
90+ case HTTP_NOT_ACCEPTABLE: return " Not Acceptable";
91+ case HTTP_PROXY_AUTH: return " Proxy Authentication Required";
92+ case HTTP_CLIENT_TIMEOUT: return " Request Time-Out";
93+ case HTTP_CONFLICT: return " Conflict";
94+ case HTTP_GONE: return " Gone";
95+ case HTTP_LENGTH_REQUIRED: return " Length Required";
96+ case HTTP_PRECON_FAILED: return " Precondition Failed";
97+ case HTTP_ENTITY_TOO_LARGE: return " Request Entity Too Large";
98+ case HTTP_REQ_TOO_LONG: return " Request-URI Too Large";
99+ case HTTP_UNSUPPORTED_TYPE: return " Unsupported Media Type";
100+ case HTTP_INTERNAL_ERROR: return " Internal Server Error";
101+ case HTTP_NOT_IMPLEMENTED: return " Not Implemented";
102+ case HTTP_BAD_GATEWAY: return " Bad Gateway";
103+ case HTTP_UNAVAILABLE: return " Service Unavailable";
104+ case HTTP_GATEWAY_TIMEOUT: return " Gateway Timeout";
105+ case HTTP_VERSION: return " HTTP Version Not Supported";
106+ default: return "";
107+ }
108+ }
109+}
java/pkg/sun/net/httpserver/ContextList.java+97−0
@@ -0,0 +1,97 @@
1+/*
2+ * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package sun.net.httpserver;
27+
28+import java.util.*;
29+import com.sun.net.httpserver.*;
30+import com.sun.net.httpserver.spi.*;
31+
32+class ContextList {
33+
34+ final static int MAX_CONTEXTS = 50;
35+
36+ LinkedList<HttpContextImpl> list = new LinkedList<HttpContextImpl>();
37+
38+ public synchronized void add (HttpContextImpl ctx) {
39+ assert ctx.getPath() != null;
40+ list.add (ctx);
41+ }
42+
43+ public synchronized int size () {
44+ return list.size();
45+ }
46+
47+ /* initially contexts are located only by protocol:path.
48+ * Context with longest prefix matches (currently case-sensitive)
49+ */
50+ synchronized HttpContextImpl findContext (String protocol, String path) {
51+ return findContext (protocol, path, false);
52+ }
53+
54+ synchronized HttpContextImpl findContext (String protocol, String path, boolean exact) {
55+ protocol = protocol.toLowerCase();
56+ String longest = "";
57+ HttpContextImpl lc = null;
58+ for (HttpContextImpl ctx: list) {
59+ if (!ctx.getProtocol().equals(protocol)) {
60+ continue;
61+ }
62+ String cpath = ctx.getPath();
63+ if (exact && !cpath.equals (path)) {
64+ continue;
65+ } else if (!exact && !path.startsWith(cpath)) {
66+ continue;
67+ }
68+ if (cpath.length() > longest.length()) {
69+ longest = cpath;
70+ lc = ctx;
71+ }
72+ }
73+ return lc;
74+ }
75+
76+ public synchronized void remove (String protocol, String path)
77+ throws IllegalArgumentException
78+ {
79+ HttpContextImpl ctx = findContext (protocol, path, true);
80+ if (ctx == null) {
81+ throw new IllegalArgumentException ("cannot remove element from list");
82+ }
83+ list.remove (ctx);
84+ }
85+
86+ public synchronized void remove (HttpContextImpl context)
87+ throws IllegalArgumentException
88+ {
89+ for (HttpContextImpl ctx: list) {
90+ if (ctx.equals (context)) {
91+ list.remove (ctx);
92+ return;
93+ }
94+ }
95+ throw new IllegalArgumentException ("no such context in list");
96+ }
97+}
java/pkg/sun/net/httpserver/DefaultHttpServerProvider.java+41−0
@@ -0,0 +1,41 @@
1+/*
2+ * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package sun.net.httpserver;
27+
28+import java.net.*;
29+import java.io.*;
30+import com.sun.net.httpserver.*;
31+import com.sun.net.httpserver.spi.*;
32+
33+public class DefaultHttpServerProvider extends HttpServerProvider {
34+ public HttpServer createHttpServer (InetSocketAddress addr, int backlog) throws IOException {
35+ return new HttpServerImpl (addr, backlog);
36+ }
37+
38+ public HttpsServer createHttpsServer (InetSocketAddress addr, int backlog) throws IOException {
39+ return new HttpsServerImpl (addr, backlog);
40+ }
41+}
java/pkg/sun/net/httpserver/Event.java+46−0
@@ -0,0 +1,46 @@
1+/*
2+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package sun.net.httpserver;
27+
28+import com.sun.net.httpserver.*;
29+import com.sun.net.httpserver.spi.*;
30+
31+class Event {
32+
33+ ExchangeImpl exchange;
34+
35+ protected Event (ExchangeImpl t) {
36+ this.exchange = t;
37+ }
38+}
39+
40+class WriteFinishedEvent extends Event {
41+ WriteFinishedEvent (ExchangeImpl t) {
42+ super (t);
43+ assert !t.writefinished;
44+ t.writefinished = true;
45+ }
46+}
java/pkg/sun/net/httpserver/ExchangeImpl.java+456−0
@@ -0,0 +1,456 @@
1+/*
2+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package sun.net.httpserver;
27+
28+import java.io.*;
29+import java.net.*;
30+import javax.net.ssl.*;
31+import java.util.*;
32+import java.util.logging.Logger;
33+import java.text.*;
34+import com.sun.net.httpserver.*;
35+
36+class ExchangeImpl {
37+
38+ Headers reqHdrs, rspHdrs;
39+ Request req;
40+ String method;
41+ boolean writefinished;
42+ URI uri;
43+ HttpConnection connection;
44+ long reqContentLen;
45+ long rspContentLen;
46+ /* raw streams which access the socket directly */
47+ InputStream ris;
48+ OutputStream ros;
49+ Thread thread;
50+ /* close the underlying connection when this exchange finished */
51+ boolean close;
52+ boolean closed;
53+ boolean http10 = false;
54+
55+ /* for formatting the Date: header */
56+ private static final String pattern = "EEE, dd MMM yyyy HH:mm:ss zzz";
57+ private static final TimeZone gmtTZ = TimeZone.getTimeZone("GMT");
58+ private static final ThreadLocal<DateFormat> dateFormat =
59+ new ThreadLocal<DateFormat>() {
60+ @Override protected DateFormat initialValue() {
61+ DateFormat df = new SimpleDateFormat(pattern, Locale.US);
62+ df.setTimeZone(gmtTZ);
63+ return df;
64+ }
65+ };
66+
67+ private static final String HEAD = "HEAD";
68+
69+ /* streams which take care of the HTTP protocol framing
70+ * and are passed up to higher layers
71+ */
72+ InputStream uis;
73+ OutputStream uos;
74+ LeftOverInputStream uis_orig; // uis may have be a user supplied wrapper
75+ PlaceholderOutputStream uos_orig;
76+
77+ boolean sentHeaders; /* true after response headers sent */
78+ Map<String,Object> attributes;
79+ int rcode = -1;
80+ HttpPrincipal principal;
81+ ServerImpl server;
82+
83+ ExchangeImpl (
84+ String m, URI u, Request req, long len, HttpConnection connection
85+ ) throws IOException {
86+ this.req = req;
87+ this.reqHdrs = req.headers();
88+ this.rspHdrs = new Headers();
89+ this.method = m;
90+ this.uri = u;
91+ this.connection = connection;
92+ this.reqContentLen = len;
93+ /* ros only used for headers, body written directly to stream */
94+ this.ros = req.outputStream();
95+ this.ris = req.inputStream();
96+ server = getServerImpl();
97+ server.startExchange();
98+ }
99+
100+ public Headers getRequestHeaders () {
101+ return new UnmodifiableHeaders (reqHdrs);
102+ }
103+
104+ public Headers getResponseHeaders () {
105+ return rspHdrs;
106+ }
107+
108+ public URI getRequestURI () {
109+ return uri;
110+ }
111+
112+ public String getRequestMethod (){
113+ return method;
114+ }
115+
116+ public HttpContextImpl getHttpContext (){
117+ return connection.getHttpContext();
118+ }
119+
120+ private boolean isHeadRequest() {
121+ return HEAD.equals(getRequestMethod());
122+ }
123+
124+ public void close () {
125+ if (closed) {
126+ return;
127+ }
128+ closed = true;
129+
130+ /* close the underlying connection if,
131+ * a) the streams not set up yet, no response can be sent, or
132+ * b) if the wrapper output stream is not set up, or
133+ * c) if the close of the input/outpu stream fails
134+ */
135+ try {
136+ if (uis_orig == null || uos == null) {
137+ connection.close();
138+ return;
139+ }
140+ if (!uos_orig.isWrapped()) {
141+ connection.close();
142+ return;
143+ }
144+ if (!uis_orig.isClosed()) {
145+ uis_orig.close();
146+ }
147+ uos.close();
148+ } catch (IOException e) {
149+ connection.close();
150+ }
151+ }
152+
153+ public InputStream getRequestBody () {
154+ if (uis != null) {
155+ return uis;
156+ }
157+ if (reqContentLen == -1L) {
158+ uis_orig = new ChunkedInputStream (this, ris);
159+ uis = uis_orig;
160+ } else {
161+ uis_orig = new FixedLengthInputStream (this, ris, reqContentLen);
162+ uis = uis_orig;
163+ }
164+ return uis;
165+ }
166+
167+ LeftOverInputStream getOriginalInputStream () {
168+ return uis_orig;
169+ }
170+
171+ public int getResponseCode () {
172+ return rcode;
173+ }
174+
175+ public OutputStream getResponseBody () {
176+ /* TODO. Change spec to remove restriction below. Filters
177+ * cannot work with this restriction
178+ *
179+ * if (!sentHeaders) {
180+ * throw new IllegalStateException ("headers not sent");
181+ * }
182+ */
183+ if (uos == null) {
184+ uos_orig = new PlaceholderOutputStream (null);
185+ uos = uos_orig;
186+ }
187+ return uos;
188+ }
189+
190+
191+ /* returns the place holder stream, which is the stream
192+ * returned from the 1st call to getResponseBody()
193+ * The "real" ouputstream is then placed inside this
194+ */
195+ PlaceholderOutputStream getPlaceholderResponseBody () {
196+ getResponseBody();
197+ return uos_orig;
198+ }
199+
200+ public void sendResponseHeaders (int rCode, long contentLen)
201+ throws IOException
202+ {
203+ if (sentHeaders) {
204+ throw new IOException ("headers already sent");
205+ }
206+ this.rcode = rCode;
207+ String statusLine = "HTTP/1.1 "+rCode+Code.msg(rCode)+"\r\n";
208+ OutputStream tmpout = new BufferedOutputStream (ros);
209+ PlaceholderOutputStream o = getPlaceholderResponseBody();
210+ tmpout.write (bytes(statusLine, 0), 0, statusLine.length());
211+ boolean noContentToSend = false; // assume there is content
212+ rspHdrs.set ("Date", dateFormat.get().format (new Date()));
213+
214+ /* check for response type that is not allowed to send a body */
215+
216+ if ((rCode>=100 && rCode <200) /* informational */
217+ ||(rCode == 204) /* no content */
218+ ||(rCode == 304)) /* not modified */
219+ {
220+ if (contentLen != -1) {
221+ Logger logger = server.getLogger();
222+ String msg = "sendResponseHeaders: rCode = "+ rCode
223+ + ": forcing contentLen = -1";
224+ logger.warning (msg);
225+ }
226+ contentLen = -1;
227+ }
228+
229+ if (isHeadRequest()) {
230+ /* HEAD requests should not set a content length by passing it
231+ * through this API, but should instead manually set the required
232+ * headers.*/
233+ if (contentLen >= 0) {
234+ final Logger logger = server.getLogger();
235+ String msg =
236+ "sendResponseHeaders: being invoked with a content length for a HEAD request";
237+ logger.warning (msg);
238+ }
239+ noContentToSend = true;
240+ contentLen = 0;
241+ } else { /* not a HEAD request */
242+ if (contentLen == 0) {
243+ if (http10) {
244+ o.setWrappedStream (new UndefLengthOutputStream (this, ros));
245+ close = true;
246+ } else {
247+ rspHdrs.set ("Transfer-encoding", "chunked");
248+ o.setWrappedStream (new ChunkedOutputStream (this, ros));
249+ }
250+ } else {
251+ if (contentLen == -1) {
252+ noContentToSend = true;
253+ contentLen = 0;
254+ }
255+ rspHdrs.set("Content-length", Long.toString(contentLen));
256+ o.setWrappedStream (new FixedLengthOutputStream (this, ros, contentLen));
257+ }
258+ }
259+ write (rspHdrs, tmpout);
260+ this.rspContentLen = contentLen;
261+ tmpout.flush() ;
262+ tmpout = null;
263+ sentHeaders = true;
264+ if (noContentToSend) {
265+ WriteFinishedEvent e = new WriteFinishedEvent (this);
266+ server.addEvent (e);
267+ closed = true;
268+ }
269+ server.logReply (rCode, req.requestLine(), null);
270+ }
271+
272+ void write (Headers map, OutputStream os) throws IOException {
273+ Set<Map.Entry<String,List<String>>> entries = map.entrySet();
274+ for (Map.Entry<String,List<String>> entry : entries) {
275+ String key = entry.getKey();
276+ byte[] buf;
277+ List<String> values = entry.getValue();
278+ for (String val : values) {
279+ int i = key.length();
280+ buf = bytes (key, 2);
281+ buf[i++] = ':';
282+ buf[i++] = ' ';
283+ os.write (buf, 0, i);
284+ buf = bytes (val, 2);
285+ i = val.length();
286+ buf[i++] = '\r';
287+ buf[i++] = '\n';
288+ os.write (buf, 0, i);
289+ }
290+ }
291+ os.write ('\r');
292+ os.write ('\n');
293+ }
294+
295+ private byte[] rspbuf = new byte [128]; // used by bytes()
296+
297+ /**
298+ * convert string to byte[], using rspbuf
299+ * Make sure that at least "extra" bytes are free at end
300+ * of rspbuf. Reallocate rspbuf if not big enough.
301+ * caller must check return value to see if rspbuf moved
302+ */
303+ private byte[] bytes (String s, int extra) {
304+ int slen = s.length();
305+ if (slen+extra > rspbuf.length) {
306+ int diff = slen + extra - rspbuf.length;
307+ rspbuf = new byte [2* (rspbuf.length + diff)];
308+ }
309+ char c[] = s.toCharArray();
310+ for (int i=0; i<c.length; i++) {
311+ rspbuf[i] = (byte)c[i];
312+ }
313+ return rspbuf;
314+ }
315+
316+ public InetSocketAddress getRemoteAddress (){
317+ Socket s = connection.getChannel().socket();
318+ InetAddress ia = s.getInetAddress();
319+ int port = s.getPort();
320+ return new InetSocketAddress (ia, port);
321+ }
322+
323+ public InetSocketAddress getLocalAddress (){
324+ Socket s = connection.getChannel().socket();
325+ InetAddress ia = s.getLocalAddress();
326+ int port = s.getLocalPort();
327+ return new InetSocketAddress (ia, port);
328+ }
329+
330+ public String getProtocol (){
331+ String reqline = req.requestLine();
332+ int index = reqline.lastIndexOf (' ');
333+ return reqline.substring (index+1);
334+ }
335+
336+ public SSLSession getSSLSession () {
337+ SSLEngine e = connection.getSSLEngine();
338+ if (e == null) {
339+ return null;
340+ }
341+ return e.getSession();
342+ }
343+
344+ public Object getAttribute (String name) {
345+ if (name == null) {
346+ throw new NullPointerException ("null name parameter");
347+ }
348+ if (attributes == null) {
349+ attributes = getHttpContext().getAttributes();
350+ }
351+ return attributes.get (name);
352+ }
353+
354+ public void setAttribute (String name, Object value) {
355+ if (name == null) {
356+ throw new NullPointerException ("null name parameter");
357+ }
358+ if (attributes == null) {
359+ attributes = getHttpContext().getAttributes();
360+ }
361+ attributes.put (name, value);
362+ }
363+
364+ public void setStreams (InputStream i, OutputStream o) {
365+ assert uis != null;
366+ if (i != null) {
367+ uis = i;
368+ }
369+ if (o != null) {
370+ uos = o;
371+ }
372+ }
373+
374+ /**
375+ * PP
376+ */
377+ HttpConnection getConnection () {
378+ return connection;
379+ }
380+
381+ ServerImpl getServerImpl () {
382+ return getHttpContext().getServerImpl();
383+ }
384+
385+ public HttpPrincipal getPrincipal () {
386+ return principal;
387+ }
388+
389+ void setPrincipal (HttpPrincipal principal) {
390+ this.principal = principal;
391+ }
392+
393+ static ExchangeImpl get (HttpExchange t) {
394+ if (t instanceof HttpExchangeImpl) {
395+ return ((HttpExchangeImpl)t).getExchangeImpl();
396+ } else {
397+ assert t instanceof HttpsExchangeImpl;
398+ return ((HttpsExchangeImpl)t).getExchangeImpl();
399+ }
400+ }
401+}
402+
403+/**
404+ * An OutputStream which wraps another stream
405+ * which is supplied either at creation time, or sometime later.
406+ * If a caller/user tries to write to this stream before
407+ * the wrapped stream has been provided, then an IOException will
408+ * be thrown.
409+ */
410+class PlaceholderOutputStream extends java.io.OutputStream {
411+
412+ OutputStream wrapped;
413+
414+ PlaceholderOutputStream (OutputStream os) {
415+ wrapped = os;
416+ }
417+
418+ void setWrappedStream (OutputStream os) {
419+ wrapped = os;
420+ }
421+
422+ boolean isWrapped () {
423+ return wrapped != null;
424+ }
425+
426+ private void checkWrap () throws IOException {
427+ if (wrapped == null) {
428+ throw new IOException ("response headers not sent yet");
429+ }
430+ }
431+
432+ public void write(int b) throws IOException {
433+ checkWrap();
434+ wrapped.write (b);
435+ }
436+
437+ public void write(byte b[]) throws IOException {
438+ checkWrap();
439+ wrapped.write (b);
440+ }
441+
442+ public void write(byte b[], int off, int len) throws IOException {
443+ checkWrap();
444+ wrapped.write (b, off, len);
445+ }
446+
447+ public void flush() throws IOException {
448+ checkWrap();
449+ wrapped.flush();
450+ }
451+
452+ public void close() throws IOException {
453+ checkWrap();
454+ wrapped.close();
455+ }
456+}
java/pkg/sun/net/httpserver/FixedLengthInputStream.java+82−0
@@ -0,0 +1,82 @@
1+/*
2+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package sun.net.httpserver;
27+
28+import java.io.*;
29+import java.net.*;
30+import com.sun.net.httpserver.*;
31+import com.sun.net.httpserver.spi.*;
32+
33+/**
34+ * a class which allows the caller to read up to a defined
35+ * number of bytes off an underlying stream
36+ * close() does not close the underlying stream
37+ */
38+
39+class FixedLengthInputStream extends LeftOverInputStream {
40+ private long remaining;
41+
42+ FixedLengthInputStream (ExchangeImpl t, InputStream src, long len) {
43+ super (t, src);
44+ this.remaining = len;
45+ }
46+
47+ protected int readImpl (byte[]b, int off, int len) throws IOException {
48+
49+ eof = (remaining == 0L);
50+ if (eof) {
51+ return -1;
52+ }
53+ if (len > remaining) {
54+ len = (int)remaining;
55+ }
56+ int n = in.read(b, off, len);
57+ if (n > -1) {
58+ remaining -= n;
59+ if (remaining == 0) {
60+ t.getServerImpl().requestCompleted (t.getConnection());
61+ }
62+ }
63+ return n;
64+ }
65+
66+ public int available () throws IOException {
67+ if (eof) {
68+ return 0;
69+ }
70+ int n = in.available();
71+ return n < remaining? n: (int)remaining;
72+ }
73+
74+ public boolean markSupported () {return false;}
75+
76+ public void mark (int l) {
77+ }
78+
79+ public void reset () throws IOException {
80+ throw new IOException ("mark/reset not supported");
81+ }
82+}
java/pkg/sun/net/httpserver/FixedLengthOutputStream.java+104−0
@@ -0,0 +1,104 @@
1+/*
2+ * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package sun.net.httpserver;
27+
28+import java.io.*;
29+import java.net.*;
30+import com.sun.net.httpserver.*;
31+import com.sun.net.httpserver.spi.*;
32+
33+/**
34+ * a class which allows the caller to write up to a defined
35+ * number of bytes to an underlying stream. The caller *must*
36+ * write the pre-defined number or else an exception will be thrown
37+ * and the whole request aborted.
38+ * normal close() does not close the underlying stream
39+ */
40+
41+class FixedLengthOutputStream extends FilterOutputStream
42+{
43+ private long remaining;
44+ private boolean eof = false;
45+ private boolean closed = false;
46+ ExchangeImpl t;
47+
48+ FixedLengthOutputStream (ExchangeImpl t, OutputStream src, long len) {
49+ super (src);
50+ this.t = t;
51+ this.remaining = len;
52+ }
53+
54+ public void write (int b) throws IOException {
55+ if (closed) {
56+ throw new IOException ("stream closed");
57+ }
58+ eof = (remaining == 0);
59+ if (eof) {
60+ throw new StreamClosedException();
61+ }
62+ out.write(b);
63+ remaining --;
64+ }
65+
66+ public void write (byte[]b, int off, int len) throws IOException {
67+ if (closed) {
68+ throw new IOException ("stream closed");
69+ }
70+ eof = (remaining == 0);
71+ if (eof) {
72+ throw new StreamClosedException();
73+ }
74+ if (len > remaining) {
75+ // stream is still open, caller can retry
76+ throw new IOException ("too many bytes to write to stream");
77+ }
78+ out.write(b, off, len);
79+ remaining -= len;
80+ }
81+
82+ public void close () throws IOException {
83+ if (closed) {
84+ return;
85+ }
86+ closed = true;
87+ if (remaining > 0) {
88+ t.close();
89+ throw new IOException ("insufficient bytes written to stream");
90+ }
91+ flush();
92+ eof = true;
93+ LeftOverInputStream is = t.getOriginalInputStream();
94+ if (!is.isClosed()) {
95+ try {
96+ is.close();
97+ } catch (IOException e) {}
98+ }
99+ WriteFinishedEvent e = new WriteFinishedEvent (t);
100+ t.getHttpContext().getServerImpl().addEvent (e);
101+ }
102+
103+ // flush is a pass-through
104+}
java/pkg/sun/net/httpserver/HttpConnection.java+196−0
@@ -0,0 +1,196 @@
1+/*
2+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package sun.net.httpserver;
27+
28+import java.io.*;
29+import javax.net.ssl.*;
30+import java.nio.channels.*;
31+import java.util.logging.Logger;
32+import com.sun.net.httpserver.*;
33+import com.sun.net.httpserver.spi.*;
34+
35+/**
36+ * encapsulates all the connection specific state for a HTTP/S connection
37+ * one of these is hung from the selector attachment and is used to locate
38+ * everything from that.
39+ */
40+class HttpConnection {
41+
42+ HttpContextImpl context;
43+ SSLEngine engine;
44+ SSLContext sslContext;
45+ SSLStreams sslStreams;
46+
47+ /* high level streams returned to application */
48+ InputStream i;
49+
50+ /* low level stream that sits directly over channel */
51+ InputStream raw;
52+ OutputStream rawout;
53+
54+ SocketChannel chan;
55+ SelectionKey selectionKey;
56+ String protocol;
57+ long time;
58+ volatile long creationTime; // time this connection was created
59+ volatile long rspStartedTime; // time we started writing the response
60+ int remaining;
61+ boolean closed = false;
62+ Logger logger;
63+
64+ public enum State {IDLE, REQUEST, RESPONSE};
65+ volatile State state;
66+
67+ public String toString() {
68+ String s = null;
69+ if (chan != null) {
70+ s = chan.toString();
71+ }
72+ return s;
73+ }
74+
75+ HttpConnection () {
76+ }
77+
78+ void setChannel (SocketChannel c) {
79+ chan = c;
80+ }
81+
82+ void setContext (HttpContextImpl ctx) {
83+ context = ctx;
84+ }
85+
86+ State getState() {
87+ return state;
88+ }
89+
90+ void setState (State s) {
91+ state = s;
92+ }
93+
94+ void setParameters (
95+ InputStream in, OutputStream rawout, SocketChannel chan,
96+ SSLEngine engine, SSLStreams sslStreams, SSLContext sslContext, String protocol,
97+ HttpContextImpl context, InputStream raw
98+ )
99+ {
100+ this.context = context;
101+ this.i = in;
102+ this.rawout = rawout;
103+ this.raw = raw;
104+ this.protocol = protocol;
105+ this.engine = engine;
106+ this.chan = chan;
107+ this.sslContext = sslContext;
108+ this.sslStreams = sslStreams;
109+ this.logger = context.getLogger();
110+ }
111+
112+ SocketChannel getChannel () {
113+ return chan;
114+ }
115+
116+ synchronized void close () {
117+ if (closed) {
118+ return;
119+ }
120+ closed = true;
121+ if (logger != null && chan != null) {
122+ logger.finest ("Closing connection: " + chan.toString());
123+ }
124+
125+ if (!chan.isOpen()) {
126+ ServerImpl.dprint ("Channel already closed");
127+ return;
128+ }
129+ try {
130+ /* need to ensure temporary selectors are closed */
131+ if (raw != null) {
132+ raw.close();
133+ }
134+ } catch (IOException e) {
135+ ServerImpl.dprint (e);
136+ }
137+ try {
138+ if (rawout != null) {
139+ rawout.close();
140+ }
141+ } catch (IOException e) {
142+ ServerImpl.dprint (e);
143+ }
144+ try {
145+ if (sslStreams != null) {
146+ sslStreams.close();
147+ }
148+ } catch (IOException e) {
149+ ServerImpl.dprint (e);
150+ }
151+ try {
152+ chan.close();
153+ } catch (IOException e) {
154+ ServerImpl.dprint (e);
155+ }
156+ }
157+
158+ /* remaining is the number of bytes left on the lowest level inputstream
159+ * after the exchange is finished
160+ */
161+ void setRemaining (int r) {
162+ remaining = r;
163+ }
164+
165+ int getRemaining () {
166+ return remaining;
167+ }
168+
169+ SelectionKey getSelectionKey () {
170+ return selectionKey;
171+ }
172+
173+ InputStream getInputStream () {
174+ return i;
175+ }
176+
177+ OutputStream getRawOutputStream () {
178+ return rawout;
179+ }
180+
181+ String getProtocol () {
182+ return protocol;
183+ }
184+
185+ SSLEngine getSSLEngine () {
186+ return engine;
187+ }
188+
189+ SSLContext getSSLContext () {
190+ return sslContext;
191+ }
192+
193+ HttpContextImpl getHttpContext () {
194+ return context;
195+ }
196+}
java/pkg/sun/net/httpserver/HttpContextImpl.java+152−0
@@ -0,0 +1,152 @@
1+/*
2+ * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package sun.net.httpserver;
27+import java.io.*;
28+import java.util.*;
29+import java.util.logging.Logger;
30+import com.sun.net.httpserver.*;
31+import com.sun.net.httpserver.spi.*;
32+
33+/**
34+ * HttpContext represents a mapping between a protocol (http or https) together with a root URI path
35+ * to a {@link HttpHandler} which is invoked to handle requests destined
36+ * for the protocol/path on the associated HttpServer.
37+ * <p>
38+ * HttpContext instances are created by {@link HttpServer#createContext(String,String,HttpHandler,Object)}
39+ * <p>
40+ */
41+class HttpContextImpl extends HttpContext {
42+
43+ private String path;
44+ private String protocol;
45+ private HttpHandler handler;
46+ private Map<String,Object> attributes = new HashMap<String,Object>();
47+ private ServerImpl server;
48+ /* system filters, not visible to applications */
49+ private LinkedList<Filter> sfilters = new LinkedList<Filter>();
50+ /* user filters, set by applications */
51+ private LinkedList<Filter> ufilters = new LinkedList<Filter>();
52+ private Authenticator authenticator;
53+ private AuthFilter authfilter;
54+
55+ /**
56+ * constructor is package private.
57+ */
58+ HttpContextImpl (String protocol, String path, HttpHandler cb, ServerImpl server) {
59+ if (path == null || protocol == null || path.length() < 1 || path.charAt(0) != '/') {
60+ throw new IllegalArgumentException ("Illegal value for path or protocol");
61+ }
62+ this.protocol = protocol.toLowerCase();
63+ this.path = path;
64+ if (!this.protocol.equals ("http") && !this.protocol.equals ("https")) {
65+ throw new IllegalArgumentException ("Illegal value for protocol");
66+ }
67+ this.handler = cb;
68+ this.server = server;
69+ authfilter = new AuthFilter(null);
70+ sfilters.add (authfilter);
71+ }
72+
73+ /**
74+ * returns the handler for this context
75+ * @return the HttpHandler for this context
76+ */
77+ public HttpHandler getHandler () {
78+ return handler;
79+ }
80+
81+ public void setHandler (HttpHandler h) {
82+ if (h == null) {
83+ throw new NullPointerException ("Null handler parameter");
84+ }
85+ if (handler != null) {
86+ throw new IllegalArgumentException ("handler already set");
87+ }
88+ handler = h;
89+ }
90+
91+ /**
92+ * returns the path this context was created with
93+ * @return this context's path
94+ */
95+ public String getPath() {
96+ return path;
97+ }
98+
99+ /**
100+ * returns the server this context was created with
101+ * @return this context's server
102+ */
103+ public HttpServer getServer () {
104+ return server.getWrapper();
105+ }
106+
107+ ServerImpl getServerImpl () {
108+ return server;
109+ }
110+
111+ /**
112+ * returns the protocol this context was created with
113+ * @return this context's path
114+ */
115+ public String getProtocol() {
116+ return protocol;
117+ }
118+
119+ /**
120+ * returns a mutable Map, which can be used to pass
121+ * configuration and other data to Filter modules
122+ * and to the context's exchange handler.
123+ * <p>
124+ * Every attribute stored in this Map will be visible to
125+ * every HttpExchange processed by this context
126+ */
127+ public Map<String,Object> getAttributes() {
128+ return attributes;
129+ }
130+
131+ public List<Filter> getFilters () {
132+ return ufilters;
133+ }
134+
135+ List<Filter> getSystemFilters () {
136+ return sfilters;
137+ }
138+
139+ public Authenticator setAuthenticator (Authenticator auth) {
140+ Authenticator old = authenticator;
141+ authenticator = auth;
142+ authfilter.setAuthenticator (auth);
143+ return old;
144+ }
145+
146+ public Authenticator getAuthenticator () {
147+ return authenticator;
148+ }
149+ Logger getLogger () {
150+ return server.getLogger();
151+ }
152+}
java/pkg/sun/net/httpserver/HttpError.java+37−0
@@ -0,0 +1,37 @@
1+/*
2+ * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package sun.net.httpserver;
27+
28+/**
29+ * A Http error
30+ */
31+class HttpError extends RuntimeException {
32+ private static final long serialVersionUID = 8769596371344178179L;
33+
34+ public HttpError (String msg) {
35+ super (msg);
36+ }
37+}
java/pkg/sun/net/httpserver/HttpExchangeImpl.java+120−0
@@ -0,0 +1,120 @@
1+/*
2+ * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package sun.net.httpserver;
27+
28+import java.io.*;
29+import java.nio.*;
30+import java.nio.channels.*;
31+import java.net.*;
32+import javax.net.ssl.*;
33+import java.util.*;
34+import sun.net.www.MessageHeader;
35+import com.sun.net.httpserver.*;
36+import com.sun.net.httpserver.spi.*;
37+
38+class HttpExchangeImpl extends HttpExchange {
39+
40+ ExchangeImpl impl;
41+
42+ HttpExchangeImpl (ExchangeImpl impl) {
43+ this.impl = impl;
44+ }
45+
46+ public Headers getRequestHeaders () {
47+ return impl.getRequestHeaders();
48+ }
49+
50+ public Headers getResponseHeaders () {
51+ return impl.getResponseHeaders();
52+ }
53+
54+ public URI getRequestURI () {
55+ return impl.getRequestURI();
56+ }
57+
58+ public String getRequestMethod (){
59+ return impl.getRequestMethod();
60+ }
61+
62+ public HttpContextImpl getHttpContext (){
63+ return impl.getHttpContext();
64+ }
65+
66+ public void close () {
67+ impl.close();
68+ }
69+
70+ public InputStream getRequestBody () {
71+ return impl.getRequestBody();
72+ }
73+
74+ public int getResponseCode () {
75+ return impl.getResponseCode();
76+ }
77+
78+ public OutputStream getResponseBody () {
79+ return impl.getResponseBody();
80+ }
81+
82+
83+ public void sendResponseHeaders (int rCode, long contentLen)
84+ throws IOException
85+ {
86+ impl.sendResponseHeaders (rCode, contentLen);
87+ }
88+
89+ public InetSocketAddress getRemoteAddress (){
90+ return impl.getRemoteAddress();
91+ }
92+
93+ public InetSocketAddress getLocalAddress (){
94+ return impl.getLocalAddress();
95+ }
96+
97+ public String getProtocol (){
98+ return impl.getProtocol();
99+ }
100+
101+ public Object getAttribute (String name) {
102+ return impl.getAttribute (name);
103+ }
104+
105+ public void setAttribute (String name, Object value) {
106+ impl.setAttribute (name, value);
107+ }
108+
109+ public void setStreams (InputStream i, OutputStream o) {
110+ impl.setStreams (i, o);
111+ }
112+
113+ public HttpPrincipal getPrincipal () {
114+ return impl.getPrincipal();
115+ }
116+
117+ ExchangeImpl getExchangeImpl () {
118+ return impl;
119+ }
120+}
java/pkg/sun/net/httpserver/HttpServerImpl.java+92−0
@@ -0,0 +1,92 @@
1+/*
2+ * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package sun.net.httpserver;
27+
28+import java.net.*;
29+import java.io.*;
30+import java.nio.*;
31+import java.security.*;
32+import java.nio.channels.*;
33+import java.util.*;
34+import java.util.concurrent.*;
35+import javax.net.ssl.*;
36+import com.sun.net.httpserver.*;
37+import com.sun.net.httpserver.spi.*;
38+
39+public class HttpServerImpl extends HttpServer {
40+
41+ ServerImpl server;
42+
43+ HttpServerImpl () throws IOException {
44+ this (new InetSocketAddress(80), 0);
45+ }
46+
47+ HttpServerImpl (
48+ InetSocketAddress addr, int backlog
49+ ) throws IOException {
50+ server = new ServerImpl (this, "http", addr, backlog);
51+ }
52+
53+ public void bind (InetSocketAddress addr, int backlog) throws IOException {
54+ server.bind (addr, backlog);
55+ }
56+
57+ public void start () {
58+ server.start();
59+ }
60+
61+ public void setExecutor (Executor executor) {
62+ server.setExecutor(executor);
63+ }
64+
65+ public Executor getExecutor () {
66+ return server.getExecutor();
67+ }
68+
69+ public void stop (int delay) {
70+ server.stop (delay);
71+ }
72+
73+ public HttpContextImpl createContext (String path, HttpHandler handler) {
74+ return server.createContext (path, handler);
75+ }
76+
77+ public HttpContextImpl createContext (String path) {
78+ return server.createContext (path);
79+ }
80+
81+ public void removeContext (String path) throws IllegalArgumentException {
82+ server.removeContext (path);
83+ }
84+
85+ public void removeContext (HttpContext context) throws IllegalArgumentException {
86+ server.removeContext (context);
87+ }
88+
89+ public InetSocketAddress getAddress() {
90+ return server.getAddress();
91+ }
92+}
java/pkg/sun/net/httpserver/HttpsExchangeImpl.java+124−0
@@ -0,0 +1,124 @@
1+/*
2+ * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package sun.net.httpserver;
27+
28+import java.io.*;
29+import java.nio.*;
30+import java.nio.channels.*;
31+import java.net.*;
32+import javax.net.ssl.*;
33+import java.util.*;
34+import sun.net.www.MessageHeader;
35+import com.sun.net.httpserver.*;
36+import com.sun.net.httpserver.spi.*;
37+
38+class HttpsExchangeImpl extends HttpsExchange {
39+
40+ ExchangeImpl impl;
41+
42+ HttpsExchangeImpl (ExchangeImpl impl) throws IOException {
43+ this.impl = impl;
44+ }
45+
46+ public Headers getRequestHeaders () {
47+ return impl.getRequestHeaders();
48+ }
49+
50+ public Headers getResponseHeaders () {
51+ return impl.getResponseHeaders();
52+ }
53+
54+ public URI getRequestURI () {
55+ return impl.getRequestURI();
56+ }
57+
58+ public String getRequestMethod (){
59+ return impl.getRequestMethod();
60+ }
61+
62+ public HttpContextImpl getHttpContext (){
63+ return impl.getHttpContext();
64+ }
65+
66+ public void close () {
67+ impl.close();
68+ }
69+
70+ public InputStream getRequestBody () {
71+ return impl.getRequestBody();
72+ }
73+
74+ public int getResponseCode () {
75+ return impl.getResponseCode();
76+ }
77+
78+ public OutputStream getResponseBody () {
79+ return impl.getResponseBody();
80+ }
81+
82+
83+ public void sendResponseHeaders (int rCode, long contentLen)
84+ throws IOException
85+ {
86+ impl.sendResponseHeaders (rCode, contentLen);
87+ }
88+
89+ public InetSocketAddress getRemoteAddress (){
90+ return impl.getRemoteAddress();
91+ }
92+
93+ public InetSocketAddress getLocalAddress (){
94+ return impl.getLocalAddress();
95+ }
96+
97+ public String getProtocol (){
98+ return impl.getProtocol();
99+ }
100+
101+ public SSLSession getSSLSession () {
102+ return impl.getSSLSession ();
103+ }
104+
105+ public Object getAttribute (String name) {
106+ return impl.getAttribute (name);
107+ }
108+
109+ public void setAttribute (String name, Object value) {
110+ impl.setAttribute (name, value);
111+ }
112+
113+ public void setStreams (InputStream i, OutputStream o) {
114+ impl.setStreams (i, o);
115+ }
116+
117+ public HttpPrincipal getPrincipal () {
118+ return impl.getPrincipal();
119+ }
120+
121+ ExchangeImpl getExchangeImpl () {
122+ return impl;
123+ }
124+}
java/pkg/sun/net/httpserver/HttpsServerImpl.java+100−0
@@ -0,0 +1,100 @@
1+/*
2+ * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package sun.net.httpserver;
27+
28+import java.net.*;
29+import java.io.*;
30+import java.nio.*;
31+import java.security.*;
32+import java.nio.channels.*;
33+import java.util.*;
34+import java.util.concurrent.*;
35+import javax.net.ssl.*;
36+import com.sun.net.httpserver.*;
37+import com.sun.net.httpserver.spi.*;
38+
39+public class HttpsServerImpl extends HttpsServer {
40+
41+ ServerImpl server;
42+
43+ HttpsServerImpl () throws IOException {
44+ this (new InetSocketAddress(443), 0);
45+ }
46+
47+ HttpsServerImpl (
48+ InetSocketAddress addr, int backlog
49+ ) throws IOException {
50+ server = new ServerImpl (this, "https", addr, backlog);
51+ }
52+
53+ public void setHttpsConfigurator (HttpsConfigurator config) {
54+ server.setHttpsConfigurator (config);
55+ }
56+
57+ public HttpsConfigurator getHttpsConfigurator () {
58+ return server.getHttpsConfigurator();
59+ }
60+
61+ public void bind (InetSocketAddress addr, int backlog) throws IOException {
62+ server.bind (addr, backlog);
63+ }
64+
65+ public void start () {
66+ server.start();
67+ }
68+
69+ public void setExecutor (Executor executor) {
70+ server.setExecutor(executor);
71+ }
72+
73+ public Executor getExecutor () {
74+ return server.getExecutor();
75+ }
76+
77+ public void stop (int delay) {
78+ server.stop (delay);
79+ }
80+
81+ public HttpContextImpl createContext (String path, HttpHandler handler) {
82+ return server.createContext (path, handler);
83+ }
84+
85+ public HttpContextImpl createContext (String path) {
86+ return server.createContext (path);
87+ }
88+
89+ public void removeContext (String path) throws IllegalArgumentException {
90+ server.removeContext (path);
91+ }
92+
93+ public void removeContext (HttpContext context) throws IllegalArgumentException {
94+ server.removeContext (context);
95+ }
96+
97+ public InetSocketAddress getAddress() {
98+ return server.getAddress();
99+ }
100+}
java/pkg/sun/net/httpserver/LeftOverInputStream.java+122−0
@@ -0,0 +1,122 @@
1+/*
2+ * Copyright (c) 2005, 2007, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package sun.net.httpserver;
27+
28+import java.io.*;
29+import com.sun.net.httpserver.*;
30+import com.sun.net.httpserver.spi.*;
31+
32+/**
33+ * a (filter) input stream which can tell us if bytes are "left over"
34+ * on the underlying stream which can be read (without blocking)
35+ * on another instance of this class.
36+ *
37+ * The class can also report if all bytes "expected" to be read
38+ * were read, by the time close() was called. In that case,
39+ * bytes may be drained to consume them (by calling drain() ).
40+ *
41+ * isEOF() returns true, when all expected bytes have been read
42+ */
43+abstract class LeftOverInputStream extends FilterInputStream {
44+ ExchangeImpl t;
45+ ServerImpl server;
46+ protected boolean closed = false;
47+ protected boolean eof = false;
48+ byte[] one = new byte [1];
49+
50+ public LeftOverInputStream (ExchangeImpl t, InputStream src) {
51+ super (src);
52+ this.t = t;
53+ this.server = t.getServerImpl();
54+ }
55+ /**
56+ * if bytes are left over buffered on *the UNDERLYING* stream
57+ */
58+ public boolean isDataBuffered () throws IOException {
59+ assert eof;
60+ return super.available() > 0;
61+ }
62+
63+ public void close () throws IOException {
64+ if (closed) {
65+ return;
66+ }
67+ closed = true;
68+ if (!eof) {
69+ eof = drain (ServerConfig.getDrainAmount());
70+ }
71+ }
72+
73+ public boolean isClosed () {
74+ return closed;
75+ }
76+
77+ public boolean isEOF () {
78+ return eof;
79+ }
80+
81+ protected abstract int readImpl (byte[]b, int off, int len) throws IOException;
82+
83+ public synchronized int read () throws IOException {
84+ if (closed) {
85+ throw new IOException ("Stream is closed");
86+ }
87+ int c = readImpl (one, 0, 1);
88+ if (c == -1 || c == 0) {
89+ return c;
90+ } else {
91+ return one[0] & 0xFF;
92+ }
93+ }
94+
95+ public synchronized int read (byte[]b, int off, int len) throws IOException {
96+ if (closed) {
97+ throw new IOException ("Stream is closed");
98+ }
99+ return readImpl (b, off, len);
100+ }
101+
102+ /**
103+ * read and discard up to l bytes or "eof" occurs,
104+ * (whichever is first). Then return true if the stream
105+ * is at eof (ie. all bytes were read) or false if not
106+ * (still bytes to be read)
107+ */
108+ public boolean drain (long l) throws IOException {
109+ int bufSize = 2048;
110+ byte[] db = new byte [bufSize];
111+ while (l > 0) {
112+ long len = readImpl (db, 0, bufSize);
113+ if (len == -1) {
114+ eof = true;
115+ return true;
116+ } else {
117+ l = l - len;
118+ }
119+ }
120+ return false;
121+ }
122+}
java/pkg/sun/net/httpserver/Request.java+402−0
@@ -0,0 +1,402 @@
1+/*
2+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package sun.net.httpserver;
27+
28+import java.util.*;
29+import java.nio.*;
30+import java.net.*;
31+import java.io.*;
32+import java.nio.channels.*;
33+import com.sun.net.httpserver.*;
34+import com.sun.net.httpserver.spi.*;
35+
36+/**
37+ */
38+class Request {
39+
40+ final static int BUF_LEN = 2048;
41+ final static byte CR = 13;
42+ final static byte LF = 10;
43+
44+ private String startLine;
45+ private SocketChannel chan;
46+ private InputStream is;
47+ private OutputStream os;
48+
49+ Request (InputStream rawInputStream, OutputStream rawout) throws IOException {
50+ this.chan = chan;
51+ is = rawInputStream;
52+ os = rawout;
53+ do {
54+ startLine = readLine();
55+ if (startLine == null) {
56+ return;
57+ }
58+ /* skip blank lines */
59+ } while (startLine == null ? false : startLine.equals (""));
60+ }
61+
62+
63+ char[] buf = new char [BUF_LEN];
64+ int pos;
65+ StringBuffer lineBuf;
66+
67+ public InputStream inputStream () {
68+ return is;
69+ }
70+
71+ public OutputStream outputStream () {
72+ return os;
73+ }
74+
75+ /**
76+ * read a line from the stream returning as a String.
77+ * Not used for reading headers.
78+ */
79+
80+ public String readLine () throws IOException {
81+ boolean gotCR = false, gotLF = false;
82+ pos = 0; lineBuf = new StringBuffer();
83+ while (!gotLF) {
84+ int c = is.read();
85+ if (c == -1) {
86+ return null;
87+ }
88+ if (gotCR) {
89+ if (c == LF) {
90+ gotLF = true;
91+ } else {
92+ gotCR = false;
93+ consume (CR);
94+ consume (c);
95+ }
96+ } else {
97+ if (c == CR) {
98+ gotCR = true;
99+ } else {
100+ consume (c);
101+ }
102+ }
103+ }
104+ lineBuf.append (buf, 0, pos);
105+ return new String (lineBuf);
106+ }
107+
108+ private void consume (int c) {
109+ if (pos == BUF_LEN) {
110+ lineBuf.append (buf);
111+ pos = 0;
112+ }
113+ buf[pos++] = (char)c;
114+ }
115+
116+ /**
117+ * returns the request line (first line of a request)
118+ */
119+ public String requestLine () {
120+ return startLine;
121+ }
122+
123+ Headers hdrs = null;
124+
125+ Headers headers () throws IOException {
126+ if (hdrs != null) {
127+ return hdrs;
128+ }
129+ hdrs = new Headers();
130+
131+ char s[] = new char[10];
132+ int len = 0;
133+
134+ int firstc = is.read();
135+
136+ // check for empty headers
137+ if (firstc == CR || firstc == LF) {
138+ int c = is.read();
139+ if (c == CR || c == LF) {
140+ return hdrs;
141+ }
142+ s[0] = (char)firstc;
143+ len = 1;
144+ firstc = c;
145+ }
146+
147+ while (firstc != LF && firstc != CR && firstc >= 0) {
148+ int keyend = -1;
149+ int c;
150+ boolean inKey = firstc > ' ';
151+ s[len++] = (char) firstc;
152+ parseloop:{
153+ while ((c = is.read()) >= 0) {
154+ switch (c) {
155+ case ':':
156+ if (inKey && len > 0)
157+ keyend = len;
158+ inKey = false;
159+ break;
160+ case '\t':
161+ c = ' ';
162+ case ' ':
163+ inKey = false;
164+ break;
165+ case CR:
166+ case LF:
167+ firstc = is.read();
168+ if (c == CR && firstc == LF) {
169+ firstc = is.read();
170+ if (firstc == CR)
171+ firstc = is.read();
172+ }
173+ if (firstc == LF || firstc == CR || firstc > ' ')
174+ break parseloop;
175+ /* continuation */
176+ c = ' ';
177+ break;
178+ }
179+ if (len >= s.length) {
180+ char ns[] = new char[s.length * 2];
181+ System.arraycopy(s, 0, ns, 0, len);
182+ s = ns;
183+ }
184+ s[len++] = (char) c;
185+ }
186+ firstc = -1;
187+ }
188+ while (len > 0 && s[len - 1] <= ' ')
189+ len--;
190+ String k;
191+ if (keyend <= 0) {
192+ k = null;
193+ keyend = 0;
194+ } else {
195+ k = String.copyValueOf(s, 0, keyend);
196+ if (keyend < len && s[keyend] == ':')
197+ keyend++;
198+ while (keyend < len && s[keyend] <= ' ')
199+ keyend++;
200+ }
201+ String v;
202+ if (keyend >= len)
203+ v = new String();
204+ else
205+ v = String.copyValueOf(s, keyend, len - keyend);
206+ hdrs.add (k,v);
207+ len = 0;
208+ }
209+ return hdrs;
210+ }
211+
212+ /**
213+ * Implements blocking reading semantics on top of a non-blocking channel
214+ */
215+
216+ static class ReadStream extends InputStream {
217+ SocketChannel channel;
218+ ByteBuffer chanbuf;
219+ byte[] one;
220+ private boolean closed = false, eof = false;
221+ ByteBuffer markBuf; /* reads may be satisifed from this buffer */
222+ boolean marked;
223+ boolean reset;
224+ int readlimit;
225+ static long readTimeout;
226+ ServerImpl server;
227+ final static int BUFSIZE = 8 * 1024;
228+
229+ public ReadStream (ServerImpl server, SocketChannel chan) throws IOException {
230+ this.channel = chan;
231+ this.server = server;
232+ chanbuf = ByteBuffer.allocate (BUFSIZE);
233+ chanbuf.clear();
234+ one = new byte[1];
235+ closed = marked = reset = false;
236+ }
237+
238+ public synchronized int read (byte[] b) throws IOException {
239+ return read (b, 0, b.length);
240+ }
241+
242+ public synchronized int read () throws IOException {
243+ int result = read (one, 0, 1);
244+ if (result == 1) {
245+ return one[0] & 0xFF;
246+ } else {
247+ return -1;
248+ }
249+ }
250+
251+ public synchronized int read (byte[] b, int off, int srclen) throws IOException {
252+
253+ int canreturn, willreturn;
254+
255+ if (closed)
256+ throw new IOException ("Stream closed");
257+
258+ if (eof) {
259+ return -1;
260+ }
261+
262+ assert channel.isBlocking();
263+
264+ if (off < 0 || srclen < 0|| srclen > (b.length-off)) {
265+ throw new IndexOutOfBoundsException ();
266+ }
267+
268+ if (reset) { /* satisfy from markBuf */
269+ canreturn = markBuf.remaining ();
270+ willreturn = canreturn>srclen ? srclen : canreturn;
271+ markBuf.get(b, off, willreturn);
272+ if (canreturn == willreturn) {
273+ reset = false;
274+ }
275+ } else { /* satisfy from channel */
276+ chanbuf.clear ();
277+ if (srclen < BUFSIZE) {
278+ chanbuf.limit (srclen);
279+ }
280+ do {
281+ willreturn = channel.read (chanbuf);
282+ } while (willreturn == 0);
283+ if (willreturn == -1) {
284+ eof = true;
285+ return -1;
286+ }
287+ chanbuf.flip ();
288+ chanbuf.get(b, off, willreturn);
289+
290+ if (marked) { /* copy into markBuf */
291+ try {
292+ markBuf.put (b, off, willreturn);
293+ } catch (BufferOverflowException e) {
294+ marked = false;
295+ }
296+ }
297+ }
298+ return willreturn;
299+ }
300+
301+ public boolean markSupported () {
302+ return true;
303+ }
304+
305+ /* Does not query the OS socket */
306+ public synchronized int available () throws IOException {
307+ if (closed)
308+ throw new IOException ("Stream is closed");
309+
310+ if (eof)
311+ return -1;
312+
313+ if (reset)
314+ return markBuf.remaining();
315+
316+ return chanbuf.remaining();
317+ }
318+
319+ public void close () throws IOException {
320+ if (closed) {
321+ return;
322+ }
323+ channel.close ();
324+ closed = true;
325+ }
326+
327+ public synchronized void mark (int readlimit) {
328+ if (closed)
329+ return;
330+ this.readlimit = readlimit;
331+ markBuf = ByteBuffer.allocate (readlimit);
332+ marked = true;
333+ reset = false;
334+ }
335+
336+ public synchronized void reset () throws IOException {
337+ if (closed )
338+ return;
339+ if (!marked)
340+ throw new IOException ("Stream not marked");
341+ marked = false;
342+ reset = true;
343+ markBuf.flip ();
344+ }
345+ }
346+
347+ static class WriteStream extends java.io.OutputStream {
348+ SocketChannel channel;
349+ ByteBuffer buf;
350+ SelectionKey key;
351+ boolean closed;
352+ byte[] one;
353+ ServerImpl server;
354+
355+ public WriteStream (ServerImpl server, SocketChannel channel) throws IOException {
356+ this.channel = channel;
357+ this.server = server;
358+ assert channel.isBlocking();
359+ closed = false;
360+ one = new byte [1];
361+ buf = ByteBuffer.allocate (4096);
362+ }
363+
364+ public synchronized void write (int b) throws IOException {
365+ one[0] = (byte)b;
366+ write (one, 0, 1);
367+ }
368+
369+ public synchronized void write (byte[] b) throws IOException {
370+ write (b, 0, b.length);
371+ }
372+
373+ public synchronized void write (byte[] b, int off, int len) throws IOException {
374+ int l = len;
375+ if (closed)
376+ throw new IOException ("stream is closed");
377+
378+ int cap = buf.capacity();
379+ if (cap < len) {
380+ int diff = len - cap;
381+ buf = ByteBuffer.allocate (2*(cap+diff));
382+ }
383+ buf.clear();
384+ buf.put (b, off, len);
385+ buf.flip ();
386+ int n;
387+ while ((n = channel.write (buf)) < l) {
388+ l -= n;
389+ if (l == 0)
390+ return;
391+ }
392+ }
393+
394+ public void close () throws IOException {
395+ if (closed)
396+ return;
397+ //server.logStackTrace ("Request.OS.close: isOpen="+channel.isOpen());
398+ channel.close ();
399+ closed = true;
400+ }
401+ }
402+}
java/pkg/sun/net/httpserver/SSLStreams.java+662−0
@@ -0,0 +1,662 @@
1+/*
2+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package sun.net.httpserver;
27+
28+import java.net.*;
29+import java.nio.*;
30+import java.io.*;
31+import java.nio.channels.*;
32+import java.util.*;
33+import java.util.concurrent.*;
34+import java.util.concurrent.locks.*;
35+import javax.net.ssl.*;
36+import javax.net.ssl.SSLEngineResult.*;
37+import com.sun.net.httpserver.*;
38+import com.sun.net.httpserver.spi.*;
39+
40+/**
41+ * given a non-blocking SocketChannel, it produces
42+ * (blocking) streams which encrypt/decrypt the SSL content
43+ * and handle the SSL handshaking automatically.
44+ */
45+
46+class SSLStreams {
47+
48+ SSLContext sslctx;
49+ SocketChannel chan;
50+ TimeSource time;
51+ ServerImpl server;
52+ SSLEngine engine;
53+ EngineWrapper wrapper;
54+ OutputStream os;
55+ InputStream is;
56+
57+ /* held by thread doing the hand-shake on this connection */
58+ Lock handshaking = new ReentrantLock();
59+
60+ SSLStreams (ServerImpl server, SSLContext sslctx, SocketChannel chan) throws IOException {
61+ this.server = server;
62+ this.time= (TimeSource)server;
63+ this.sslctx= sslctx;
64+ this.chan= chan;
65+ InetSocketAddress addr =
66+ (InetSocketAddress)chan.socket().getRemoteSocketAddress();
67+ engine = sslctx.createSSLEngine (addr.getHostName(), addr.getPort());
68+ engine.setUseClientMode (false);
69+ HttpsConfigurator cfg = server.getHttpsConfigurator();
70+ configureEngine (cfg, addr);
71+ wrapper = new EngineWrapper (chan, engine);
72+ }
73+
74+ private void configureEngine(HttpsConfigurator cfg, InetSocketAddress addr){
75+ if (cfg != null) {
76+ Parameters params = new Parameters (cfg, addr);
77+//BEGIN_TIGER_EXCLUDE
78+ cfg.configure (params);
79+ SSLParameters sslParams = params.getSSLParameters();
80+ if (sslParams != null) {
81+ engine.setSSLParameters (sslParams);
82+ } else
83+//END_TIGER_EXCLUDE
84+ {
85+ /* tiger compatibility */
86+ if (params.getCipherSuites() != null) {
87+ try {
88+ engine.setEnabledCipherSuites (
89+ params.getCipherSuites()
90+ );
91+ } catch (IllegalArgumentException e) { /* LOG */}
92+ }
93+ engine.setNeedClientAuth (params.getNeedClientAuth());
94+ engine.setWantClientAuth (params.getWantClientAuth());
95+ if (params.getProtocols() != null) {
96+ try {
97+ engine.setEnabledProtocols (
98+ params.getProtocols()
99+ );
100+ } catch (IllegalArgumentException e) { /* LOG */}
101+ }
102+ }
103+ }
104+ }
105+
106+ class Parameters extends HttpsParameters {
107+ InetSocketAddress addr;
108+ HttpsConfigurator cfg;
109+
110+ Parameters (HttpsConfigurator cfg, InetSocketAddress addr) {
111+ this.addr = addr;
112+ this.cfg = cfg;
113+ }
114+ public InetSocketAddress getClientAddress () {
115+ return addr;
116+ }
117+ public HttpsConfigurator getHttpsConfigurator() {
118+ return cfg;
119+ }
120+//BEGIN_TIGER_EXCLUDE
121+ SSLParameters params;
122+ public void setSSLParameters (SSLParameters p) {
123+ params = p;
124+ }
125+ SSLParameters getSSLParameters () {
126+ return params;
127+ }
128+//END_TIGER_EXCLUDE
129+ }
130+
131+ /**
132+ * cleanup resources allocated inside this object
133+ */
134+ void close () throws IOException {
135+ wrapper.close();
136+ }
137+
138+ /**
139+ * return the SSL InputStream
140+ */
141+ InputStream getInputStream () throws IOException {
142+ if (is == null) {
143+ is = new InputStream();
144+ }
145+ return is;
146+ }
147+
148+ /**
149+ * return the SSL OutputStream
150+ */
151+ OutputStream getOutputStream () throws IOException {
152+ if (os == null) {
153+ os = new OutputStream();
154+ }
155+ return os;
156+ }
157+
158+ SSLEngine getSSLEngine () {
159+ return engine;
160+ }
161+
162+ /**
163+ * request the engine to repeat the handshake on this session
164+ * the handshake must be driven by reads/writes on the streams
165+ * Normally, not necessary to call this.
166+ */
167+ void beginHandshake() throws SSLException {
168+ engine.beginHandshake();
169+ }
170+
171+ class WrapperResult {
172+ SSLEngineResult result;
173+
174+ /* if passed in buffer was not big enough then the
175+ * a reallocated buffer is returned here
176+ */
177+ ByteBuffer buf;
178+ }
179+
180+ int app_buf_size;
181+ int packet_buf_size;
182+
183+ enum BufType {
184+ PACKET, APPLICATION
185+ };
186+
187+ private ByteBuffer allocate (BufType type) {
188+ return allocate (type, -1);
189+ }
190+
191+ private ByteBuffer allocate (BufType type, int len) {
192+ assert engine != null;
193+ synchronized (this) {
194+ int size;
195+ if (type == BufType.PACKET) {
196+ if (packet_buf_size == 0) {
197+ SSLSession sess = engine.getSession();
198+ packet_buf_size = sess.getPacketBufferSize();
199+ }
200+ if (len > packet_buf_size) {
201+ packet_buf_size = len;
202+ }
203+ size = packet_buf_size;
204+ } else {
205+ if (app_buf_size == 0) {
206+ SSLSession sess = engine.getSession();
207+ app_buf_size = sess.getApplicationBufferSize();
208+ }
209+ if (len > app_buf_size) {
210+ app_buf_size = len;
211+ }
212+ size = app_buf_size;
213+ }
214+ return ByteBuffer.allocate (size);
215+ }
216+ }
217+
218+ /* reallocates the buffer by :-
219+ * 1. creating a new buffer double the size of the old one
220+ * 2. putting the contents of the old buffer into the new one
221+ * 3. set xx_buf_size to the new size if it was smaller than new size
222+ *
223+ * flip is set to true if the old buffer needs to be flipped
224+ * before it is copied.
225+ */
226+ private ByteBuffer realloc (ByteBuffer b, boolean flip, BufType type) {
227+ synchronized (this) {
228+ int nsize = 2 * b.capacity();
229+ ByteBuffer n = allocate (type, nsize);
230+ if (flip) {
231+ b.flip();
232+ }
233+ n.put(b);
234+ b = n;
235+ }
236+ return b;
237+ }
238+ /**
239+ * This is a thin wrapper over SSLEngine and the SocketChannel,
240+ * which guarantees the ordering of wraps/unwraps with respect to the underlying
241+ * channel read/writes. It handles the UNDER/OVERFLOW status codes
242+ * It does not handle the handshaking status codes, or the CLOSED status code
243+ * though once the engine is closed, any attempt to read/write to it
244+ * will get an exception. The overall result is returned.
245+ * It functions synchronously/blocking
246+ */
247+ class EngineWrapper {
248+
249+ SocketChannel chan;
250+ SSLEngine engine;
251+ Object wrapLock, unwrapLock;
252+ ByteBuffer unwrap_src, wrap_dst;
253+ boolean closed = false;
254+ int u_remaining; // the number of bytes left in unwrap_src after an unwrap()
255+
256+ EngineWrapper (SocketChannel chan, SSLEngine engine) throws IOException {
257+ this.chan = chan;
258+ this.engine = engine;
259+ wrapLock = new Object();
260+ unwrapLock = new Object();
261+ unwrap_src = allocate(BufType.PACKET);
262+ wrap_dst = allocate(BufType.PACKET);
263+ }
264+
265+ void close () throws IOException {
266+ }
267+
268+ /* try to wrap and send the data in src. Handles OVERFLOW.
269+ * Might block if there is an outbound blockage or if another
270+ * thread is calling wrap(). Also, might not send any data
271+ * if an unwrap is needed.
272+ */
273+ WrapperResult wrapAndSend(ByteBuffer src) throws IOException {
274+ return wrapAndSendX(src, false);
275+ }
276+
277+ WrapperResult wrapAndSendX(ByteBuffer src, boolean ignoreClose) throws IOException {
278+ if (closed && !ignoreClose) {
279+ throw new IOException ("Engine is closed");
280+ }
281+ Status status;
282+ WrapperResult r = new WrapperResult();
283+ synchronized (wrapLock) {
284+ wrap_dst.clear();
285+ do {
286+ r.result = engine.wrap (src, wrap_dst);
287+ status = r.result.getStatus();
288+ if (status == Status.BUFFER_OVERFLOW) {
289+ wrap_dst = realloc (wrap_dst, true, BufType.PACKET);
290+ }
291+ } while (status == Status.BUFFER_OVERFLOW);
292+ if (status == Status.CLOSED && !ignoreClose) {
293+ closed = true;
294+ return r;
295+ }
296+ if (r.result.bytesProduced() > 0) {
297+ wrap_dst.flip();
298+ int l = wrap_dst.remaining();
299+ assert l == r.result.bytesProduced();
300+ while (l>0) {
301+ l -= chan.write (wrap_dst);
302+ }
303+ }
304+ }
305+ return r;
306+ }
307+
308+ /* block until a complete message is available and return it
309+ * in dst, together with the Result. dst may have been re-allocated
310+ * so caller should check the returned value in Result
311+ * If handshaking is in progress then, possibly no data is returned
312+ */
313+ WrapperResult recvAndUnwrap(ByteBuffer dst) throws IOException {
314+ Status status = Status.OK;
315+ WrapperResult r = new WrapperResult();
316+ r.buf = dst;
317+ if (closed) {
318+ throw new IOException ("Engine is closed");
319+ }
320+ boolean needData;
321+ if (u_remaining > 0) {
322+ unwrap_src.compact();
323+ unwrap_src.flip();
324+ needData = false;
325+ } else {
326+ unwrap_src.clear();
327+ needData = true;
328+ }
329+ synchronized (unwrapLock) {
330+ int x;
331+ do {
332+ if (needData) {
333+ do {
334+ x = chan.read (unwrap_src);
335+ } while (x == 0);
336+ if (x == -1) {
337+ throw new IOException ("connection closed for reading");
338+ }
339+ unwrap_src.flip();
340+ }
341+ r.result = engine.unwrap (unwrap_src, r.buf);
342+ status = r.result.getStatus();
343+ if (status == Status.BUFFER_UNDERFLOW) {
344+ if (unwrap_src.limit() == unwrap_src.capacity()) {
345+ /* buffer not big enough */
346+ unwrap_src = realloc (
347+ unwrap_src, false, BufType.PACKET
348+ );
349+ } else {
350+ /* Buffer not full, just need to read more
351+ * data off the channel. Reset pointers
352+ * for reading off SocketChannel
353+ */
354+ unwrap_src.position (unwrap_src.limit());
355+ unwrap_src.limit (unwrap_src.capacity());
356+ }
357+ needData = true;
358+ } else if (status == Status.BUFFER_OVERFLOW) {
359+ r.buf = realloc (r.buf, true, BufType.APPLICATION);
360+ needData = false;
361+ } else if (status == Status.CLOSED) {
362+ closed = true;
363+ r.buf.flip();
364+ return r;
365+ }
366+ } while (status != Status.OK);
367+ }
368+ u_remaining = unwrap_src.remaining();
369+ return r;
370+ }
371+ }
372+
373+ /**
374+ * send the data in the given ByteBuffer. If a handshake is needed
375+ * then this is handled within this method. When this call returns,
376+ * all of the given user data has been sent and any handshake has been
377+ * completed. Caller should check if engine has been closed.
378+ */
379+ public WrapperResult sendData (ByteBuffer src) throws IOException {
380+ WrapperResult r=null;
381+ while (src.remaining() > 0) {
382+ r = wrapper.wrapAndSend(src);
383+ Status status = r.result.getStatus();
384+ if (status == Status.CLOSED) {
385+ doClosure ();
386+ return r;
387+ }
388+ HandshakeStatus hs_status = r.result.getHandshakeStatus();
389+ if (hs_status != HandshakeStatus.FINISHED &&
390+ hs_status != HandshakeStatus.NOT_HANDSHAKING)
391+ {
392+ doHandshake(hs_status);
393+ }
394+ }
395+ return r;
396+ }
397+
398+ /**
399+ * read data thru the engine into the given ByteBuffer. If the
400+ * given buffer was not large enough, a new one is allocated
401+ * and returned. This call handles handshaking automatically.
402+ * Caller should check if engine has been closed.
403+ */
404+ public WrapperResult recvData (ByteBuffer dst) throws IOException {
405+ /* we wait until some user data arrives */
406+ WrapperResult r = null;
407+ assert dst.position() == 0;
408+ while (dst.position() == 0) {
409+ r = wrapper.recvAndUnwrap (dst);
410+ dst = (r.buf != dst) ? r.buf: dst;
411+ Status status = r.result.getStatus();
412+ if (status == Status.CLOSED) {
413+ doClosure ();
414+ return r;
415+ }
416+
417+ HandshakeStatus hs_status = r.result.getHandshakeStatus();
418+ if (hs_status != HandshakeStatus.FINISHED &&
419+ hs_status != HandshakeStatus.NOT_HANDSHAKING)
420+ {
421+ doHandshake (hs_status);
422+ }
423+ }
424+ dst.flip();
425+ return r;
426+ }
427+
428+ /* we've received a close notify. Need to call wrap to send
429+ * the response
430+ */
431+ void doClosure () throws IOException {
432+ try {
433+ handshaking.lock();
434+ ByteBuffer tmp = allocate(BufType.APPLICATION);
435+ WrapperResult r;
436+ do {
437+ tmp.clear();
438+ tmp.flip ();
439+ r = wrapper.wrapAndSendX (tmp, true);
440+ } while (r.result.getStatus() != Status.CLOSED);
441+ } finally {
442+ handshaking.unlock();
443+ }
444+ }
445+
446+ /* do the (complete) handshake after acquiring the handshake lock.
447+ * If two threads call this at the same time, then we depend
448+ * on the wrapper methods being idempotent. eg. if wrapAndSend()
449+ * is called with no data to send then there must be no problem
450+ */
451+ void doHandshake (HandshakeStatus hs_status) throws IOException {
452+ try {
453+ handshaking.lock();
454+ ByteBuffer tmp = allocate(BufType.APPLICATION);
455+ while (hs_status != HandshakeStatus.FINISHED &&
456+ hs_status != HandshakeStatus.NOT_HANDSHAKING)
457+ {
458+ WrapperResult r = null;
459+ switch (hs_status) {
460+ case NEED_TASK:
461+ Runnable task;
462+ while ((task = engine.getDelegatedTask()) != null) {
463+ /* run in current thread, because we are already
464+ * running an external Executor
465+ */
466+ task.run();
467+ }
468+ /* fall thru - call wrap again */
469+ case NEED_WRAP:
470+ tmp.clear();
471+ tmp.flip();
472+ r = wrapper.wrapAndSend(tmp);
473+ break;
474+
475+ case NEED_UNWRAP:
476+ tmp.clear();
477+ r = wrapper.recvAndUnwrap (tmp);
478+ if (r.buf != tmp) {
479+ tmp = r.buf;
480+ }
481+ assert tmp.position() == 0;
482+ break;
483+ }
484+ hs_status = r.result.getHandshakeStatus();
485+ }
486+ } finally {
487+ handshaking.unlock();
488+ }
489+ }
490+
491+ /**
492+ * represents an SSL input stream. Multiple https requests can
493+ * be sent over one stream. closing this stream causes an SSL close
494+ * input.
495+ */
496+ class InputStream extends java.io.InputStream {
497+
498+ ByteBuffer bbuf;
499+ boolean closed = false;
500+
501+ /* this stream eof */
502+ boolean eof = false;
503+
504+ boolean needData = true;
505+
506+ InputStream () {
507+ bbuf = allocate (BufType.APPLICATION);
508+ }
509+
510+ public int read (byte[] buf, int off, int len) throws IOException {
511+ if (closed) {
512+ throw new IOException ("SSL stream is closed");
513+ }
514+ if (eof) {
515+ return 0;
516+ }
517+ int available=0;
518+ if (!needData) {
519+ available = bbuf.remaining();
520+ needData = (available==0);
521+ }
522+ if (needData) {
523+ bbuf.clear();
524+ WrapperResult r = recvData (bbuf);
525+ bbuf = r.buf== bbuf? bbuf: r.buf;
526+ if ((available=bbuf.remaining()) == 0) {
527+ eof = true;
528+ return 0;
529+ } else {
530+ needData = false;
531+ }
532+ }
533+ /* copy as much as possible from buf into users buf */
534+ if (len > available) {
535+ len = available;
536+ }
537+ bbuf.get (buf, off, len);
538+ return len;
539+ }
540+
541+ public int available () throws IOException {
542+ return bbuf.remaining();
543+ }
544+
545+ public boolean markSupported () {
546+ return false; /* not possible with SSLEngine */
547+ }
548+
549+ public void reset () throws IOException {
550+ throw new IOException ("mark/reset not supported");
551+ }
552+
553+ public long skip (long s) throws IOException {
554+ int n = (int)s;
555+ if (closed) {
556+ throw new IOException ("SSL stream is closed");
557+ }
558+ if (eof) {
559+ return 0;
560+ }
561+ int ret = n;
562+ while (n > 0) {
563+ if (bbuf.remaining() >= n) {
564+ bbuf.position (bbuf.position()+n);
565+ return ret;
566+ } else {
567+ n -= bbuf.remaining();
568+ bbuf.clear();
569+ WrapperResult r = recvData (bbuf);
570+ bbuf = r.buf==bbuf? bbuf: r.buf;
571+ }
572+ }
573+ return ret; /* not reached */
574+ }
575+
576+ /**
577+ * close the SSL connection. All data must have been consumed
578+ * before this is called. Otherwise an exception will be thrown.
579+ * [Note. May need to revisit this. not quite the normal close() symantics
580+ */
581+ public void close () throws IOException {
582+ eof = true;
583+ engine.closeInbound ();
584+ }
585+
586+ public int read (byte[] buf) throws IOException {
587+ return read (buf, 0, buf.length);
588+ }
589+
590+ byte single[] = new byte [1];
591+
592+ public int read () throws IOException {
593+ int n = read (single, 0, 1);
594+ if (n == 0) {
595+ return -1;
596+ } else {
597+ return single[0] & 0xFF;
598+ }
599+ }
600+ }
601+
602+ /**
603+ * represents an SSL output stream. plain text data written to this stream
604+ * is encrypted by the stream. Multiple HTTPS responses can be sent on
605+ * one stream. closing this stream initiates an SSL closure
606+ */
607+ class OutputStream extends java.io.OutputStream {
608+ ByteBuffer buf;
609+ boolean closed = false;
610+ byte single[] = new byte[1];
611+
612+ OutputStream() {
613+ buf = allocate(BufType.APPLICATION);
614+ }
615+
616+ public void write(int b) throws IOException {
617+ single[0] = (byte)b;
618+ write (single, 0, 1);
619+ }
620+
621+ public void write(byte b[]) throws IOException {
622+ write (b, 0, b.length);
623+ }
624+ public void write(byte b[], int off, int len) throws IOException {
625+ if (closed) {
626+ throw new IOException ("output stream is closed");
627+ }
628+ while (len > 0) {
629+ int l = len > buf.capacity() ? buf.capacity() : len;
630+ buf.clear();
631+ buf.put (b, off, l);
632+ len -= l;
633+ off += l;
634+ buf.flip();
635+ WrapperResult r = sendData (buf);
636+ if (r.result.getStatus() == Status.CLOSED) {
637+ closed = true;
638+ if (len > 0) {
639+ throw new IOException ("output stream is closed");
640+ }
641+ }
642+ }
643+ }
644+
645+ public void flush() throws IOException {
646+ /* no-op */
647+ }
648+
649+ public void close() throws IOException {
650+ WrapperResult r=null;
651+ engine.closeOutbound();
652+ closed = true;
653+ HandshakeStatus stat = HandshakeStatus.NEED_WRAP;
654+ buf.clear();
655+ while (stat == HandshakeStatus.NEED_WRAP) {
656+ r = wrapper.wrapAndSend (buf);
657+ stat = r.result.getHandshakeStatus();
658+ }
659+ assert r.result.getStatus() == Status.CLOSED;
660+ }
661+ }
662+}
java/pkg/sun/net/httpserver/ServerConfig.java+175−0
@@ -0,0 +1,175 @@
1+/*
2+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package sun.net.httpserver;
27+
28+import com.sun.net.httpserver.*;
29+import com.sun.net.httpserver.spi.*;
30+import java.util.logging.Logger;
31+import java.security.PrivilegedAction;
32+
33+/**
34+ * Parameters that users will not likely need to set
35+ * but are useful for debugging
36+ */
37+
38+class ServerConfig {
39+
40+ static int clockTick;
41+
42+ static final int DEFAULT_CLOCK_TICK = 10000 ; // 10 sec.
43+
44+ /* These values must be a reasonable multiple of clockTick */
45+ static final long DEFAULT_IDLE_INTERVAL = 30 ; // 5 min
46+ static final int DEFAULT_MAX_IDLE_CONNECTIONS = 200 ;
47+
48+ static final long DEFAULT_MAX_REQ_TIME = -1; // default: forever
49+ static final long DEFAULT_MAX_RSP_TIME = -1; // default: forever
50+ static final long DEFAULT_TIMER_MILLIS = 1000;
51+
52+ static final long DEFAULT_DRAIN_AMOUNT = 64 * 1024;
53+
54+ static long idleInterval;
55+ static long drainAmount; // max # of bytes to drain from an inputstream
56+ static int maxIdleConnections;
57+
58+ // max time a request or response is allowed to take
59+ static long maxReqTime;
60+ static long maxRspTime;
61+ static long timerMillis;
62+ static boolean debug = false;
63+
64+ static {
65+
66+ idleInterval = ((Long)java.security.AccessController.doPrivileged(
67+ new sun.security.action.GetLongAction(
68+ "sun.net.httpserver.idleInterval",
69+ DEFAULT_IDLE_INTERVAL))).longValue() * 1000;
70+
71+ clockTick = ((Integer)java.security.AccessController.doPrivileged(
72+ new sun.security.action.GetIntegerAction(
73+ "sun.net.httpserver.clockTick",
74+ DEFAULT_CLOCK_TICK))).intValue();
75+
76+ maxIdleConnections = ((Integer)java.security.AccessController.doPrivileged(
77+ new sun.security.action.GetIntegerAction(
78+ "sun.net.httpserver.maxIdleConnections",
79+ DEFAULT_MAX_IDLE_CONNECTIONS))).intValue();
80+
81+ drainAmount = ((Long)java.security.AccessController.doPrivileged(
82+ new sun.security.action.GetLongAction(
83+ "sun.net.httpserver.drainAmount",
84+ DEFAULT_DRAIN_AMOUNT))).longValue();
85+
86+ maxReqTime = ((Long)java.security.AccessController.doPrivileged(
87+ new sun.security.action.GetLongAction(
88+ "sun.net.httpserver.maxReqTime",
89+ DEFAULT_MAX_REQ_TIME))).longValue();
90+
91+ maxRspTime = ((Long)java.security.AccessController.doPrivileged(
92+ new sun.security.action.GetLongAction(
93+ "sun.net.httpserver.maxRspTime",
94+ DEFAULT_MAX_RSP_TIME))).longValue();
95+
96+ timerMillis = ((Long)java.security.AccessController.doPrivileged(
97+ new sun.security.action.GetLongAction(
98+ "sun.net.httpserver.timerMillis",
99+ DEFAULT_TIMER_MILLIS))).longValue();
100+
101+ debug = ((Boolean)java.security.AccessController.doPrivileged(
102+ new sun.security.action.GetBooleanAction(
103+ "sun.net.httpserver.debug"))).booleanValue();
104+ }
105+
106+
107+ static void checkLegacyProperties (final Logger logger) {
108+
109+ // legacy properties that are no longer used
110+ // print a warning to logger if they are set.
111+
112+ java.security.AccessController.doPrivileged(
113+ new PrivilegedAction<Void>() {
114+ public Void run () {
115+ if (System.getProperty("sun.net.httpserver.readTimeout")
116+ !=null)
117+ {
118+ logger.warning ("sun.net.httpserver.readTimeout "+
119+ "property is no longer used. "+
120+ "Use sun.net.httpserver.maxReqTime instead."
121+ );
122+ }
123+ if (System.getProperty("sun.net.httpserver.writeTimeout")
124+ !=null)
125+ {
126+ logger.warning ("sun.net.httpserver.writeTimeout "+
127+ "property is no longer used. Use "+
128+ "sun.net.httpserver.maxRspTime instead."
129+ );
130+ }
131+ if (System.getProperty("sun.net.httpserver.selCacheTimeout")
132+ !=null)
133+ {
134+ logger.warning ("sun.net.httpserver.selCacheTimeout "+
135+ "property is no longer used."
136+ );
137+ }
138+ return null;
139+ }
140+ }
141+ );
142+ }
143+
144+ static boolean debugEnabled () {
145+ return debug;
146+ }
147+
148+ static long getIdleInterval () {
149+ return idleInterval;
150+ }
151+
152+ static int getClockTick () {
153+ return clockTick;
154+ }
155+
156+ static int getMaxIdleConnections () {
157+ return maxIdleConnections;
158+ }
159+
160+ static long getDrainAmount () {
161+ return drainAmount;
162+ }
163+
164+ static long getMaxReqTime () {
165+ return maxReqTime;
166+ }
167+
168+ static long getMaxRspTime () {
169+ return maxRspTime;
170+ }
171+
172+ static long getTimerMillis () {
173+ return timerMillis;
174+ }
175+}
java/pkg/sun/net/httpserver/ServerImpl.java+870−0
@@ -0,0 +1,870 @@
1+/*
2+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package sun.net.httpserver;
27+
28+import java.net.*;
29+import java.io.*;
30+import java.nio.*;
31+import java.security.*;
32+import java.nio.channels.*;
33+import java.util.*;
34+import java.util.concurrent.*;
35+import java.util.logging.Logger;
36+import java.util.logging.Level;
37+import javax.net.ssl.*;
38+import com.sun.net.httpserver.*;
39+import com.sun.net.httpserver.spi.*;
40+import sun.net.httpserver.HttpConnection.State;
41+
42+/**
43+ * Provides implementation for both HTTP and HTTPS
44+ */
45+class ServerImpl implements TimeSource {
46+
47+ private String protocol;
48+ private boolean https;
49+ private Executor executor;
50+ private HttpsConfigurator httpsConfig;
51+ private SSLContext sslContext;
52+ private ContextList contexts;
53+ private InetSocketAddress address;
54+ private ServerSocketChannel schan;
55+ private Selector selector;
56+ private SelectionKey listenerKey;
57+ private Set<HttpConnection> idleConnections;
58+ private Set<HttpConnection> allConnections;
59+ /* following two are used to keep track of the times
60+ * when a connection/request is first received
61+ * and when we start to send the response
62+ */
63+ private Set<HttpConnection> reqConnections;
64+ private Set<HttpConnection> rspConnections;
65+ private List<Event> events;
66+ private Object lolock = new Object();
67+ private volatile boolean finished = false;
68+ private volatile boolean terminating = false;
69+ private boolean bound = false;
70+ private boolean started = false;
71+ private volatile long time; /* current time */
72+ private volatile long subticks = 0;
73+ private volatile long ticks; /* number of clock ticks since server started */
74+ private HttpServer wrapper;
75+
76+ final static int CLOCK_TICK = ServerConfig.getClockTick();
77+ final static long IDLE_INTERVAL = ServerConfig.getIdleInterval();
78+ final static int MAX_IDLE_CONNECTIONS = ServerConfig.getMaxIdleConnections();
79+ final static long TIMER_MILLIS = ServerConfig.getTimerMillis ();
80+ final static long MAX_REQ_TIME=getTimeMillis(ServerConfig.getMaxReqTime());
81+ final static long MAX_RSP_TIME=getTimeMillis(ServerConfig.getMaxRspTime());
82+ final static boolean timer1Enabled = MAX_REQ_TIME != -1 || MAX_RSP_TIME != -1;
83+
84+ private Timer timer, timer1;
85+ private Logger logger;
86+
87+ ServerImpl (
88+ HttpServer wrapper, String protocol, InetSocketAddress addr, int backlog
89+ ) throws IOException {
90+
91+ this.protocol = protocol;
92+ this.wrapper = wrapper;
93+ this.logger = Logger.getLogger ("com.sun.net.httpserver");
94+ ServerConfig.checkLegacyProperties (logger);
95+ https = protocol.equalsIgnoreCase ("https");
96+ this.address = addr;
97+ contexts = new ContextList();
98+ schan = ServerSocketChannel.open();
99+ if (addr != null) {
100+ ServerSocket socket = schan.socket();
101+ socket.bind (addr, backlog);
102+ bound = true;
103+ }
104+ selector = Selector.open ();
105+ schan.configureBlocking (false);
106+ listenerKey = schan.register (selector, SelectionKey.OP_ACCEPT);
107+ dispatcher = new Dispatcher();
108+ idleConnections = Collections.synchronizedSet (new HashSet<HttpConnection>());
109+ allConnections = Collections.synchronizedSet (new HashSet<HttpConnection>());
110+ reqConnections = Collections.synchronizedSet (new HashSet<HttpConnection>());
111+ rspConnections = Collections.synchronizedSet (new HashSet<HttpConnection>());
112+ time = System.currentTimeMillis();
113+ timer = new Timer ("server-timer", true);
114+ timer.schedule (new ServerTimerTask(), CLOCK_TICK, CLOCK_TICK);
115+ if (timer1Enabled) {
116+ timer1 = new Timer ("server-timer1", true);
117+ timer1.schedule (new ServerTimerTask1(),TIMER_MILLIS,TIMER_MILLIS);
118+ logger.config ("HttpServer timer1 enabled period in ms: "+TIMER_MILLIS);
119+ logger.config ("MAX_REQ_TIME: "+MAX_REQ_TIME);
120+ logger.config ("MAX_RSP_TIME: "+MAX_RSP_TIME);
121+ }
122+ events = new LinkedList<Event>();
123+ logger.config ("HttpServer created "+protocol+" "+ addr);
124+ }
125+
126+ public void bind (InetSocketAddress addr, int backlog) throws IOException {
127+ if (bound) {
128+ throw new BindException ("HttpServer already bound");
129+ }
130+ if (addr == null) {
131+ throw new NullPointerException ("null address");
132+ }
133+ ServerSocket socket = schan.socket();
134+ socket.bind (addr, backlog);
135+ bound = true;
136+ }
137+
138+ public void start () {
139+ if (!bound || started || finished) {
140+ throw new IllegalStateException ("server in wrong state");
141+ }
142+ if (executor == null) {
143+ executor = new DefaultExecutor();
144+ }
145+ Thread t = new Thread (dispatcher);
146+ started = true;
147+ t.start();
148+ }
149+
150+ public void setExecutor (Executor executor) {
151+ if (started) {
152+ throw new IllegalStateException ("server already started");
153+ }
154+ this.executor = executor;
155+ }
156+
157+ private static class DefaultExecutor implements Executor {
158+ public void execute (Runnable task) {
159+ task.run();
160+ }
161+ }
162+
163+ public Executor getExecutor () {
164+ return executor;
165+ }
166+
167+ public void setHttpsConfigurator (HttpsConfigurator config) {
168+ if (config == null) {
169+ throw new NullPointerException ("null HttpsConfigurator");
170+ }
171+ if (started) {
172+ throw new IllegalStateException ("server already started");
173+ }
174+ this.httpsConfig = config;
175+ sslContext = config.getSSLContext();
176+ }
177+
178+ public HttpsConfigurator getHttpsConfigurator () {
179+ return httpsConfig;
180+ }
181+
182+ public void stop (int delay) {
183+ if (delay < 0) {
184+ throw new IllegalArgumentException ("negative delay parameter");
185+ }
186+ terminating = true;
187+ try { schan.close(); } catch (IOException e) {}
188+ selector.wakeup();
189+ long latest = System.currentTimeMillis() + delay * 1000;
190+ while (System.currentTimeMillis() < latest) {
191+ delay();
192+ if (finished) {
193+ break;
194+ }
195+ }
196+ finished = true;
197+ selector.wakeup();
198+ synchronized (allConnections) {
199+ for (HttpConnection c : allConnections) {
200+ c.close();
201+ }
202+ }
203+ allConnections.clear();
204+ idleConnections.clear();
205+ timer.cancel();
206+ if (timer1Enabled) {
207+ timer1.cancel();
208+ }
209+ }
210+
211+ Dispatcher dispatcher;
212+
213+ public synchronized HttpContextImpl createContext (String path, HttpHandler handler) {
214+ if (handler == null || path == null) {
215+ throw new NullPointerException ("null handler, or path parameter");
216+ }
217+ HttpContextImpl context = new HttpContextImpl (protocol, path, handler, this);
218+ contexts.add (context);
219+ logger.config ("context created: " + path);
220+ return context;
221+ }
222+
223+ public synchronized HttpContextImpl createContext (String path) {
224+ if (path == null) {
225+ throw new NullPointerException ("null path parameter");
226+ }
227+ HttpContextImpl context = new HttpContextImpl (protocol, path, null, this);
228+ contexts.add (context);
229+ logger.config ("context created: " + path);
230+ return context;
231+ }
232+
233+ public synchronized void removeContext (String path) throws IllegalArgumentException {
234+ if (path == null) {
235+ throw new NullPointerException ("null path parameter");
236+ }
237+ contexts.remove (protocol, path);
238+ logger.config ("context removed: " + path);
239+ }
240+
241+ public synchronized void removeContext (HttpContext context) throws IllegalArgumentException {
242+ if (!(context instanceof HttpContextImpl)) {
243+ throw new IllegalArgumentException ("wrong HttpContext type");
244+ }
245+ contexts.remove ((HttpContextImpl)context);
246+ logger.config ("context removed: " + context.getPath());
247+ }
248+
249+ public InetSocketAddress getAddress() {
250+ return (InetSocketAddress)schan.socket().getLocalSocketAddress();
251+ }
252+
253+ Selector getSelector () {
254+ return selector;
255+ }
256+
257+ void addEvent (Event r) {
258+ synchronized (lolock) {
259+ events.add (r);
260+ selector.wakeup();
261+ }
262+ }
263+
264+ /* main server listener task */
265+
266+ class Dispatcher implements Runnable {
267+
268+ private void handleEvent (Event r) {
269+ ExchangeImpl t = r.exchange;
270+ HttpConnection c = t.getConnection();
271+ try {
272+ if (r instanceof WriteFinishedEvent) {
273+
274+ int exchanges = endExchange();
275+ if (terminating && exchanges == 0) {
276+ finished = true;
277+ }
278+ responseCompleted (c);
279+ LeftOverInputStream is = t.getOriginalInputStream();
280+ if (!is.isEOF()) {
281+ t.close = true;
282+ }
283+ if (t.close || idleConnections.size() >= MAX_IDLE_CONNECTIONS) {
284+ c.close();
285+ allConnections.remove (c);
286+ } else {
287+ if (is.isDataBuffered()) {
288+ /* don't re-enable the interestops, just handle it */
289+ requestStarted (c);
290+ handle (c.getChannel(), c);
291+ } else {
292+ connsToRegister.add (c);
293+ }
294+ }
295+ }
296+ } catch (IOException e) {
297+ logger.log (
298+ Level.FINER, "Dispatcher (1)", e
299+ );
300+ c.close();
301+ }
302+ }
303+
304+ final LinkedList<HttpConnection> connsToRegister =
305+ new LinkedList<HttpConnection>();
306+
307+ void reRegister (HttpConnection c) {
308+ /* re-register with selector */
309+ try {
310+ SocketChannel chan = c.getChannel();
311+ chan.configureBlocking (false);
312+ SelectionKey key = chan.register (selector, SelectionKey.OP_READ);
313+ key.attach (c);
314+ c.selectionKey = key;
315+ c.time = getTime() + IDLE_INTERVAL;
316+ idleConnections.add (c);
317+ } catch (IOException e) {
318+ dprint(e);
319+ logger.log(Level.FINER, "Dispatcher(8)", e);
320+ c.close();
321+ }
322+ }
323+
324+ public void run() {
325+ while (!finished) {
326+ try {
327+ ListIterator<HttpConnection> li =
328+ connsToRegister.listIterator();
329+ for (HttpConnection c : connsToRegister) {
330+ reRegister(c);
331+ }
332+ connsToRegister.clear();
333+
334+ List<Event> list = null;
335+ selector.select(1000);
336+ synchronized (lolock) {
337+ if (events.size() > 0) {
338+ list = events;
339+ events = new LinkedList<Event>();
340+ }
341+ }
342+
343+ if (list != null) {
344+ for (Event r: list) {
345+ handleEvent (r);
346+ }
347+ }
348+
349+ /* process the selected list now */
350+
351+ Set<SelectionKey> selected = selector.selectedKeys();
352+ Iterator<SelectionKey> iter = selected.iterator();
353+ while (iter.hasNext()) {
354+ SelectionKey key = iter.next();
355+ iter.remove ();
356+ if (key.equals (listenerKey)) {
357+ if (terminating) {
358+ continue;
359+ }
360+ SocketChannel chan = schan.accept();
361+ if (chan == null) {
362+ continue; /* cancel something ? */
363+ }
364+ chan.configureBlocking (false);
365+ SelectionKey newkey = chan.register (selector, SelectionKey.OP_READ);
366+ HttpConnection c = new HttpConnection ();
367+ c.selectionKey = newkey;
368+ c.setChannel (chan);
369+ newkey.attach (c);
370+ requestStarted (c);
371+ allConnections.add (c);
372+ } else {
373+ try {
374+ if (key.isReadable()) {
375+ boolean closed;
376+ SocketChannel chan = (SocketChannel)key.channel();
377+ HttpConnection conn = (HttpConnection)key.attachment();
378+
379+ key.cancel();
380+ chan.configureBlocking (true);
381+ if (idleConnections.remove(conn)) {
382+ // was an idle connection so add it
383+ // to reqConnections set.
384+ requestStarted (conn);
385+ }
386+ handle (chan, conn);
387+ } else {
388+ assert false;
389+ }
390+ } catch (CancelledKeyException e) {
391+ handleException(key, null);
392+ } catch (IOException e) {
393+ handleException(key, e);
394+ }
395+ }
396+ }
397+ // call the selector just to process the cancelled keys
398+ selector.selectNow();
399+ } catch (IOException e) {
400+ logger.log (Level.FINER, "Dispatcher (4)", e);
401+ } catch (Exception e) {
402+ e.printStackTrace();
403+ logger.log (Level.FINER, "Dispatcher (7)", e);
404+ }
405+ }
406+ }
407+
408+ private void handleException (SelectionKey key, Exception e) {
409+ HttpConnection conn = (HttpConnection)key.attachment();
410+ if (e != null) {
411+ logger.log (Level.FINER, "Dispatcher (2)", e);
412+ }
413+ closeConnection(conn);
414+ }
415+
416+ public void handle (SocketChannel chan, HttpConnection conn)
417+ throws IOException
418+ {
419+ try {
420+ Exchange t = new Exchange (chan, protocol, conn);
421+ executor.execute (t);
422+ } catch (HttpError e1) {
423+ logger.log (Level.FINER, "Dispatcher (4)", e1);
424+ closeConnection(conn);
425+ } catch (IOException e) {
426+ logger.log (Level.FINER, "Dispatcher (5)", e);
427+ closeConnection(conn);
428+ }
429+ }
430+ }
431+
432+ static boolean debug = ServerConfig.debugEnabled ();
433+
434+ static synchronized void dprint (String s) {
435+ if (debug) {
436+ System.out.println (s);
437+ }
438+ }
439+
440+ static synchronized void dprint (Exception e) {
441+ if (debug) {
442+ System.out.println (e);
443+ e.printStackTrace();
444+ }
445+ }
446+
447+ Logger getLogger () {
448+ return logger;
449+ }
450+
451+ private void closeConnection(HttpConnection conn) {
452+ conn.close();
453+ allConnections.remove(conn);
454+ switch (conn.getState()) {
455+ case REQUEST:
456+ reqConnections.remove(conn);
457+ break;
458+ case RESPONSE:
459+ rspConnections.remove(conn);
460+ break;
461+ case IDLE:
462+ idleConnections.remove(conn);
463+ break;
464+ }
465+ assert !reqConnections.remove(conn);
466+ assert !rspConnections.remove(conn);
467+ assert !idleConnections.remove(conn);
468+ }
469+
470+ /* per exchange task */
471+
472+ class Exchange implements Runnable {
473+ SocketChannel chan;
474+ HttpConnection connection;
475+ HttpContextImpl context;
476+ InputStream rawin;
477+ OutputStream rawout;
478+ String protocol;
479+ ExchangeImpl tx;
480+ HttpContextImpl ctx;
481+ boolean rejected = false;
482+
483+ Exchange (SocketChannel chan, String protocol, HttpConnection conn) throws IOException {
484+ this.chan = chan;
485+ this.connection = conn;
486+ this.protocol = protocol;
487+ }
488+
489+ public void run () {
490+ /* context will be null for new connections */
491+ context = connection.getHttpContext();
492+ boolean newconnection;
493+ SSLEngine engine = null;
494+ String requestLine = null;
495+ SSLStreams sslStreams = null;
496+ try {
497+ if (context != null ) {
498+ this.rawin = connection.getInputStream();
499+ this.rawout = connection.getRawOutputStream();
500+ newconnection = false;
501+ } else {
502+ /* figure out what kind of connection this is */
503+ newconnection = true;
504+ if (https) {
505+ if (sslContext == null) {
506+ logger.warning ("SSL connection received. No https contxt created");
507+ throw new HttpError ("No SSL context established");
508+ }
509+ sslStreams = new SSLStreams (ServerImpl.this, sslContext, chan);
510+ rawin = sslStreams.getInputStream();
511+ rawout = sslStreams.getOutputStream();
512+ engine = sslStreams.getSSLEngine();
513+ connection.sslStreams = sslStreams;
514+ } else {
515+ rawin = new BufferedInputStream(
516+ new Request.ReadStream (
517+ ServerImpl.this, chan
518+ ));
519+ rawout = new Request.WriteStream (
520+ ServerImpl.this, chan
521+ );
522+ }
523+ connection.raw = rawin;
524+ connection.rawout = rawout;
525+ }
526+ Request req = new Request (rawin, rawout);
527+ requestLine = req.requestLine();
528+ if (requestLine == null) {
529+ /* connection closed */
530+ closeConnection(connection);
531+ return;
532+ }
533+ int space = requestLine.indexOf (' ');
534+ if (space == -1) {
535+ reject (Code.HTTP_BAD_REQUEST,
536+ requestLine, "Bad request line");
537+ return;
538+ }
539+ String method = requestLine.substring (0, space);
540+ int start = space+1;
541+ space = requestLine.indexOf(' ', start);
542+ if (space == -1) {
543+ reject (Code.HTTP_BAD_REQUEST,
544+ requestLine, "Bad request line");
545+ return;
546+ }
547+ String uriStr = requestLine.substring (start, space);
548+ URI uri = new URI (uriStr);
549+ start = space+1;
550+ String version = requestLine.substring (start);
551+ Headers headers = req.headers();
552+ String s = headers.getFirst ("Transfer-encoding");
553+ long clen = 0L;
554+ if (s !=null && s.equalsIgnoreCase ("chunked")) {
555+ clen = -1L;
556+ } else {
557+ s = headers.getFirst ("Content-Length");
558+ if (s != null) {
559+ clen = Long.parseLong(s);
560+ }
561+ if (clen == 0) {
562+ requestCompleted (connection);
563+ }
564+ }
565+ ctx = contexts.findContext (protocol, uri.getPath());
566+ if (ctx == null) {
567+ reject (Code.HTTP_NOT_FOUND,
568+ requestLine, "No context found for request");
569+ return;
570+ }
571+ connection.setContext (ctx);
572+ if (ctx.getHandler() == null) {
573+ reject (Code.HTTP_INTERNAL_ERROR,
574+ requestLine, "No handler for context");
575+ return;
576+ }
577+ tx = new ExchangeImpl (
578+ method, uri, req, clen, connection
579+ );
580+ String chdr = headers.getFirst("Connection");
581+ Headers rheaders = tx.getResponseHeaders();
582+
583+ if (chdr != null && chdr.equalsIgnoreCase ("close")) {
584+ tx.close = true;
585+ }
586+ if (version.equalsIgnoreCase ("http/1.0")) {
587+ tx.http10 = true;
588+ if (chdr == null) {
589+ tx.close = true;
590+ rheaders.set ("Connection", "close");
591+ } else if (chdr.equalsIgnoreCase ("keep-alive")) {
592+ rheaders.set ("Connection", "keep-alive");
593+ int idle=(int)ServerConfig.getIdleInterval()/1000;
594+ int max=(int)ServerConfig.getMaxIdleConnections();
595+ String val = "timeout="+idle+", max="+max;
596+ rheaders.set ("Keep-Alive", val);
597+ }
598+ }
599+
600+ if (newconnection) {
601+ connection.setParameters (
602+ rawin, rawout, chan, engine, sslStreams,
603+ sslContext, protocol, ctx, rawin
604+ );
605+ }
606+ /* check if client sent an Expect 100 Continue.
607+ * In that case, need to send an interim response.
608+ * In future API may be modified to allow app to
609+ * be involved in this process.
610+ */
611+ String exp = headers.getFirst("Expect");
612+ if (exp != null && exp.equalsIgnoreCase ("100-continue")) {
613+ logReply (100, requestLine, null);
614+ sendReply (
615+ Code.HTTP_CONTINUE, false, null
616+ );
617+ }
618+ /* uf is the list of filters seen/set by the user.
619+ * sf is the list of filters established internally
620+ * and which are not visible to the user. uc and sc
621+ * are the corresponding Filter.Chains.
622+ * They are linked together by a LinkHandler
623+ * so that they can both be invoked in one call.
624+ */
625+ List<Filter> sf = ctx.getSystemFilters();
626+ List<Filter> uf = ctx.getFilters();
627+
628+ Filter.Chain sc = new Filter.Chain(sf, ctx.getHandler());
629+ Filter.Chain uc = new Filter.Chain(uf, new LinkHandler (sc));
630+
631+ /* set up the two stream references */
632+ tx.getRequestBody();
633+ tx.getResponseBody();
634+ if (https) {
635+ uc.doFilter (new HttpsExchangeImpl (tx));
636+ } else {
637+ uc.doFilter (new HttpExchangeImpl (tx));
638+ }
639+
640+ } catch (IOException e1) {
641+ logger.log (Level.FINER, "ServerImpl.Exchange (1)", e1);
642+ closeConnection(connection);
643+ } catch (NumberFormatException e3) {
644+ reject (Code.HTTP_BAD_REQUEST,
645+ requestLine, "NumberFormatException thrown");
646+ } catch (URISyntaxException e) {
647+ reject (Code.HTTP_BAD_REQUEST,
648+ requestLine, "URISyntaxException thrown");
649+ } catch (Exception e4) {
650+ logger.log (Level.FINER, "ServerImpl.Exchange (2)", e4);
651+ closeConnection(connection);
652+ }
653+ }
654+
655+ /* used to link to 2 or more Filter.Chains together */
656+
657+ class LinkHandler implements HttpHandler {
658+ Filter.Chain nextChain;
659+
660+ LinkHandler (Filter.Chain nextChain) {
661+ this.nextChain = nextChain;
662+ }
663+
664+ public void handle (HttpExchange exchange) throws IOException {
665+ nextChain.doFilter (exchange);
666+ }
667+ }
668+
669+ void reject (int code, String requestStr, String message) {
670+ rejected = true;
671+ logReply (code, requestStr, message);
672+ sendReply (
673+ code, false, "<h1>"+code+Code.msg(code)+"</h1>"+message
674+ );
675+ closeConnection(connection);
676+ }
677+
678+ void sendReply (
679+ int code, boolean closeNow, String text)
680+ {
681+ try {
682+ StringBuilder builder = new StringBuilder (512);
683+ builder.append ("HTTP/1.1 ")
684+ .append (code).append (Code.msg(code)).append ("\r\n");
685+
686+ if (text != null && text.length() != 0) {
687+ builder.append ("Content-Length: ")
688+ .append (text.length()).append ("\r\n")
689+ .append ("Content-Type: text/html\r\n");
690+ } else {
691+ builder.append ("Content-Length: 0\r\n");
692+ text = "";
693+ }
694+ if (closeNow) {
695+ builder.append ("Connection: close\r\n");
696+ }
697+ builder.append ("\r\n").append (text);
698+ String s = builder.toString();
699+ byte[] b = s.getBytes("ISO8859_1");
700+ rawout.write (b);
701+ rawout.flush();
702+ if (closeNow) {
703+ closeConnection(connection);
704+ }
705+ } catch (IOException e) {
706+ logger.log (Level.FINER, "ServerImpl.sendReply", e);
707+ closeConnection(connection);
708+ }
709+ }
710+
711+ }
712+
713+ void logReply (int code, String requestStr, String text) {
714+ if (!logger.isLoggable(Level.FINE)) {
715+ return;
716+ }
717+ if (text == null) {
718+ text = "";
719+ }
720+ String r;
721+ if (requestStr.length() > 80) {
722+ r = requestStr.substring (0, 80) + "<TRUNCATED>";
723+ } else {
724+ r = requestStr;
725+ }
726+ String message = r + " [" + code + " " +
727+ Code.msg(code) + "] ("+text+")";
728+ logger.fine (message);
729+ }
730+
731+ long getTicks() {
732+ return ticks;
733+ }
734+
735+ public long getTime() {
736+ return time;
737+ }
738+
739+ void delay () {
740+ Thread.yield();
741+ try {
742+ Thread.sleep (200);
743+ } catch (InterruptedException e) {}
744+ }
745+
746+ private int exchangeCount = 0;
747+
748+ synchronized void startExchange () {
749+ exchangeCount ++;
750+ }
751+
752+ synchronized int endExchange () {
753+ exchangeCount --;
754+ assert exchangeCount >= 0;
755+ return exchangeCount;
756+ }
757+
758+ HttpServer getWrapper () {
759+ return wrapper;
760+ }
761+
762+ void requestStarted (HttpConnection c) {
763+ c.creationTime = getTime();
764+ c.setState (State.REQUEST);
765+ reqConnections.add (c);
766+ }
767+
768+ // called after a request has been completely read
769+ // by the server. This stops the timer which would
770+ // close the connection if the request doesn't arrive
771+ // quickly enough. It then starts the timer
772+ // that ensures the client reads the response in a timely
773+ // fashion.
774+
775+ void requestCompleted (HttpConnection c) {
776+ assert c.getState() == State.REQUEST;
777+ reqConnections.remove (c);
778+ c.rspStartedTime = getTime();
779+ rspConnections.add (c);
780+ c.setState (State.RESPONSE);
781+ }
782+
783+ // called after response has been sent
784+ void responseCompleted (HttpConnection c) {
785+ assert c.getState() == State.RESPONSE;
786+ rspConnections.remove (c);
787+ c.setState (State.IDLE);
788+ }
789+
790+ /**
791+ * TimerTask run every CLOCK_TICK ms
792+ */
793+ class ServerTimerTask extends TimerTask {
794+ public void run () {
795+ LinkedList<HttpConnection> toClose = new LinkedList<HttpConnection>();
796+ time = System.currentTimeMillis();
797+ ticks ++;
798+ synchronized (idleConnections) {
799+ for (HttpConnection c : idleConnections) {
800+ if (c.time <= time) {
801+ toClose.add (c);
802+ }
803+ }
804+ for (HttpConnection c : toClose) {
805+ idleConnections.remove (c);
806+ allConnections.remove (c);
807+ c.close();
808+ }
809+ }
810+ }
811+ }
812+
813+ class ServerTimerTask1 extends TimerTask {
814+
815+ // runs every TIMER_MILLIS
816+ public void run () {
817+ LinkedList<HttpConnection> toClose = new LinkedList<HttpConnection>();
818+ time = System.currentTimeMillis();
819+ synchronized (reqConnections) {
820+ if (MAX_REQ_TIME != -1) {
821+ for (HttpConnection c : reqConnections) {
822+ if (c.creationTime + TIMER_MILLIS + MAX_REQ_TIME <= time) {
823+ toClose.add (c);
824+ }
825+ }
826+ for (HttpConnection c : toClose) {
827+ logger.log (Level.FINE, "closing: no request: " + c);
828+ reqConnections.remove (c);
829+ allConnections.remove (c);
830+ c.close();
831+ }
832+ }
833+ }
834+ toClose = new LinkedList<HttpConnection>();
835+ synchronized (rspConnections) {
836+ if (MAX_RSP_TIME != -1) {
837+ for (HttpConnection c : rspConnections) {
838+ if (c.rspStartedTime + TIMER_MILLIS +MAX_RSP_TIME <= time) {
839+ toClose.add (c);
840+ }
841+ }
842+ for (HttpConnection c : toClose) {
843+ logger.log (Level.FINE, "closing: no response: " + c);
844+ rspConnections.remove (c);
845+ allConnections.remove (c);
846+ c.close();
847+ }
848+ }
849+ }
850+ }
851+ }
852+
853+ void logStackTrace (String s) {
854+ logger.finest (s);
855+ StringBuilder b = new StringBuilder ();
856+ StackTraceElement[] e = Thread.currentThread().getStackTrace();
857+ for (int i=0; i<e.length; i++) {
858+ b.append (e[i].toString()).append("\n");
859+ }
860+ logger.finest (b.toString());
861+ }
862+
863+ static long getTimeMillis(long secs) {
864+ if (secs == -1) {
865+ return -1;
866+ } else {
867+ return secs * 1000;
868+ }
869+ }
870+}
java/pkg/sun/net/httpserver/StreamClosedException.java+32−0
@@ -0,0 +1,32 @@
1+/*
2+ * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package sun.net.httpserver;
27+
28+import java.io.*;
29+
30+class StreamClosedException extends IOException {
31+ private static final long serialVersionUID = -4485921499356327937L;
32+}
java/pkg/sun/net/httpserver/TimeSource.java+30−0
@@ -0,0 +1,30 @@
1+/*
2+ * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package sun.net.httpserver;
27+
28+interface TimeSource {
29+ public long getTime();
30+}
java/pkg/sun/net/httpserver/UndefLengthOutputStream.java+81−0
@@ -0,0 +1,81 @@
1+/*
2+ * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package sun.net.httpserver;
27+
28+import java.io.*;
29+import java.net.*;
30+import com.sun.net.httpserver.*;
31+import com.sun.net.httpserver.spi.*;
32+
33+/**
34+ * a class which allows the caller to write an indefinite
35+ * number of bytes to an underlying stream , but without using
36+ * chunked encoding. Used for http/1.0 clients only
37+ * The underlying connection needs to be closed afterwards.
38+ */
39+
40+class UndefLengthOutputStream extends FilterOutputStream
41+{
42+ private boolean closed = false;
43+ ExchangeImpl t;
44+
45+ UndefLengthOutputStream (ExchangeImpl t, OutputStream src) {
46+ super (src);
47+ this.t = t;
48+ }
49+
50+ public void write (int b) throws IOException {
51+ if (closed) {
52+ throw new IOException ("stream closed");
53+ }
54+ out.write(b);
55+ }
56+
57+ public void write (byte[]b, int off, int len) throws IOException {
58+ if (closed) {
59+ throw new IOException ("stream closed");
60+ }
61+ out.write(b, off, len);
62+ }
63+
64+ public void close () throws IOException {
65+ if (closed) {
66+ return;
67+ }
68+ closed = true;
69+ flush();
70+ LeftOverInputStream is = t.getOriginalInputStream();
71+ if (!is.isClosed()) {
72+ try {
73+ is.close();
74+ } catch (IOException e) {}
75+ }
76+ WriteFinishedEvent e = new WriteFinishedEvent (t);
77+ t.getHttpContext().getServerImpl().addEvent (e);
78+ }
79+
80+ // flush is a pass-through
81+}
java/pkg/sun/net/httpserver/UnmodifiableHeaders.java+101−0
@@ -0,0 +1,101 @@
1+/*
2+ * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package sun.net.httpserver;
27+
28+import java.util.*;
29+import com.sun.net.httpserver.*;
30+
31+class UnmodifiableHeaders extends Headers {
32+
33+ Headers map;
34+
35+ UnmodifiableHeaders(Headers map) {
36+ this.map = map;
37+ }
38+
39+ public int size() {return map.size();}
40+
41+ public boolean isEmpty() {return map.isEmpty();}
42+
43+ public boolean containsKey(Object key) {
44+ return map.containsKey (key);
45+ }
46+
47+ public boolean containsValue(Object value) {
48+ return map.containsValue(value);
49+ }
50+
51+ public List<String> get(Object key) {
52+ return map.get(key);
53+ }
54+
55+ public String getFirst (String key) {
56+ return map.getFirst(key);
57+ }
58+
59+
60+ public List<String> put(String key, List<String> value) {
61+ return map.put (key, value);
62+ }
63+
64+ public void add (String key, String value) {
65+ throw new UnsupportedOperationException ("unsupported operation");
66+ }
67+
68+ public void set (String key, String value) {
69+ throw new UnsupportedOperationException ("unsupported operation");
70+ }
71+
72+ public List<String> remove(Object key) {
73+ throw new UnsupportedOperationException ("unsupported operation");
74+ }
75+
76+ public void putAll(Map<? extends String,? extends List<String>> t) {
77+ throw new UnsupportedOperationException ("unsupported operation");
78+ }
79+
80+ public void clear() {
81+ throw new UnsupportedOperationException ("unsupported operation");
82+ }
83+
84+ public Set<String> keySet() {
85+ return Collections.unmodifiableSet (map.keySet());
86+ }
87+
88+ public Collection<List<String>> values() {
89+ return Collections.unmodifiableCollection(map.values());
90+ }
91+
92+ /* TODO check that contents of set are not modifable : security */
93+
94+ public Set<Map.Entry<String, List<String>>> entrySet() {
95+ return Collections.unmodifiableSet (map.entrySet());
96+ }
97+
98+ public boolean equals(Object o) {return map.equals(o);}
99+
100+ public int hashCode() {return map.hashCode();}
101+ }
java/pkg/sun/net/httpserver/mkfile+33−0
@@ -0,0 +1,33 @@
1+<../../../../../mkconfig
2+
3+TARG=\
4+ AuthFilter.dis\
5+ ChunkedInputStream.dis\
6+ ChunkedOutputStream.dis\
7+ Code.dis\
8+ ContextList.dis\
9+ DefaultHttpServerProvider.dis\
10+ Event.dis\
11+ ExchangeImpl.dis\
12+ FixedLengthInputStream.dis\
13+ FixedLengthOutputStream.dis\
14+ HttpConnection.dis\
15+ HttpContextImpl.dis\
16+ HttpError.dis\
17+ HttpExchangeImpl.dis\
18+ HttpServerImpl.dis\
19+ HttpsExchangeImpl.dis\
20+ HttpsServerImpl.dis\
21+ LeftOverInputStream.dis\
22+ Request.dis\
23+ ServerConfig.dis\
24+ ServerImpl.dis\
25+ SSLStreams.dis\
26+ StreamClosedException.dis\
27+ TimeSource.dis\
28+ UndefLengthOutputStream.dis\
29+ UnmodifiableHeaders.dis\
30+
31+DISBIN=$ROOT/java/dis/java/java/sun/net/httpserver
32+
33+<$ROOT/mkfiles/mkjava