logo

httpc

barebones HTTP client, intended for simple usage like downloading filesgit clone https://hacktivis.me/git/httpc.git
commit: faadcbaa492ca5d73d7a196affad47ab5cd9b46a
parent 3527ac7133512a5ad3f72564ef03de64b2355a38
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date:   Sat,  1 Jun 2024 07:07:53 +0200

Add support for -o and -v

Diffstat:

Mhttpc.c69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 63 insertions(+), 6 deletions(-)

diff --git a/httpc.c b/httpc.c @@ -4,12 +4,16 @@ #include <limits.h> // PAGESIZE #include <tls.h> +#include <errno.h> #include <stdio.h> // fprintf -#include <unistd.h> // write -#include <string.h> // strlen +#include <unistd.h> // write, fsync +#include <string.h> // strlen, strerror #include <stdlib.h> // abort +#include <stdbool.h> +#include <fcntl.h> // open, O_* int body = 0; +bool verbose = false; static size_t read_header(const char *res, ssize_t len) @@ -28,8 +32,12 @@ read_header(const char *res, ssize_t len) return i+1; } - fwrite(res, 1, header_len, stderr); - fputs("\n", stderr); + if(verbose) + { + fputs("> ", stderr); + fwrite(res, 1, header_len, stderr); + fputs("\n", stderr); + } return i+1; } @@ -45,6 +53,37 @@ read_header(const char *res, ssize_t len) int main(int argc, char *argv[]) { + int out_flags = O_WRONLY | O_CLOEXEC | O_CREAT | O_NOCTTY | O_TRUNC; + char *out_name = NULL; + int out = -1; + + int c = -1; + while((c = getopt(argc, argv, ":o:v")) != -1) + { + switch(c) + { + case 'o': + out_name = optarg; + break; + case 'v': + verbose = true; + break; + } + } + + argv += optind; + argc -= optind; + + // FIXME: URL basename + if(out_name == NULL) out_name = "body"; + + out = open(out_name, out_flags, 0644); + if(out < 0) + { + fprintf(stderr, "httpc: Failed opening destination file '%s': %s\n", out_name, strerror(errno)); + return 1; + } + const char *hostname = "lanodan.eu"; const char *target = "/"; const char *port = "443"; @@ -66,9 +105,12 @@ main(int argc, char *argv[]) return 1; } + int err = 0; + if(tls_handshake(tls_ctx) != 0) { fprintf(stderr, "httpc: TLS Handshake Error: %s\n", tls_error(tls_ctx)); + err = 1; goto cleanup; } @@ -82,10 +124,13 @@ Connection: close\r\n\ snprintf(req, PAGESIZE, req_fmt, target, hostname); + if(verbose) write(STDERR_FILENO, req, strlen(req)); + ssize_t nwrite = tls_write(tls_ctx, req, strlen(req)); if(nwrite < 0) { fprintf(stderr, "httpc: Write Error: %s\n", tls_error(tls_ctx)); + err = 1; goto cleanup; } @@ -110,7 +155,19 @@ Connection: close\r\n\ // TODO: Read status while(body == 0 && off < nread) off += read_header(res+off, nread); - if(body == 1) write(STDOUT_FILENO, res+off, nread-off); + if(body == 1) write(out, res+off, nread-off); + } + + if(fsync(out) < 0) + { + fprintf(stderr, "httpc: Failed syncing destination file '%s' to disk: %s\n", out_name, strerror(errno)); + err = 1; + } + + if(close(out) < 0) + { + fprintf(stderr, "httpc: Failed closing destination file '%s': %s\n", out_name, strerror(errno)); + err = 1; } cleanup: @@ -118,5 +175,5 @@ cleanup: tls_free(tls_ctx); tls_config_free(tls_cfg); - return 0; + return err; }