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