nkiss

Unnamed repository; edit this file 'description' to name the repository.
git clone git://git.nihaljere.xyz/nkiss
Log | Files | Refs

commit 7470481c1eff46db13b807c8da0d13aed08c2b1d
parent b45edeef75e1ab2ad82158c4b8a29cdf6fe0d80a
Author: Nihal Jere <nihal@nihaljere.xyz>
Date:   Wed, 17 Feb 2021 23:47:43 -0600

http.c: use spaces instead of tabs

Diffstat:
Mhttp.c | 692++++++++++++++++++++++++++++++++++++++++---------------------------------------
1 file changed, 354 insertions(+), 338 deletions(-)

diff --git a/http.c b/http.c @@ -15,17 +15,17 @@ #include "util.h" -#define READ_BUF_SIZ 16384 +#define READ_BUF_SIZ 16384 #ifndef TLS_CA_CERT_FILE #define TLS_CA_CERT_FILE "/etc/ssl/cert.pem" #endif struct uri { - char proto[48]; - char host[256]; - char path[2048]; - char port[6]; /* numeric port */ + char proto[48]; + char host[256]; + char path[2048]; + char port[6]; /* numeric port */ }; /* time-out in seconds */ @@ -42,355 +42,371 @@ FILE *dest; static void sighandler(int signo) { - if (signo == SIGALRM) - _exit(2); + if (signo == SIGALRM) + _exit(2); } static int parseuri(const char *s, struct uri *u) { - const char *p = s, *b; - char *endptr = NULL; - size_t i; - unsigned long l; - - u->proto[0] = u->host[0] = u->path[0] = u->port[0] = '\0'; - if (!*p) - return 0; - - /* protocol part */ - for (p = s; *p && (isalpha((unsigned char)*p) || isdigit((unsigned char)*p) || - *p == '+' || *p == '-' || *p == '.'); p++) - ; - if (!strncmp(p, "://", 3)) { - if ((size_t)(p - s) >= sizeof(u->proto)) - return -1; /* protocol too long */ - memcpy(u->proto, s, p - s); - u->proto[p - s] = '\0'; - p += 3; /* skip "://" */ - } else { - return -1; /* no protocol specified */ - } - - /* IPv6 address */ - if (*p == '[') { - /* bracket not found or host too long */ - if (!(b = strchr(p, ']')) || (size_t)(b - p) >= (ssize_t)sizeof(u->host)) - return -1; - memcpy(u->host, p + 1, b - p - 1); - u->host[b - p - 1] = '\0'; - p = b + 1; - } else { - /* domain / host part, skip until port, path or end. */ - if ((i = strcspn(p, ":/")) >= sizeof(u->host)) - return -1; /* host too long */ - memcpy(u->host, p, i); - u->host[i] = '\0'; - p = &p[i]; - } - /* port */ - if (*p == ':') { - if ((i = strcspn(++p, "/")) >= sizeof(u->port)) - return -1; /* port too long */ - memcpy(u->port, p, i); - u->port[i] = '\0'; - /* check for valid port: range 1 - 65535 */ - errno = 0; - l = strtoul(u->port, &endptr, 10); - if (errno || u->port[0] == '\0' || *endptr || - !l || l > 65535) - return -1; - p = &p[i]; - } - if (u->host[0]) { - p = &p[strspn(p, "/")]; - memcpy(u->path, "/", 2); - } else { - return -1; - } - /* treat truncation as an error */ - if (strlcat(u->path, p, sizeof(u->path)) >= sizeof(u->path)) - return -1; - return 0; + const char *p = s, *b; + char *endptr = NULL; + size_t i; + unsigned long l; + + u->proto[0] = u->host[0] = u->path[0] = u->port[0] = '\0'; + if (!*p) + return 0; + + /* protocol part */ + for (p = s; *p && (isalpha((unsigned char)*p) || isdigit((unsigned char)*p) || + *p == '+' || *p == '-' || *p == '.'); p++) + ; + if (!strncmp(p, "://", 3)) { + if ((size_t)(p - s) >= sizeof(u->proto)) + return -1; /* protocol too long */ + memcpy(u->proto, s, p - s); + u->proto[p - s] = '\0'; + p += 3; /* skip "://" */ + } else { + return -1; /* no protocol specified */ + } + + /* IPv6 address */ + if (*p == '[') { + /* bracket not found or host too long */ + if (!(b = strchr(p, ']')) || (size_t)(b - p) >= (ssize_t)sizeof(u->host)) + return -1; + memcpy(u->host, p + 1, b - p - 1); + u->host[b - p - 1] = '\0'; + p = b + 1; + } else { + /* domain / host part, skip until port, path or end. */ + if ((i = strcspn(p, ":/")) >= sizeof(u->host)) + return -1; /* host too long */ + memcpy(u->host, p, i); + u->host[i] = '\0'; + p = &p[i]; + } + /* port */ + if (*p == ':') { + if ((i = strcspn(++p, "/")) >= sizeof(u->port)) + return -1; /* port too long */ + memcpy(u->port, p, i); + u->port[i] = '\0'; + /* check for valid port: range 1 - 65535 */ + errno = 0; + l = strtoul(u->port, &endptr, 10); + if (errno || u->port[0] == '\0' || *endptr || + !l || l > 65535) + return -1; + p = &p[i]; + } + if (u->host[0]) { + p = &p[strspn(p, "/")]; + memcpy(u->path, "/", 2); + } else { + return -1; + } + /* treat truncation as an error */ + if (strlcat(u->path, p, sizeof(u->path)) >= sizeof(u->path)) + return -1; + return 0; } static int edial(const char *host, const char *port) { - struct addrinfo hints, *res, *res0; - int error, save_errno, s; - const char *cause = NULL; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = AI_NUMERICSERV; /* numeric port only */ - if ((error = getaddrinfo(host, port, &hints, &res0))) - die("%s: %s: %s:%s", __func__, gai_strerror(error), host, port); - s = -1; - for (res = res0; res; res = res->ai_next) { - s = socket(res->ai_family, res->ai_socktype, - res->ai_protocol); - if (s == -1) { - cause = "socket"; - continue; - } - - if (connect(s, res->ai_addr, res->ai_addrlen) == -1) { - cause = "connect"; - save_errno = errno; - close(s); - errno = save_errno; - s = -1; - continue; - } - break; - } - if (s == -1) - die("%s: %s: %s:%s", __func__, cause, host, port); - freeaddrinfo(res0); - - return s; + struct addrinfo hints, *res, *res0; + int error, save_errno, s; + const char *cause = NULL; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_NUMERICSERV; /* numeric port only */ + if ((error = getaddrinfo(host, port, &hints, &res0))) + die("%s: %s: %s:%s", __func__, gai_strerror(error), host, port); + s = -1; + for (res = res0; res; res = res->ai_next) { + s = socket(res->ai_family, res->ai_socktype, + res->ai_protocol); + if (s == -1) { + cause = "socket"; + continue; + } + + if (connect(s, res->ai_addr, res->ai_addrlen) == -1) { + cause = "connect"; + save_errno = errno; + close(s); + errno = save_errno; + s = -1; + continue; + } + break; + } + if (s == -1) + die("%s: %s: %s:%s", __func__, cause, host, port); + freeaddrinfo(res0); + + return s; } static int https_request(void) { - struct tls *t; - char buf[READ_BUF_SIZ], *p; - const char *errstr; - size_t n, len; - ssize_t r; - int httpok = 0, ret = 1, stdport; - - if (!(t = tls_client())) { - fprintf(stderr, "tls_client: %s\n", tls_error(t)); - goto err; - } - if (tls_configure(t, tls_config)) { - fprintf(stderr, "tls_configure: %s\n", tls_error(t)); - goto err; - } - - if (tls_connect(t, u.host, u.port) == -1) - die("tls_connect: %s", tls_error(t)); - - stdport = u.port[0] == '\0' || strcmp(u.port, "443") == 0; - - /* create and send HTTP header */ - r = snprintf(buf, sizeof(buf), - "GET %s HTTP/1.0\r\n" - "Host: %s%s%s\r\n" - "Connection: close\r\n" - "\r\n", u.path, u.host, - stdport ? "" : ":", - stdport ? "" : u.port); - if (r < 0 || (size_t)r >= sizeof(buf)) { - fprintf(stderr, "not writing header because it is truncated"); - goto err; - } - - for (len = r, p = buf; len > 0; ) { - r = tls_write(t, p, len); - if (r == TLS_WANT_POLLIN || r == TLS_WANT_POLLOUT) { - continue; - } else if (r == -1) { - fprintf(stderr, "tls_write: %s\n", tls_error(t)); - goto err; - } - p += r; - len -= r; - } - - /* NOTE: HTTP header must fit in the buffer */ - for (len = 0; len < sizeof(buf);) { - /* NOTE: buffer size is -1 to NUL terminate the buffer for a - string comparison. */ - r = tls_read(t, &buf[len], sizeof(buf) - len - 1); - if (r == TLS_WANT_POLLIN || r == TLS_WANT_POLLOUT) { - continue; - } else if (r == 0) { - break; - } else if (r == -1) { - errstr = tls_error(t); - fprintf(stderr, "tls_read: %s\n", errstr ? errstr : ""); - goto err; - } - len += r; - } - buf[len] = '\0'; - - if (!strncmp(buf, "HTTP/1.0 200 ", sizeof("HTTP/1.0 200 ") - 1) || - !strncmp(buf, "HTTP/1.1 200 ", sizeof("HTTP/1.1 200 ") - 1)) - httpok = 1; - - if (!(p = strstr(buf, "\r\n\r\n"))) { - fprintf(stderr, "no HTTP header found or header too big\n"); - goto err; - } - *p = '\0'; /* NUL terminate header part */ - p += strlen("\r\n\r\n"); - - if (httpok) { - n = len - (p - buf); - r = fwrite(p, 1, n, dest); - if (ferror(dest)) { - fprintf(stderr, "fwrite: %s\n", strerror(errno)); - goto err; - } - } else { - /* if not 200 OK print header */ - fputs(buf, stderr); - fputs("\r\n\r\n", stderr); - /* NOTE: we are nice and keep reading (not closing) until the server is done. */ - } - - while (1) { - r = tls_read(t, &buf, sizeof(buf)); - if (r == TLS_WANT_POLLIN || r == TLS_WANT_POLLOUT) { - continue; - } else if (r == 0) { - break; - } else if (r == -1) { - errstr = tls_error(t); - fprintf(stderr, "tls_read: %s\n", errstr ? errstr : ""); - goto err; - } - len += r; - - if (httpok) { - r = fwrite(buf, 1, r, dest); - if (ferror(dest)) { - fprintf(stderr, "fwrite: %s\n", strerror(errno)); - goto err; - } - } - - } - ret = 0; + struct tls *t; + char buf[READ_BUF_SIZ], *p; + const char *errstr; + size_t n, len; + ssize_t r; + int status = 0, ret = 1, stdport; + + if (!(t = tls_client())) { + fprintf(stderr, "tls_client: %s\n", tls_error(t)); + goto err; + } + if (tls_configure(t, tls_config)) { + fprintf(stderr, "tls_configure: %s\n", tls_error(t)); + goto err; + } + + if (tls_connect(t, u.host, u.port) == -1) + die("tls_connect: %s", tls_error(t)); + + stdport = u.port[0] == '\0' || strcmp(u.port, "443") == 0; + + /* create and send HTTP header */ + r = snprintf(buf, sizeof(buf), + "GET %s HTTP/1.0\r\n" + "Host: %s%s%s\r\n" + "Connection: close\r\n" + "\r\n", u.path, u.host, + stdport ? "" : ":", + stdport ? "" : u.port); + if (r < 0 || (size_t)r >= sizeof(buf)) { + fprintf(stderr, "not writing header because it is truncated"); + goto err; + } + + for (len = r, p = buf; len > 0; ) { + r = tls_write(t, p, len); + if (r == TLS_WANT_POLLIN || r == TLS_WANT_POLLOUT) { + continue; + } else if (r == -1) { + fprintf(stderr, "tls_write: %s\n", tls_error(t)); + goto err; + } + p += r; + len -= r; + } + + /* NOTE: HTTP header must fit in the buffer */ + for (len = 0; len < sizeof(buf);) { + /* NOTE: buffer size is -1 to NUL terminate the buffer for a + string comparison. */ + r = tls_read(t, &buf[len], sizeof(buf) - len - 1); + if (r == TLS_WANT_POLLIN || r == TLS_WANT_POLLOUT) { + continue; + } else if (r == 0) { + break; + } else if (r == -1) { + errstr = tls_error(t); + fprintf(stderr, "tls_read: %s\n", errstr ? errstr : ""); + goto err; + } + len += r; + } + buf[len] = '\0'; + + if (!strncmp(buf, "HTTP/1.0 200 ", sizeof("HTTP/1.0 200 ") - 1) || + !strncmp(buf, "HTTP/1.1 200 ", sizeof("HTTP/1.1 200 ") - 1)) + status = 1; + + if (!(p = strstr(buf, "\r\n\r\n"))) { + fprintf(stderr, "no HTTP header found or header too big\n"); + goto err; + } + *p = '\0'; /* NUL terminate header part */ + p += strlen("\r\n\r\n"); + + if (status) { + n = len - (p - buf); + r = fwrite(p, 1, n, dest); + if (ferror(dest)) { + fprintf(stderr, "fwrite: %s\n", strerror(errno)); + goto err; + } + } else { + /* if not 200 OK print header */ + fputs(buf, stderr); + fputs("\r\n\r\n", stderr); + /* NOTE: we are nice and keep reading (not closing) until the server is done. */ + } + + while (1) { + r = tls_read(t, &buf, sizeof(buf)); + if (r == TLS_WANT_POLLIN || r == TLS_WANT_POLLOUT) { + continue; + } else if (r == 0) { + break; + } else if (r == -1) { + errstr = tls_error(t); + fprintf(stderr, "tls_read: %s\n", errstr ? errstr : ""); + goto err; + } + len += r; + + if (status) { + r = fwrite(buf, 1, r, dest); + if (ferror(dest)) { + fprintf(stderr, "fwrite: %s\n", strerror(errno)); + goto err; + } + } + + } + ret = 0; err: - if (t) { - tls_close(t); - tls_free(t); - } + if (t) { + tls_close(t); + tls_free(t); + } - return httpok ? ret : 2; + return status ? ret : 2; } static int http_request(void) { - char buf[READ_BUF_SIZ], *p; - size_t n, len; - ssize_t r; - int fd = -1, httpok = 0, ret = 1, stdport; - - fd = edial(u.host, u.port); - - stdport = u.port[0] == '\0' || strcmp(u.port, "80") == 0; - - /* create and send HTTP header */ - r = snprintf(buf, sizeof(buf), - "GET %s HTTP/1.0\r\n" - "Host: %s%s%s\r\n" - "Connection: close\r\n" - "\r\n", u.path, u.host, - stdport ? "" : ":", - stdport ? "" : u.port); - if (r < 0 || (size_t)r >= sizeof(buf)) { - fprintf(stderr, "not writing header because it is truncated"); - goto err; - } - - for (len = r, p = buf; len > 0; p += r, len -= r) { - if ((r = write(fd, p, len)) == -1) { - fprintf(stderr, "write: %s\n", strerror(errno)); - goto err; - } - } - - /* NOTE: HTTP header must fit in the buffer */ - for (len = 0; len < sizeof(buf); len += r) { - /* NOTE: buffer size is -1 to NUL terminate the buffer for a - string comparison. */ - if ((r = read(fd, &buf[len], sizeof(buf) - len - 1)) == 0) - break; - if (r == -1) { - fprintf(stderr, "read: %s\n", strerror(errno)); - goto err; - } - } - buf[len] = '\0'; - - if (!strncmp(buf, "HTTP/1.0 200 ", sizeof("HTTP/1.0 200 ") - 1) || - !strncmp(buf, "HTTP/1.1 200 ", sizeof("HTTP/1.1 200 ") - 1)) - httpok = 1; - - if (!(p = strstr(buf, "\r\n\r\n"))) { - fprintf(stderr, "no HTTP header found or header too big\n"); - goto err; - } - *p = '\0'; /* NUL terminate header part */ - p += strlen("\r\n\r\n"); - - if (httpok) { - n = len - (p - buf); - r = fwrite(p, 1, n, dest); - if (ferror(dest)) { - fprintf(stderr, "fwrite: %s\n", strerror(errno)); - goto err; - } - } else { - /* if not 200 OK print header */ - fputs(buf, stderr); - fputs("\r\n\r\n", stderr); - /* NOTE: we are nice and keep reading (not closing) until the server is done. */ - } - - while (1) { - r = read(fd, &buf, sizeof(buf)); - if (r == 0) - break; - if (r == -1) { - fprintf(stderr, "read: %s\n", strerror(errno)); - goto err; - } - len += r; - - if (httpok) { - r = fwrite(buf, 1, r, dest); - if (ferror(dest)) { - fprintf(stderr, "fwrite: %s\n", strerror(errno)); - goto err; - } - } - - } - ret = 0; + char buf[READ_BUF_SIZ], *p; + size_t n, len; + ssize_t r; + int fd = -1, status = 0, ret = 1, stdport; + + fd = edial(u.host, u.port); + + stdport = u.port[0] == '\0' || strcmp(u.port, "80") == 0; + + /* create and send HTTP header */ + r = snprintf(buf, sizeof(buf), + "GET %s HTTP/1.0\r\n" + "Host: %s%s%s\r\n" + "Connection: close\r\n" + "\r\n", u.path, u.host, + stdport ? "" : ":", + stdport ? "" : u.port); + if (r < 0 || (size_t)r >= sizeof(buf)) { + fprintf(stderr, "not writing header because it is truncated"); + goto err; + } + + for (len = r, p = buf; len > 0; p += r, len -= r) { + if ((r = write(fd, p, len)) == -1) { + fprintf(stderr, "write: %s\n", strerror(errno)); + goto err; + } + } + + /* NOTE: HTTP header must fit in the buffer */ + for (len = 0; len < sizeof(buf); len += r) { + /* NOTE: buffer size is -1 to NUL terminate the buffer for a + string comparison. */ + if ((r = read(fd, &buf[len], sizeof(buf) - len - 1)) == 0) + break; + if (r == -1) { + fprintf(stderr, "read: %s\n", strerror(errno)); + goto err; + } + } + buf[len] = '\0'; + + if (!strncmp(buf, "HTTP/1.0 ", sizeof("HTTP/1.0 ") - 1) || + !strncmp(buf, "HTTP/1.1 ", sizeof("HTTP/1.1 ") - 1)) { + p = buf + sizeof("HTTP/1.1 ") - 1; + /* OK, we can read response */ + if (!strncmp(p, "200 ", sizeof("200 ") - 1)) { + status = 2; + /* redirection */ + } else if (!strncmp(p, "302 ", sizeof("302 ") - 1) || + !strncmp(p, "303 ", sizeof("303 ") - 1) || + !strncmp(p, "307 ", sizeof("307 ") - 1)) { + status = 3; + } + } + + if (!(p = strstr(buf, "\r\n\r\n"))) { + fprintf(stderr, "no HTTP header found or header too big\n"); + goto err; + } + *p = '\0'; /* NUL terminate header part */ + p += strlen("\r\n\r\n"); + + if (status == 2) { + n = len - (p - buf); + r = fwrite(p, 1, n, dest); + if (ferror(dest)) { + fprintf(stderr, "fwrite: %s\n", strerror(errno)); + goto err; + } + } else if (status == 3) { + p = strstr(buf, "\r\nLocation: "); + if (p == NULL) { + fprintf(stderr, "http: no Location given for 3xx response\n"); + goto err; + } + } else { + /* if not 200 OK print header */ + fputs(buf, stderr); + fputs("\r\n\r\n", stderr); + /* NOTE: we are nice and keep reading (not closing) until the server is done. */ + } + + while (1) { + r = read(fd, &buf, sizeof(buf)); + if (r == 0) + break; + if (r == -1) { + fprintf(stderr, "read: %s\n", strerror(errno)); + goto err; + } + len += r; + + if (status == 2) { + r = fwrite(buf, 1, r, dest); + if (ferror(dest)) { + fprintf(stderr, "fwrite: %s\n", strerror(errno)); + goto err; + } + } + + } + ret = 0; err: - if (fd != -1) - close(fd); - return httpok ? ret : 2; + if (fd != -1) + close(fd); + return status ? ret : 2; } int http_fetch(char *loc, char *path) { - int statuscode; + int statuscode; - if (strlen(loc) > 2047) - die("%s: url too long: %s", __func__, url); + if (strlen(loc) > 2047) + die("%s: url too long: %s", __func__, url); strcpy(url, loc); - if (parseuri(url, &u) == -1) - die("invalid url: %s", url); + if (parseuri(url, &u) == -1) + die("invalid url: %s", url); - if (config_timeout > 0) { - signal(SIGALRM, sighandler); - } + if (config_timeout > 0) { + signal(SIGALRM, sighandler); + } mkdirs(dirname(path)); @@ -398,26 +414,26 @@ http_fetch(char *loc, char *path) die("%s: failed to open %s:", __func__, path); } - if (!strcmp(u.proto, "https")) { - if (tls_init()) - die("tls_init failed"); - if (!(tls_config = tls_config_new())) - die("tls config failed"); - if (!u.port[0] && !strcmp(u.proto, "https")) - memcpy(u.port, "443", 4); - statuscode = https_request(); - } else if (!strcmp(u.proto, "http")) { - if (!u.port[0]) - memcpy(u.port, "80", 3); - statuscode = http_request(); - } else { - if (u.proto[0]) - die("unsupported protocol specified: %s", u.proto); - else - die("no protocol specified"); - } + if (!strcmp(u.proto, "https")) { + if (tls_init()) + die("tls_init failed"); + if (!(tls_config = tls_config_new())) + die("tls config failed"); + if (!u.port[0] && !strcmp(u.proto, "https")) + memcpy(u.port, "443", 4); + statuscode = https_request(); + } else if (!strcmp(u.proto, "http")) { + if (!u.port[0]) + memcpy(u.port, "80", 3); + statuscode = http_request(); + } else { + if (u.proto[0]) + die("unsupported protocol specified: %s", u.proto); + else + die("no protocol specified"); + } fclose(dest); - return statuscode; + return statuscode; }