From 0b45b6e5de1ba4224ced67a9952e009d0f4139a0 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Sat, 2 Jul 2016 11:28:42 +0200 Subject: use +0000 instead of UTC by default as timezone in output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All apt versions support numeric as well as 3-character timezones just fine and its actually hard to write code which doesn't "accidently" accepts it. So why change? Documenting the Date/Valid-Until fields in the Release file is easy to do in terms of referencing the datetime format used e.g. in the Debian changelogs (policy ยง4.4). This format specifies only the numeric timezones through, not the nowadays obsolete 3-character ones, so in the interest of least surprise we should use the same format even through it carries a small risk of regression in other clients (which encounter repositories created with apt-ftparchive). In case it is really regressing in practice, the hidden option -o APT::FTPArchive::Release::NumericTimezone=0 can be used to go back to good old UTC as timezone. The EDSP and EIPP protocols use this 'new' format, the text interface used to communicate with the acquire methods does not for compatibility reasons even if none of our methods would be effected and I doubt any other would (in these instances the timezone is 'GMT' as that is what HTTP/1.1 requires). Note that this is only true for apt talking to methods, (libapt-based) methods talking to apt will respond with the 'new' format. It is therefore strongly adviced to support both also in method input. --- apt-pkg/acquire-item.cc | 8 ++++---- apt-pkg/acquire-method.cc | 6 +++--- apt-pkg/contrib/strutl.cc | 10 +++++++++- apt-pkg/contrib/strutl.h | 12 +++++++++++- apt-pkg/edsp.cc | 4 ++-- cmdline/apt-cache.cc | 2 +- doc/external-dependency-solver-protocol.txt | 5 +++-- doc/external-installation-planner-protocol.txt | 5 +++-- ftparchive/writer.cc | 12 ++++++++---- methods/http.cc | 4 ++-- methods/https.cc | 2 +- test/integration/framework | 10 +++++----- test/interactive-helper/aptwebserver.cc | 6 +++--- 13 files changed, 55 insertions(+), 31 deletions(-) diff --git a/apt-pkg/acquire-item.cc b/apt-pkg/acquire-item.cc index 5ae9229d9..71cb18811 100644 --- a/apt-pkg/acquire-item.cc +++ b/apt-pkg/acquire-item.cc @@ -1167,7 +1167,7 @@ string pkgAcqMetaBase::Custom600Headers() const string const FinalFile = GetFinalFilename(); struct stat Buf; if (stat(FinalFile.c_str(),&Buf) == 0) - Header += "\nLast-Modified: " + TimeRFC1123(Buf.st_mtime); + Header += "\nLast-Modified: " + TimeRFC1123(Buf.st_mtime, false); return Header; } @@ -1916,7 +1916,7 @@ void pkgAcqBaseIndex::Failed(std::string const &Message,pkgAcquire::MethodConfig if (timespec == 0) ErrorText.append(""); else - ErrorText.append(TimeRFC1123(timespec)); + ErrorText.append(TimeRFC1123(timespec, true)); ErrorText.append("\n"); } /*}}}*/ @@ -1969,7 +1969,7 @@ string pkgAcqDiffIndex::Custom600Headers() const if (stat(Final.c_str(),&Buf) != 0) return "\nIndex-File: true"; - return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime); + return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime, false); } /*}}}*/ void pkgAcqDiffIndex::QueueOnIMSHit() const /*{{{*/ @@ -2881,7 +2881,7 @@ string pkgAcqIndex::Custom600Headers() const struct stat Buf; if (stat(Final.c_str(),&Buf) == 0) - msg += "\nLast-Modified: " + TimeRFC1123(Buf.st_mtime); + msg += "\nLast-Modified: " + TimeRFC1123(Buf.st_mtime, false); } if(Target.IsOptional) diff --git a/apt-pkg/acquire-method.cc b/apt-pkg/acquire-method.cc index 82f4b626d..a9fff661b 100644 --- a/apt-pkg/acquire-method.cc +++ b/apt-pkg/acquire-method.cc @@ -148,7 +148,7 @@ void pkgAcqMethod::URIStart(FetchResult &Res) std::cout << "Size: " << std::to_string(Res.Size) << "\n"; if (Res.LastModified != 0) - std::cout << "Last-Modified: " << TimeRFC1123(Res.LastModified) << "\n"; + std::cout << "Last-Modified: " << TimeRFC1123(Res.LastModified, true) << "\n"; if (Res.ResumePoint != 0) std::cout << "Resume-Point: " << std::to_string(Res.ResumePoint) << "\n"; @@ -187,7 +187,7 @@ void pkgAcqMethod::URIDone(FetchResult &Res, FetchResult *Alt) std::cout << "Size: " << std::to_string(Res.Size) << "\n"; if (Res.LastModified != 0) - std::cout << "Last-Modified: " << TimeRFC1123(Res.LastModified) << "\n"; + std::cout << "Last-Modified: " << TimeRFC1123(Res.LastModified, true) << "\n"; printHashStringList(&Res.Hashes); @@ -216,7 +216,7 @@ void pkgAcqMethod::URIDone(FetchResult &Res, FetchResult *Alt) std::cout << "Alt-Size: " << std::to_string(Alt->Size) << "\n"; if (Alt->LastModified != 0) - std::cout << "Alt-Last-Modified: " << TimeRFC1123(Alt->LastModified) << "\n"; + std::cout << "Alt-Last-Modified: " << TimeRFC1123(Alt->LastModified, true) << "\n"; printHashStringList(&Alt->Hashes); diff --git a/apt-pkg/contrib/strutl.cc b/apt-pkg/contrib/strutl.cc index d0bc938e4..7b6bb2854 100644 --- a/apt-pkg/contrib/strutl.cc +++ b/apt-pkg/contrib/strutl.cc @@ -749,6 +749,10 @@ int StringToBool(const string &Text,int Default) /* This converts a time_t into a string time representation that is year 2000 complient and timezone neutral */ string TimeRFC1123(time_t Date) +{ + return TimeRFC1123(Date, false); +} +string TimeRFC1123(time_t Date, bool const NumericTimezone) { struct tm Conv; if (gmtime_r(&Date, &Conv) == NULL) @@ -757,10 +761,14 @@ string TimeRFC1123(time_t Date) auto const posix = std::locale("C.UTF-8"); std::ostringstream datestr; datestr.imbue(posix); - APT::StringView const fmt("%a, %d %b %Y %H:%M:%S GMT"); + APT::StringView const fmt("%a, %d %b %Y %H:%M:%S"); std::use_facet>(posix).put( std::ostreambuf_iterator(datestr), datestr, ' ', &Conv, fmt.data(), fmt.data() + fmt.size()); + if (NumericTimezone) + datestr << " +0000"; + else + datestr << " GMT"; return datestr.str(); } /*}}}*/ diff --git a/apt-pkg/contrib/strutl.h b/apt-pkg/contrib/strutl.h index a32aaf06d..f3591d65f 100644 --- a/apt-pkg/contrib/strutl.h +++ b/apt-pkg/contrib/strutl.h @@ -66,7 +66,17 @@ std::string TimeToStr(unsigned long Sec); std::string Base64Encode(const std::string &Str); std::string OutputInDepth(const unsigned long Depth, const char* Separator=" "); std::string URItoFileName(const std::string &URI); -std::string TimeRFC1123(time_t Date); +APT_DEPRECATED_MSG("Specify if GMT is required or a numeric timezone can be used") std::string TimeRFC1123(time_t Date); +/** returns a datetime string as needed by HTTP/1.1 and Debian files. + * + * Note: The date will always be represented in a UTC timezone + * + * @param Date to be represented as a string + * @param NumericTimezone is preferred in general, but HTTP/1.1 requires the use + * of GMT as timezone instead. \b true means that the timezone should be denoted + * as "+0000" while \b false uses "GMT". + */ +std::string TimeRFC1123(time_t Date, bool const NumericTimezone); /** parses time as needed by HTTP/1.1 and Debian files. * * HTTP/1.1 prefers dates in RFC1123 format (but the other two obsolete date formats diff --git a/apt-pkg/edsp.cc b/apt-pkg/edsp.cc index 55bc0fcbd..27b269fd2 100644 --- a/apt-pkg/edsp.cc +++ b/apt-pkg/edsp.cc @@ -911,14 +911,14 @@ bool EDSP::WriteSolutionStanza(FileFd &output, char const * const Type, pkgCache /*}}}*/ // EDSP::WriteProgess - pulse to the given file descriptor /*{{{*/ bool EDSP::WriteProgress(unsigned short const percent, const char* const message, FILE* output) { - fprintf(output, "Progress: %s\n", TimeRFC1123(time(NULL)).c_str()); + fprintf(output, "Progress: %s\n", TimeRFC1123(time(NULL), true).c_str()); fprintf(output, "Percentage: %d\n", percent); fprintf(output, "Message: %s\n\n", message); fflush(output); return true; } bool EDSP::WriteProgress(unsigned short const percent, const char* const message, FileFd &output) { - return WriteOkay(output, "Progress: ", TimeRFC1123(time(NULL)), "\n", + return WriteOkay(output, "Progress: ", TimeRFC1123(time(NULL), true), "\n", "Percentage: ", percent, "\n", "Message: ", message, "\n\n") && output.Flush(); } diff --git a/cmdline/apt-cache.cc b/cmdline/apt-cache.cc index 6153f0e49..0d7425c48 100644 --- a/cmdline/apt-cache.cc +++ b/cmdline/apt-cache.cc @@ -380,7 +380,7 @@ static bool Dump(CommandLine &) std::cout << " Size: " << F->Size << std::endl; std::cout << " ID: " << F->ID << std::endl; std::cout << " Flags: " << F->Flags << std::endl; - std::cout << " Time: " << TimeRFC1123(F->mtime) << std::endl; + std::cout << " Time: " << TimeRFC1123(F->mtime, true) << std::endl; std::cout << " Archive: " << DeNull(F.Archive()) << std::endl; std::cout << " Component: " << DeNull(F.Component()) << std::endl; std::cout << " Version: " << DeNull(F.Version()) << std::endl; diff --git a/doc/external-dependency-solver-protocol.txt b/doc/external-dependency-solver-protocol.txt index 452212602..566890665 100644 --- a/doc/external-dependency-solver-protocol.txt +++ b/doc/external-dependency-solver-protocol.txt @@ -352,8 +352,9 @@ information to APT using **progress stanzas**. A progress stanza starts with the Progress field and might contain the following fields: - **Progress:** (mandatory). The value of this field is a date and time - timestamp, in RFC 2822 format. The timestamp provides a time - annotation for the progress report. + timestamp from the UTC timezone, in RFC 2822 format (see 'date -uR' as + an example). The timestamp provides a time annotation for the + progress report. - **Percentage:** (optional). An integer from 0 to 100, representing the completion of the dependency solving process, as declared by the diff --git a/doc/external-installation-planner-protocol.txt b/doc/external-installation-planner-protocol.txt index 319d139c6..44fa8ff53 100644 --- a/doc/external-installation-planner-protocol.txt +++ b/doc/external-installation-planner-protocol.txt @@ -280,8 +280,9 @@ information to APT using **progress stanzas**. A progress stanza starts with the Progress field and might contain the following fields: - **Progress:** (mandatory). The value of this field is a date and time - timestamp, in RFC 2822 format. The timestamp provides a time - annotation for the progress report. + timestamp from the UTC timezone, in RFC 2822 format (see 'date -uR' as + an example). The timestamp provides a time annotation for the + progress report. - **Percentage:** (optional). An integer from 0 to 100, representing the completion of the installation planning process, as declared by the diff --git a/ftparchive/writer.cc b/ftparchive/writer.cc index dbeaa16a6..c34a04d1a 100644 --- a/ftparchive/writer.cc +++ b/ftparchive/writer.cc @@ -969,11 +969,15 @@ bool ContentsWriter::ReadFromPkgs(string const &PkgFile,string const &PkgCompres /* */ static std::string formatUTCDateTime(time_t const now) { + bool const NumericTimezone = _config->FindB("APT::FTPArchive::Release::NumericTimezone", true); // TimeRFC1123 uses GMT to satisfy HTTP/1.1 - std::string datetime = TimeRFC1123(now); - auto const lastspace = datetime.rfind(' '); - if (likely(lastspace != std::string::npos)) - datetime.replace(lastspace + 1, 3, "UTC"); + std::string datetime = TimeRFC1123(now, NumericTimezone); + if (NumericTimezone == false) + { + auto const lastspace = datetime.rfind(' '); + if (likely(lastspace != std::string::npos)) + datetime.replace(lastspace + 1, 3, "UTC"); + } return datetime; } ReleaseWriter::ReleaseWriter(FileFd * const GivenOutput, string const &/*DB*/) : FTWScanner(GivenOutput) diff --git a/methods/http.cc b/methods/http.cc index fc54ece3a..a283162a2 100644 --- a/methods/http.cc +++ b/methods/http.cc @@ -737,9 +737,9 @@ void HttpMethod::SendReq(FetchItem *Itm) struct stat SBuf; if (stat(Itm->DestFile.c_str(),&SBuf) >= 0 && SBuf.st_size > 0) Req << "Range: bytes=" << SBuf.st_size << "-\r\n" - << "If-Range: " << TimeRFC1123(SBuf.st_mtime) << "\r\n"; + << "If-Range: " << TimeRFC1123(SBuf.st_mtime, false) << "\r\n"; else if (Itm->LastModified != 0) - Req << "If-Modified-Since: " << TimeRFC1123(Itm->LastModified).c_str() << "\r\n"; + Req << "If-Modified-Since: " << TimeRFC1123(Itm->LastModified, false).c_str() << "\r\n"; if (Server->Proxy.User.empty() == false || Server->Proxy.Password.empty() == false) Req << "Proxy-Authorization: Basic " diff --git a/methods/https.cc b/methods/https.cc index 35992ee96..92f786d17 100644 --- a/methods/https.cc +++ b/methods/https.cc @@ -388,7 +388,7 @@ bool HttpsMethod::Fetch(FetchItem *Itm) std::string Buf; strprintf(Buf, "Range: bytes=%lli-", (long long) SBuf.st_size); headers = curl_slist_append(headers, Buf.c_str()); - strprintf(Buf, "If-Range: %s", TimeRFC1123(SBuf.st_mtime).c_str()); + strprintf(Buf, "If-Range: %s", TimeRFC1123(SBuf.st_mtime, false).c_str()); headers = curl_slist_append(headers, Buf.c_str()); } else if(Itm->LastModified > 0) diff --git a/test/integration/framework b/test/integration/framework index 8ca878148..4aa89cf20 100644 --- a/test/integration/framework +++ b/test/integration/framework @@ -219,10 +219,10 @@ gdb() { runapt command gdb --quiet -ex run "$CMD" --args "$CMD" "$@" } lastmodification() { - date -u -d "@$(stat -c '%Y' "${TMPWORKINGDIRECTORY}/$1")" '+%a, %d %b %Y %H:%M:%S GMT' + date -u -d "@$(stat -c '%Y' "${TMPWORKINGDIRECTORY}/$1")" -R } releasefiledate() { - grep "^${2:-Date}:" "$1" | cut -d' ' -f 2- | sed -e 's#UTC#GMT#' + grep "^${2:-Date}:" "$1" | cut -d' ' -f 2- } exitwithstatus() { @@ -1016,13 +1016,13 @@ NotAutomatic: yes' "$dir/Release" fi if [ -n "$DATE" -a "$DATE" != "now" ]; then for release in $(find ./aptarchive -name 'Release'); do - sed -i "s/^Date: .*$/Date: $(date -u -d "$DATE" '+%a, %d %b %Y %H:%M:%S %Z')/" "$release" + sed -i "s/^Date: .*$/Date: $(date -u -d "$DATE" -R)/" "$release" touch -d "$DATE" "$release" done fi if [ -n "$VALIDUNTIL" ]; then sed -i "/^Date: / a\ -Valid-Until: $(date -u -d "$VALIDUNTIL" '+%a, %d %b %Y %H:%M:%S %Z')" $(find ./aptarchive -name 'Release') +Valid-Until: $(date -u -d "$VALIDUNTIL" -R)" $(find ./aptarchive -name 'Release') fi msgdone "info" } @@ -1154,7 +1154,7 @@ signreleasefiles() { } redatereleasefiles() { - local DATE="$(date -u -d "$1" '+%a, %d %b %Y %H:%M:%S %Z')" + local DATE="$(date -u -d "$1" -R)" for release in $(find aptarchive/ -name 'Release'); do sed -i "s/^Date: .*$/Date: ${DATE}/" "$release" touch -d "$DATE" "$release" diff --git a/test/interactive-helper/aptwebserver.cc b/test/interactive-helper/aptwebserver.cc index 3e91406ab..817760ec3 100644 --- a/test/interactive-helper/aptwebserver.cc +++ b/test/interactive-helper/aptwebserver.cc @@ -99,7 +99,7 @@ static void addFileHeaders(std::list &headers, FileFd &data)/*{{{*/ if (_config->FindB("aptwebserver::support::last-modified", true) == true) { std::string lastmodified("Last-Modified: "); - lastmodified.append(TimeRFC1123(data.ModificationTime())); + lastmodified.append(TimeRFC1123(data.ModificationTime(), false)); headers.push_back(lastmodified); } } @@ -128,7 +128,7 @@ static bool sendHead(int const client, int const httpcode, std::listd_name << "\">" << namelist[i]->d_name << "" << "" << SizeToStr(fs.st_size) << "B"; } - listing << "" << TimeRFC1123(fs.st_mtime) << "" << std::endl; + listing << "" << TimeRFC1123(fs.st_mtime, true) << "" << std::endl; } listing << "" << std::endl; -- cgit v1.2.3