From 3f15f41ddc3a9e47d9ad02993e7881a63ed6ea78 Mon Sep 17 00:00:00 2001 From: "Adam D. Ruppe" Date: Mon, 11 Feb 2019 21:43:54 -0500 Subject: [PATCH] smaller buffer tbh no need for something so huge --- cgi.d | 190 +++++++++++++++++++++++++++++++++++++++++++++++++++------ jpeg.d | 8 +-- 2 files changed, 177 insertions(+), 21 deletions(-) diff --git a/cgi.d b/cgi.d index fa2e5ae..ef33624 100644 --- a/cgi.d +++ b/cgi.d @@ -6147,7 +6147,7 @@ auto formatReturnValueAsHtml(T)(T t) { /++ The base class for the [dispatcher] object support. +/ -class WebObject() { +class WebObject(Helper = void) { Cgi cgi; void initialize(Cgi cgi) { this.cgi = cgi; @@ -6234,6 +6234,8 @@ class WebObject() { FIXME: explain this better +/ auto serveApi(T)(string urlPrefix) { + assert(urlPrefix[$ - 1] == '/'); + import arsd.dom; import arsd.jsvar; @@ -6294,6 +6296,124 @@ auto serveApi(T)(string urlPrefix) { return DispatcherDefinition!handler(urlPrefix, false); } +/++ + The base of all REST objects. ++/ +class RestObject(Helper = void) { + + import arsd.dom; + import arsd.jsvar; + + /// Show + void show() {} + /// ditto + void show(string urlId) { + load(urlId); + show(); + } + + enum AccessCheck { + allowed, + denied, + nonExistant, + } + + enum Operation { + show, + create, + replace, + remove, + update + } + + enum UpdateResult { + accessDenied, + noSuchResource, + success, + failure, + unnecessary + } + + enum ValidationResult { + valid, + invalid + } + + ValidationResult delegate(typeof(this)) validateFromReflection; + Element delegate(typeof(this)) toHtmlFromReflection; + var delegate(typeof(this)) toJsonFromReflection; + + /// Override this to provide access control to this object. + AccessCheck accessCheck(string urlId, Operation operation) { + return AccessCheck.allowed; + } + + ValidationResult validate() { + if(validateFromReflection !is null) + return validateFromReflection(this); + return ValidationResult.valid; + } + + // The functions with more arguments are the low-level ones, + // they forward to the ones with fewer arguments by default. + + void create() {} // POST on a parent collection - this is called from a collection class after the members are updated + + void replace() {} + void replace(string urlId, scope void delegate() applyChanges) { + load(urlId); + applyChanges(); + replace(); + } + + void update(string[] fieldList) {} + void update(string urlId, scope void delegate() applyChanges, string[] fieldList) { + load(urlId); + applyChanges(); + update(fieldList); + } + + void remove() {} + + void remove(string urlId) { + load(urlId); + remove(); + } + + abstract void load(string urlId) {} + abstract void save() {} + + Element toHtml() { + if(toHtmlFromReflection) + return toHtmlFromReflection(this); + else + assert(0); + } + + var toJson() { + if(toJsonFromReflection) + return toJsonFromReflection(this); + else + assert(0); + } +} + +/++ + Base class for REST collections. ++/ +class CollectionOf(Obj, Helper = void) : RestObject!(Helper) { + void index() {} + override void create() {} + override void load(string urlId) { assert(0); } + override void save() { assert(0); } + override void show() { + index(); + } + override void show(string urlId) { + show(); + } +} + /++ Serves a REST object, similar to a Ruby on Rails resource. @@ -6375,11 +6495,17 @@ auto serveApi(T)(string urlPrefix) { int id; string name; - void show() {} // automated! GET of this specific thing + // the default implementations of the urlId ones is to call load(that_id) then call the arg-less one. + // but you can override them to do it differently. + + // any member which is of type RestObject can be linked automatically via href btw. + + void show() {} + void show(string urlId) {} // automated! GET of this specific thing void create() {} // POST on a parent collection - this is called from a collection class after the members are updated - void replace() {} // this is the PUT; really, it just updates all fields. - void update() {} // PATCH, it updates some fields. - void remove() {} // DELETE + void replace(string urlId) {} // this is the PUT; really, it just updates all fields. + void update(string urlId, string[] fieldList) {} // PATCH, it updates some fields. + void remove(string urlId) {} // DELETE void load(string urlId) {} // the default implementation of show() populates the id, then @@ -6405,22 +6531,52 @@ auto serveApi(T)(string urlPrefix) { User create() {} // You MAY implement this, but the default is to create a new object, populate it from args, and then call create() on the child } - // so CollectionOf will mixin the stuff to forward it - - OK, the underlying functions are actually really low level - - GET(string url) - POST(string url) - PUT(string url) - - The url starts with the initial thing passed. - - It is the mixins that actually do the work. +/ auto serveRestObject(T)(string urlPrefix) { + assert(urlPrefix[$ - 1] != '/', "Do NOT use a trailing slash on REST objects."); static bool handler(string urlPrefix, Cgi cgi) { string url = cgi.pathInfo[urlPrefix.length .. $]; + if(url.length && url[$ - 1] == '/') { + // remove the final slash... + cgi.setResponseLocation(".."); + return true; + } + + string urlId = null; + if(url.length && url[0] == '/') { + // asking for a subobject + urlId = url[1 .. $]; + foreach(idx, ch; urlId) { + if(ch == '/') { + urlId = urlId[0 .. idx]; + break; + } + } + } + + // FIXME: support precondition failed, if-modified-since, expectation failed, etc. + + auto obj = new T(); + obj.toHtmlFromReflection = delegate(t) { + import arsd.dom; + return Element.make("div", T.stringof ~ "/" ~ urlId); + }; + // FIXME: populate reflection info delegates + + switch(cgi.requestMethod) { + case Cgi.RequestMethod.GET: + obj.show(urlId); + cgi.write(obj.toHtml().toString, true); + break; + case Cgi.RequestMethod.POST: + case Cgi.RequestMethod.PUT: + case Cgi.RequestMethod.PATCH: + case Cgi.RequestMethod.DELETE: + default: + // FIXME: OPTIONS, HEAD + } + return true; } return DispatcherDefinition!handler(urlPrefix, false); @@ -6445,7 +6601,7 @@ auto serveStaticFile(string urlPrefix, string filename = null, string contentTyp } auto serveRedirect(string urlPrefix, string redirectTo) { - + // FIXME } /+ diff --git a/jpeg.d b/jpeg.d index 5ec08c4..1bd106e 100644 --- a/jpeg.d +++ b/jpeg.d @@ -3148,8 +3148,8 @@ public ubyte[] decompress_jpeg_image_from_file(bool useMalloc=false) (const(char bool m_eof_flag, m_error_flag; if (filename.length == 0) throw new Exception("cannot open unnamed file"); - if (filename.length < 2048) { - char[2049] buffer; + if (filename.length < 512) { + char[513] buffer; //import core.stdc.stdlib : alloca; auto tfn = buffer[0 .. filename.length + 1]; // (cast(char*)alloca(filename.length+1))[0..filename.length+1]; tfn[0..filename.length] = filename[]; @@ -3340,8 +3340,8 @@ public MemoryImage readJpeg (const(char)[] filename) { bool m_eof_flag, m_error_flag; if (filename.length == 0) throw new Exception("cannot open unnamed file"); - if (filename.length < 2048) { - char[2049] buffer; + if (filename.length < 512) { + char[513] buffer; //import core.stdc.stdlib : alloca; auto tfn = buffer[0 .. filename.length + 1]; // (cast(char*)alloca(filename.length+1))[0..filename.length+1]; tfn[0..filename.length] = filename[];