1 A Simple NIO-based HTTP/HTTPS Server Example
2
3
4 INTRODUCTION
5 ============
6 This directory contains a simple HTTP/HTTPS server. HTTP/HTTPS are two
7 common network protocols that provide for data transfer, and are more
8 fully described in RFC 2616 and RFC 2818 (Available at
9 http://www.ietf.org ). HTTPS is essentially HTTP after the connection
10 has been secured with SSL/TLS. TLS is the successor to SSL, and is
11 described in RFC 2246.
12
13 This server was written to demonstrate some of the functionality new to
14 the Java 2 platform. The demo is not meant to be a full tutorial, and
15 assumes the reader has some familiarity with the subject matter.
16
17 In particular, it shows:
18
19 New I/O (java.nio, java.nio.channels, java.util.regex, java.nio.charset)
20
21 Introduced in version 1.4 of the platform, NIO was designed to
22 overcome some of the scalability limitations found in the
23 existing blocking java.net.* API's, and to address other
24 concepts such as Regular Expression parsing and Character
25 Sets.
26
27 This server demonstrates:
28
29 ByteBuffer
30 Blocking and Non-Blocking I/O
31 SocketChannel
32 ServerSocketChannel
33 Selector
34 CharacterSet
35 Pattern matching using Regular Expressions
36
37 JSSE (javax.net.ssl)
38
39 Introduced in version 1.4 of the platform, JSSE provides
40 network security using SSL/TLS for java.net.Socket-based
41 traffic. In version 1.5, the SSLEngine API was introduced
42 which separates the SSL/TLS functionality from the underlying
43 I/O model. By making this separation, applications can adapt
44 I/O and compute strategies to best fit their circumstances.
45
46 This server demonstrates:
47
48 Using SSLEngine to create a HTTPS server
49 Creating simple key material for use with HTTPS
50
51 Concurrency Library (java.util.concurrent)
52
53 Introduced in version 1.5 of the platform, the concurrency
54 library provides a mechanism which decouples task submission
55 from the mechanics of how each task will be run.
56
57 This server demonstrates:
58
59 A ThreadPool with a fixed number of threads, which is
60 based on the number of available processors.
61
62
63 SETUP
64 =====
65
66 The server must be built on version 1.5 (or later) of the platform.
67 Invoking the following should be sufficient:
68
69 % mkdir build
70 % javac -source 1.5 -target 1.5 -d build *.java
71
72 The following creates the document root:
73
74 % mkdir root
75
76 All documents should be placed in this directory.
77
78 For HTTPS, the server authenticates itself to clients by using simple
79 Public Key Infrastructure (PKI) credentials in the form of
80 X509Certificates. You must create the server's credentials before
81 attempting to run the server in "-secure" mode. The server is
82 currently hardcoded to look for its credentials in a file called
83 "testkeys".
84
85 In this example, we'll create credentials for a fictional widget web
86 site owned by the ubiquitous "Xyzzy, Inc.". When you run this in your
87 own environment, replace "widgets.xyzzy.com" with the hostname of your
88 server.
89
90 The easiest way to create the SSL/TLS credentials is to use the
91 java keytool, by doing the following:
92
93 (<CR> represents your end-of-line key)
94
95 % keytool -genkey -keyalg rsa -keystore testkeys -alias widgets
96 Enter keystore password: passphrase
97 What is your first and last name?
98 [Unknown]: widgets.xyzzy.com<CR>
99 What is the name of your organizational unit?
100 [Unknown]: Consumer Widgets Group<CR>
101 What is the name of your organization?
102 [Unknown]: Xyzzy, Inc.<CR>
103 What is the name of your City or Locality?
104 [Unknown]: Arcata<CR>
105 What is the name of your State or Province?
106 [Unknown]: CA<CR>
107 What is the two-letter country code for this unit?
108 [Unknown]: US<CR>
109 Is CN=widgets.xyzzy.com, OU=Consumer Widgets Group, O="Xyzzy, Inc.",
110 L=Arcata, ST=CA, C=US correct?
111 [no]: yes<CR>
112
113 Enter key password for <mykey>
114 (RETURN if same as keystore password): <CR>
115
116 This directory also contain a very simple URL reader (URLDumper), which
117 connects to a specified URL and places all output into a specified file.
118
119
120 SERVER EXECUTION
121 ================
122
123 % java -classpath build Server N1
124
125 Usage: Server <type> [options]
126 type:
127 B1 Blocking/Single-threaded Server
128 BN Blocking/Multi-threaded Server
129 BP Blocking/Pooled-thread Server
130 N1 Nonblocking/Single-threaded Server
131 N2 Nonblocking/Dual-threaded Server
132
133 options:
134 -port port port number
135 default: 8000
136 -backlog backlog backlog
137 default: 1024
138 -secure encrypt with SSL/TLS
139 default is insecure
140
141 "http://" URLs should be used with insecure mode, and
142 "https://" for secure mode.
143
144 The "B*" servers use classic blocking I/O: in other words, calls to
145 read()/write() will not return until the I/O operation has completed. The
146 "N*" servers use non-blocking mode and Selectors to determine which
147 Channels are ready to perform I/O.
148
149 B1: A single-threaded server which completely services each
150 connection before moving to the next.
151
152 B2: A multi-threaded server which creates a new thread for each
153 connection. This is not efficient for large numbers of
154 connections.
155
156 BP: A multi-threaded server which creates a pool of threads for use
157 by the server. The Thread pool decides how to schedule those
158 threads.
159
160 N1: A single-threaded server. All accept() and read()/write()
161 operations are performed by a single thread, but only after
162 being selected for those operations by a Selector.
163
164 N2: A dual-threaded server which performs accept()s in one thread, and
165 services requests in a second. Both threads use select().
166
167
168 CLIENT EXECUTION
169 ================
170 You can test the server using any standard browser such as Internet
171 Explorer or Mozilla, but since the browser will not trust the
172 credentials you just created, you may need to accept the credentials
173 via the browser's pop-up dialog box.
174
175 Alternatively, to use the certificates using the simple included JSSE
176 client URLDumper, export the server certificate into a new truststore,
177 and then run the application using the new truststore.
178
179 % keytool -export -keystore testkeys -alias widgets -file widgets.cer
180 Enter keystore password: passphrase<CR>
181 Certificate stored in file <widgets.cer>
182
183 % keytool -import -keystore trustCerts -alias widgetServer \
184 -file widgets.cer
185 Enter keystore password: passphrase<CR>
186 Owner: CN=widgets.xyzzy.com, OU=Consumer, O="xyzzy, inc.", L=Arcata,
187 ST=CA, C=US
188 Issuer: CN=widgets.xyzzy.com, OU=Consumer, O="xyzzy, inc.",
189 L=Arcata, ST=CA, C=US
190 Serial number: 4086cc7a
191 Valid from: Wed Apr 21 12:33:14 PDT 2004 until: Tue Jul 20 12:33:14
192 PDT 2004
193 Certificate fingerprints:
194 MD5: 39:71:42:CD:BF:0D:A9:8C:FB:8B:4A:CD:F8:6D:19:1F
195 SHA1: 69:5D:38:E9:F4:6C:E5:A7:4C:EA:45:8E:FB:3E:F3:9A:84:01:6F:22
196 Trust this certificate? [no]: yes<CR>
197 Certificate was added to keystore
198
199 % java -classpath build -Djavax.net.ssl.trustStore=trustCerts \
200 -Djavax.net.ssl.TrustStorePassword=passphrase \
201 URLDumper https://widgets.xyzzy.com:8000/ outputFile
202
203 NOTE: The server must be run with "-secure" in order to receive
204 "https://" URLs.
205
206 WARNING: This is just a simple example for code exposition, you should
207 spend more time understanding PKI security concerns.
208
209
210 SOURCE CODE OVERVIEW
211 ====================
212
213 The main class is Server, which handles program startup, and is
214 subclassed by the "B*" and "N*" server classes.
215
216 Following a successful accept(), the "B*" variants each create a
217 RequestServicer object to perform the actual request/reply operations. The
218 primary differences between the different "B*" servers is how the
219 RequestServicer is actually run:
220
221 B1: RequestServicer.run() is directly called.
222 BN: A new thread is started, and the thread calls RequestServicer.run().
223 BP: A ThreadPool is created, and the pool framework is given Runnable
224 tasks to complete.
225
226 In the "N*" variations, a Dispatcher object is created, which is
227 responsible for performing the select, and then issuing the
228 corresponding handler:
229
230 N1: A single thread is used for all accept()/read()/write() operations
231 N2: Similar to N1, but a separate thread is used for the accept()
232 operations.
233
234 In all cases, once the connection has been accepted, a ChannelIO object
235 is created to handle all I/O. In the insecure case, the corresponding
236 SocketChannel methods are directly called. However in the secure case,
237 more manipulations are needed to first secure the channel, then
238 encrypt/decrypt the data, and finally properly send any shutdown
239 messages. ChannelIOSecure extends ChannelIO, and provides the secure
240 variants of the corresponding ChannelIO calls.
241
242 RequestServicer and RequestHandler are the main drivers for the
243 blocking and non-blocking variants, respectively. They are responsible
244 for:
245
246 Performing any initial handshaking
247
248 Reading the request data
249 All data is stored in a local buffer in the ChannelIO
250 structure.
251
252 Parsing the request
253 The request data is obtained from the ChannelIO object, and
254 is processed by Request class, which represents the
255 parsed URI address.
256
257 Locating/preparing/sending the data or reporting error conditions.
258 A Reply object is created which represents the entire object to send,
259 including the HTTP/HTTPS headers.
260
261 Shutdown/closing the channel.
262
263
264 CLOSING THOUGHTS
265 ================
266 This example represents a simple server: it is not production quality.
267 It was primarily meant to demonstrate the new APIs in versions 1.4 and
268 1.5 of the platform.
269
270 This example could certainly be expanded to address other areas of
271 concern: for example, assigning multiple threads to handle the selected
272 Channels, or delegating SSLEngine tasks to multiple threads. There are
273 so many ways to implement compute and I/O strategies, we encourage you
274 to experiment and find what works best for your situation.
275
276 To steal a phrase from many textbooks:
277
278 "It is left as an exercise for the reader..."
279
280