2 MiddleMan filtering proxy server
3 Copyright (C) 2002 Jason McLaughlin
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include <sys/types.h>
32 #endif /* HAVE_ZLIB */
36 strncpy which always NULL terminates
38 char *s_strncpy(char *d, char *s, size_t len)
42 for (; len && (*dest = *s); s++, dest++, len--);
49 strncat which always NULL terminates
51 char *s_strncat(char *d, char *s, size_t len)
55 for (; len && *dest; dest++, len--);
56 for (; len && (*dest = *s); s++, dest++, len--);
64 case-insensitive strstr
66 char *s_strcasestr(char *haystack, char *needle) {
69 for (; *haystack; haystack++) {
70 for (tmp = haystack, n = needle; *tmp && *n && tolower(*tmp) == tolower(*n); tmp++, n++);
71 if (!*n) return haystack;
78 free memory used by FILEBUF-type structure
80 void filebuf_free(FILEBUF * filebuf)
85 if (filebuf->data != NULL)
87 if (filebuf->type != NULL)
96 FILEBUF *filebuf_new()
100 filebuf = xmalloc(sizeof(FILEBUF));
102 filebuf->data = NULL;
103 filebuf->type = NULL;
104 filebuf->size = filebuf->realsize = 0;
111 reduce filebuf size to actual size of contents
113 void filebuf_shorten(FILEBUF * filebuf)
115 if (filebuf->realsize > filebuf->size) {
116 filebuf->realsize = filebuf->size;
117 filebuf->data = xrealloc(filebuf->data, filebuf->size);
122 append data to a file buffer
124 void filebuf_add(FILEBUF * filebuf, const char *data, int len)
130 filebuf_resize(filebuf, filebuf->size + len);
132 memcpy(&filebuf->data[x], data, len);
137 add formatted data to filebuf
139 void filebuf_addf(FILEBUF * filebuf, const char *fmt, ...)
145 va_start(valist, fmt);
146 ret = vsnprintf(buf, sizeof(buf), fmt, valist);
149 filebuf_add(filebuf, buf, ret);
153 resize a filebuf (without adding anything)
155 void filebuf_resize(FILEBUF * filebuf, int newsize)
157 if (filebuf->realsize >= newsize && filebuf->realsize <= newsize + FILEBUF_ALIGNMENT && filebuf->data != NULL)
158 filebuf->size = newsize;
159 else if (newsize != 0) {
160 filebuf->realsize = ALIGN2(newsize, FILEBUF_ALIGNMENT);
161 filebuf->data = xrealloc(filebuf->data, filebuf->realsize);
162 filebuf->size = newsize;
167 return descriptive error for a code
169 char *code_to_error(int code)
175 return "Document Moved";
179 return "Not Modified";
181 return "Bad Request";
187 return "Authenticaton required";
189 return "Internal Error";
191 return "Not Implemented";
193 return "Service Temporarily Unavailable";
195 return "Connection Failed";
204 strdup which uses xmalloc
206 char *xstrdup(char *s)
208 return strcpy(xmalloc(strlen(s) + 1), s);
212 strndup which uses xmalloc
214 char *xstrndup(char *s, int len)
216 return s_strncpy(xmalloc(((strlen(s) < len) ? strlen(s) : len) + 1), s, len);
220 convert an error flag into a template name
222 char *error_to_template(int error)
240 free HOSTENT structure
242 void hostent_free(HOSTENT * hostent)
244 xfree(hostent->addr);
249 return TRUE if a string appears to be an IP address
251 int isip(char *string)
255 for (; *string; string++) {
258 else if (!isdigit((int) *string))
262 return (dots == 3) ? TRUE : FALSE;
266 convert string to uppercase
268 void string_tolower(char *string)
270 for (; *string; string++)
271 *string = tolower(*string);
275 replace characters that have a special meaning in html with their respective entity
277 char *string_to_html(char *s, int newlines)
282 filebuf = filebuf_new();
286 filebuf_add(filebuf, """, 6);
288 filebuf_add(filebuf, "<", 4);
290 filebuf_add(filebuf, ">", 4);
292 filebuf_add(filebuf, "&", 5);
293 else if (newlines == TRUE && *s == '\n')
294 filebuf_add(filebuf, "<br>", 4);
296 filebuf_add(filebuf, s, 1);
299 filebuf_add(filebuf, "", 1);
300 filebuf_shorten(filebuf);
304 filebuf->data = NULL;
305 filebuf_free(filebuf);
311 decode all hex characters in a url
313 char *url_decode(char *url, int len)
315 char *ret, *u = url, tmp[3];
320 filebuf = filebuf_new();
322 while (*u && u - url < len) {
323 if (*u == '%' && u[1] != '\0') {
327 filebuf_addf(filebuf, "%c", strtol(tmp, NULL, 16));
330 } else if (*u == '+') {
331 filebuf_add(filebuf, " ", 1);
335 filebuf_add(filebuf, u, 1);
341 filebuf_add(filebuf, "", 1);
342 filebuf_shorten(filebuf);
346 filebuf->data = NULL;
347 filebuf_free(filebuf);
353 encode special characters in a url
355 char *url_encode(char *url, int len)
360 filebuf = filebuf_new();
362 for (; *u && u - url < len; u++) {
364 filebuf_add(filebuf, "+", 1);
365 else if ((*u >= 0 && *u <= 42) || (*u >= 58 && *u <= 64) || (*u >= 91 && *u <= 96) || *u >= 123)
366 filebuf_addf(filebuf, "%%%.2x", *u);
368 filebuf_add(filebuf, u, 1);
371 filebuf_add(filebuf, "", 1);
372 filebuf_shorten(filebuf);
376 filebuf->data = NULL;
377 filebuf_free(filebuf);
383 write a filebuf to a file
385 int filebuf_save(FILEBUF * filebuf, char *filename)
389 fd = open(filename, O_CREAT | O_WRONLY);
393 ret = write(fd, filebuf->data, filebuf->size);
401 escape all <, >, and \'s in a string destined for the xml file
403 char *string_to_xml(char *s)
408 filebuf = filebuf_new();
412 filebuf_add(filebuf, "\\\\", 2);
414 filebuf_add(filebuf, "\\<", 2);
416 filebuf_add(filebuf, "\\>", 2);
418 filebuf_add(filebuf, s, 1);
421 filebuf_add(filebuf, "", 1);
422 filebuf_shorten(filebuf);
426 filebuf->data = NULL;
427 filebuf_free(filebuf);
433 tokenize a string and return a NULL-terminated char **
435 char **string_break(char *s, char d)
438 char **ret = NULL, *start = s;
442 ret = xrealloc(ret, sizeof(char *) * (count + 2));
443 ret[count] = xstrndup(start, s - start);
452 ret = xrealloc(ret, sizeof(char *) * (count + 2));
453 ret[count] = xstrndup(start, s - start);
465 read a file into a filebuf
467 int filebuf_read(FILEBUF * filebuf, char *filename)
472 fd = open(filename, O_RDONLY);
476 while ((x = read(fd, buf, BLOCKSIZE)) > 0) {
477 filebuf_add(filebuf, buf, x);
488 replace area of filebuf at specified offset and length with something else
490 void filebuf_replace(FILEBUF * filebuf, int so, int eo, char *replace)
493 int len2 = strlen(replace);
496 filebuf_resize(filebuf, filebuf->size + (len2 - len1));
499 memmove(&filebuf->data[eo + (len2 - len1)], &filebuf->data[eo], filebuf->size - eo);
502 filebuf_resize(filebuf, filebuf->size + (len2 - len1));
504 memcpy(&filebuf->data[so], replace, len2);
508 gzip compress contents of a FILEBUF
509 note: zlib doesn't provide any api's for doing in-memory compression/decompression in gzip format,
510 so a temp file has to be used.
512 int filebuf_gzip(FILEBUF *filebuf) {
518 s_strncpy(tmpfile, TEMPFILE, sizeof(tmpfile));
520 fd = mkstemp(tmpfile);
521 if (fd == -1) return FALSE;
523 gzf = gzdopen(fd, "w");
531 while (x < filebuf->size) {
532 ret = gzwrite(gzf, &filebuf->data[x], filebuf->size - x);
546 FREE_AND_NULL(filebuf->data);
549 filebuf_read(filebuf, tmpfile);
554 #endif /* HAVE_ZLIB */
560 ungzip the contents of a filebuf using zlib and a temporary file
562 int filebuf_ungzip(FILEBUF *filebuf) {
565 char tmpfile[64], buf[BLOCKSIZE];
566 FILEBUF *new_filebuf;
569 s_strncpy(tmpfile, TEMPFILE, sizeof(tmpfile));
571 fd = mkstemp(tmpfile);
572 if (fd == -1) return FALSE;
574 while (x < filebuf->size) {
575 ret = write(fd, &filebuf->data[x], filebuf->size - x);
588 gzf = gzopen(tmpfile, "r");
595 new_filebuf = filebuf_new();
598 ret = gzread(gzf, buf, sizeof(buf));
604 filebuf_free(new_filebuf);
607 } else if (ret == 0) break;
609 filebuf_add(new_filebuf, buf, ret);
615 xfree(filebuf->data);
616 filebuf->data = new_filebuf->data;
617 filebuf->size = new_filebuf->size;
619 new_filebuf->data = NULL;
620 filebuf_free(new_filebuf);
623 #endif /* HAVE_ZLIB */