handle errors nicely: warn without crashing - surf-adblock - Surf adblock web e… | |
git clone git://git.codemadness.org/surf-adblock | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit 9014575ee36dc784da9f519c41d44932d248b772 | |
parent 8f646ec95953602d0667766aa81e1a329ff05d13 | |
Author: Quentin Rameau <[email protected]> | |
Date: Sun, 17 Jul 2016 14:33:04 +0200 | |
handle errors nicely: warn without crashing | |
We don't want to crash the whole webprocess on error (do we?). | |
Warn when an error happened and bail out. | |
Diffstat: | |
M surf-adblock.c | 166 ++++++++++++++++++-----------… | |
1 file changed, 98 insertions(+), 68 deletions(-) | |
--- | |
diff --git a/surf-adblock.c b/surf-adblock.c | |
@@ -72,10 +72,10 @@ struct filtertype { | |
int allowinverse; | |
int allownormal; | |
int onlyexception; | |
- void (*fn)(struct filterrule *, char *); | |
+ int (*fn)(struct filterrule *, char *); | |
}; | |
-static void parsedomainsoption(struct filterrule *, char *); | |
+static int parsedomainsoption(struct filterrule *, char *); | |
#define STRP(s) s,sizeof(s)-1 | |
@@ -123,74 +123,73 @@ weprintf(const char *fmt, ...) | |
va_end(ap); | |
} | |
-static void | |
-eprintf(const char *fmt, ...) | |
-{ | |
- va_list ap; | |
- | |
- fprintf(stderr, "surf-adblock: "); | |
- | |
- va_start(ap, fmt); | |
- vfprintf(stderr, fmt, ap); | |
- va_end(ap); | |
- | |
- exit(1); | |
-} | |
- | |
-static void | |
+static size_t | |
string_buffer_realloc(String *s, size_t newsz) | |
{ | |
+ char *tmp; | |
size_t allocsz; | |
for (allocsz = 64; allocsz <= newsz; allocsz *= 2) | |
; | |
- if (!(s->data = realloc(s->data, allocsz))) | |
- eprintf("realloc: %s\n", strerror(errno)); | |
- s->bufsiz = alloclen; | |
+ if (!(tmp = realloc(s->data, allocsz))) { | |
+ weprintf("realloc: %s\n", strerror(errno)); | |
+ } else { | |
+ s->data = tmp; | |
+ s->datasz = allocsz; | |
+ } | |
+ | |
+ return s->datasz; | |
} | |
-static void | |
+static size_t | |
string_append(String *s, const char *data, size_t len) | |
{ | |
+ size_t newlen; | |
+ | |
if (!len) | |
- return; | |
+ return len; | |
+ | |
+ newlen = s->len + len; | |
/* check if allocation is necesary, don't shrink buffer, | |
* should be more than datasz ofcourse. */ | |
- if (s->len + len >= s->datasz) | |
- string_buffer_realloc(s, s->len + len + 1); | |
+ if (newlen >= s->datasz) { | |
+ if (string_buffer_realloc(s, newlen + 1) <= newlen) | |
+ return 0; | |
+ } | |
memcpy(s->data + s->len, data, len); | |
- s->len += len; | |
+ s->len = newlen; | |
s->data[s->len] = '\0'; | |
+ return len; | |
} | |
void * | |
-ecalloc(size_t nmemb, size_t size) | |
+wecalloc(size_t nmemb, size_t size) | |
{ | |
void *p; | |
if (!(p = calloc(nmemb, size))) | |
- eprintf("calloc: %s\n", strerror(errno)); | |
+ weprintf("calloc: %s\n", strerror(errno)); | |
return p; | |
} | |
char * | |
-estrndup(const char *s, size_t n) | |
+westrndup(const char *s, size_t n) | |
{ | |
char *p; | |
if (!(p = strndup(s, n))) | |
- eprintf("strndup: %s\n", strerror(errno)); | |
+ weprintf("strndup: %s\n", strerror(errno)); | |
return p; | |
} | |
char * | |
-estrdup(const char *s) | |
+westrdup(const char *s) | |
{ | |
char *p; | |
if (!(p = strdup(s))) | |
- eprintf("strdup: %s\n", strerror(errno)); | |
+ weprintf("strdup: %s\n", strerror(errno)); | |
return p; | |
} | |
@@ -395,10 +394,10 @@ match(const char *pat, const char *str, int fcase) | |
domain=... if domain is prefixed with ~, ignore. | |
multiple domains can be separated with | | |
*/ | |
-struct filterdomain * | |
-parsedomains(char *s, int sep) | |
+static int | |
+parsedomains(char *s, int sep, struct filterdomain **head) | |
{ | |
- struct filterdomain *head = NULL, *d, *last = NULL; | |
+ struct filterdomain *d, *last = *head = NULL; | |
char *p; | |
int inverse; | |
@@ -414,12 +413,14 @@ parsedomains(char *s, int sep) | |
if ((p = strchr(s, sep))) /* TODO: should not contain , */ | |
*p = '\0'; | |
- d = ecalloc(1, sizeof(struct filterdomain)); | |
+ if (!(d = wecalloc(1, sizeof(struct filterdomain)))) | |
+ return -1; | |
+ if (!(d->domain = westrdup(s))) | |
+ return -1; | |
d->inverse = inverse; | |
- d->domain = estrdup(s); | |
- if (!head) | |
- head = last = d; | |
+ if (!*head) | |
+ *head = last = d; | |
else | |
last = last->next = d; | |
@@ -429,10 +430,10 @@ parsedomains(char *s, int sep) | |
} | |
} while (p); | |
- return head; | |
+ return (*head != NULL); | |
} | |
-void | |
+static int | |
parsedomainselement(struct filterrule *f, char *s) | |
{ | |
struct filterdomain *d, *last; | |
@@ -440,14 +441,17 @@ parsedomainselement(struct filterrule *f, char *s) | |
for (last = f->domains; last && last->next; last = last->next) | |
; | |
- d = parsedomains(s, ','); | |
+ if (parsedomains(s, ',', &d) < 0) | |
+ return -1; | |
if (last) | |
last->next = d; | |
else | |
f->domains = d; | |
+ | |
+ return (d != NULL); | |
} | |
-void | |
+static int | |
parsedomainsoption(struct filterrule *f, char *s) | |
{ | |
struct filterdomain *d, *last; | |
@@ -455,11 +459,14 @@ parsedomainsoption(struct filterrule *f, char *s) | |
for (last = f->domains; last && last->next; last = last->next) | |
; | |
- d = parsedomains(s, '|'); | |
+ if (parsedomains(s, '|', &d) < 0) | |
+ return -1; | |
if (last) | |
last->next = d; | |
else | |
f->domains = d; | |
+ | |
+ return (d != NULL); | |
} | |
int | |
@@ -574,9 +581,11 @@ parserule(struct filterrule *f, char *s) | |
if ((p = strstr(s, "#@#"))) { | |
*p = '\0'; | |
- parsedomainselement(f, s); | |
+ if (parsedomainselement(f, s) < 0) | |
+ return -1; | |
*p = '#'; | |
- f->css = estrdup(p + 3); | |
+ if (!(f->css = westrdup(p + 3))) | |
+ return -1; | |
f->isexception = 1; | |
goto end; /* end of CSS rule */ | |
} | |
@@ -585,9 +594,11 @@ parserule(struct filterrule *f, char *s) | |
"Simplified element hiding syntax" is not supported. */ | |
if ((p = strstr(s, "##"))) { | |
*p = '\0'; | |
- parsedomainselement(f, s); | |
+ if (parsedomainselement(f, s) < 0) | |
+ return -1; | |
*p = '#'; | |
- f->css = estrdup(p + 2); | |
+ if (!(f->css = westrdup(p + 2))) | |
+ return -1; | |
goto end; /* end of rule */ | |
} | |
@@ -607,12 +618,14 @@ parserule(struct filterrule *f, char *s) | |
/* no options, use rest of line as uri. */ | |
if (!(p = strrchr(s, '$'))) { | |
- f->uri = estrdup(s); | |
+ if (!(f->uri = westrdup(s))) | |
+ return -1; | |
goto end; | |
} | |
/* has options */ | |
- f->uri = estrndup(s, p - s); | |
+ if (!(f->uri = westrndup(s, p - s))) | |
+ return -1; | |
s = ++p; | |
/* blockmask, has options? default: allow all options, case-sensitive | |
@@ -674,10 +687,11 @@ debugrule(struct filterrule *r) | |
struct filterrule * | |
loadrules(FILE *fp) | |
{ | |
+ struct filterrule f, *r, *rn = NULL, *rules = NULL; | |
char *line = NULL; | |
size_t linesiz = 0; | |
ssize_t n; | |
- struct filterrule f, *r, *rn = NULL, *rules = NULL; | |
+ int ret; | |
/* TODO: handle ferror() */ | |
/* load rules */ | |
@@ -687,13 +701,16 @@ loadrules(FILE *fp) | |
if (n > 0 && line[n - 1] == '\r') | |
line[--n] = '\0'; | |
- if (parserule(&f, line)) { | |
- r = ecalloc(1, sizeof(struct filterrule)); | |
+ if ((ret = parserule(&f, line) > 0)) { | |
+ if (!(r = wecalloc(1, sizeof(struct filterrule)))) | |
+ return NULL; | |
if (!rules) | |
rules = rn = r; | |
else | |
rn = rn->next = r; | |
memcpy(rn, &f, sizeof(struct filterrule)); | |
+ } else if (ret < 0) { | |
+ return NULL; | |
} | |
} | |
return rules; | |
@@ -704,7 +721,8 @@ newpage(WebKitWebPage *page) | |
{ | |
Page *p; | |
- p = ecalloc(1, sizeof(Page)); | |
+ if (!(p = wecalloc(1, sizeof(Page)))) | |
+ return NULL; | |
p->next = pages; | |
pages = p; | |
@@ -724,13 +742,15 @@ documentloaded(WebKitWebPage *wp, Page *p) | |
struct filterrule *r; | |
const char *uri = webkit_web_page_get_uri(p->webpage); | |
char *domain; | |
+ size_t len; | |
if (!uri || (strncmp(uri, "http://", sizeof("http://") - 1) && | |
strncmp(uri, "https://", sizeof("https://") - 1))) | |
return; | |
domain = strstr(uri, "://") + sizeof("://") - 1; | |
- domain = estrndup(domain, strcspn(domain, "/")); | |
+ if (!(domain = westrndup(domain, strcspn(domain, "/")))) | |
+ return; | |
printf("uri: %s\n", uri); | |
printf("domain: %s\n", domain); | |
@@ -741,8 +761,12 @@ documentloaded(WebKitWebPage *wp, Page *p) | |
for (r = rules; r; r = r->next) { | |
if (!r->css || !r->domains || !matchrule(r, "", "", domain)) | |
continue; | |
- string_append(&sitecss, r->css, strlen(r->css)); | |
- string_append(&sitecss, STRP("{display:none;}")); | |
+ len = strlen(r->css); | |
+ if (string_append(&sitecss, r->css, len) < len) | |
+ return; | |
+ len = sizeof("{display:none;}") -1; | |
+ if (string_append(&sitecss, "{display:none;}", len) < len) | |
+ return; | |
} | |
printf("sitecss: %s\n", sitecss.data ? sitecss.data : "<empty>"); | |
#endif | |
@@ -786,7 +810,8 @@ sendrequest(WebKitWebPage *wp, WebKitURIRequest *req, | |
return FALSE; | |
domain = strstr(uri, "://") + sizeof("://") - 1; | |
- domain = estrndup(domain, strcspn(domain, "/")); | |
+ if (!(domain = westrndup(domain, strcspn(domain, "/")))) | |
+ return FALSE; | |
/* match rules */ | |
for (r = rules; r; r = r->next) { | |
@@ -809,12 +834,13 @@ sendrequest(WebKitWebPage *wp, WebKitURIRequest *req, | |
static void | |
webpagecreated(WebKitWebExtension *e, WebKitWebPage *p, gpointer unused) | |
{ | |
- Page *np = newpage(p); | |
+ Page *np; | |
+ | |
+ if (!(np = newpage(p))) | |
+ return; | |
- g_signal_connect(p, "document-loaded", | |
- G_CALLBACK(documentloaded), np); | |
- g_signal_connect(p, "send-request", | |
- G_CALLBACK(sendrequest), np); | |
+ g_signal_connect(p, "document-loaded", G_CALLBACK(documentloaded), np); | |
+ g_signal_connect(p, "send-request", G_CALLBACK(sendrequest), np); | |
} | |
G_MODULE_EXPORT void | |
@@ -823,6 +849,7 @@ webkit_web_extension_initialize(WebKitWebExtension *ext) | |
struct filterrule *r; | |
FILE *fp; | |
char filepath[PATH_MAX], *e; | |
+ size_t len; | |
int n; | |
if ((e = getenv("SURF_ADBLOCK_FILE"))) { | |
@@ -840,12 +867,12 @@ webkit_web_extension_initialize(WebKitWebExtension *ext) | |
if (!(fp = fopen(filepath, "r"))) { | |
weprintf("fatal: cannot open rules file %s: %s\n", | |
- filepath, strerror(errno)); | |
+ filepath, strerror(errno)); | |
return; | |
} | |
if (!(rules = loadrules(fp))) { | |
weprintf("fatal: cannot read rules file %s: %s\n", | |
- filepath, strerror(errno)); | |
+ filepath, strerror(errno)); | |
return; | |
} | |
fclose(fp); | |
@@ -855,10 +882,13 @@ webkit_web_extension_initialize(WebKitWebExtension *ext) | |
if (!r->css || r->domains) | |
continue; | |
- string_append(&globalcss, r->css, strlen(r->css)); | |
- string_append(&globalcss, STRP("{display:none;}")); | |
+ len = strlen(r->css); | |
+ if (string_append(&globalcss, r->css, strlen(r->css)) < len) | |
+ return; | |
+ len = sizeof("{display:none;}") - 1; | |
+ if (string_append(&globalcss, "{display:none;}", len) < len) | |
+ return; | |
} | |
- g_signal_connect(ext, "page-created", | |
- G_CALLBACK(webpagecreated), NULL); | |
+ g_signal_connect(ext, "page-created", G_CALLBACK(webpagecreated), NULL… | |
} |