Monday, November 08, 2010 at 12:06 AM.
system.verbs.builtins.webserver.responders.default.methods.GET
<<Script: system.verbs.builtins.webserver.responders.default.methods.GET; Version 2; Date: Thu, 21 May 1998 17:45:30 GMT; ID: RAB <<Add the checking of form so that tables or directories taht are missing the trailing / gets redirected to include the / <<Script: system.verbs.builtins.webserver.responders.default.methods.GET; Version 1; Date: Fri, 08 May 1998 17:44:37 GMT; ID: RAB <<General information <<This responder will serve data out of the ODB or the file system. If a script is in the server path, the result of that script is what gets served. <<All elements to be served live in the default.data.docTree table. This table may be nested if desired and 3 types exhibit "special" behavior. <<If an element in the objects table is of type "address", that value will be dereferenced and URI traversal will continue from that point. <<If an element in the objects table is of type "filespec", that value will be used and serving will commence from the file system. <<If an element in the objects table is of type "script", then that script will be executed and the result returned. <<Options/User settings <<default.data.docTree is the root in which all items are served. The Web Admin can add anthing they would like published to this table . <<default.data.prefs contains the options that control what is displayed <<default.data.prefs.fileAutoIndex: When set true will generate an HTML page of a file directory if so requested. <<Note: You will never get a direcotry listing if a default file is present in the directory. <<default.data.prefsfileDefault: Is a list of file names in desired order. If the URI specifies a directory and starting from the <<beginning of that list one of those files is found in the specified directory, it will be served as if that filename was <<part of the URI. <<default.data.prefs.ODBautoIndex: When set true will generate an HTML page of a table if so reqested. <<Note: You will never get a table listing if a default file is present in the table <<default.data.prefs.ODBdefault: Is a list of ODB names in desired order. If the URI specifies a table and starting from the <<beginning of that list one of those elements is found in the specified table, it will be served as if that element was <<part of the URI. on get (adrParamTable) { local (objType, mimeType); //For type info local (adrRequestHeaders, adrResponseHeaders); local (dataTableAdr, responderTableAdr, docTreeTableAdr, prefsTableAdr); local (objName); on getFileTypeInfo(name) { if file.isFolder (name) { mimeType = "text/directory"; objType = ' '} else { objType = file.type (name); case sys.os() { // decide what the MIME type is osMacOS { if defined (user.webserver.prefs.type2MIME.[objType]) { mimeType = user.webserver.prefs.type2MIME.[objType]} else { mimeType = "text/html"}}; osWin95; osWinNT { local (ext = objType); // this might not always work ext = string.replaceAll (ext, " ", ""); // strip spaces if defined (user.webserver.prefs.ext2MIME.[ext]) { mimeType= user.webserver.prefs.ext2MIME.[ext]} else { mimeType = "text/plain"}}}}}; on getODBTypeInfo(name) { if (typeOf (name^) == binaryType) { objType = getBinaryType (name^)} else { objType = typeOf (name^)}; if defined (user.webserver.prefs.type2MIME.[objType]) { mimeType = user.webserver.prefs.type2MIME.[objType]} else { mimeType = "text/html"}}; on addFileItem (name, elementName) { local (hrefName, elementModTime, elementSize); elementName = string.popTrailing (elementName, file.getPathChar()); hrefName = adrParamTable^.URI; if not (hrefName endsWith "/") { hrefName = hrefName + "/"}; hrefName = hrefName + string.urlEncode (elementName); elementName = xml.convertToDisplayName (elementName); elementModTime = file.modified(name); if file.isFolder (name) { elementSize = "-"; if not (hrefName endsWith "/") { hrefName = hrefName + "/"}} else { elementSize = string.megabyteString (file.size(name))}; getFileTypeInfo(name); return (webserver.util.directoryDisplay.add (mimeType, hrefName, elementName, elementSize, elementModTime))}; on addODBItem (name) { local (elementName, hrefName, elementModTime, elementSize); elementName = nameOf(name^); hrefName = adrParamTable^.URI; if not (hrefName endsWith "/") { hrefName = hrefName + "/"}; hrefName = hrefName + string.urlEncode (elementName); elementName = xml.convertToDisplayName (elementName); elementSize = sizeOf (name^); if objType == outlineType { elementSize = elementSize + " lines"} else { if objType == tableType { elementSize = elementSize + " items"; if not (hrefName endsWith "/") { hrefName = hrefName + "/"}} else { if elementSize > 9999 { //if greater then 4 characters then convert to Mb or Kb elementSize = string.megabyteString (elementSize)}}}; elementModTime = timeModified(name); return (webserver.util.directoryDisplay.add (mimeType, hrefName, elementName, elementSize, elementModTime))}; on checkForm() { <<Check for correct form (i.e. trailing backslash) or redirect (called if a table or directory) if not (adrParamTable^.path endsWith "/") { if sizeof(adrParamTable^.path) > 0 { adrResponseHeaders^.location = adrParamTable^.URI + "/"; adrResponseHeaders^.URI = adrResponseHeaders^.location; // I think this is to support OLD style redirects adrParamTable^.code = 301; //Yes 301 not 302 since this is a permanent redirect adrParamTable^.responseBody = webserver.util.buildErrorPage ("301 Moved Permanently", "Your specification of " + adrParamTable^.path + " was missing the trailing /"); return (false)}}; return (true)}; adrRequestHeaders = @adrParamTable^.requestHeaders; adrResponseHeaders = @adrParamTable^.responseHeaders; responderTableAdr = adrParamTable^.responderTableAdr; // the responder table dataTableAdr = @responderTableAdr^.["data"]; //This table contains the user data for this responder docTreeTableAdr = @dataTableAdr^.["docTree"]; //This table is the base "server" root prefsTableAdr = @dataTableAdr^.["prefs"]; //This table contains the user prefs for this responder bundle { //parse the URl into an ODB/file path objName = string.urlDecode(adrParamTable^.path); if objName beginswith "/odb" { objName = string.replace (objName, "/odb", "")}; if objName beginswith "/file" { objName = string.replace (objName, "/file", "")}; <<The following is the main security and path processing script. The result from this script is an error or the final <<file or odb specification for the responder to serve. if ! webserver.util.pathToAddressExt (objName, docTreeTableAdr, adrParamTable) { return (true)}; //The error is already set. objName = adrParamTable^.resultPath}; //as returned from pathToAddressExt if adrParamTable^.resultType == addressType { // we are serving out of the ODB if (defined (adrHeaderTable^.["If-Modified-Since"]) && (date (adrHeaderTable^.["If-Modified-Since"]) >= timeModified (address(objname)))) { adrParamTable^.code = 304; // the cached object is fresh, so don't send it again return (true)}; on doscript(name) { <<do it adrResponseHeaders^.["Content-Type"] = "text/html"; adrParamTable^.code = 200; adrParamTable^.responseBody = callscript (name, nil, adrParamTable); return (true)}; on serve (name) { getODBTypeInfo(name); if (objType == scriptType) or (objType == codeType) { return (doScript(name))}; adrParamTable^.responseBody = string(name^); adrResponseHeaders^.["Content-Type"] = mimeType; adrParamTable^.code = 200; return (true)}; <<Start the serving process getODBTypeInfo(objName); if objType == tableType { local (i); <<Check for correct form (i.e. trailing backslash) or redirect if not checkForm() { return (true)}; <<Check for the default element to render for i in prefsTableAdr^.ODBdefault { local (default); default = @objName^.[i]; if defined (default^) { adrParamTable^.path = string.popTrailing (adrParamTable^.path, "/"); adrParamTable^.path = adrParamTable^.path + "/" + i; adrParamTable^.URI = string.urlEncode(adrParamTable^.path); return (this^ (adrParamTable))}}; // Yes we recurse here so default behaves correctly if prefsTableAdr^.ODBautoIndex { local (responseText, leafName); adrResponseHeaders^.["Last-Modified"] = date.netstandardString ( timeModified (objName)); adrResponseHeaders^.["Content-Type"] = "text/html"; responseText = webserver.util.directoryDisplay.start (adrParamTable^.path); for i = 1 to sizeof(objName^) { leafName = @objName^[i]; getODBTypeInfo(leafName); if objType == filespecType { if file.exists (leafName^) { responseText = responseText + addFileItem (leafName^, nameof (leafName^))}} else { responseText = responseText + addODBItem (leafName)}}; adrParamTable^.responseBody = responseText + webserver.util.directoryDisplay.finish()} else { //Tables are not served adrParamTable^.code = 403; adrParamTable^.responseBody = webserver.util.buildErrorPage ("403 Forbidden", "Access to the object " + adrParamTable^.path + " is forbidden."); return (true)}} else { // Not a table return (serve (objName))}; adrParamTable^.code = 200} else { //otherwise it should be serving out of the file system if adrParamTable^.resultType == filespecType { // we are serving out of the File System if (defined (adrHeaderTable^.["If-Modified-Since"]) && (date (adrHeaderTable^.["If-Modified-Since"]) >=file.modified(objname))) { adrParamTable^.code = 304; // the cached object is fresh, so don't send it again return (true)}; on serve (name) { getFileTypeInfo (name); adrResponseHeaders^.["Last-Modified"] = date.netstandardString ( file.modified (name)); adrResponseHeaders^.["Content-Type"] = mimeType; if defined (adrRequestHeaders^.["Accept-Encoding"]) { // cool encoding magic if ((adrRequestHeaders^.["Accept-Encoding"] contains "deflate") && (file.exists (name+".def"))) { <<the client accepts deflated files and we just happen to have one if (file.modified (name+".def") >= file.modified (name)) { // make sure it's not an old version adrResponseHeaders^.["Content-Encoding"] = "deflate"; adrResponseHeaders^.["Vary"] = "Accept-Encoding"; // let caches know that we negotiated this response name = name + ".def"}}; if ((adrRequestHeaders^.["Accept-Encoding"] contains "gzip") && (file.exists (name +".gz"))) { <<the client accepts gzipped files and we just happen to have one if (file.modified (name+".gz") >= file.modified (name)) { // make sure it's not an old version adrResponseHeaders^.["Content-Encoding"] = "gzip"; adrResponseHeaders^.["Vary"] = "Accept-Encoding"; // let caches know that we negotiated this response name = name + ".gz"}}}; adrParamTable^.code = 200; adrParamTable^.responseBody = file.readWholeFile (name); return (true)}; <<Start the serving process if file.isFolder (objName) { local (i); <<Check for correct form (i.e. trailing backslash) or redirect if not checkForm() { return (true)}; <<Check for the default element to render for i in prefsTableAdr^.fileDefault { local (default); default = string.popTrailing (objName, file.getPathChar()) + file.getPathChar() + i; if file.exists (default) { return(serve(default))}}; <<There is no default file - serve the directory if desired if prefsTableAdr^.fileAutoIndex { local (responseText, leafName); adrResponseHeaders^.["Last-Modified"] = date.netstandardString ( file.modified (objName)); adrResponseHeaders^.["Content-Type"] = "text/html"; responseText = webserver.util.directoryDisplay.start (adrParamTable^.path); fileloop (leafName in objName) { if file.isVisible (leafName) { responseText = responseText + addFileItem (leafName, file.fileFromPath (leafName))}; }; adrParamTable^.responseBody = responseText + webserver.util.directoryDisplay.finish()} else { //Directories are not served adrParamTable^.code = 403; adrParamTable^.responseBody = webserver.util.buildErrorPage ("403 Forbidden", "Access to the object " + adrParamTable^.path + " is forbidden."); return (true)}} else { // Just a simple file... return (serve (objName))}; adrParamTable^.code = 200} else { //this should never occur adrParamTable^.code = 500; adrParamTable^.responseBody = webserver.util.buildErrorPage ("500 Internal Server Error", "The type of the object " + adrParamTable^.path + " is unknown.")}}; return (true)} <<bundle //Testing code <<local (paramTable) <<new (tableType, @paramTable) <<new (tableType, @paramTable.requestHeaders) <<new (tableType, @paramTable.responseHeaders) <<paramTable.responder = "default" <<paramTable.responderTableAdr = @user.webserver.responders.default <<paramTable.path = "/misc/foo" <<paramTable.URI = string.urlEncode (paramTable.path) <<get (@paramTable)
This listing is for code that runs in the OPML Editor environment. I created these listings because I wanted the search engines to index it, so that when I want to look up something in my codebase I don't have to use the much slower search functionality in my object database. Dave Winer.