shithub: s3

Download patch

ref: 3b8f99d834e0be3b0a7ef5e47224a8f6077e3656
parent: 541380f17a9c441d785620a2c83ba78ea4d1261d
author: Jacob Moody <moody@posixcafe.org>
date: Mon Jul 28 05:49:48 EDT 2025

s3cp: clean up

--- a/s3cp.c
+++ b/s3cp.c
@@ -12,6 +12,14 @@
 	char *region;
 } S3;
 
+typedef struct {
+	char method[16];
+	char time[128];
+	uchar payhash[SHA2_256dlen];
+	char authhdr[512];
+	char mime[32];
+} Hreq;
+
 static void
 datetime(char *date, int ndate, char *time, int ntime)
 {
@@ -23,7 +31,6 @@
 }
 
 #define hmac(data, dlen, key, klen, digest) hmac_sha2_256(data, dlen, key, klen, digest, nil)
-#define hash(data, dlen, digest) sha2_256(data, dlen, digest, nil)
 
 static void
 mkkey(char *key, char *date, char *region, char *service, uchar out[SHA2_256dlen])
@@ -38,69 +45,52 @@
 }
 
 static void
-prepupload(S3 *s3, int cfd, char *path, uchar hash[SHA2_256dlen], char *mime)
+mkhreq(Hreq *hreq, S3 *s3, char *method, char *path)
 {
 	char date[64];
-	char time[128];
 	uchar key[SHA2_256dlen], sig[SHA2_256dlen];
 	char buf[512], req[512];
+	char *sgndhdr;
 
-	datetime(date, sizeof date, time, sizeof time);
+	datetime(date, sizeof date, hreq->time, sizeof hreq->time);
+	if(strcmp(method, "PUT") == 0){
+		snprint(buf, sizeof buf, "content-type:%s\nhost:%s\nx-amz-content-sha256:%.*lH\nx-amz-date:%s\n",
+			hreq->mime, s3->host, SHA2_256dlen, hreq->payhash, hreq->time);
+		sgndhdr = "content-type;host;x-amz-content-sha256;x-amz-date";
+	} else if(strcmp(method, "GET") == 0){
+		hreq->mime[0] = 0;
+		sha2_256(nil, 0, hreq->payhash, nil);
+		snprint(buf, sizeof buf, "host:%s\nx-amz-date:%s\n", s3->host, hreq->time);
+		sgndhdr = "host;x-amz-date";
+	} else
+		sysfatal("invalid method");
 
-	snprint(buf, sizeof buf, "content-type:%s\nhost:%s\nx-amz-content-sha256:%.*lH\nx-amz-date:%s\n",
-		mime, s3->host, SHA2_256dlen, hash, time);
-	snprint(req, sizeof req, "PUT\n/%s/%s\n%s\n%s\n%s\n%.*lH",
-		s3->bucket, path, "", buf, "content-type;host;x-amz-content-sha256;x-amz-date", SHA2_256dlen, hash);
-	hash((uchar*)req, strlen(req), key);
+	snprint(req, sizeof req, "%s\n/%s/%s\n%s\n%s\n%s\n%.*lH",
+		method, s3->bucket, path, "", buf, sgndhdr, SHA2_256dlen, hreq->payhash);
+	sha2_256((uchar*)req, strlen(req), key, nil);
 	snprint(buf, sizeof buf, "%s\n%s\n%s/%s/%s/aws4_request\n%.*lH",
-		"AWS4-HMAC-SHA256", time, date, s3->region, "s3", SHA2_256dlen, key);
+		"AWS4-HMAC-SHA256", hreq->time, date, s3->region, "s3", SHA2_256dlen, key);
 	mkkey(s3->secret, date, s3->region, "s3", key);
 	hmac((uchar*)buf, strlen(buf), key, SHA2_256dlen, sig);
-	snprint(buf, sizeof buf, "%s Credential=%s/%s/%s/%s/aws4_request, SignedHeaders=%s, Signature=%.*lH",
-		"AWS4-HMAC-SHA256", s3->access, date, s3->region, "s3", "content-type;host;x-amz-content-sha256;x-amz-date",
-		SHA2_256dlen, sig);
 
-	if(fprint(cfd, "url %s/%s/%s", s3->endpoint, s3->bucket, path) < 0)
-		sysfatal("url: %r");
-	if(fprint(cfd, "request PUT") < 0)
-		sysfatal("request: %r");
-	if(fprint(cfd, "headers Authorization:%s", buf) < 0)
-		sysfatal("headers2: %r");
-	if(fprint(cfd, "headers x-amz-date:%s\nx-amz-content-sha256:%.*lH", time, SHA2_256dlen, hash) < 0)
-		sysfatal("headers: %r");
-	if(fprint(cfd, "contenttype %s", mime) < 0)
-		sysfatal("contenttype: %r");
+	snprint(hreq->authhdr, sizeof hreq->authhdr, "%s Credential=%s/%s/%s/%s/aws4_request, SignedHeaders=%s, Signature=%.*lH",
+		"AWS4-HMAC-SHA256", s3->access, date, s3->region, "s3", sgndhdr, SHA2_256dlen, sig);
+	snprint(hreq->method, sizeof hreq->method, "%s", method);
 }
 
 static void
