// $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.
+ HTTP Acquire Method - This is the HTTP aquire method for APT.
It uses HTTP/1.1 and many of the fancy options there-in, such as
pipelining, range, if-range and so on.
#include <stdio.h>
#include <errno.h>
#include <string.h>
-#include <iostream>
#include <apti18n.h>
// Internet stuff
#include <netdb.h>
+#include "config.h"
#include "connect.h"
#include "rfc2553emu.h"
#include "http.h"
unsigned long PipelineDepth = 10;
unsigned long TimeOut = 120;
bool Debug = false;
+URI Proxy;
-
+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;
++I;
- if (I < InP && Buf[I%Size] == '\r')
- ++I;
if (Single == false)
{
- if (Buf[I%Size] != '\n')
- continue;
- ++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;
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
Req += string("Authorization: Basic ") +
Base64Encode(Uri.User + ":" + Uri.Password) + "\r\n";
- Req += "User-Agent: Debian APT-HTTP/1.3\r\n\r\n";
+ Req += "User-Agent: Ubuntu APT-HTTP/1.3 ("VERSION")\r\n\r\n";
if (Debug == true)
cerr << Req << endl;
{
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)
failure */
if (Srv->Result < 200 || Srv->Result >= 300)
{
+ char err[255];
+ snprintf(err,sizeof(err)-1,"HttpError%i",Srv->Result);
+ SetFailReason(err);
_error->Error("%u %s",Srv->Result,Srv->Code);
if (Srv->HaveContent == true)
return 4;
depth. */
bool HttpMethod::Fetch(FetchItem *)
{
- if (Server == 0)
+ if (Server == 0)
return true;
// Queue the requests
int Depth = -1;
- bool Tail = false;
for (FetchItem *I = Queue; I != 0 && Depth < (signed)PipelineDepth;
I = I->Next, Depth++)
{
if (Server->Comp(I->Uri) == false)
break;
if (QueueBack == I)
- Tail = true;
- if (Tail == true)
{
QueueBack = I->Next;
SendReq(I,Server->Out);
delete Server;
Server = new ServerState(Queue->Uri,this);
}
-
/* If the server has explicitly said this is the last connection
then we pre-emptively shut down the pipeline and tear down
the connection. This will speed up HTTP/1.0 servers a tad
URIDone(Res);
}
else
- Fail(true);
-
+ {
+ if (Server->ServerFd == -1)
+ {
+ FailCounter++;
+ _error->Discard();
+ Server->Close();
+
+ if (FailCounter >= 2)
+ {
+ Fail(_("Connection failed"),true);
+ FailCounter = 0;
+ }
+
+ QueueBack = Queue;
+ }
+ else
+ Fail(true);
+ }
break;
}
}
/*}}}*/
-int main()
-{
- setlocale(LC_ALL, "");
-
- HttpMethod Mth;
-
- return Mth.Loop();
-}