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:
M | http.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);