-prepdownload(S3 *s3, int cfd, char *path)
+prep(S3 *s3, int cfd, char *path, Hreq *hreq)
 {
-	char date[64];
-	char time[128];
-	uchar hash[SHA2_256dlen], key[SHA2_256dlen], sig[SHA2_256dlen];
-	char buf[512], req[512];
-
-	datetime(date, sizeof date, time, sizeof time);
-	hash(nil, 0, hash);
-
-	snprint(buf, sizeof buf, "host:%s\nx-amz-date:%s\n", s3->host, time);
-	snprint(req, sizeof req, "GET\n/%s/%s\n%s\n%s\n%s\n%.*lH",
-		s3->bucket, path, "", buf, "host;x-amz-date", SHA2_256dlen, hash);
-	hash((uchar*)req, strlen(req), key);
-	snprint(buf, sizeof buf, "%s\n%s\n%s/%s/%s/aws4_request\n%.*lH",
-		"AWS4-HMAC-SHA256", time, date, s3->region, "s3", SHA2_256dlen, key);
-	mkkey(s3->secret, date, s3->region, "s3", key);
-	hmac((uchar*)buf, strlen(buf), key, SHA2_256dlen, sig);
-	snprint(buf, sizeof buf, "%s Credential=%s/%s/%s/%s/aws4_request, SignedHeaders=%s, Signature=%.*lH",
-		"AWS4-HMAC-SHA256", s3->access, date, s3->region, "s3", "host;x-amz-date",
-		SHA2_256dlen, sig);
-
 	if(fprint(cfd, "url %s/%s/%s", s3->endpoint, s3->bucket, path) < 0)
 		sysfatal("url: %r");
-	if(fprint(cfd, "headers Authorization:%s", buf) < 0)
+	if(fprint(cfd, "request %s", hreq->method) < 0)
+		sysfatal("request: %r");
+	if(fprint(cfd, "headers Authorization:%s", hreq->authhdr) < 0)
 		sysfatal("headers2: %r");
-	if(fprint(cfd, "headers x-amz-date:%s\nx-amz-content-sha256:%.*lH", time, SHA2_256dlen, hash) < 0)
+	if(fprint(cfd, "headers x-amz-date:%s\nx-amz-content-sha256:%.*lH", hreq->time, SHA2_256dlen, hreq->payhash) < 0)
 		sysfatal("headers: %r");
+	if(hreq->mime[0] != 0 && fprint(cfd, "contenttype %s", hreq->mime) < 0)
+		sysfatal("contenttype: %r");
 }
 
 static void
@@ -110,11 +100,13 @@
 	long n;
 	char buf[64];
 	char data[8192];
+	Hreq hreq;
 
 	fd = create(localpath, OWRITE, 0644);
 	if(fd < 0)
 		sysfatal("download create: %r");
-	prepdownload(s3, cfd, path);
+	mkhreq(&hreq, s3, "GET", path);
+	prep(s3, cfd, path, &hreq);
 	snprint(buf, sizeof buf, "/mnt/web/%s/body", conn);
 	bfd = open(buf, OREAD);
 	if(bfd < 0)
@@ -129,8 +121,8 @@
 	}
 }
 
-static char*
-mimetype(char *path)
+static void
+mimetype(char *path, char *out, int nout)
 {
 	int p[2];
 	char buf[256];
@@ -152,7 +144,7 @@
 		if(n <= 0)
 			sysfatal("no mimetype found");
 		buf[n - 1] = 0;
-		return strdup(buf);
+		snprint(out, nout, "%s", buf);
 	}
 }
 
@@ -159,15 +151,14 @@
 static void
 upload(S3 *s3, char *path, char *localpath, int cfd, char *conn)
 {
-	char *mime;
 	DigestState *ds;
-	uchar hash[SHA2_256dlen];
 	uchar data[8192];
 	long n;
 	int fd, bfd;
 	char buf[256];
+	Hreq hreq;
 
-	mime = mimetype(localpath);
+	mimetype(localpath, hreq.mime, sizeof hreq.mime);
 	fd = open(localpath, OREAD);
 	if(fd < 0)
 		sysfatal("upload open: %r");
@@ -179,10 +170,11 @@
 			break;
 		ds = sha2_256(data, n, nil, ds);
 	}
-	sha2_256(nil, 0, hash, ds);
+	sha2_256(nil, 0, hreq.payhash, ds);
 	seek(fd, 0, 0);
 
-	prepupload(s3, cfd, path, hash, mime);
+	mkhreq(&hreq, s3, "PUT", path);
+	prep(s3, cfd, path, &hreq);
 	snprint(buf, sizeof buf, "/mnt/web/%s/postbody", conn);
 	bfd = open(buf, OWRITE);
 	if(bfd < 0)
--