
1 // 2 // Copyright (c) 2007, Brian Frank and Andy Frank 3 // Licensed under the Academic Free License version 3.0 4 // 5 // History: 6 // 21 Dec 07 Brian Frank Creation 7 // 8 9 ** 10 ** WebService implements the standard pipeline for 11 ** processing a web request. 12 ** 13 abstract const class WebService : Thread 14 { 15 16 ////////////////////////////////////////////////////////////////////////// 17 // Construction 18 ////////////////////////////////////////////////////////////////////////// 19 20 ** 21 ** Constructor with thread name. 22 ** 23 new make(Str name) : super(name) {} 24 25 ////////////////////////////////////////////////////////////////////////// 26 // Pipeline 27 ////////////////////////////////////////////////////////////////////////// 28 29 ** 30 ** Run the standard pipeline of steps needed to process 31 ** a web request. This call routes to a series of method 32 ** calls which all begin with "step". 33 ** 34 virtual Void pipeline(WebReq req, WebRes res) 35 { 36 if (!stepInit(req, res)) return 37 try 38 { 39 if (!stepResource(req, res)) return 40 if (!stepWeblet(req, res)) return 41 if (!stepService(req, res)) return 42 } 43 catch (Err err) 44 { 45 err.trace 46 } 47 finally 48 { 49 stepCleanup(req, res) 50 } 51 } 52 53 ** 54 ** The init step is responsible for initializing thread 55 ** local state before any processing is started. Return 56 ** if processing should continue. 57 ** 58 virtual Bool stepInit(WebReq req, WebRes res) 59 { 60 if (log.isDebug) 61 { 62 log.debug("==============================") 63 log.debug("stepInit [$req.uri]") 64 } 65 66 // mount request, response as thread locals 67 Thread.locals["web.req"] = req 68 Thread.locals["web.res"] = res 69 return true 70 } 71 72 ** 73 ** Resolve the request Uri to a Resource in my 74 ** namespace. Return if processing should continue. 75 ** 76 virtual Bool stepResource(WebReq req, WebRes res) 77 { 78 if (log.isDebug) log.debug("stepResolve [$req.uri]") 79 80 // attempt to resolve 81 r := req.uri.resolve(null, false) 82 if (log.isDebug) log.debug(" resolved = $r") 83 84 // if resolved successfully we are done 85 if (r != null) 86 { 87 req.resource = r 88 return true 89 } 90 91 // if not resolved, return 401 92 res.statusCode = 404 93 res.headers.clear 94 res.headers["Content-Type"] = "text/plain" 95 res.out.print("Not found: $req.uri\n") 96 return false 97 } 98 99 ** 100 ** Resolve the weblet to use for servicing request on 101 ** the resource. Return if processing should continue. 102 ** 103 virtual Bool stepWeblet(WebReq req, WebRes res) 104 { 105 if (log.isDebug) log.debug("stepWeblet[$req.uri]") 106 107 // TODO: use fixed weblet for now 108 Weblet weblet := null 109 if (req.resource is File && !req.resource.isDir) 110 { 111 weblet = FileWeblet.make 112 } 113 else 114 { 115 weblet = Type.find("webui::DefaultPage").make 116 } 117 118 if (log.isDebug) log.debug(" weblet = $weblet.type") 119 120 // save to thread local 121 Thread.locals["web.weblet"] = weblet 122 return true 123 } 124 125 ** 126 ** Use the page and widget to service the request. 127 ** 128 virtual Bool stepService(WebReq req, WebRes res) 129 { 130 Weblet weblet := Thread.locals["web.weblet"] 131 weblet.service 132 return true 133 } 134 135 ** 136 ** The cleanup step is always run to cleanup 137 ** thread local state. 138 ** 139 virtual Void stepCleanup(WebReq req, WebRes res) 140 { 141 if (log.isDebug) log.debug("stepCleanup [$req.uri]") 142 143 // cleanup thread locals 144 Thread.locals.remove("web.req") 145 Thread.locals.remove("web.res") 146 Thread.locals.remove("web.weblet") 147 } 148 149 internal const static Log log := Log.get("web.pipeline") 150 }