Big renaming
[cilux] / src / drivers / op / cache.c
diff --git a/src/drivers/op/cache.c b/src/drivers/op/cache.c
new file mode 100644 (file)
index 0000000..fcc7f5b
--- /dev/null
@@ -0,0 +1,182 @@
+
+/* -}{----------------------------------------------------------------------- */
+
+#include <kernelapi.h>
+#include <notification.h>
+
+/* -}{----------------------------------------------------------------------- */
+
+extern void   ensure_self_sub(ni_event* evq);
+
+/* -}{----------------------------------------------------------------------- */
+
+#define TMPBUFSIZE  4096
+static char   tmpbuf[TMPBUFSIZE];
+
+/* -}{----------------------------------------------------------------------- */
+
+static void cache_read(char*, char*, char*, int, k_stat, void*);
+static void entity_written(char*, char*, char*, int, k_stat, void*);
+static void write_headers(char* path, ni_resource* res);
+static void headers_written(char*, char*, char*, int, k_stat, void*);
+
+
+/* -}{----------------------------------------------------------------------- */
+
+char* make_cache_path(char* uri)
+{
+       char* path;
+       size_t l=strlen(uri);
+       if(l>100){ k_log_out("URI too long to save: %s", uri); return 0; }
+       if(*(uri+l-1)!='/'){
+               path=k_strdup(uri);
+       }
+       else{
+               path=k_malloc(l+1+10);
+               sprintf(path, "%sindex.html", uri);
+       }
+       return path;
+}
+
+void look_in_file_cache(ni_event* evq)
+{
+       k_hashtable* sub=evq->ent_head;
+       char* uri=k_hashtable_get(sub, "Sub-To:");
+       size_t l=strlen(uri);
+
+       if(l>100){ ensure_self_sub(evq); return; }
+
+       char hdr[128];
+       if(*(uri+l-1)!='/') sprintf(hdr, "%s.hdr", uri);
+       else                sprintf(hdr, "%sindex.html.hdr", uri);
+
+       if(strstr(hdr, "..")){ ensure_self_sub(evq); return; }
+       if(strchr(hdr, '?' )){ ensure_self_sub(evq); return; }
+
+       char* c=strchr(hdr, ':');
+       char* e=strchr(hdr, '/');
+       if(c && c< e) *c='-';
+
+       k_file_read(".", k_strdup(hdr), USE_MALL, 0, cache_read, evq);
+}
+
+void save_in_file_cache(ni_resource* res)
+{
+       char*        uri     =res->uri;
+       char*        path    =make_cache_path(uri); if(!path) return;
+       k_hashtable* ent_head=res->ent_head;
+       void*        data    =res->entity;
+       int          partial =k_hashtable_is(     ent_head, "Status:", "206");
+       size_t       size    =k_hashtable_get_int(ent_head, "Content-Length:");
+       char*        conrange=k_hashtable_get(    ent_head, "Content-Range:");
+       int          constant=k_hashtable_is(     ent_head, "CUX:", "C");
+
+       if(!data){
+               write_headers(path, res);
+       }
+       else
+       if(constant){
+               int ok=k_file_sync(data, size);
+               if(!ok){
+                       k_log_err("Failed to write (sync mmap): %s", uri);
+                       k_free(path);
+                       return;
+               }
+               write_headers(path, res);
+       }
+       else{
+               if(partial){
+                       k_log_out("save_in_file_cache partial %s", conrange);
+                       if(!conrange || strncmp(conrange, "0-", 2)){
+                               k_log_err("not saving partial");
+                               k_free(path);
+                               return;
+                       }
+                       size=atoi(conrange+2);
+               }
+               k_log_out("save_in_file_cache updateable: %d bytes", size);
+               k_file_write(".", path, data, size, entity_written, res);
+       }
+}
+
+/* -}{----------------------------------------------------------------------- */
+
+void entity_written(char*  basedir,
+                    char*  path,
+                    char*  data,
+                    int    usedmmap,
+                    k_stat kstat,
+                    void*  context)
+{
+       if(data) k_log_out("File cache entity written: %s", path);
+       else{
+               k_log_err("Failed to write entity:    %s", path); 
+               k_free(path);
+               return;
+       }
+       ni_resource* res=context;
+       write_headers(path, res);
+}
+
+void write_headers(char* path, ni_resource* res)
+{
+       snprintf(tmpbuf, TMPBUFSIZE, "%s.hdr", path);
+       k_free(path); path=k_strdup(tmpbuf);
+       k_hashtable_snprintf(res->ent_head, tmpbuf, TMPBUFSIZE);
+       k_file_write(".", path, tmpbuf, strlen(tmpbuf), headers_written, 0);
+}
+
+void headers_written(char*  basedir,
+                     char*  path,
+                     char*  data,
+                     int    usedmmap,
+                     k_stat kstat,
+                     void*  context)
+{
+       if(data) k_log_out("File cache headers written: %s", path);
+       else     k_log_err("Failed to write headers:    %s", path);
+       k_free(path);
+}
+
+void cache_read(char*  basedir,
+                char*  path,
+                char*  data,
+                int    usedmmap,
+                k_stat kstat,
+                void*  context)
+{
+       if(!data) k_log_out("no cache of %s", path);
+       else      k_log_out("file cache read: %d  %s", kstat.size, path);
+       char* e=strstr(path, ".hdr");
+       if(e){
+               ni_event* evq=context;
+               if(!data){ k_free(path); ensure_self_sub(evq); return; }
+
+               char* header=data;
+               *(header+kstat.size-2)=0;
+               k_hashtable* ent_head=k_hashtable_new("nHeaders/cache_read", 1);
+               k_hashtable_put(ent_head, "", header);
+               if(!ni_get_headers(header, 0, ent_head)){
+                       k_hashtable_delete(ent_head);
+                       k_free(path);
+                       ensure_self_sub(evq);
+                       return;
+               }
+               ni_event_delete(evq);
+               *e=0;
+               ni_event* evt=ni_event_new(0, 0, ent_head, 0);
+               int constant=k_hashtable_is(ent_head, "CUX:", "C");
+               size_t m=constant? USE_MMAP: USE_MALL;
+               k_file_read(".", path, m, 0, cache_read, evt);
+               return;
+       }
+       ni_event* evt=context;
+       k_free(path);
+       evt->entity=data;
+       ni_event_show(evt, "File Cache Found:");
+       k_event_post("on", evt);
+}
+
+/* -}{----------------------------------------------------------------------- */
+
+