Changeset 109
- Timestamp:
- 07/17/05 14:51:53 (3 years ago)
- Files:
-
- trunk/app.xml (modified) (1 diff)
- trunk/dsp/DSPGrammar.d (modified) (2 diffs)
- trunk/dsp/DSPProcessor.d (modified) (5 diffs)
- trunk/dsp/ServletGenerator.d (modified) (1 diff)
- trunk/dsp/Util.d (modified) (2 diffs)
- trunk/dsp/servlet/DSPAttributes.d (modified) (1 diff)
- trunk/dsp/servlet/DSPLibraryCache.d (modified) (1 diff)
- trunk/dsp/servlet/DSPRequest.d (modified) (1 diff)
- trunk/dsp/servlet/DSPServlet.d (modified) (8 diffs)
- trunk/dsp/tags/Include.d (modified) (2 diffs)
- trunk/dsp/tags/Servlet.d (modified) (1 diff)
- trunk/dspconf/config.xml (modified) (1 diff)
- trunk/dspconf/custom_tag.dsp (modified) (1 diff)
- trunk/dspconf/dsp_capture.dsp (modified) (1 diff)
- trunk/dspconf/dsp_page.dsp (added)
- trunk/xml/XMLParser.d (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/app.xml
r75 r109 5 5 <applications> 6 6 <!-- note: the 'path' must be an absolute path in this version (sorry) --> 7 <application name="/ foo/bar" path="c:/dev/dsp/trunk/dspconf" />7 <application name="/dspconf" path="c:/dev/dsp/trunk/dspconf" /> 8 8 </applications> trunk/dsp/DSPGrammar.d
r108 r109 37 37 public static char[] rawPreamble = "dsp"; 38 38 public static char[] preamble = "dsp:"; 39 public static char[] newline = " \n";39 public static char[] newline = "";//"\n"; 40 40 41 41 public static char[] servletPrefix = "__servlet_"; … … 58 58 public static char[] pathToNamespace(char[] path){ 59 59 //TODO: improve this to be more intellegent in handling non-namespace chars 60 return path.replace(". ","_").replace("\\",".").replace("/",".");60 return path.replace(".\\","").replace(".","_").replace("\\",".").replace("/","."); 61 61 } 62 62 trunk/dsp/DSPProcessor.d
r108 r109 55 55 56 56 void xmlProcessingInstruction(char[] name,char[] data){ 57 with(context){ 57 with(context){ 58 58 if(name.startsWith(DSPGrammar.preamble)){ 59 // provide #line token 60 generator.appendLineNumber("xmlProcessingInstruction.test",parser.getPosition.line); 61 59 62 char[] instruction = name[DSPGrammar.preamble.length..$]; 60 63 switch(instruction){ … … 108 111 switch(generator.getContentMode()){ 109 112 case ServletGenerator.LiteralContentMode: 113 // provide #line token 114 generator.appendLineNumber("xmlStartElement.test",parser.getPosition.line); 115 110 116 // real DSP tag - attempt to deduce its type and handle it 111 117 if(name.startsWith(DSPGrammar.preamble)){ … … 145 151 case ServletGenerator.OutCodeContentMode: 146 152 case ServletGenerator.CodeContentMode: 147 // get tag stack from the tag library148 153 throw new DSPException("cannot nest tags inside of a code-only tag."); 149 154 break; … … 153 158 154 159 void xmlEndElement(char[] name,XMLAttributes attribs,bit isEmpty){ 155 with(context){ 160 with(context){ 156 161 // real DSP tag - attempt to deduce its type and handle it 157 162 if(name.startsWith(DSPGrammar.preamble)){ … … 174 179 void xmlText(char[] text){ 175 180 with(context){ 181 // provide #line token 182 generator.appendLineNumber("xmlText.test",parser.getPosition.line); 183 176 184 switch(context.generator.getContentMode()){ 177 185 case ServletGenerator.LiteralContentMode: trunk/dsp/ServletGenerator.d
r108 r109 95 95 } 96 96 97 public void appendLineNumber(char[] file,uint line){ 98 servletBody ~= "\n#line " ~ std.string.toString(line) ~ " \"" ~ file ~ "\"" ~ "\n";//DSPGrammar.newline; 99 } 100 97 101 public void appendBody(char[] text){ 98 102 if(outputSegment){ trunk/dsp/Util.d
r102 r109 30 30 private import mango.io.Buffer; 31 31 private import mango.io.Tokenizer; 32 private import mango.io.FileConst; 32 33 33 34 import std.string; … … 68 69 conduit.close(); 69 70 } 71 72 /** 73 Cleans an entire path by resolving "//", "./" and "../" sequences 74 75 Throws an exception if the path resolves to below the root of the given path 76 */ 77 char[] cleanPath(char[] path){ 78 printf("cleanPath: %.*s\n",path); 79 char[][] segments; 80 int lastSep = 0; 81 for(int i=0; i<path.length; i++){ 82 if(path[i] == '\\' || path[i] == '/'){ // catch both kinds 83 char[] segment = path[lastSep..i]; 84 if(segment == "."){ 85 // do nothing 86 } 87 else if(segment == ".."){ 88 if(segments.length == 0){ 89 throw new Exception("cannot resolve path"); 90 } 91 segments.length = segments.length - 1; // go up one level 92 } 93 else if(segment.length > 0){ 94 printf("segment: '%.*s'\n",segment); 95 segments ~= segment; 96 } 97 lastSep = i+1; 98 } 99 } 100 if(lastSep == 0){ 101 printf("no sub-segments\n"); 102 return path; 103 } 104 else{ 105 printf("segments: %d lastSep == %d \n",segments.length,lastSep); 106 } 107 108 segments ~= path[lastSep..$]; 109 110 char[] output = ""; 111 foreach(int i,char[] segment; segments){ 112 if(i > 0) output ~= FileConst.PathSeparatorString; 113 output ~= segment; 114 } 115 116 printf("output: %.*s\n",output); 117 118 return output; 119 } trunk/dsp/servlet/DSPAttributes.d
r102 r109 46 46 return defaultValue; 47 47 } 48 49 void empty(inout DSPAttributes attribs){ 50 attribs = DSPAttributes.init; 51 52 //HACK: make the attribute collection non-null, but empty, by adding and then removing one element 53 attribs["foo"] = box(null); 54 attribs.remove("foo"); 55 56 return attribs; 57 } trunk/dsp/servlet/DSPLibraryCache.d
r108 r109 27 27 28 28 private import dsp.servlet.DSPLibrary; 29 30 /*31 /+32 Behavior:33 34 As each library is used, it is promoted up one position in the cache.35 The overall action is not unlike a bubble-sort, where multiple sorting36 actions eventually sort the cache out.37 +/38 class DSPLibraryCache{39 struct CacheEntry{40 DSPLibrary lib;41 char[] key;42 }43 44 CacheEntry[] positions;45 DSPLibrary[char[]] cache;46 uint freeCount;47 48 this(uint capacity){49 freeCount = capacity;50 positions.length = capacity;51 }52 53 protected void addLibrary(DSPLibrary lib,char[] key){54 debug printf("addLibrary\n");55 56 if(freeCount==0){57 // search for the lowest ranking library that is not in use58 for(uint i=positions.length-1; i>=0; i--){59 if(!positions[i].lib.inUse){60 61 // close out the library62 positions[i].lib.unload();63 64 // remove the entry from the cache65 cache.remove(positions[i].key);66 67 // replace the idle library with this one instead68 positions[i].lib = lib;69 positions[i].key = key;70 cache[key] = lib;71 72 return;73 }74 }75 76 // balloon the cache since all libs are being used77 freeCount++;78 79 //(fallthrough)80 }81 82 positions[$-freeCount] = lib;83 cache[key] = lib;84 freeCount--;85 }86 87 protected void removeLibrary(DSPLibrary lib){88 debug printf("removeLibrary\n");89 assert(!lib.inUse);90 91 for(uint i=0; i<positions.length; i++){92 if(positions[i].lib == lib){93 char[] key = positions[i].key;94 if(i < positions.length-1){95 positions[i..$-1] = [i+1..$]; // move entire array up to fill the gap96 }97 positions[$-1] = null;98 freeCount++;99 cache.remove(key);100 return;101 }102 }103 assert(false);104 }105 106 protected void getLibrary(char[] key){107 debug printf("getLibrary\n");108 if(key in cache){109 for(uint i=0; i<positions.length; i++){110 111 }112 return cache[key];113 }114 return null;115 }116 117 118 void put(char[] path,DSPLibrary lib){119 // place entry in the queue120 if(lib){121 synchronized(this){122 assert(!(path in cache));123 addLibrary(lib,path.dup);124 }125 }126 127 // remove the entry from the queue128 else{129 //remove this entry from the list130 synchronized(this){131 removeLibrary(lib);132 }133 }134 }135 136 DSPLibrary get(char[] path){137 DSPLibrary result;138 synchronized(this) result = getLibrary(lib);139 return result;140 }141 142 char[] toString(){143 char[] output = "";144 return output;145 }146 }*/147 148 149 150 29 private import mango.cache.HashMap; 151 30 trunk/dsp/servlet/DSPRequest.d
r104 r109 43 43 public this(IProviderBridge bridge){ 44 44 super(bridge); 45 reset(); 45 46 } 46 47 47 48 public void reset(){ 48 attribs = null;49 attribs.empty(); 49 50 contentData = null; 50 51 servletName = "default"; trunk/dsp/servlet/DSPServlet.d
r104 r109 41 41 private import dsp.RequestConfig; 42 42 private import dsp.ServletCompilationContext; 43 private import dsp.Util; 43 44 44 45 private import mango.servlet.Servlet; … … 56 57 private import std.string; 57 58 58 /*59 <desc>60 DSPServlet: dll-per-file implementation61 </desc><desc>62 The size of the dlls is directly related to the size of the libraries contributed to its63 compilation. Presently, the libs are floating arount 100kb in size each, due to the inclusion64 of phobos and mango. Possibly loading those libs as dlls could reduce the size, as would recompiling65 them for a release or reduced-capability set.66 </desc><desc>67 dll-per-file is not just for a development time practice, as it is very tunable. The QueuedCache68 can be used to good effect to expire infrequently used libs that needn't be loaded all the time.69 </desc>70 */71 72 59 class DSPServlet : Servlet{ 73 60 private static Logger logger; 74 61 protected DSPLibraryCache cache; 75 62 DSPServletContext context; 63 char[][] AppRoots; 64 76 65 77 66 static this (){ … … 90 79 DSPLibrary recoverLibrary(FilePath path){ 91 80 char[] libraryPath = context.getBasePath ~ "/" ~ context.getConfiguration.get("cache-directory"); 92 libraryPath ~= path.getName [1..$]~ ".dll";81 libraryPath ~= path.getName ~ ".dll"; 93 82 94 83 debug printf("attempting to recover: %.*s\n",libraryPath); … … 160 149 DSPLibrary lib = cast(DSPLibrary)cache.get(pathInfo); 161 150 162 debug{151 // debug{ 163 152 if(lib){ 164 153 printf("cache lib: %.*s = %.*s\n",pathInfo,lib.toString()); 165 154 } 166 155 else{ 167 printf("cache lib: %.*s = [not present]\n", request.getPathInfo);168 } 169 }156 printf("cache lib: %.*s = [not present]\n",pathInfo); 157 } 158 // } 170 159 171 160 // attempt to recover the lib from the file cache … … 194 183 void service (IServletRequest request, IServletResponse response){ 195 184 FilePath path = new FilePath(request.getPathInfo); 185 186 //TODO: provide configurable filtering support here 196 187 197 188 if(path.getExtension == "dsp"){ … … 212 203 // run the servlet 213 204 if(lib){ 205 debug printf("servicing servlet\n"); 206 lib.inUse = true; 214 207 lib.service(dspRequest,dspResponse); 208 lib.inUse = false; 209 debug printf("done servicing servlet\n"); 215 210 216 211 if(dspResponse.isExceptionSet){ … … 273 268 public ServiceHandleDelegate getServletHandleForFile(IDSPRequest request,char[] filename){ 274 269 FilePath requestPath = new FilePath(request.getPathInfo); 275 FilePath path = new FilePath( requestPath.getPath() ~ filename);270 FilePath path = new FilePath(cleanPath(requestPath.getPath() ~ "/" ~ filename)); 276 271 277 272 //TODO: include support for http://, https:// and file:// protocols. … … 307 302 if(size == 0) size = 20; 308 303 309 debug printf("(cache config) size: %d threads: %d\n",size,threads); 304 debug printf("(cache config) size: %d threads: %d\n",size,threads); 310 305 311 306 cache = new DSPLibraryCache(size,threads); 307 308 // get the redirect 312 309 } 313 310 } trunk/dsp/tags/Include.d
r102 r109 34 34 private import dsp.DSPTag; 35 35 private import dsp.DSPException; 36 private import dsp.Register; 36 37 private import dsp.ServletCompilationContext; 37 38 … … 55 56 switch(attribs.get("as","output")){ 56 57 case "output": 57 // TODO: add a runtime way of evaluating the filename dynamically, and outputting the file's contents58 // dependency mapping makes sure this doesn't need to be done at runtime 58 59 generator.appendOutput(filedata); 60 61 // output the contents at runtime instead, evaluating the filename 62 //Register reg = generator.evaluateExpression(filename); 63 //generator.appendBody("response.copyFile (request.getContext," ~ reg.box() ~ ");" ~ DSPGrammar.newline); 59 64 break; 60 65 trunk/dsp/tags/Servlet.d
r104 r109 58 58 char[] servletName = generator.popString(); 59 59 ServletGenerator oldGenerator = generator.popGenerator(); 60 61 generator.end(); 62 oldGenerator.appendStatic(generator.getServletFunction(servletName)); 63 60 64 context.generator = oldGenerator; 61 62 oldGenerator.end();63 generator.appendStatic(oldGenerator.getServletFunction(servletName));64 65 } 65 66 } trunk/dspconf/config.xml
r102 r109 6 6 <runtime-directory value=""/> 7 7 <build-options value="-inline -release"/> 8 <!-- 9 <error code="404" file="404.html" /> 10 <error code="500" file="500.html" /> 11 12 <approot file="application.dsp" /> 13 14 <default file="index.dsp" /> 15 <default file="index.html" /> 16 17 <redirect file="config.xml" code="404" /> 18 <redirect file="404.html" code="404" /> 19 <redirect file="500.html" code="404" /> 20 <redirect pattern=".*\.inc" code="404" /> 21 22 <block aspect="HTTP-REFERER" pattern="badsite\.com" /> 23 <block aspect="IP-ADDRESS" pattern="10\.0\.0\.1" /> 24 --> 8 25 </config> trunk/dspconf/custom_tag.dsp
r105 r109 13 13 <x:custom:foo/> 14 14 <x:customfoobar/> 15 16 <dsp:tag name="x:custom2" file="dsp_servlet.dsp" /> 17 18 <x:custom2/> 19 <x:custom2:test/> 15 20 </body> 16 21 </html> trunk/dspconf/dsp_capture.dsp
r102 r109 6 6 7 7 <dsp:capture var="content"> 8 hello world8 This is was generated inside a dsp:capture tag. 9 9 </dsp:capture> 10 10 trunk/xml/XMLParser.d
r100 r109 96 96 exception("unexpected token (expected '" ~ charTConvert(match) ~ "' not '" ~ charTConvert(next) ~ "')"); 97 97 } 98 cursor++;99 if(cursor == '\n'){98 if(source[cursor] == '\n'){ 99 //writefln("newline: (%d,%d)",pos.line,pos.column); 100 100 pos.line++; 101 101 pos.column = 1; … … 104 104 pos.column++; 105 105 } 106 cursor++; 106 107 pos.offset=cursor; 107 //writefln("getNext: '% c'",next);108 //writefln("getNext: '%d' (%d,%d)",next,pos.line,pos.column); 108 109 return next; 109 110 }
