using web::WebRequsing afIoc::Inject** A Request Handler that maps uris to files on the file system.** ** Example, to map all uris prefixed with '/pub/' to files under the '<app>/etc/web/' directory, ** in your AppModule:** ** pre>** @Contribute { serviceType=FileHandler# }** static Void contributeFileHandler(MappedConfig conf) {** conf[`/pub/`] = `etc/web/`.toFile** }** <pre** ** Don't forget to `Route` '/pub/***' URIs to 'FileHandler':**** pre>** @Contribute { serviceType=Routes# }** static Void contributeRoutes(OrderedConfig conf) {** ...** conf.add(Route(`/pub/***`, FileHandler#service))** ...** }** <pre** ** Now all requests to '/pub/css/mystyle.css' will map to 'etc/web/css/mystyle.css'** ** @uses MappedConfig of 'Uri:File'constmixin FileHandler {** Returns a `File` on the file system, as mapped from the given uri.abstract File service(Uri remainingUri := ``)}internalconstclass FileHandlerImpl : FileHandler { @Injectprivateconst HttpRequest reqprivateconst Uri:File dirMappingsinternalnew make(Uri:File dirMappings, |This|? in := null){ in?.call(this)// nullable for unit tests// verify file and uri mappings dirMappings.each |file, uri| {if(!file.exists)throw BedSheetErr(BsErrMsgs.fileHandlerFileNotExist(file))if(!file.isDir)throw BedSheetErr(BsErrMsgs.fileHandlerFileNotDir(file))if(!uri.isPathOnly)throw BedSheetErr(BsErrMsgs.fileHandlerUriNotPathOnly(uri))if(!uri.isPathAbs)throw BedSheetErr(BsErrMsgs.fileHandlerUriMustStartWithSlash(uri))if(!uri.isDir)throw BedSheetErr(BsErrMsgs.fileHandlerUriMustEndWithSlash(uri))}this.dirMappings = dirMappings.toImmutable}override File service(Uri remainingUri := ``){// use pathStr to knockout any unwanted query str matchedUri := req.modRel.pathStr[0..<-remainingUri.pathStr.size].toUri// throw Err if user mapped the Route but forgot to contribute a matching dir to this handler if(!dirMappings.containsKey(matchedUri)){ msg := """<p><b>The path '${matchedUri}' is unknown. </b></p> <p><b>Add the following to your AppModule: </b></p> <code>@Contribute { serviceType=FileHandler# } static Void contributeFileMapping(MappedConfig conf) { conf[`${matchedUri}`] = `/path/to/files/`.toFile }</code> """throw HttpStatusErr(501, msg)}// We pass 'false' to prevent Errs being thrown if the uri is a dir but doesn't end in '/'.// The 'false' appends a '/' automatically - it's nicer web behaviour// FUTURE: configure this behaviour once we've thought up a nice name for the config!return dirMappings[matchedUri].plus(remainingUri, false)// currently it's the FileResponseProcessor that throws a 404 if the file doesn't exist}}