// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: http.cc,v 1.56 2003/02/12 15:33:36 doogie Exp $
+// $Id: http.cc,v 1.59 2004/05/08 19:42:35 mdz Exp $
/* ######################################################################
HTTP Aquire Method - This is the HTTP aquire method for APT.
##################################################################### */
/*}}}*/
// Include Files /*{{{*/
-#include <apti18n.h>
#include <apt-pkg/fileutl.h>
#include <apt-pkg/acquire-method.h>
#include <apt-pkg/error.h>
#include <errno.h>
#include <string.h>
#include <iostream>
+#include <apti18n.h>
// Internet stuff
#include <netdb.h>
unsigned long TimeOut = 120;
bool Debug = false;
+
+unsigned long CircleBuf::BwReadLimit=0;
+unsigned long CircleBuf::BwTickReadData=0;
+struct timeval CircleBuf::BwReadTick={0,0};
+const unsigned int CircleBuf::BW_HZ=10;
+
// CircleBuf::CircleBuf - Circular input buffer /*{{{*/
// ---------------------------------------------------------------------
/* */
{
Buf = new unsigned char[Size];
Reset();
+
+ CircleBuf::BwReadLimit = _config->FindI("Acquire::http::Dl-Limit",0)*1024;
}
/*}}}*/
// CircleBuf::Reset - Reset to the default state /*{{{*/
is non-blocking.. */
bool CircleBuf::Read(int Fd)
{
+ unsigned long BwReadMax;
+
while (1)
{
// Woops, buffer is full
if (InP - OutP == Size)
return true;
-
+
+ // what's left to read in this tick
+ BwReadMax = CircleBuf::BwReadLimit/BW_HZ;
+
+ if(CircleBuf::BwReadLimit) {
+ struct timeval now;
+ gettimeofday(&now,0);
+
+ unsigned long d = (now.tv_sec-CircleBuf::BwReadTick.tv_sec)*1000000 +
+ now.tv_usec-CircleBuf::BwReadTick.tv_usec;
+ if(d > 1000000/BW_HZ) {
+ CircleBuf::BwReadTick = now;
+ CircleBuf::BwTickReadData = 0;
+ }
+
+ if(CircleBuf::BwTickReadData >= BwReadMax) {
+ usleep(1000000/BW_HZ);
+ return true;
+ }
+ }
+
// Write the buffer segment
int Res;
- Res = read(Fd,Buf + (InP%Size),LeftRead());
+ if(CircleBuf::BwReadLimit) {
+ Res = read(Fd,Buf + (InP%Size),
+ BwReadMax > LeftRead() ? LeftRead() : BwReadMax);
+ } else
+ Res = read(Fd,Buf + (InP%Size),LeftRead());
+ if(Res > 0 && BwReadLimit > 0)
+ CircleBuf::BwTickReadData += Res;
+
if (Res == 0)
return false;
if (Res < 0)
{
if (Buf[I%Size] != '\n')
continue;
- for (I++; I < InP && Buf[I%Size] == '\r'; I++);
+ ++I;
if (Single == false)
{
- if (Buf[I%Size] != '\n')
- continue;
- for (I++; I < InP && Buf[I%Size] == '\r'; I++);
+ if (I < InP && Buf[I%Size] == '\r')
+ ++I;
+ if (I >= InP || Buf[I%Size] != '\n')
+ continue;
+ ++I;
}
- if (I > InP)
- I = InP;
-
Data = "";
while (OutP < I)
{
unsigned long Sz = LeftWrite();
if (Sz == 0)
return false;
- if (I - OutP < LeftWrite())
+ if (I - OutP < Sz)
Sz = I - OutP;
Data += string((char *)(Buf + (OutP%Size)),Sz);
OutP += Sz;
{
if (sscanf(Line.c_str(),"HTTP/%u.%u %u %[^\n]",&Major,&Minor,
&Result,Code) != 4)
- return _error->Error(_("The http server sent an invalid reply header"));
+ return _error->Error(_("The HTTP server sent an invalid reply header"));
}
else
{
Major = 0;
Minor = 9;
if (sscanf(Line.c_str(),"HTTP %u %[^\n]",&Result,Code) != 2)
- return _error->Error(_("The http server sent an invalid reply header"));
+ return _error->Error(_("The HTTP server sent an invalid reply header"));
}
/* Check the HTTP response header to get the default persistance
return true;
if (sscanf(Val.c_str(),"%lu",&Size) != 1)
- return _error->Error(_("The http server sent an invalid Content-Length header"));
+ return _error->Error(_("The HTTP server sent an invalid Content-Length header"));
return true;
}
HaveContent = true;
if (sscanf(Val.c_str(),"bytes %lu-%*u/%lu",&StartPos,&Size) != 2)
- return _error->Error(_("The http server sent an invalid Content-Range header"));
+ return _error->Error(_("The HTTP server sent an invalid Content-Range header"));
if ((unsigned)StartPos > Size)
- return _error->Error(_("This http server has broken range support"));
+ return _error->Error(_("This HTTP server has broken range support"));
return true;
}
will glitch HTTP/1.0 proxies because they do not filter it out and
pass it on, HTTP/1.1 says the connection should default to keep alive
and we expect the proxy to do this */
- if (Proxy.empty() == true)
+ if (Proxy.empty() == true || Proxy.Host.empty())
sprintf(Buf,"GET %s HTTP/1.1\r\nHost: %s\r\nConnection: keep-alive\r\n",
QuoteString(Uri.Path,"~").c_str(),ProperHost.c_str());
else
and a no-store directive for archives. */
sprintf(Buf,"GET %s HTTP/1.1\r\nHost: %s\r\n",
Itm->Uri.c_str(),ProperHost.c_str());
- if (_config->FindB("Acquire::http::No-Cache",false) == true)
- strcat(Buf,"Cache-Control: no-cache\r\nPragma: no-cache\r\n");
- else
+ // only generate a cache control header if we actually want to
+ // use a cache
+ if (_config->FindB("Acquire::http::No-Cache",false) == false)
{
if (Itm->IndexFile == true)
sprintf(Buf+strlen(Buf),"Cache-Control: max-age=%u\r\n",
- _config->FindI("Acquire::http::Max-Age",60*60*24));
+ _config->FindI("Acquire::http::Max-Age",0));
else
{
if (_config->FindB("Acquire::http::No-Store",false) == true)
}
}
}
+ // generate a no-cache header if needed
+ if (_config->FindB("Acquire::http::No-Cache",false) == true)
+ strcat(Buf,"Cache-Control: no-cache\r\nPragma: no-cache\r\n");
+
string Req = Buf;
{
if (File != 0)
{
- SetNonBlock(File->Fd(),false);
+ // on GNU/kFreeBSD, apt dies on /dev/null because non-blocking
+ // can't be set
+ if (File->Name() != "/dev/null")
+ SetNonBlock(File->Fd(),false);
if (Srv->In.WriteSpace() == false)
return true;
// Dump the buffer to the file
if (Srv->State == ServerState::Data)
{
- SetNonBlock(File->Fd(),false);
+ // on GNU/kFreeBSD, apt dies on /dev/null because non-blocking
+ // can't be set
+ if (File->Name() != "/dev/null")
+ SetNonBlock(File->Fd(),false);
while (Srv->In.WriteSpace() == true)
{
if (Srv->In.Write(File->Fd()) == false)
{
Srv->Close();
if (LErrno == 0)
- return _error->Error(_("Error reading from server Remote end closed connection"));
+ return _error->Error(_("Error reading from server. Remote end closed connection"));
errno = LErrno;
return _error->Errno("read",_("Error reading from server"));
}
// The header data is bad
case 2:
{
- _error->Error(_("Bad header Data"));
+ _error->Error(_("Bad header data"));
Fail(true);
RotateDNS();
continue;
int main()
{
+ setlocale(LC_ALL, "");
+
HttpMethod Mth;
return Mth.Loop();