root/cgi/cgi.h

/* [previous][next][first][last][top][bottom][index][help] */

INCLUDED FROM


DEFINITIONS

This source file includes following definitions.
  1. my_strdup
  2. dup2nul
  3. norm_path
  4. gzip_init
  5. gzip_start
  6. http_header_end
  7. http_header_html
  8. http_header_attachment
  9. cache_clean
  10. cache_full
  11. cache_init
  12. cache_end

   1 #ifndef __cgi_cgi__
   2 #define __cgi_cgi__ 1
   3 
   4 #include <unistd.h>
   5 #include <string.h>
   6 #include <stdlib.h>
   7 #include <stdio.h>
   8 #include <time.h>
   9 
  10 #ifdef USE_BOEHM
  11 # include <gc.h>
  12 # define my_malloc  GC_MALLOC
  13 # define my_realloc GC_REALLOC
  14 # define my_free(x)
  15 static char *
  16 my_strdup(const char *s)
  17 {
  18         size_t l = strlen(s);
  19         char *r = GC_MALLOC_ATOMIC(l + 1);
  20 
  21         if (!r) return NULL;
  22         *r = '\0';
  23         strncat(r, s, l);
  24 
  25         return r;
  26 }
  27 #else
  28 # define my_malloc  malloc
  29 # define my_realloc realloc
  30 # define my_free    free
  31 # define my_strdup  strdup
  32 #endif
  33 
  34 #define MINL 511
  35 #define MINB 512
  36 
  37 static char *
  38 dup2nul(const char *t, size_t tsz)
  39 {
  40         char *r = my_malloc(tsz + 1);
  41 
  42         if (!r) return NULL;
  43 
  44         r[tsz] = '\0';
  45         memcpy(r, t, tsz);
  46 
  47         return r;
  48 }
  49 
  50 
  51 static char *
  52 norm_path(const char *p, int root)
  53 {
  54         size_t s = strlen(p);
  55         char *cp, *cp2, *t = my_malloc(s + 2);
  56         int i;
  57 
  58         if (!t) return NULL;
  59 
  60         /* guarantee root */
  61         memcpy(t + 1, p, s + 1);
  62         *t = '/';
  63 
  64         /* remove duplicate slashes */
  65         cp = t; while (*cp != '\0') {
  66                 while (*cp == '/' && *(cp + 1) == '/') {
  67                         memmove(cp, cp + 1, strlen(cp + 1) + 1);
  68                 }
  69                 cp++;
  70         }
  71 
  72         /* remove cwd */
  73         cp = t; while (*cp != '\0') {
  74                 while (*cp == '/'
  75                     && *(cp + 1) == '.'
  76                     && *(cp + 2) == '/') {
  77                         memmove(cp, cp + 2, strlen(cp + 2) + 1);
  78                 }
  79                 cp++;
  80         }
  81 
  82         /* remove parents */
  83         cp = t; while (*cp != '\0') {
  84                 while (*cp == '/'
  85                     && *(cp + 1) == '.'
  86                     && *(cp + 2) == '.'
  87                     && *(cp + 3) == '/') {
  88                         *cp = '\0';
  89                         cp2 = strrchr(t, '/');
  90                         cp2 = cp2 ? cp2 : cp;
  91                         memmove(cp2, cp + 3, strlen(cp + 3) + 1);
  92                 }
  93                 cp++;
  94         }
  95 
  96         /* remove leading */
  97         cp = t; while((cp = strrchr(cp, '/')) && *(cp + 1) == '\0')
  98                 *cp = '\0';
  99 
 100         /* remove root */
 101         if (!root && *t == '/')
 102                 memmove(t, t + 1, strlen(t));
 103 
 104         return t;
 105 }
 106 
 107 
 108 #define thing_empty(x,y) (x)?(x):(y)
 109 
 110 /* close end a of s, adjust t to mean to b of s */
 111 #define dup_pat(s, a, b, t) do { close(s[a]);   \
 112                         dup2(s[b], t);          \
 113                         close(s[b]); } while (0)
 114 #define dup_sgl(a, t) do { dup2(a, t); \
 115         close(a); } while (0)
 116 
 117 
 118 struct cache {
 119         char filen[MINB];
 120         char fileu[MINB];
 121         int new_entry;
 122 };
 123 
 124 extern struct cache cstate;
 125 
 126 
 127 static int
 128 gzip_init(void)
 129 {
 130         char *env = getenv("HTTP_ACCEPT_ENCODING");
 131 
 132         if (env && strstr(env, "gzip")) {
 133                 printf("Content-Encoding: gzip\n\
 134 Vary: Accept-Encoding\n");
 135 
 136                 return 0;
 137         }
 138 
 139         return -1;
 140 }
 141 
 142 
 143 static void
 144 gzip_start(void)
 145 {
 146         int pfd[2];
 147         pid_t p;
 148 
 149         fflush(stdout);
 150 
 151         if (pipe(pfd) < 0)      return; /* err */
 152         if ((p = fork()) < 0)   return; /* err */
 153         if (p == 0) {
 154                 dup_pat(pfd, 1, 0, STDIN_FILENO);
 155 
 156                 execlp("gzip", "gzip", "-9cf",
 157                     (char *) NULL);
 158         } else dup_pat(pfd, 0, 1, STDOUT_FILENO);
 159 }
 160 
 161 
 162 static void
 163 http_header_end(int gzip)
 164 {
 165         printf("\n");
 166 
 167         if (gzip) gzip_start();
 168 }
 169 
 170 
 171 static void
 172 http_header_html(void)
 173 {
 174         printf("Content-type: text/html\n");
 175 }
 176 
 177 
 178 static void
 179 http_header_attachment(int binary, const char *name)
 180 {
 181         printf("Content-Type: %s\n\
 182 Content-Disposition: inline; filename=\"%s\"\n",
 183             binary ? "application/octet-stream" : "text/plain", name);
 184 }
 185 
 186 
 187 # ifdef CACHE_CODE
 188 
 189 #include <sys/stat.h>
 190 #include <dirent.h>
 191 #include <xxhash.h>
 192 
 193 static size_t
 194 cache_clean(void)
 195 {
 196         char cfilen[MINB] = {0};
 197         DIR *d = opendir(TMP_DIR);
 198         FILE *fp;
 199         struct dirent *e;
 200         struct stat sb;
 201         size_t a = 0;
 202         time_t now = time(NULL);
 203         time_t then = 0;
 204 
 205         if (!d) return MAX_CACHE;
 206 
 207 #define CACHE_LAST TMP_DIR "/last_" CACHE_CODE
 208         if (!(fp = fopen(CACHE_LAST, "r+")))
 209                 if (!(fp = fopen(CACHE_LAST, "w+")))
 210                         goto cc_prohibit_skip;
 211 
 212         fread(&then, sizeof(time_t), 1, fp); /* XXX: if this fails we get 0 */
 213         if (now - then < 240) return 0;
 214         fseek(fp, 0, SEEK_SET);
 215 
 216  cc_prohibit_skip:
 217         while ((e = readdir(d))) {
 218                 if (!(strstr(e->d_name, CACHE_CODE) == e->d_name)) continue;
 219 
 220                 snprintf(cfilen, MINB, TMP_DIR "/%s", e->d_name);
 221                 if (stat(cfilen, &sb) < 0)
 222                         continue;
 223 
 224                 if ((time(NULL) - sb.st_mtim.tv_sec) > 480)
 225                         unlink(cfilen);
 226                 else
 227                         a += sb.st_size;
 228         }
 229 
 230         closedir(d);
 231         fwrite(&now, sizeof(time_t), 1, fp);
 232         fclose(fp);
 233 
 234         return a;
 235 }
 236 
 237 
 238 static int
 239 cache_full(void)
 240 {
 241         if (cache_clean() >= MAX_CACHE)
 242                 return 1;
 243 
 244         return 0;
 245 }
 246 
 247 
 248 static int
 249 cache_init(void *ptr, size_t sz)
 250 {
 251         XXH64_hash_t state;
 252         XXH64_canonical_t cano;
 253         FILE *cf;
 254         char cbuf[MINB];
 255         int pfd[2];
 256         pid_t p;
 257         size_t i;
 258 
 259         state = XXH3_64bits(ptr, sz);
 260         XXH64_canonicalFromHash(&cano, state);
 261 
 262         /* construct our cache filenames */
 263         strncat(cstate.filen, TMP_DIR "/" CACHE_CODE "_", MINL);
 264         for(i = 0; i < sizeof(cano.digest); ++i) {
 265                 char hdp[3] = {0};
 266                 snprintf(hdp, 3, "%02X", cano.digest[i]);
 267                 strncat(cstate.filen, hdp, MINL);
 268         }
 269         snprintf(cstate.fileu, MINB, "%s-%d", cstate.filen, rand());
 270 
 271         if (getenv("NO_CGI_CACHE"))
 272                 return -1;
 273 
 274         if ((cf = fopen(cstate.filen, "r"))) {
 275                 do {
 276                         i = fread(cbuf, 1, MINB, cf);
 277                         fwrite(cbuf, 1, i, stdout);
 278                 } while (i > 0);
 279 
 280                 return 1; /* cached */
 281         } else {
 282                 /* XXX: need better error handling here */
 283 
 284                 if (cache_full())
 285                         return -1;
 286 
 287                 cstate.new_entry = 1;
 288 
 289                 fflush(stdout);
 290 
 291                 if (pipe(pfd) < 0)      return -1; /* err */
 292                 if ((p = fork()) < 0)   return -1; /* err */
 293                 if (p == 0) {
 294                         dup_pat(pfd , 1, 0, STDIN_FILENO);
 295 
 296                         execlp("tee", "tee", cstate.fileu,
 297                             (char *) NULL);
 298                 } else dup_pat(pfd, 0, 1, STDOUT_FILENO);
 299         }
 300 
 301         return 0; /* process page */
 302 }
 303 
 304 
 305 static void
 306 cache_end(int e)
 307 {
 308         struct stat sb;
 309 
 310         if (cstate.new_entry) {
 311                 if (e == 0
 312                     && stat(cstate.fileu, &sb) >= 0
 313                     && sb.st_size < MAX_SINGLE_CACHE) {
 314                         rename(cstate.fileu, cstate.filen);
 315 
 316                         return;
 317                 }
 318 
 319                 unlink(cstate.fileu);
 320         }
 321 }
 322 
 323 
 324 # endif
 325 
 326 #endif

/* [previous][next][first][last][top][bottom][index][help] */