first import of old cilux linux platform code
[cilux] / src / drivers / np / cache.c
1
2 /* -}{----------------------------------------------------------------------- */
3
4 #include <kernelapi.h>
5 #include <ni.h>
6
7 /* -}{----------------------------------------------------------------------- */
8
9 extern void   ensure_self_sub(ni_event* evq);
10
11 /* -}{----------------------------------------------------------------------- */
12
13 #define TMPBUFSIZE  4096
14 static char   tmpbuf[TMPBUFSIZE];
15
16 /* -}{----------------------------------------------------------------------- */
17
18 static void cache_read(char*, char*, char*, int, k_stat, void*);
19 static void entity_written(char*, char*, char*, int, k_stat, void*);
20 static void write_headers(char* path, ni_resource* res);
21 static void headers_written(char*, char*, char*, int, k_stat, void*);
22
23
24 /* -}{----------------------------------------------------------------------- */
25
26 char* make_cache_path(char* uri)
27 {
28         char* path;
29         size_t l=strlen(uri);
30         if(l>100){ k_log_out("URI too long to save: %s", uri); return 0; }
31         if(*(uri+l-1)!='/'){
32                 path=k_strdup(uri);
33         }
34         else{
35                 path=k_malloc(l+1+10);
36                 sprintf(path, "%sindex.html", uri);
37         }
38         return path;
39 }
40
41 void look_in_file_cache(ni_event* evq)
42 {
43         k_hashtable* sub=evq->ent_head;
44         char* uri=k_hashtable_get(sub, "Sub-To:");
45         size_t l=strlen(uri);
46
47         if(l>100){ ensure_self_sub(evq); return; }
48
49         char hdr[128];
50         if(*(uri+l-1)!='/') sprintf(hdr, "%s.hdr", uri);
51         else                sprintf(hdr, "%sindex.html.hdr", uri);
52
53         if(strstr(hdr, "..")){ ensure_self_sub(evq); return; }
54         if(strchr(hdr, '?' )){ ensure_self_sub(evq); return; }
55
56         char* c=strchr(hdr, ':');
57         char* e=strchr(hdr, '/');
58         if(c && c< e) *c='-';
59
60         k_file_read(".", k_strdup(hdr), USE_MALL, 0, cache_read, evq);
61 }
62
63 void save_in_file_cache(ni_resource* res)
64 {
65         char*        uri     =res->uri;
66         char*        path    =make_cache_path(uri); if(!path) return;
67         k_hashtable* ent_head=res->ent_head;
68         void*        data    =res->entity;
69         int          partial =k_hashtable_is(     ent_head, "Status:", "206");
70         size_t       size    =k_hashtable_get_int(ent_head, "Content-Length:");
71         char*        conrange=k_hashtable_get(    ent_head, "Content-Range:");
72         int          constant=k_hashtable_is(     ent_head, "CUX:", "C");
73
74         if(!data){
75                 write_headers(path, res);
76         }
77         else
78         if(constant){
79                 int ok=k_file_sync(data, size);
80                 if(!ok){
81                         k_log_err("Failed to write (sync mmap): %s", uri);
82                         k_free(path);
83                         return;
84                 }
85                 write_headers(path, res);
86         }
87         else{
88                 if(partial){
89                         k_log_out("save_in_file_cache partial %s", conrange);
90                         if(!conrange || strncmp(conrange, "0-", 2)){
91                                 k_log_err("not saving partial");
92                                 k_free(path);
93                                 return;
94                         }
95                         size=atoi(conrange+2);
96                 }
97                 k_log_out("save_in_file_cache updateable: %d bytes", size);
98                 k_file_write(".", path, data, size, entity_written, res);
99         }
100 }
101
102 /* -}{----------------------------------------------------------------------- */
103
104 void entity_written(char*  basedir,
105                     char*  path,
106                     char*  data,
107                     int    usedmmap,
108                     k_stat kstat,
109                     void*  context)
110 {
111         if(data) k_log_out("File cache entity written: %s", path);
112         else{
113                 k_log_err("Failed to write entity:    %s", path); 
114                 k_free(path);
115                 return;
116         }
117         ni_resource* res=context;
118         write_headers(path, res);
119 }
120
121 void write_headers(char* path, ni_resource* res)
122 {
123         snprintf(tmpbuf, TMPBUFSIZE, "%s.hdr", path);
124         k_free(path); path=k_strdup(tmpbuf);
125         k_hashtable_snprintf(res->ent_head, tmpbuf, TMPBUFSIZE);
126         k_file_write(".", path, tmpbuf, strlen(tmpbuf), headers_written, 0);
127 }
128
129 void headers_written(char*  basedir,
130                      char*  path,
131                      char*  data,
132                      int    usedmmap,
133                      k_stat kstat,
134                      void*  context)
135 {
136         if(data) k_log_out("File cache headers written: %s", path);
137         else     k_log_err("Failed to write headers:    %s", path);
138         k_free(path);
139 }
140
141 void cache_read(char*  basedir,
142                 char*  path,
143                 char*  data,
144                 int    usedmmap,
145                 k_stat kstat,
146                 void*  context)
147 {
148         if(!data) k_log_out("no cache of %s", path);
149         else      k_log_out("file cache read: %d  %s", kstat.size, path);
150         char* e=strstr(path, ".hdr");
151         if(e){
152                 ni_event* evq=context;
153                 if(!data){ k_free(path); ensure_self_sub(evq); return; }
154
155                 char* header=data;
156                 *(header+kstat.size-2)=0;
157                 k_hashtable* ent_head=k_hashtable_new("nHeaders/cache_read", 1);
158                 k_hashtable_put(ent_head, "", header);
159                 if(!ni_get_headers(header, 0, ent_head)){
160                         k_hashtable_delete(ent_head);
161                         k_free(path);
162                         ensure_self_sub(evq);
163                         return;
164                 }
165                 ni_event_delete(evq);
166                 *e=0;
167                 ni_event* evt=ni_event_new(0, 0, ent_head, 0);
168                 int constant=k_hashtable_is(ent_head, "CUX:", "C");
169                 size_t m=constant? USE_MMAP: USE_MALL;
170                 k_file_read(".", path, m, 0, cache_read, evt);
171                 return;
172         }
173         ni_event* evt=context;
174         k_free(path);
175         evt->entity=data;
176         ni_event_show(evt, "File Cache Found:");
177         k_event_post("ni", evt);
178 }
179
180 /* -}{----------------------------------------------------------------------- */
181
182