Protocol Error and Last-modified header invalid -- time-stamp ignored.

Protocol Error and Last-modified header invalid -- time-stamp ignored.

(1.1) By sodface on 2021-09-05 12:08:27 edited from 1.0 [link] [source]

Dr. Hipp, the latest Alpine OS update has introduced a failure with downloading packages from my personal package repo served by althttpd.

Alpine's package manager, apk version 3.12.5 works ok but the OS upgrade updated the apk version to 3.12.7 and I now see this error about my repo at

server:~$ sudo apk update
ERROR: Protocol error

Further, GNU wget produces a different message, but does actually download the APKINDEX.tar.gz file:

Last-modified header invalid -- time-stamp ignored.

I'm still trying to figure out how best to isolate the issue. I'm not sure if the "Protocol error" that apk produces and the invalid header that wget reports are related or not.

I did notice that the headers reported by firefox for use a UTC timezone abbreviation in the Last-Modified header:

HTTP/1.1 200 OK
Connection: keep-alive
Date: Sat, 04 Sep 2021 20:29:06 UTC
Last-Modified: Sat, 04 Sep 2021 07:00:12 UTC
Cache-Control: max-age=120
ETag: "m6133197csde0"
Content-type: application/x-gzip
Content-length: 3552

One of the Alpine repos uses GMT:

HTTP/1.1 200 OK
Server: nginx
Content-Type: application/octet-stream
Last-Modified: Sat, 04 Sep 2021 17:18:32 GMT
ETag: "6133aa68-9bc1f"
Strict-Transport-Security: max-age=31536000
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Via: 1.1 varnish, 1.1 varnish
Content-Length: 637983
Accept-Ranges: bytes
Date: Sat, 04 Sep 2021 20:34:23 GMT
Age: 3
Connection: keep-alive
X-Served-By: cache-lga21972-LGA, cache-fty21344-FTY
X-Cache: HIT, HIT
X-Cache-Hits: 1, 1
X-Timer: S1630787664.677636,VS0,VE18

rfc7231 section

Seems to indicate that it should be GMT?

I'm still troubleshooting but I have to go out soon so I wanted to post my initial findings in case you see this in the interim.

(2.1) By sodface on 2021-09-05 12:06:10 edited from 2.0 in reply to 1.0 [source]

As a test, I made the following change which fixes both issues noted in my first post:

server:~$ diff althttpd.c althttpd.c.gmt 
--- althttpd.c
+++ althttpd.c.gmt
@@ -617,7 +617,7 @@
   struct tm *tm;
   static char zDate[100];
   tm = gmtime(&t);
-  strftime(zDate, sizeof(zDate), "%a, %d %b %Y %H:%M:%S %Z", tm);
+  strftime(zDate, sizeof(zDate), "%a, %d %b %Y %H:%M:%S GMT", tm);
   return zDate;

I think the issue I'm seeing might be specific to musl libc. There is some discussion on the musl mailing list:


about %Z but I don't understand it enough to know whether it's relevant. I'd already changed the timezone on my server to GMT as it was set to EST5EDT but althttpd was still returning headers as UTC.

(5) By sodface on 2021-09-10 01:21:25 in reply to 2.1 [link] [source]

I don't know anything about C, but this page on strftime says:

If a struct tm broken-down time structure is created or modified by gmtime() or gmtime_r(), it is unspecified whether the result of the %Z and %z conversion specifiers shall refer to UTC or the current local timezone, when strftime() is called with such a broken-down time structure.

And this page says this about gmtime:

The gmtime() function shall convert the time in seconds since the Epoch pointed to by timer into a broken-down time, expressed as Coordinated Universal Time (UTC).

So if the tm struct is always in UTC by virtue of being created by gmtime, and the result of %Z is unspecified, maybe replacing %Z with GMT isn't a terrible fix and should produce the correct/desired date string format on both glibc and musl based systems?

(6) By sodface on 2021-09-19 11:57:09 in reply to 5 [link] [source]

See also:

Rich Felker made this comment related to issues with %Z

I think if applications want to use zones other than the actual configured zone with strftime, they need to just do something like expand the %Z themselves with the string they want before calling strftime (note: this requires quoting any % in the name). I looked hard for a better solution that wouldn't crash valid applications, and couldn't find one at the time.

I think replacing %Z with GMT (as in the proposed patch above) is consistent with Rich's comment.

(3.1) By sodface on 2021-09-05 12:07:00 edited from 3.0 in reply to 1.0 [link] [source]

I just noticed this forum post:


where %z vs %Z in the date format was discussed and this commit that made the change:


As I mentioned above, I have a feeling that I'm seeing "UTC" vs "GMT" due to some difference between musl libc and glibc, or I'm missing a needed configuration somewhere at the OS level.

(4) By sodface on 2021-09-10 00:11:34 in reply to 1.1 [link] [source]

See this musl libc commit from 2017:


use the name UTC instead of GMT for UTC timezone notes by maintainer:

both C and POSIX use the term UTC to specify related functionality, despite POSIX defining it as something more like UT1 or historical (pre-UTC) GMT without leap seconds. neither specifies the associated string for %Z. old choice of "GMT" violated principle of least surprise for users and some applications/tests. use "UTC" instead.

(7) By sodface on 2021-09-19 12:00:03 in reply to 1.1 [link] [source]

I've cross posted all of this into an Alpine GitLab issue.

I will let it sit for another week or so to see if I get any additional feedback from the Alpine community and then submit a merge request for the Alpine package I maintain with the above patch.