ilibgcgi.c - libgcgi - REST library for Gopher Err bitreich.org 70 hgit clone git://bitreich.org/libgcgi/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/libgcgi/ URL:git://bitreich.org/libgcgi/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/libgcgi/ bitreich.org 70 1Log /scm/libgcgi/log.gph bitreich.org 70 1Files /scm/libgcgi/files.gph bitreich.org 70 1Refs /scm/libgcgi/refs.gph bitreich.org 70 1Tags /scm/libgcgi/tag bitreich.org 70 1README /scm/libgcgi/file/README.gph bitreich.org 70 1LICENSE /scm/libgcgi/file/LICENSE.gph bitreich.org 70 i--- Err bitreich.org 70 ilibgcgi.c (6502B) Err bitreich.org 70 i--- Err bitreich.org 70 i 1 #include Err bitreich.org 70 i 2 #include Err bitreich.org 70 i 3 #include Err bitreich.org 70 i 4 #include Err bitreich.org 70 i 5 #include Err bitreich.org 70 i 6 #include Err bitreich.org 70 i 7 #include Err bitreich.org 70 i 8 #include Err bitreich.org 70 i 9 #include Err bitreich.org 70 i 10 #include Err bitreich.org 70 i 11 #include Err bitreich.org 70 i 12 Err bitreich.org 70 i 13 #include "libgcgi.h" Err bitreich.org 70 i 14 Err bitreich.org 70 i 15 #define GCGI_MATCH_NUM 5 Err bitreich.org 70 i 16 Err bitreich.org 70 i 17 char *gcgi_gopher_search; Err bitreich.org 70 i 18 char *gcgi_gopher_path; Err bitreich.org 70 i 19 char *gcgi_gopher_host; Err bitreich.org 70 i 20 char *gcgi_gopher_port; Err bitreich.org 70 i 21 struct gcgi_var_list gcgi_gopher_query; Err bitreich.org 70 i 22 Err bitreich.org 70 i 23 void Err bitreich.org 70 i 24 gcgi_fatal(char *fmt, ...) Err bitreich.org 70 i 25 { Err bitreich.org 70 i 26 va_list va; Err bitreich.org 70 i 27 char msg[1024]; Err bitreich.org 70 i 28 Err bitreich.org 70 i 29 va_start(va, fmt); Err bitreich.org 70 i 30 vsnprintf(msg, sizeof msg, fmt, va); Err bitreich.org 70 i 31 printf("error: %s\n", msg); Err bitreich.org 70 i 32 exit(1); Err bitreich.org 70 i 33 } Err bitreich.org 70 i 34 Err bitreich.org 70 i 35 static char * Err bitreich.org 70 i 36 gcgi_fopenread(char *path) Err bitreich.org 70 i 37 { Err bitreich.org 70 i 38 FILE *fp; Err bitreich.org 70 i 39 char *buf; Err bitreich.org 70 i 40 ssize_t ssz; Err bitreich.org 70 i 41 size_t sz; Err bitreich.org 70 i 42 Err bitreich.org 70 i 43 if ((fp = fopen(path, "r")) == NULL) Err bitreich.org 70 i 44 return NULL; Err bitreich.org 70 i 45 if (fseek(fp, 0, SEEK_END) == -1) Err bitreich.org 70 i 46 return NULL; Err bitreich.org 70 i 47 if ((ssz = ftell(fp)) == -1) Err bitreich.org 70 i 48 return NULL; Err bitreich.org 70 i 49 sz = ssz; Err bitreich.org 70 i 50 if (fseek(fp, 0, SEEK_SET) == -1) Err bitreich.org 70 i 51 return NULL; Err bitreich.org 70 i 52 if ((buf = malloc(sz + 1)) == NULL) Err bitreich.org 70 i 53 return NULL; Err bitreich.org 70 i 54 if (fread(buf, sz, 1, fp) == sz) { Err bitreich.org 70 i 55 errno = EFBIG; Err bitreich.org 70 i 56 goto error_free; Err bitreich.org 70 i 57 } Err bitreich.org 70 i 58 if (ferror(fp)) Err bitreich.org 70 i 59 goto error_free; Err bitreich.org 70 i 60 fclose(fp); Err bitreich.org 70 i 61 buf[sz] = '\0'; Err bitreich.org 70 i 62 return buf; Err bitreich.org 70 i 63 error_free: Err bitreich.org 70 i 64 free(buf); Err bitreich.org 70 i 65 return NULL; Err bitreich.org 70 i 66 } Err bitreich.org 70 i 67 Err bitreich.org 70 i 68 static int Err bitreich.org 70 i 69 gcgi_cmp_var(const void *v1, const void *v2) Err bitreich.org 70 i 70 { Err bitreich.org 70 i 71 return strcasecmp(((struct gcgi_var *)v1)->key, ((struct gcgi_var *)v2)->key); Err bitreich.org 70 i 72 } Err bitreich.org 70 i 73 Err bitreich.org 70 i 74 static void Err bitreich.org 70 i 75 gcgi_add_var(struct gcgi_var_list *vars, char *key, char *val) Err bitreich.org 70 i 76 { Err bitreich.org 70 i 77 void *mem; Err bitreich.org 70 i 78 Err bitreich.org 70 i 79 vars->len++; Err bitreich.org 70 i 80 if ((mem = realloc(vars->list, vars->len * sizeof *vars->list)) == NULL) Err bitreich.org 70 i 81 gcgi_fatal("realloc"); Err bitreich.org 70 i 82 vars->list = mem; Err bitreich.org 70 i 83 vars->list[vars->len-1].key = key; Err bitreich.org 70 i 84 vars->list[vars->len-1].val = val; Err bitreich.org 70 i 85 } Err bitreich.org 70 i 86 Err bitreich.org 70 i 87 static void Err bitreich.org 70 i 88 gcgi_sort_var_list(struct gcgi_var_list *vars) Err bitreich.org 70 i 89 { Err bitreich.org 70 i 90 qsort(vars->list, vars->len, sizeof *vars->list, gcgi_cmp_var); Err bitreich.org 70 i 91 } Err bitreich.org 70 i 92 Err bitreich.org 70 i 93 char * Err bitreich.org 70 i 94 gcgi_get_var(struct gcgi_var_list *vars, char *key) Err bitreich.org 70 i 95 { Err bitreich.org 70 i 96 struct gcgi_var *v, q = { .key = key }; Err bitreich.org 70 i 97 Err bitreich.org 70 i 98 v = bsearch(&q, vars->list, vars->len, sizeof *vars->list, gcgi_cmp_var); Err bitreich.org 70 i 99 return (v == NULL) ? NULL : v->val; Err bitreich.org 70 i 100 } Err bitreich.org 70 i 101 Err bitreich.org 70 i 102 void Err bitreich.org 70 i 103 gcgi_set_var(struct gcgi_var_list *vars, char *key, char *val) Err bitreich.org 70 i 104 { Err bitreich.org 70 i 105 struct gcgi_var *v, q; Err bitreich.org 70 i 106 Err bitreich.org 70 i 107 q.key = key; Err bitreich.org 70 i 108 v = bsearch(&q, vars->list, vars->len, sizeof *vars->list, gcgi_cmp_var); Err bitreich.org 70 i 109 if (v != NULL) { Err bitreich.org 70 i 110 v->val = val; Err bitreich.org 70 i 111 return; Err bitreich.org 70 i 112 } Err bitreich.org 70 i 113 gcgi_add_var(vars, key, val); Err bitreich.org 70 i 114 gcgi_sort_var_list(vars); Err bitreich.org 70 i 115 } Err bitreich.org 70 i 116 Err bitreich.org 70 i 117 void Err bitreich.org 70 i 118 gcgi_read_var_list(struct gcgi_var_list *vars, char *path) Err bitreich.org 70 i 119 { Err bitreich.org 70 i 120 char *line, *tail, *key, *s; Err bitreich.org 70 i 121 Err bitreich.org 70 i 122 line = NULL; Err bitreich.org 70 i 123 Err bitreich.org 70 i 124 if ((tail = vars->buf = gcgi_fopenread(path)) == NULL) Err bitreich.org 70 i 125 gcgi_fatal("opening %s: %s", path, strerror(errno)); Err bitreich.org 70 i 126 while ((line = strsep(&tail, "\n")) != NULL) { Err bitreich.org 70 i 127 if (line[0] == '\0') Err bitreich.org 70 i 128 break; Err bitreich.org 70 i 129 key = strsep(&line, ":"); Err bitreich.org 70 i 130 if (line == NULL || *line++ != ' ') Err bitreich.org 70 i 131 gcgi_fatal("%s: missing ': ' separator", path); Err bitreich.org 70 i 132 gcgi_add_var(vars, key, line); Err bitreich.org 70 i 133 } Err bitreich.org 70 i 134 gcgi_set_var(vars, "text", tail ? tail : ""); Err bitreich.org 70 i 135 gcgi_set_var(vars, "file", (s = strrchr(path, '/')) ? s + 1 : path); Err bitreich.org 70 i 136 gcgi_sort_var_list(vars); Err bitreich.org 70 i 137 } Err bitreich.org 70 i 138 Err bitreich.org 70 i 139 void Err bitreich.org 70 i 140 gcgi_free_var_list(struct gcgi_var_list *vars) Err bitreich.org 70 i 141 { Err bitreich.org 70 i 142 free(vars->buf); Err bitreich.org 70 i 143 free(vars->list); Err bitreich.org 70 i 144 } Err bitreich.org 70 i 145 Err bitreich.org 70 i 146 int Err bitreich.org 70 i 147 gcgi_write_var_list(struct gcgi_var_list *vars, char *dst) Err bitreich.org 70 i 148 { Err bitreich.org 70 i 149 FILE *fp; Err bitreich.org 70 i 150 struct gcgi_var *v; Err bitreich.org 70 i 151 size_t n; Err bitreich.org 70 i 152 char path[1024]; Err bitreich.org 70 i 153 char *text; Err bitreich.org 70 i 154 Err bitreich.org 70 i 155 text = NULL; Err bitreich.org 70 i 156 Err bitreich.org 70 i 157 snprintf(path, sizeof path, "%s.tmp", dst); Err bitreich.org 70 i 158 if ((fp = fopen(path, "w")) == NULL) Err bitreich.org 70 i 159 gcgi_fatal("opening '%s' for writing", path); Err bitreich.org 70 i 160 Err bitreich.org 70 i 161 for (v = vars->list, n = vars->len; n > 0; v++, n--) { Err bitreich.org 70 i 162 if (strcasecmp(v->key, "text") == 0) { Err bitreich.org 70 i 163 text = text ? text : v->val; Err bitreich.org 70 i 164 continue; Err bitreich.org 70 i 165 } Err bitreich.org 70 i 166 assert(strchr(v->key, '\n') == NULL); Err bitreich.org 70 i 167 assert(strchr(v->val, '\n') == NULL); Err bitreich.org 70 i 168 fprintf(fp, "%s: %s\n", v->key, v->val); Err bitreich.org 70 i 169 } Err bitreich.org 70 i 170 fprintf(fp, "\n%s", text ? text : ""); Err bitreich.org 70 i 171 Err bitreich.org 70 i 172 fclose(fp); Err bitreich.org 70 i 173 if (rename(path, dst) == -1) Err bitreich.org 70 i 174 gcgi_fatal( "renaming '%s' to '%s'", path, dst); Err bitreich.org 70 i 175 return 0; Err bitreich.org 70 i 176 } Err bitreich.org 70 i 177 Err bitreich.org 70 i 178 static int Err bitreich.org 70 i 179 gcgi_match(char const *glob, char *path, char **matches, size_t m) Err bitreich.org 70 i 180 { Err bitreich.org 70 i 181 if (m >= GCGI_MATCH_NUM) Err bitreich.org 70 i 182 gcgi_fatal("too many wildcards in glob"); Err bitreich.org 70 i 183 matches[m] = NULL; Err bitreich.org 70 i 184 while (*glob != '*' && *path != '\0' && *glob == *path) Err bitreich.org 70 i 185 glob++, path++; Err bitreich.org 70 i 186 if (glob[0] == '*') { Err bitreich.org 70 i 187 if (*glob != '\0' && gcgi_match(glob + 1, path, matches, m + 1)) { Err bitreich.org 70 i 188 if (matches[m] == NULL) Err bitreich.org 70 i 189 matches[m] = path; Err bitreich.org 70 i 190 *path = '\0'; Err bitreich.org 70 i 191 return 1; Err bitreich.org 70 i 192 } else if (*path != '\0' && gcgi_match(glob, path + 1, matches, m)) { Err bitreich.org 70 i 193 matches[m] = (char *)path; Err bitreich.org 70 i 194 return 1; Err bitreich.org 70 i 195 } Err bitreich.org 70 i 196 } Err bitreich.org 70 i 197 return *glob == '\0' && *path == '\0'; Err bitreich.org 70 i 198 } Err bitreich.org 70 i 199 Err bitreich.org 70 i 200 static void Err bitreich.org 70 i 201 gcgi_decode_url(struct gcgi_var_list *vars, char *s) Err bitreich.org 70 i 202 { Err bitreich.org 70 i 203 char *tok, *eq; Err bitreich.org 70 i 204 Err bitreich.org 70 i 205 while ((tok = strsep(&s, "&"))) { Err bitreich.org 70 i 206 if ((eq = strchr(tok, '=')) == NULL) Err bitreich.org 70 i 207 continue; Err bitreich.org 70 i 208 *eq = '\0'; Err bitreich.org 70 i 209 gcgi_add_var(vars, tok, eq + 1); Err bitreich.org 70 i 210 } Err bitreich.org 70 i 211 gcgi_sort_var_list(vars); Err bitreich.org 70 i 212 } Err bitreich.org 70 i 213 Err bitreich.org 70 i 214 void Err bitreich.org 70 i 215 gcgi_handle_request(struct gcgi_handler h[], char **argv, int argc) Err bitreich.org 70 i 216 { Err bitreich.org 70 i 217 char *query_string; Err bitreich.org 70 i 218 Err bitreich.org 70 i 219 if (argc != 5) Err bitreich.org 70 i 220 gcgi_fatal("wrong number of arguments: %c", argc); Err bitreich.org 70 i 221 assert(argv[0] && argv[1] && argv[2] && argv[3]); Err bitreich.org 70 i 222 Err bitreich.org 70 i 223 /* executable.[d]cgi $search $arguments $host $port */ Err bitreich.org 70 i 224 gcgi_gopher_search = argv[1]; Err bitreich.org 70 i 225 gcgi_gopher_path = argv[2]; Err bitreich.org 70 i 226 gcgi_gopher_host = argv[3]; Err bitreich.org 70 i 227 gcgi_gopher_port = argv[4]; Err bitreich.org 70 i 228 query_string = strchr(gcgi_gopher_path, '?'); Err bitreich.org 70 i 229 if (query_string != NULL) { Err bitreich.org 70 i 230 *query_string++ = '\0'; Err bitreich.org 70 i 231 gcgi_decode_url(&gcgi_gopher_query, query_string); Err bitreich.org 70 i 232 } Err bitreich.org 70 i 233 Err bitreich.org 70 i 234 for (; h->glob != NULL; h++) { Err bitreich.org 70 i 235 char *matches[GCGI_MATCH_NUM + 1]; Err bitreich.org 70 i 236 if (!gcgi_match(h->glob, gcgi_gopher_path, matches, 0)) Err bitreich.org 70 i 237 continue; Err bitreich.org 70 i 238 h->fn(matches); Err bitreich.org 70 i 239 return; Err bitreich.org 70 i 240 } Err bitreich.org 70 i 241 gcgi_fatal("no handler for '%s'", gcgi_gopher_path); Err bitreich.org 70 i 242 } Err bitreich.org 70 i 243 Err bitreich.org 70 i 244 static char* Err bitreich.org 70 i 245 gcgi_next_var(char *head, char **tail) Err bitreich.org 70 i 246 { Err bitreich.org 70 i 247 char *beg, *end; Err bitreich.org 70 i 248 Err bitreich.org 70 i 249 if ((beg = strstr(head, "{{")) == NULL Err bitreich.org 70 i 250 || (end = strstr(beg, "}}")) == NULL) Err bitreich.org 70 i 251 return NULL; Err bitreich.org 70 i 252 *beg = *end = '\0'; Err bitreich.org 70 i 253 *tail = end + strlen("}}"); Err bitreich.org 70 i 254 return beg + strlen("{{"); Err bitreich.org 70 i 255 } Err bitreich.org 70 i 256 Err bitreich.org 70 i 257 void Err bitreich.org 70 i 258 gcgi_print_gophermap(char type, char *desc, char *path, char *host, char *port) Err bitreich.org 70 i 259 { Err bitreich.org 70 i 260 assert(type >= 0x30); Err bitreich.org 70 i 261 printf("%c%s\t%s\t%s\t%s\n", type, desc, path, host, port); Err bitreich.org 70 i 262 } Err bitreich.org 70 i 263 Err bitreich.org 70 i 264 void Err bitreich.org 70 i 265 gcgi_print_gph(char type, char *desc, char *path, char *host, char *port) Err bitreich.org 70 i 266 { Err bitreich.org 70 i 267 assert(type >= 0x30); Err bitreich.org 70 i 268 if (host == NULL) Err bitreich.org 70 i 269 host = "server"; Err bitreich.org 70 i 270 if (port == NULL) Err bitreich.org 70 i 271 port = "port"; Err bitreich.org 70 i 272 printf("[%c|%s|%s|%s|%s]\n", type, desc, path, host, port); Err bitreich.org 70 i 273 } Err bitreich.org 70 i 274 Err bitreich.org 70 i 275 void Err bitreich.org 70 i 276 gcgi_template(char const *path, struct gcgi_var_list *vars) Err bitreich.org 70 i 277 { Err bitreich.org 70 i 278 FILE *fp; Err bitreich.org 70 i 279 size_t sz; Err bitreich.org 70 i 280 char *line, *head, *tail, *key, *val; Err bitreich.org 70 i 281 Err bitreich.org 70 i 282 if ((fp = fopen(path, "r")) == NULL) Err bitreich.org 70 i 283 gcgi_fatal("opening template %s", path); Err bitreich.org 70 i 284 sz = 0; Err bitreich.org 70 i 285 line = NULL; Err bitreich.org 70 i 286 while (getline(&line, &sz, fp) > 0) { Err bitreich.org 70 i 287 head = tail = line; Err bitreich.org 70 i 288 for (; (key = gcgi_next_var(head, &tail)); head = tail) { Err bitreich.org 70 i 289 fputs(head, stdout); Err bitreich.org 70 i 290 if ((val = gcgi_get_var(vars, key))) Err bitreich.org 70 i 291 fputs(val, stdout); Err bitreich.org 70 i 292 else Err bitreich.org 70 i 293 fprintf(stdout, "{{error:%s}}", key); Err bitreich.org 70 i 294 } Err bitreich.org 70 i 295 fputs(tail, stdout); Err bitreich.org 70 i 296 } Err bitreich.org 70 i 297 if (ferror(fp)) Err bitreich.org 70 i 298 gcgi_fatal("reading from template: %s", strerror(errno)); Err bitreich.org 70 i 299 fclose(fp); Err bitreich.org 70 i 300 } Err bitreich.org 70 .