1 package com.quadcap.http.server22; 2 3 40 41 import java.util.Date ; 42 import java.util.Enumeration ; 43 import java.util.Hashtable ; 44 import java.util.Properties ; 45 import java.util.Random ; 46 import java.util.Vector ; 47 48 import java.io.File ; 49 import java.io.FileInputStream ; 50 import java.io.FileOutputStream ; 51 import java.io.InputStream ; 52 import java.io.IOException ; 53 import java.io.PrintWriter ; 54 55 import java.text.SimpleDateFormat ; 56 57 import java.net.InetAddress ; 58 import java.net.MalformedURLException ; 59 import java.net.Socket ; 60 import java.net.URL ; 61 import java.net.URLConnection ; 62 63 import javax.servlet.RequestDispatcher ; 64 import javax.servlet.Servlet ; 65 import javax.servlet.ServletContext ; 66 import javax.servlet.ServletException ; 67 import javax.servlet.ServletRequest ; 68 import javax.servlet.ServletResponse ; 69 70 import javax.servlet.http.HttpServlet ; 71 import javax.servlet.http.HttpServletRequest ; 72 import javax.servlet.http.HttpSession ; 73 import javax.servlet.http.HttpSessionContext ; 74 75 import com.quadcap.net.server.Server; 76 import com.quadcap.net.server.Worker; 77 78 import com.quadcap.util.threads.Command; 79 import com.quadcap.util.threads.PeriodicScheduler; 80 81 import com.quadcap.util.text.OctetMap; 82 import com.quadcap.util.text.Scanner; 83 84 import com.quadcap.io.dir.Directory; 85 86 import com.quadcap.util.Config; 87 import com.quadcap.util.Debug; 88 import com.quadcap.util.Util; 89 90 95 public class WebServer { 96 Random random = new Random (); 97 98 101 String hostName = null; 102 103 106 Hashtable contexts = new Hashtable (); 107 108 111 Hashtable mimeTypes = new Hashtable (); 112 113 WebApplication defaultContext = null; 114 115 File tmpDir; 116 117 long sessionCount = 0; 118 static final int defaultInactiveInterval = 60; 119 static final int expireCheckerInterval = 60; 120 121 PeriodicScheduler expireChecker; 122 123 PrintWriter reqStream; 124 125 Server server; 126 127 134 183 public void init(Properties p) 184 throws Exception 185 { 186 p.put("workerClass", "com.quadcap.http.server22.WebWorker"); 187 server = new Server(p, this); 188 189 String tmp = p.getProperty("tempDir", "repository"); 190 tmpDir = new File (tmp); 191 if (!tmpDir.isDirectory() && !tmpDir.mkdirs()) { 192 throw new IOException ("Can't create temp directory: " + tmp); 193 } 194 195 tmp = p.getProperty("requestLog", "web.log"); 196 reqStream = new PrintWriter (new FileOutputStream (tmp)); 197 198 InputStream dis = ClassLoader.getSystemResourceAsStream( 199 "com/quadcap/http/server22/mime.types"); 200 if (dis != null) { 201 try { 202 parseMimeTypes(dis); 203 } finally { 204 dis.close(); 205 } 206 } 207 208 Enumeration e = Config.getMatchingProps(p, "context.*.root"); 209 while (e.hasMoreElements()) { 210 String context = e.nextElement().toString(); 211 String c = "context." + context; 212 String root = p.getProperty(c + ".root"); 213 String docBase = p.getProperty(c + ".docBase"); 214 if (docBase == null) { 215 Debug.println(0, "No docBase specified for context " + 216 context); 217 } else { 218 try { 219 WebApplication app = addWebApplication(root, docBase); 220 if (context.equals("default")) { 221 defaultContext = app; 222 } 223 } catch (Throwable t) { 224 Debug.print(t); 225 } 226 } 227 } 228 229 boolean found = false; 230 e = Config.getMatchingProps(p, "acceptor.*.port"); 231 while (e.hasMoreElements()) { 232 found = true; 233 String acceptor = e.nextElement().toString(); 234 String a = "acceptor." + acceptor; 235 Properties ap = new Properties (); 236 ap.put("port", p.getProperty(a + ".port")); 237 ap.put("queueDepth", p.getProperty(a + ".queueDepth", "32")); 238 Debug.println("startAcceptor: " + ap.get("port")); 239 server.startAcceptor(ap); 240 } 241 242 expireChecker = new PeriodicScheduler(server.getThreadGroup(), 243 "expire checker", 244 this); 245 expireChecker.add("Check for expired sessions", 246 new ExpireChecker(), 247 expireCheckerInterval * 1000); 248 expireChecker.start(); 249 if (!found) { 250 Debug.println(0, "No acceptor.<name>.port properties found!!"); 251 } 252 } 253 254 public void stop() { 255 server.stop(); 256 } 257 258 final void parseMimeTypes(InputStream is) throws IOException { 259 Scanner s = new Scanner(is); 260 s.skipWhile(OctetMap.crlfChars); 261 int c; 262 while ((c = s.peek()) >= 0) { 263 if (c == '#') { 264 s.skipUntil(OctetMap.crlfChars); 265 } else { 266 String mimeType = s.parseWhile(OctetMap.uriChars); 267 s.skipWhile(OctetMap.wsChars); 268 while ((c = s.peek()) >= 0 && OctetMap.tokenChars.has(c)) { 269 String ext = s.parseWhile(OctetMap.tokenChars); 270 mimeTypes.put(ext, mimeType); 271 s.skipWhile(OctetMap.wsChars); 272 } 273 s.skipUntil(OctetMap.crlfChars); 274 } 275 s.skipWhile(OctetMap.crlfChars); 276 } 277 is.close(); 278 } 279 280 public void removeWebApplication(String root) { 281 WebApplication app = getContextForRoot(root); 282 if (app != null) { 283 contexts.remove(root); 284 app.shutdown(); 285 } 286 } 287 288 public WebApplication addWebApplication(String root, String docBase) 289 throws IOException , ServletException 290 { 291 int len = root.length(); 293 if (len > 0 && root.charAt(len-1) == '/') { 294 root = root.substring(0, len-1); 295 } 296 if (Trace.level() > 1) { 298 Debug.println("addWebApplication(" + root + ", " + docBase + ")"); 299 } 300 302 WebApplication oldApp = (WebApplication)contexts.get(root); 303 if (oldApp != null) { 304 try { 305 Debug.println("[Shutting down old app for " + root + ": " + 306 oldApp); 307 oldApp.shutdown(); 308 } catch (Throwable t) { 309 } 310 } 311 312 File dir = new File (docBase); 313 Directory d = Directory.getDirectory(dir); 314 WebApplication app = new WebApplication(); 315 app.init(this, root, d); 316 317 contexts.put(root, app); 318 319 320 return app; 321 } 322 323 329 public String getServerInfo() { 330 return "Quadcap Web Server 3.4"; 333 } 335 336 339 public String getMimeTypeForExt(String ext) { 340 String type = (String )mimeTypes.get(ext.toLowerCase()); 341 return type; 342 } 343 344 347 public WebApplication getContext(String path) { 348 WebApplication ret = (WebApplication)contexts.get(path); 349 for (int i = path.length() - 1; ret == null && i >= 0; i--) { 350 if (path.charAt(i) == '/') { 351 String subPath = path.substring(0, i); 352 ret = (WebApplication)contexts.get(subPath); 353 } 354 } 355 if (ret == null) ret = defaultContext; 356 Debug.println("defaultContext = " + defaultContext); 357 return ret; 358 } 359 360 String makeSessionId() { 361 int r = random.nextInt() & 0xfffffff; 362 return "" + (sessionCount++) + "." + r + "." + 363 System.currentTimeMillis(); 364 } 365 366 public void expireSessions() { 367 Enumeration e = contexts.elements(); 368 while (e.hasMoreElements()) { 369 WebApplication app = (WebApplication)e.nextElement(); 370 app.expireSessions(); 371 } 372 } 373 374 final File getTempDir() { 375 return tmpDir; 376 } 377 378 public Enumeration getContextRoots() { 379 return contexts.keys(); 380 } 381 382 public WebApplication getContextForRoot(String root) { 383 return (WebApplication)contexts.get(root); 384 } 385 386 public static void main(String args[]) { 387 Properties p = Config.getProperties(); 388 WebServer w = new WebServer(); 389 try { 390 w.init(p); 391 } catch (Throwable t) { 392 Debug.print(t); 393 } 394 } 395 396 static SimpleDateFormat df; 397 static { 398 df = new SimpleDateFormat ("yyyy/MM/dd HH:mm:ss.SSS"); 399 } 400 public void requestLog(String s) { 401 reqStream.println(df.format(new Date ()) + " " + s); 402 reqStream.flush(); 403 } 404 } 405 406 407 class ExpireChecker implements Command { 408 public void execute(Object context) { 409 ((WebServer)context).expireSessions(); 410 } 411 } 412 413 | Popular Tags |