wdvi

network DVI viewer
Log | Files | Refs

commit f16a22fb193d673187e1a198ab625548a1200995
parent 065cd56c9b1bc19235f0329dff7d5f94087490ec
Author: Kyle Milz <krwmilz@gmail.com>
Date:   Fri, 10 Sep 2021 16:18:45 +0000

replace sscanf(%n) use in parse_headers()

Use a combination of strtok() and sscanf() to replace sscanf() %n use
which I understand is a stupid feature. Add more error checking in
parse_headers() too.

Diffstat:
Mhttp.c | 61+++++++++++++++++++++++++++++++++----------------------------
1 file changed, 33 insertions(+), 28 deletions(-)

diff --git a/http.c b/http.c @@ -44,10 +44,10 @@ struct url { }; struct http_headers { - char proto[9]; /* HTTP/1.1 or whatever */ - int status; /* 200, 404, etc */ - char status_text[32]; /* 416 may be the longest? */ - int content_len; /* Content-Length: */ + char ver[15]; /* Should be enough, RFC2616 3.1 */ + int stat; /* 200, 404, etc */ + char stat_text[32]; /* 416 may be the longest? */ + int cont_len; /* Content-Length: */ }; @@ -333,28 +333,31 @@ send_request(SSL *tls, struct url *url) * free. */ static struct http_headers * -parse_headers(char *buf, int bytes_read) +parse_headers(char *hdr, int hdr_len) { - char header[32], value[32]; /* unbounded len? */ struct http_headers *res; - int pos; + char *line; if ((res = calloc(1, sizeof(struct http_headers))) == NULL) err(1, NULL); + if ((line = strtok(hdr, "\r\n")) == NULL) + goto free_res; + /* First line of response is 'HTTP/1.1 200 OK' for example. */ - sscanf(buf, "%8s %i %31[^\r\n]%n", res->proto, &res->status, - res->status_text, &pos); - buf += pos; - - while (sscanf(buf, "%31s %31[^\r\n]%n", header, value, &pos) != EOF) { - if (strcmp(header, "Content-Length:") == 0) - res->content_len = atoi(value); - - buf += pos; + if (sscanf(line, "%15s %i %31s", res->ver, &res->stat, + res->stat_text) != 3) + goto free_res; + + /* We only care about Content-Length right now. */ + while ((line = strtok(NULL, "\r\n")) != NULL) { + if (sscanf(line, "Content-Length: %ui", &res->cont_len) == 1) + return res; } - return res; +free_res: + free(res); + return NULL; } static FILE * @@ -366,7 +369,7 @@ read_response(SSL *tls, struct url *url) int total_bytes = 0; FILE *dvi_file = NULL; - /* This buffer must be null terminated. */ + /* We will be parsing text out of this, lets avoid surprises */ buf = calloc(1, SSL_BUF_SIZE); /* First read yields the HTTP header response in its entirety. */ @@ -377,23 +380,25 @@ read_response(SSL *tls, struct url *url) } /* We must free returned response. */ - response = parse_headers(buf, nbytes); + if ((response = parse_headers(buf, nbytes)) == NULL) { + warning_popup_long("%s: malformed HTTP header", "OK", NULL, + url->hostname); + goto free_buf; + } - if (response->status != 200) { + if (response->stat != 200) { warning_popup_long("%s: %i %s", "OK", NULL, url->orig_url, - response->status, response->status_text); + response->stat, response->stat_text); goto free_response; } /* XDvi does all its processing with FILE streams. */ - if ((dvi_file = fmemopen(NULL, response->content_len, "r+")) == NULL) + if ((dvi_file = fmemopen(NULL, response->cont_len, "r+")) == NULL) err(1, "fmemopen"); /* Second (or more) reads are the HTTP body response. */ - while (total_bytes < response->content_len) { - nbytes = SSL_read(tls, buf, SSL_BUF_SIZE); - - if (nbytes < 1) { + while (total_bytes < response->cont_len) { + if ((nbytes = SSL_read(tls, buf, SSL_BUF_SIZE)) < 1) { warning_popup_long("SSL_read: %s: %s", "OK", NULL, url->hostname, SSL_strerror(tls, nbytes)); fclose(dvi_file); @@ -412,9 +417,9 @@ read_response(SSL *tls, struct url *url) printf("Number of HTTP body bytes: %i\n", total_bytes); - if (total_bytes != response->content_len) + if (total_bytes != response->cont_len) warning_popup_long("HTTP body len: expected %i but read %i\n", - "OK", NULL, response->content_len, nbytes); + "OK", NULL, response->cont_len, nbytes); free_response: free(response);