step */
bool pkgAcquire::Item::Rename(string From,string To)
{
- if (rename(From.c_str(),To.c_str()) == 0)
+ if (From == To || rename(From.c_str(),To.c_str()) == 0)
return true;
std::string S;
return false;
}
/*}}}*/
-void pkgAcquire::Item::QueueURI(ItemDesc &Item) /*{{{*/
+// Acquire::Item::QueueURI and specialisations from child classes /*{{{*/
+/* The idea here is that an item isn't queued if it exists on disk and the
+ transition manager was a hit as this means that the files it contains
+ the checksums for can't be updated either (or they are and we are asking
+ for a hashsum mismatch to happen which helps nobody) */
+bool pkgAcquire::Item::QueueURI(ItemDesc &Item)
{
+ std::string const FinalFile = GetFinalFilename();
+ if (TransactionManager != NULL && TransactionManager->IMSHit == true &&
+ FileExists(FinalFile) == true)
+ {
+ PartialFile = DestFile = FinalFile;
+ Status = StatDone;
+ return false;
+ }
+
Owner->Enqueue(Item);
+ return true;
+}
+/* The transition manager InRelease itself (or its older sisters-in-law
+ Release & Release.gpg) is always queued as this allows us to rerun gpgv
+ on it to verify that we aren't stalled with old files */
+bool pkgAcqMetaBase::QueueURI(pkgAcquire::ItemDesc &Item)
+{
+ Owner->Enqueue(Item);
+ return true;
+}
+/* the Diff/Index needs to queue also the up-to-date complete index file
+ to ensure that the list cleaner isn't eating it */
+bool pkgAcqDiffIndex::QueueURI(pkgAcquire::ItemDesc &Item)
+{
+ if (pkgAcquire::Item::QueueURI(Item) == true)
+ return true;
+ QueueOnIMSHit();
+ return false;
}
/*}}}*/
void pkgAcquire::Item::Dequeue() /*{{{*/
return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
}
/*}}}*/
+void pkgAcqDiffIndex::QueueOnIMSHit() const /*{{{*/
+{
+ // list cleanup needs to know that this file as well as the already
+ // present index is ours, so we create an empty diff to save it for us
+ new pkgAcqIndexDiffs(Owner, TransactionManager, Target,
+ ExpectedHashes, MetaIndexParser);
+}
+ /*}}}*/
bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile) /*{{{*/
{
// failing here is fine: our caller will take care of trying to
// we have the same sha1 as the server so we are done here
if(Debug)
std::clog << "pkgAcqDiffIndex: Package file " << CurrentPackagesFile << " is up-to-date" << std::endl;
-
- // list cleanup needs to know that this file as well as the already
- // present index is ours, so we create an empty diff to save it for us
- new pkgAcqIndexDiffs(Owner, TransactionManager, Target,
- ExpectedHashes, MetaIndexParser);
+ QueueOnIMSHit();
return true;
}
if(Debug)
std::clog << "allDone: " << DestFile << "\n" << std::endl;
}
+}
+ /*}}}*/
+// AcqBaseIndex - Constructor /*{{{*/
+pkgAcqBaseIndex::pkgAcqBaseIndex(pkgAcquire *Owner,
+ pkgAcqMetaBase *TransactionManager,
+ struct IndexTarget const * const Target,
+ HashStringList const &ExpectedHashes,
+ indexRecords *MetaIndexParser)
+: Item(Owner, ExpectedHashes, TransactionManager), Target(Target),
+ MetaIndexParser(MetaIndexParser)
+{
}
/*}}}*/
// AcqBaseIndex::VerifyHashByMetaKey - verify hash for the given metakey /*{{{*/
TransactionManager->TransactionStageCopy(this, DestFile, GetFinalFilename());
return;
+}
+ /*}}}*/
+// AcqMetaBase - Constructor /*{{{*/
+pkgAcqMetaBase::pkgAcqMetaBase(pkgAcquire *Owner,
+ const std::vector<IndexTarget*>* IndexTargets,
+ indexRecords* MetaIndexParser,
+ std::string const &RealURI,
+ HashStringList const &ExpectedHashes,
+ pkgAcqMetaBase *TransactionManager)
+: Item(Owner, ExpectedHashes, TransactionManager),
+ MetaIndexParser(MetaIndexParser), IndexTargets(IndexTargets),
+ AuthPass(false), RealURI(RealURI), IMSHit(false)
+{
}
/*}}}*/
// AcqMetaBase::Add - Add a item to the current Transaction /*{{{*/
std::cerr << "Signature verification succeeded: "
<< DestFile << std::endl;
- // Download further indexes with verification
- //
- // it would be really nice if we could simply do
- // if (IMSHit == false) QueueIndexes(true)
- // and skip the download if the Release file has not changed
- // - but right now the list cleaner will needs to be tricked
- // to not delete all our packages/source indexes in this case
+ // Download further indexes with verification
QueueIndexes(true);
return true;
// make sure to verify against the right file on I-M-S hit
IMSHit = StringToBool(LookupTag(Message,"IMS-Hit"),false);
if(IMSHit)
+ {
+ // for simplicity, the transaction manager is always InRelease
+ // even if it doesn't exist.
+ if (TransactionManager != NULL)
+ TransactionManager->IMSHit = true;
DestFile = GetFinalFilename();
+ }
// set Item to complete as the remaining work is all local (verify etc)
Complete = true;
<< "Expected Hash:" << std::endl;
for (HashStringList::const_iterator hs = ExpectedIndexHashes.begin(); hs != ExpectedIndexHashes.end(); ++hs)
std::cerr << "\t- " << hs->toStr() << std::endl;
- std::cerr << "For: " << Record->MetaKeyFilename << std::endl;
+ std::cerr << "For: " << ((Record == NULL) ? "<NULL>" : Record->MetaKeyFilename) << std::endl;
}
if (verify == true && ExpectedIndexHashes.empty() == true)
pkgAcquire *Owner;
/** \brief Insert this item into its owner's queue.
+ *
+ * The method is designed to check if the request would end
+ * in an IMSHit and if it determines that it would, it isn't
+ * queueing the Item and instead sets it to completion instantly.
*
* \param Item Metadata about this item (its URI and
* description).
+ * \return true if the item was inserted, false if IMSHit was detected
*/
- void QueueURI(ItemDesc &Item);
+ virtual bool QueueURI(ItemDesc &Item);
/** \brief Remove this item from its owner's queue. */
void Dequeue();
*/
bool AuthPass;
- // required to deal gracefully with problems caused by incorrect ims hits
- bool IMSHit;
-
/** \brief The URI of the signature file. Unlike Desc.URI, this is
* never modified; it is used to determine the file that is being
* downloaded.
virtual std::string GetFinalFilename() const;
public:
+ // This refers more to the Transaction-Manager than the actual file
+ bool IMSHit;
+
virtual std::string DescURI() {return RealURI; };
+ virtual bool QueueURI(pkgAcquire::ItemDesc &Item);
// transaction code
void Add(Item *I);
indexRecords* MetaIndexParser,
std::string const &RealURI,
HashStringList const &ExpectedHashes=HashStringList(),
- pkgAcqMetaBase *TransactionManager=NULL)
- : Item(Owner, ExpectedHashes, TransactionManager),
- MetaIndexParser(MetaIndexParser), IndexTargets(IndexTargets),
- AuthPass(false), IMSHit(false), RealURI(RealURI) {};
+ pkgAcqMetaBase *TransactionManager=NULL);
};
/*}}}*/
/** \brief An acquire item that downloads the detached signature {{{
pkgAcqMetaBase *TransactionManager,
struct IndexTarget const * const Target,
HashStringList const &ExpectedHashes,
- indexRecords *MetaIndexParser)
- : Item(Owner, ExpectedHashes, TransactionManager), Target(Target),
- MetaIndexParser(MetaIndexParser) {};
+ indexRecords *MetaIndexParser);
};
/*}}}*/
/** \brief An item that is responsible for fetching an index file of {{{
/** \brief Get the full pathname of the final file for the current URI */
virtual std::string GetFinalFilename() const;
+ virtual bool QueueURI(pkgAcquire::ItemDesc &Item);
public:
// Specialized action members
virtual void Failed(std::string Message,pkgAcquire::MethodConfig *Cnf);
* false otherwise.
*/
bool ParseDiffIndex(std::string IndexDiffFile);
-
/** \brief Create a new pkgAcqDiffIndex.
*
struct IndexTarget const * const Target,
HashStringList const &ExpectedHashes,
indexRecords *MetaIndexParser);
+ private:
+ APT_HIDDEN void QueueOnIMSHit() const;
};
/*}}}*/
/** \brief An item that is responsible for fetching client-merge patches {{{
virtual std::string GetFinalFilename() const;
public:
-
// Specialized action members
virtual void Failed(std::string Message,pkgAcquire::MethodConfig *Cnf);
virtual void Done(std::string Message,unsigned long long Size,
struct MethodConfig;
struct ItemDesc;
friend class Item;
+ friend class pkgAcqMetaBase;
friend class Queue;
typedef std::vector<Item *>::iterator ItemIterator;
}
webserverconfig() {
+ local WEBSERVER="${3:-http://localhost:8080}"
local NOCHECK=false
if [ "$1" = '--no-check' ]; then
NOCHECK=true
local URI
if [ -n "$2" ]; then
msgtest "Set webserver config option '${1}' to" "$2"
- URI="http://localhost:8080/_config/set/${1}/${2}"
+ URI="${WEBSERVER}/_config/set/${1}/${2}"
else
msgtest 'Clear webserver config option' "${1}"
- URI="http://localhost:8080/_config/clear/${1}"
+ URI="${WEBSERVER}/_config/clear/${1}"
fi
if downloadfile "$URI" "$STATUS" > "$DOWNLOG"; then
msgpass
}
listcurrentlistsdirectory() {
- find rootdir/var/lib/apt/lists -maxdepth 1 -type d | while read line; do
- stat --format '%U:%G:%a:%n' "$line"
- done
- find rootdir/var/lib/apt/lists -maxdepth 1 \! -type d | while read line; do
- stat --format '%U:%G:%a:%s:%y:%n' "$line"
- done
+ {
+ find rootdir/var/lib/apt/lists -maxdepth 1 -type d | while read line; do
+ stat --format '%U:%G:%a:%n' "$line"
+ done
+ find rootdir/var/lib/apt/lists -maxdepth 1 \! -type d | while read line; do
+ stat --format '%U:%G:%a:%s:%y:%n' "$line"
+ done
+ } | sort
}
### convinience hacks ###
}
methodtest() {
+ # less complicated test setup this way
+ webserverconfig 'aptwebserver::support::modified-since' 'false' "$1"
+ webserverconfig 'aptwebserver::support::last-modified' 'false' "$1" # curl is clever and sees hits here also
+
msgmsg 'Test with' "$1" 'and clean start'
rm -rf rootdir/var/lib/apt/lists rootdir/var/lib/apt/lists.good
# normal update works fine
setupenvironment
configarchitecture 'amd64'
-buildsimplenativepackage 'unrelated' 'all' '0.5~squeeze1' 'unstable'
+insertpackage 'unstable' 'unrelated' 'all' '0.5~squeeze1'
+insertsource 'unstable' 'unrelated' 'all' '0.5~squeeze1'
setupaptarchive --no-update
changetowebserver
runtest() {
- configallowinsecurerepositories "${1:-false}"
+ if [ -n "$1" ]; then
+ configallowinsecurerepositories 'true'
+ else
+ configallowinsecurerepositories 'false'
+ fi
- rm -f rootdir/var/lib/apt/lists/localhost*
+ rm -rf rootdir/var/lib/apt/lists/
- if [ "$1" = 'true' ]; then
- testwarning aptget update
- else
- testsuccess aptget update
+ local TEST="test${1:-success}"
+ $TEST aptget update
+ if [ "$1" = 'failure' ]; then
+ # accept the outdated Release file so we can check Hit behaviour
+ "test${2:-success}" aptget update -o Acquire::Min-ValidTime=99999999999
fi
+ listcurrentlistsdirectory > listsdir.lst
+ testsuccess grep '_Packages\(\.gz\)\?$' listsdir.lst
+ testsuccess grep '_Sources\(\.gz\)\?$' listsdir.lst
+ testsuccess grep '_Translation-en\(\.gz\)\?$' listsdir.lst
# ensure no leftovers in partial
- testfailure ls "rootdir/var/lib/apt/lists/partial/*"
+ testfailure ls 'rootdir/var/lib/apt/lists/partial/*'
# check that I-M-S header is kept in redirections
- testequal "$EXPECT" aptget update -o Debug::pkgAcquire::Worker=0 -o Debug::Acquire::http=0
-
- # ensure that we still do a hash check on ims hit
- msgtest 'Test I-M-S' 'reverify'
- aptget update -o Debug::pkgAcquire::Auth=1 2>&1 | grep -A2 'ReceivedHash:' | grep -q -- '- SHA' && msgpass || msgfail
+ echo "$EXPECT" | sed -e 's#(invalid since [^)]\+)#(invalid since)#' > expected.output
+ $TEST aptget update -o Debug::pkgAcquire::Worker=0 -o Debug::Acquire::http=0
+ sed -i -e 's#(invalid since [^)]\+)#(invalid since)#' rootdir/tmp/${TEST}.output
+ testequal "$(cat expected.output)" cat rootdir/tmp/${TEST}.output
+ testfileequal 'listsdir.lst' "$(listcurrentlistsdirectory)"
+
+ # ensure that we still do a hash check for other files on ims hit of Release
+ if grep -q '^Hit .* \(InRelease\|Release.gpg\)$' expected.output ; then
+ $TEST aptget update -o Debug::Acquire::gpgv=1
+ cp rootdir/tmp/${TEST}.output goodsign.output
+ testfileequal 'listsdir.lst' "$(listcurrentlistsdirectory)"
+ testsuccess grep '^Got GOODSIG, key ID:GOODSIG' goodsign.output
+ fi
# ensure no leftovers in partial
- testfailure ls "rootdir/var/lib/apt/lists/partial/*"
+ testfailure ls 'rootdir/var/lib/apt/lists/partial/*'
}
-msgmsg "InRelease"
-EXPECT="Hit http://localhost:8080 unstable InRelease
-Hit http://localhost:8080 unstable/main Sources
-Hit http://localhost:8080 unstable/main amd64 Packages
-Hit http://localhost:8080 unstable/main Translation-en
-Reading package lists..."
-# with InRelease
+msgmsg 'InRelease'
+EXPECT='Hit http://localhost:8080 unstable InRelease
+Reading package lists...'
+echo 'Acquire::GzipIndexes "0";' > rootdir/etc/apt/apt.conf.d/02compressindex
runtest
-
-# with gzip
-echo "Acquire::GzipIndexes "1";" > rootdir/etc/apt/apt.conf.d/02compressindex
+echo 'Acquire::GzipIndexes "1";' > rootdir/etc/apt/apt.conf.d/02compressindex
runtest
-msgmsg "Release/Release.gpg"
-# with Release/Release.gpg
-EXPECT="Ign http://localhost:8080 unstable InRelease
+msgmsg 'Release/Release.gpg'
+EXPECT='Ign http://localhost:8080 unstable InRelease
404 Not Found
Hit http://localhost:8080 unstable Release
Hit http://localhost:8080 unstable Release.gpg
-Hit http://localhost:8080 unstable/main Sources
-Hit http://localhost:8080 unstable/main amd64 Packages
-Hit http://localhost:8080 unstable/main Translation-en
-Reading package lists..."
-
+Reading package lists...'
find aptarchive -name 'InRelease' -delete
-
-echo "Acquire::GzipIndexes "0";" > rootdir/etc/apt/apt.conf.d/02compressindex
+echo 'Acquire::GzipIndexes "0";' > rootdir/etc/apt/apt.conf.d/02compressindex
runtest
-
-echo "Acquire::GzipIndexes "1";" > rootdir/etc/apt/apt.conf.d/02compressindex
+echo 'Acquire::GzipIndexes "1";' > rootdir/etc/apt/apt.conf.d/02compressindex
runtest
-# no Release.gpg or InRelease
-msgmsg "Release only"
+msgmsg 'Release only'
EXPECT="Ign http://localhost:8080 unstable InRelease
404 Not Found
Hit http://localhost:8080 unstable Release
Ign http://localhost:8080 unstable Release.gpg
404 Not Found
-Hit http://localhost:8080 unstable/main Sources
-Hit http://localhost:8080 unstable/main amd64 Packages
-Hit http://localhost:8080 unstable/main Translation-en
Reading package lists...
W: The data from 'http://localhost:8080 unstable Release.gpg' is not signed. Packages from that repository can not be authenticated."
+find aptarchive -name 'Release.gpg' -delete
+echo 'Acquire::GzipIndexes "0";' > rootdir/etc/apt/apt.conf.d/02compressindex
+runtest 'warning'
+echo 'Acquire::GzipIndexes "1";' > rootdir/etc/apt/apt.conf.d/02compressindex
+runtest 'warning'
+
+
+# make the release file old
+find aptarchive -name '*Release' -exec sed -i \
+ -e "s#^Date: .*\$#Date: $(date -d '-2 weeks' '+%a, %d %b %Y %H:%M:%S %Z')#" \
+ -e '/^Valid-Until: / d' -e "/^Date: / a\
+Valid-Until: $(date -d '-1 weeks' '+%a, %d %b %Y %H:%M:%S %Z')" '{}' \;
+signreleasefiles
+
+msgmsg 'expired InRelease'
+EXPECT='Hit http://localhost:8080 unstable InRelease
+E: Release file for http://localhost:8080/dists/unstable/InRelease is expired (invalid since). Updates for this repository will not be applied.'
+echo 'Acquire::GzipIndexes "0";' > rootdir/etc/apt/apt.conf.d/02compressindex
+runtest 'failure'
+echo 'Acquire::GzipIndexes "1";' > rootdir/etc/apt/apt.conf.d/02compressindex
+runtest 'failure'
+
+msgmsg 'expired Release/Release.gpg'
+EXPECT='Ign http://localhost:8080 unstable InRelease
+ 404 Not Found
+Hit http://localhost:8080 unstable Release
+Hit http://localhost:8080 unstable Release.gpg
+E: Release file for http://localhost:8080/dists/unstable/Release.gpg is expired (invalid since). Updates for this repository will not be applied.'
+find aptarchive -name 'InRelease' -delete
+echo 'Acquire::GzipIndexes "0";' > rootdir/etc/apt/apt.conf.d/02compressindex
+runtest 'failure'
+echo 'Acquire::GzipIndexes "1";' > rootdir/etc/apt/apt.conf.d/02compressindex
+runtest 'failure'
+msgmsg 'expired Release only'
+EXPECT="Ign http://localhost:8080 unstable InRelease
+ 404 Not Found
+Hit http://localhost:8080 unstable Release
+Ign http://localhost:8080 unstable Release.gpg
+ 404 Not Found
+W: The data from 'http://localhost:8080 unstable Release.gpg' is not signed. Packages from that repository can not be authenticated.
+E: Release file for http://localhost:8080/dists/unstable/InRelease is expired (invalid since). Updates for this repository will not be applied."
find aptarchive -name 'Release.gpg' -delete
+echo 'Acquire::GzipIndexes "0";' > rootdir/etc/apt/apt.conf.d/02compressindex
+runtest 'failure' 'warning'
+echo 'Acquire::GzipIndexes "1";' > rootdir/etc/apt/apt.conf.d/02compressindex
+runtest 'failure' 'warning'
-echo "Acquire::GzipIndexes "0";" > rootdir/etc/apt/apt.conf.d/02compressindex
-runtest "true"
-echo "Acquire::GzipIndexes "1";" > rootdir/etc/apt/apt.conf.d/02compressindex
-runtest "true"
+msgmsg 'no Release at all'
+EXPECT="Ign http://localhost:8080 unstable InRelease
+ 404 Not Found
+Ign http://localhost:8080 unstable Release
+ 404 Not Found
+Hit http://localhost:8080 unstable/main Sources
+Hit http://localhost:8080 unstable/main amd64 Packages
+Hit http://localhost:8080 unstable/main Translation-en
+Reading package lists...
+W: The repository 'http://localhost:8080 unstable Release' does not have a Release file. This is deprecated, please contact the owner of the repository."
+find aptarchive -name '*Release*' -delete
+echo 'Acquire::GzipIndexes "0";
+Acquire::PDiffs "0";' > rootdir/etc/apt/apt.conf.d/02compressindex
+runtest 'warning'
+echo 'Acquire::GzipIndexes "1";
+Acquire::PDiffs "0";' > rootdir/etc/apt/apt.conf.d/02compressindex
+runtest 'warning'
--- /dev/null
+#!/bin/sh
+set -e
+
+TESTDIR=$(readlink -f $(dirname $0))
+. $TESTDIR/framework
+
+setupenvironment
+configarchitecture 'amd64' 'i386'
+
+insertpackage 'unstable' 'apt' 'all' '1.0'
+
+setupaptarchive --no-update
+
+methodtest() {
+ msgmsg 'Test with' "$1"
+ rm -rf rootdir/var/lib/apt/lists
+ # get our cache populated
+ testsuccess aptget update
+ listcurrentlistsdirectory > listsdir.lst
+
+ # hit again with a good cache
+ testsuccessequal "Hit $1 unstable InRelease
+Reading package lists..." aptget update
+ testfileequal 'listsdir.lst' "$(listcurrentlistsdirectory)"
+
+ # drop an architecture, which means the file should be gone now
+ configarchitecture 'i386'
+ sed '/_binary-amd64_Packages/ d' listsdir.lst > listsdir-without-amd64.lst
+ testsuccessequal "Hit $1 unstable InRelease
+Reading package lists..." aptget update
+ testfileequal 'listsdir-without-amd64.lst' "$(listcurrentlistsdirectory)"
+
+ # readd arch so its downloaded again
+ configarchitecture 'amd64' 'i386'
+ testsuccessequal "Hit $1 unstable InRelease
+Get:1 $1 unstable/main amd64 Packages [$(stat -c '%s' 'aptarchive/dists/unstable/main/binary-amd64/Packages.gz') B]
+Reading package lists..." aptget update
+ testfileequal 'listsdir.lst' "$(listcurrentlistsdirectory)"
+}
+
+changetowebserver
+methodtest 'http://localhost:8080'
+
+changetohttpswebserver
+methodtest 'https://localhost:4433'
}
testsetup 'file'
+
changetowebserver
+webserverconfig 'aptwebserver::support::modified-since' 'false' "$1"
+webserverconfig 'aptwebserver::support::last-modified' 'false' "$1" # curl is clever and sees hits here also
+
testsetup 'http'
+changetohttpswebserver
+
+testsetup 'https'
# check that I-M-S header is kept in redirections
testsuccessequal "Hit $1 unstable InRelease
-Hit $1 unstable/main Sources
-Hit $1 unstable/main amd64 Packages
-Hit $1 unstable/main Translation-en
Reading package lists..." aptget update
msgtest 'Test redirection works in' 'package download'
PKGFILE="${TESTDIR}/$(echo "$(basename $0)" | sed 's#^test-#Packages-#')"
wasmergeused() {
- msgtest 'Test for successful execution of' "$*"
- local OUTPUT=$(mktemp)
- addtrap "rm $OUTPUT;"
- if aptget update "$@" >${OUTPUT} 2>&1; then
- msgpass
- else
- echo
- cat $OUTPUT
- msgfail
- fi
+ testsuccess aptget update "$@"
msgtest 'No intermediate patch files' 'still exist'
local EDS="$(find rootdir/var/lib/apt/lists -name '*.ed' -o -name '*.ed.*')"
fi
msgtest 'Check if the right pdiff merger was used'
- if grep -q '^pkgAcqIndexMergeDiffs::Done(): rred' $OUTPUT; then
+ if grep -q '^pkgAcqIndexMergeDiffs::Done(): rred' rootdir/tmp/testsuccess.output; then
if echo "$*" | grep -q -- '-o Acquire::PDiffs::Merge=1'; then
msgpass
else
msgmsg "Testcase: index is already up-to-date: $*"
find rootdir/var/lib/apt/lists -name '*diff_Index' -type f -delete
testsuccess aptget update "$@"
+ testequal 'Hit http://localhost:8080 InRelease
+Reading package lists...' aptget update "$@" -o Debug::Acquire::Transaction=0 -o Debug::pkgAcquire::Diffs=0
testsuccessequal "$(cat ${PKGFILE}-new)
" aptcache show apt newstuff
contentlength << "Content-Length: " << data.FileSize();
headers.push_back(contentlength.str());
}
- std::string lastmodified("Last-Modified: ");
- lastmodified.append(TimeRFC1123(data.ModificationTime()));
- headers.push_back(lastmodified);
+ if (_config->FindB("aptwebserver::support::last-modified", true) == true)
+ {
+ std::string lastmodified("Last-Modified: ");
+ lastmodified.append(TimeRFC1123(data.ModificationTime()));
+ headers.push_back(lastmodified);
+ }
}
/*}}}*/
static void addDataHeaders(std::list<std::string> &headers, std::string &data)/*{{{*/