Date: Sun, 16 Mar 2008 16:51:22 -0700 (PDT) From: Nick Barkas <snb@threerings.net> To: FreeBSD-gnats-submit@FreeBSD.org Subject: ports/121771: [patch] Add https support to sysutils/apt Message-ID: <20080316235122.3312917070@maguro.moduli.net> Resent-Message-ID: <200803170010.m2H0A3dM003332@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 121771 >Category: ports >Synopsis: [patch] Add https support to sysutils/apt >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-ports-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: maintainer-update >Submitter-Id: current-users >Arrival-Date: Mon Mar 17 00:10:02 UTC 2008 >Closed-Date: >Last-Modified: >Originator: Nick Barkas >Release: FreeBSD 7.0-RELEASE i386 >Organization: Three Rings Design, Inc. >Environment: System: FreeBSD maguro.moduli.net 7.0-RELEASE FreeBSD 7.0-RELEASE #0: Sun Feb 24 19:59:52 UTC 2008 root@logan.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC i386 >Description: The following patch contains a backport of https support from Apt 0.7. This is a useful feature that would be nice to have now, even though there is not yet a stable release of Apt 0.7. >How-To-Repeat: >Fix: --- patch-apt-https begins here --- diff -ruN apt/Makefile apt-https/Makefile --- apt/Makefile Sat Aug 4 04:41:19 2007 +++ apt-https/Makefile Thu Mar 13 18:25:02 2008 @@ -6,6 +6,7 @@ PORTNAME= apt PORTVERSION= 0.6.46.4.1 +PORTREVISION= 1 CATEGORIES= sysutils MASTER_SITES= ${MASTER_SITE_DEBIAN_POOL} DISTNAME= apt_0.6.46.4-0.1 @@ -18,6 +19,7 @@ RUN_DEPENDS= ${BUILD_DEPENDS} \ dpkg:${PORTSDIR}/archivers/dpkg \ gpg:${PORTSDIR}/security/gnupg1 +LIB_DEPENDS= curl.3:${PORTSDIR}/ftp/curl GNU_CONFIGURE= yes USE_GMAKE= yes @@ -40,6 +42,7 @@ PLIST_SUB+= APTDIR=${APTDIR:C,^/,,} post-patch: + ${CP} ${FILESDIR}/https.cc ${FILESDIR}/https.h ${WRKSRC}/methods/ ${REINPLACE_CMD} -e 's|@PREFIX@|${PREFIX}|g' -e \ 's|@APTDIR@|${APTDIR}|g' -e 's|@DPKGDIR@|${DPKGDIR}|g' -e \ 's|@LOCALBASE@|${LOCALBASE}|g' \ @@ -76,6 +79,7 @@ ${INSTALL_PROGRAM} ${WRKSRC}/bin/methods/gpgv ${PREFIX}/libexec/apt/methods ${INSTALL_PROGRAM} ${WRKSRC}/bin/methods/gzip ${PREFIX}/libexec/apt/methods ${INSTALL_PROGRAM} ${WRKSRC}/bin/methods/http ${PREFIX}/libexec/apt/methods + ${INSTALL_PROGRAM} ${WRKSRC}/bin/methods/https ${PREFIX}/libexec/apt/methods ${INSTALL_PROGRAM} ${WRKSRC}/bin/methods/rred ${PREFIX}/libexec/apt/methods ${INSTALL_PROGRAM} ${WRKSRC}/bin/methods/rsh ${PREFIX}/libexec/apt/methods (cd ${PREFIX}/libexec/apt/methods; ${LN} -sf rsh ssh; ${LN} -sf gzip bzip2) diff -ruN apt/files/https.cc apt-https/files/https.cc --- apt/files/https.cc Wed Dec 31 16:00:00 1969 +++ apt-https/files/https.cc Thu Mar 13 17:50:55 2008 @@ -0,0 +1,273 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: http.cc,v 1.59 2004/05/08 19:42:35 mdz Exp $ +/* ###################################################################### + + HTTPS Acquire Method - This is the HTTPS aquire method for APT. + + It uses libcurl + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#include <apt-pkg/fileutl.h> +#include <apt-pkg/acquire-method.h> +#include <apt-pkg/error.h> +#include <apt-pkg/hashes.h> + +#include <sys/stat.h> +#include <sys/time.h> +#include <utime.h> +#include <unistd.h> +#include <signal.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <iostream> +#include <apti18n.h> +#include <sstream> + +#include "config.h" +#include "https.h" + + /*}}}*/ +using namespace std; + +size_t +HttpsMethod::write_data(void *buffer, size_t size, size_t nmemb, void *userp) +{ + HttpsMethod *me = (HttpsMethod *)userp; + + if(me->File->Write(buffer, size*nmemb) != true) + return false; + + return size*nmemb; +} + +int +HttpsMethod::progress_callback(void *clientp, double dltotal, double dlnow, + double ultotal, double ulnow) +{ + HttpsMethod *me = (HttpsMethod *)clientp; + if(dltotal > 0 && me->Res.Size == 0) { + me->Res.Size = (unsigned long)dltotal; + me->URIStart(me->Res); + } + return 0; +} + +void HttpsMethod::SetupProxy() +{ + URI ServerName = Queue->Uri; + + // Determine the proxy setting + if (getenv("http_proxy") == 0) + { + string DefProxy = _config->Find("Acquire::http::Proxy"); + string SpecificProxy = _config->Find("Acquire::http::Proxy::" + ServerName.Host); + if (SpecificProxy.empty() == false) + { + if (SpecificProxy == "DIRECT") + Proxy = ""; + else + Proxy = SpecificProxy; + } + else + Proxy = DefProxy; + } + + // Parse no_proxy, a , separated list of domains + if (getenv("no_proxy") != 0) + { + if (CheckDomainList(ServerName.Host,getenv("no_proxy")) == true) + Proxy = ""; + } + + // Determine what host and port to use based on the proxy settings + string Host; + if (Proxy.empty() == true || Proxy.Host.empty() == true) + { + } + else + { + if (Proxy.Port != 0) + curl_easy_setopt(curl, CURLOPT_PROXYPORT, Proxy.Port); + curl_easy_setopt(curl, CURLOPT_PROXY, Proxy.Host.c_str()); + } +} + + +// HttpsMethod::Fetch - Fetch an item /*{{{*/ +// --------------------------------------------------------------------- +/* This adds an item to the pipeline. We keep the pipeline at a fixed + depth. */ +bool HttpsMethod::Fetch(FetchItem *Itm) +{ + stringstream ss; + struct stat SBuf; + struct curl_slist *headers=NULL; + char curl_errorstr[CURL_ERROR_SIZE]; + long curl_responsecode; + + // TODO: + // - http::Timeout + // - http::Pipeline-Depth + // - error checking/reporting + // - more debug options? (CURLOPT_DEBUGFUNCTION?) + + curl_easy_reset(curl); + SetupProxy(); + + // callbacks + curl_easy_setopt(curl, CURLOPT_URL, Itm->Uri.c_str()); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, this); + curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progress_callback); + curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, this); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, false); + curl_easy_setopt(curl, CURLOPT_FAILONERROR, true); + curl_easy_setopt(curl, CURLOPT_FILETIME, true); + + // FIXME: https: offer various options of verification + bool peer_verify = _config->FindB("Acquire::https::Verify-Peer", false); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, peer_verify); + + // sslcert file + string pem = _config->Find("Acquire::https::SslCert",""); + if(pem != "") + curl_easy_setopt(curl, CURLOPT_SSLCERT, pem.c_str()); + + // CA-Dir + string certdir = _config->Find("Acquire::https::CaPath",""); + if(certdir != "") + curl_easy_setopt(curl, CURLOPT_CAPATH, certdir.c_str()); + + // Server-verify + int verify = _config->FindI("Acquire::https::Verify-Host",2); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, verify); + + // cache-control + if(_config->FindB("Acquire::http::No-Cache",false) == false) + { + // cache enabled + if (_config->FindB("Acquire::http::No-Store",false) == true) + headers = curl_slist_append(headers,"Cache-Control: no-store"); + ioprintf(ss, "Cache-Control: max-age=%u", _config->FindI("Acquire::http::Max-Age",0)); + headers = curl_slist_append(headers, ss.str().c_str()); + } else { + // cache disabled by user + headers = curl_slist_append(headers, "Cache-Control: no-cache"); + headers = curl_slist_append(headers, "Pragma: no-cache"); + } + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + + // speed limit + int dlLimit = _config->FindI("Acquire::http::Dl-Limit",0)*1024; + if (dlLimit > 0) + curl_easy_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE, dlLimit); + + // set header + curl_easy_setopt(curl, CURLOPT_USERAGENT,"Debian APT-CURL/1.0 ("VERSION")"); + + // debug + if(_config->FindB("Debug::Acquire::https", false)) + curl_easy_setopt(curl, CURLOPT_VERBOSE, true); + + // error handling + curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_errorstr); + + // if we have the file send an if-range query with a range header + if (stat(Itm->DestFile.c_str(),&SBuf) >= 0 && SBuf.st_size > 0) + { + char Buf[1000]; + sprintf(Buf,"Range: bytes=%li-\r\nIf-Range: %s\r\n", + (long)SBuf.st_size - 1, + TimeRFC1123(SBuf.st_mtime).c_str()); + headers = curl_slist_append(headers, Buf); + } + else if(Itm->LastModified > 0) + { + curl_easy_setopt(curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_IFMODSINCE); + curl_easy_setopt(curl, CURLOPT_TIMEVALUE, Itm->LastModified); + } + + // go for it - if the file exists, append on it + File = new FileFd(Itm->DestFile, FileFd::WriteAny); + if (File->Size() > 0) + File->Seek(File->Size() - 1); + + // keep apt updated + Res.Filename = Itm->DestFile; + + // get it! + CURLcode success = curl_easy_perform(curl); + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &curl_responsecode); + + long curl_servdate; + curl_easy_getinfo(curl, CURLINFO_FILETIME, &curl_servdate); + + // cleanup + if(success != 0) + { + unlink(File->Name().c_str()); + _error->Error(curl_errorstr); + Fail(); + return true; + } + File->Close(); + + // Timestamp + struct utimbuf UBuf; + if (curl_servdate != -1) { + UBuf.actime = curl_servdate; + UBuf.modtime = curl_servdate; + utime(File->Name().c_str(),&UBuf); + } + + // check the downloaded result + struct stat Buf; + if (stat(File->Name().c_str(),&Buf) == 0) + { + Res.Filename = File->Name(); + Res.LastModified = Buf.st_mtime; + Res.IMSHit = false; + if (curl_responsecode == 304) + { + unlink(File->Name().c_str()); + Res.IMSHit = true; + Res.LastModified = Itm->LastModified; + Res.Size = 0; + URIDone(Res); + return true; + } + Res.Size = Buf.st_size; + } + + // take hashes + Hashes Hash; + FileFd Fd(Res.Filename, FileFd::ReadOnly); + Hash.AddFD(Fd.Fd(), Fd.Size()); + Res.TakeHashes(Hash); + + // keep apt updated + URIDone(Res); + + // cleanup + Res.Size = 0; + delete File; + curl_slist_free_all(headers); + + return true; +}; + +int main() +{ + setlocale(LC_ALL, ""); + + HttpsMethod Mth; + curl_global_init(CURL_GLOBAL_SSL) ; + + return Mth.Run(); +} + + diff -ruN apt/files/https.h apt-https/files/https.h --- apt/files/https.h Wed Dec 31 16:00:00 1969 +++ apt-https/files/https.h Thu Mar 13 17:50:57 2008 @@ -0,0 +1,48 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/// $Id: http.h,v 1.12 2002/04/18 05:09:38 jgg Exp $ +// $Id: http.h,v 1.12 2002/04/18 05:09:38 jgg Exp $ +/* ###################################################################### + + HTTP Acquire Method - This is the HTTP aquire method for APT. + + ##################################################################### */ + /*}}}*/ + +#ifndef APT_HTTP_H +#define APT_HTTP_H + +#define MAXLEN 360 + +#include <iostream> +#include <curl/curl.h> + +using std::cout; +using std::endl; + +class HttpsMethod; + + +class HttpsMethod : public pkgAcqMethod +{ + + virtual bool Fetch(FetchItem *); + static size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp); + static int progress_callback(void *clientp, double dltotal, double dlnow, + double ultotal, double ulnow); + void SetupProxy(); + CURL *curl; + FetchResult Res; + + public: + FileFd *File; + + HttpsMethod() : pkgAcqMethod("1.2",Pipeline | SendConfig) + { + File = 0; + curl = curl_easy_init(); + }; +}; + +URI Proxy; + +#endif diff -ruN apt/files/patch-methods_makefile apt-https/files/patch-methods_makefile --- apt/files/patch-methods_makefile Sun Feb 11 15:00:35 2007 +++ apt-https/files/patch-methods_makefile Thu Mar 13 18:01:09 2008 @@ -1,6 +1,6 @@ ---- methods/makefile.orig Sun Apr 2 04:04:07 2006 -+++ methods/makefile Mon Oct 23 16:30:57 2006 -@@ -12,63 +12,63 @@ +--- methods/makefile.orig Mon Dec 4 06:37:36 2006 ++++ methods/makefile Thu Mar 13 17:54:25 2008 +@@ -12,63 +12,70 @@ # The file method PROGRAM=file @@ -50,6 +50,13 @@ SOURCE = http.cc rfc2553emu.cc connect.cc include $(PROGRAM_H) ++# The https method ++PROGRAM=https ++SLIBS = -lapt-pkg $(SOCKETLIBS) $(INTLLIBS) -lcurl ++LIB_MAKES = apt-pkg/makefile ++SOURCE = https.cc ++include $(PROGRAM_H) ++ # The ftp method PROGRAM=ftp -SLIBS = -lapt-pkg $(SOCKETLIBS) diff -ruN apt/pkg-plist apt-https/pkg-plist --- apt/pkg-plist Sun Feb 11 15:00:35 2007 +++ apt-https/pkg-plist Thu Mar 13 18:09:51 2008 @@ -22,6 +22,7 @@ libexec/apt/methods/gpgv libexec/apt/methods/gzip libexec/apt/methods/http +libexec/apt/methods/https libexec/apt/methods/rred libexec/apt/methods/rsh libexec/apt/methods/ssh --- patch-apt-https ends here --- >Release-Note: >Audit-Trail: >Unformatted:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20080316235122.3312917070>