X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/5cb5d8dc4318227ca3ec8976f67e8cfd2302d1ff..90d642804ca96ba640d2c2fbd0620b69670ee827:/methods/http.cc diff --git a/methods/http.cc b/methods/http.cc index c52ddc458..9cb6d1b21 100644 --- a/methods/http.cc +++ b/methods/http.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: http.cc,v 1.9 1998/12/05 04:19:05 jgg Exp $ +// $Id: http.cc,v 1.24 1999/01/30 08:23:49 jgg Exp $ /* ###################################################################### HTTP Aquire Method - This is the HTTP aquire method for APT. @@ -51,6 +51,8 @@ string HttpMethod::FailFile; int HttpMethod::FailFd = -1; time_t HttpMethod::FailTime = 0; +unsigned long PipelineDepth = 10; +unsigned long TimeOut = 120; // CircleBuf::CircleBuf - Circular input buffer /*{{{*/ // --------------------------------------------------------------------- @@ -245,7 +247,7 @@ void CircleBuf::Stats() // --------------------------------------------------------------------- /* */ ServerState::ServerState(URI Srv,HttpMethod *Owner) : Owner(Owner), - In(64*1024), Out(1*1024), + In(64*1024), Out(4*1024), ServerName(Srv) { Reset(); @@ -309,7 +311,7 @@ bool ServerState::Open() // Lookup the host hostent *Addr = gethostbyname(Host.c_str()); - if (Addr == 0) + if (Addr == 0 || Addr->h_addr_list[0] == 0) return _error->Error("Could not resolve '%s'",Host.c_str()); LastHost = Host; LastHostA = *(in_addr *)(Addr->h_addr_list[0]); @@ -326,10 +328,30 @@ bool ServerState::Open() server.sin_family = AF_INET; server.sin_port = htons(Port); server.sin_addr = LastHostA; - if (connect(ServerFd,(sockaddr *)&server,sizeof(server)) < 0) + SetNonBlock(ServerFd,true); + if (connect(ServerFd,(sockaddr *)&server,sizeof(server)) < 0 && + errno != EINPROGRESS) return _error->Errno("socket","Could not create a socket"); - SetNonBlock(ServerFd,true); + /* This implements a timeout for connect by opening the connection + nonblocking */ + fd_set wfds; + FD_ZERO(&wfds); + FD_SET(ServerFd,&wfds); + struct timeval tv; + tv.tv_sec = TimeOut; + tv.tv_usec = 0; + int Res = 0; + if ((Res = select(ServerFd+1,0,&wfds,0,&tv)) < 0) + return _error->Errno("select","Select failed"); + if (Res == 0) + return _error->Error("Could not connect, connection timed out"); + unsigned int Err,Len=sizeof(Err); + if (getsockopt(ServerFd,SOL_SOCKET,SO_ERROR,&Err,&Len) != 0) + return _error->Errno("getsockopt","Failed"); + if (Err != 0) + return _error->Error("Could not connect."); + return true; } /*}}}*/ @@ -482,7 +504,7 @@ bool ServerState::HeaderLine(string Line) { if (Line.empty() == true) return true; - + // The http server might be trying to do something evil. if (Line.length() >= MAXLEN) return _error->Error("Got a single header line over %u chars",MAXLEN); @@ -572,9 +594,9 @@ bool ServerState::HeaderLine(string Line) void HttpMethod::SendReq(FetchItem *Itm,CircleBuf &Out) { URI Uri = Itm->Uri; - + // The HTTP server expects a hostname with a trailing :port - char Buf[300]; + char Buf[1000]; string ProperHost = Uri.Host; if (Uri.Port != 0) { @@ -582,6 +604,10 @@ void HttpMethod::SendReq(FetchItem *Itm,CircleBuf &Out) ProperHost += Buf; } + // Just in case. + if (Itm->Uri.length() >= sizeof(Buf)) + abort(); + /* Build the request. We include a keep-alive header only for non-proxy requests. This is to tweak old http/1.0 servers that do support keep-alive but not HTTP/1.1 automatic keep-alive. Doing this with a proxy server @@ -590,10 +616,29 @@ void HttpMethod::SendReq(FetchItem *Itm,CircleBuf &Out) and we expect the proxy to do this */ if (Proxy.empty() == true) sprintf(Buf,"GET %s HTTP/1.1\r\nHost: %s\r\nConnection: keep-alive\r\n", - Uri.Path.c_str(),ProperHost.c_str()); + QuoteString(Uri.Path,"~").c_str(),ProperHost.c_str()); else + { + /* Generate a cache control header if necessary. We place a max + cache age on index files, optionally set a no-cache directive + 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 + { + if (Itm->IndexFile == true) + sprintf(Buf+strlen(Buf),"Cache-Control: max-age=%u\r\n", + _config->FindI("Acquire::http::Max-Age",60*60*24)); + else + { + if (_config->FindB("Acquire::http::No-Store",false) == true) + strcat(Buf,"Cache-Control: no-store\r\n"); + } + } + } + string Req = Buf; // Check for a partial file @@ -614,12 +659,13 @@ void HttpMethod::SendReq(FetchItem *Itm,CircleBuf &Out) } } -/* if (ProxyAuth.empty() == false) - Req += string("Proxy-Authorization: Basic ") + Base64Encode(ProxyAuth) + "\r\n";*/ + if (Proxy.User.empty() == false || Proxy.Password.empty() == false) + Req += string("Proxy-Authorization: Basic ") + + Base64Encode(Proxy.User + ":" + Proxy.Password) + "\r\n"; Req += "User-Agent: Debian APT-HTTP/1.2\r\n\r\n"; // cerr << Req << endl; - + Out.Read(Req); } /*}}}*/ @@ -668,7 +714,7 @@ bool HttpMethod::Go(bool ToFile,ServerState *Srv) // Select struct timeval tv; - tv.tv_sec = 120; + tv.tv_sec = TimeOut; tv.tv_usec = 0; int Res = 0; if ((Res = select(MaxFd+1,&rfds,&wfds,&efds,&tv)) < 0) @@ -767,6 +813,7 @@ bool HttpMethod::ServerDie(ServerState *Srv) if (Srv->In.IsLimit() == false && Srv->State != ServerState::Header && Srv->Encoding != ServerState::Closes) { + Srv->Close(); if (errno == 0) return _error->Error("Error reading from server Remote end closed connection"); return _error->Errno("read","Error reading from server"); @@ -828,6 +875,7 @@ int HttpMethod::DealWithHeaders(FetchResult &Res,ServerState *Srv) return 5; FailFile = Queue->DestFile; + FailFile.c_str(); // Make sure we don't do a malloc in the signal handler FailFd = File->Fd(); FailTime = Srv->Date; @@ -888,21 +936,19 @@ bool HttpMethod::Fetch(FetchItem *) { if (Server == 0) return true; - + // Queue the requests int Depth = -1; bool Tail = false; - for (FetchItem *I = Queue; I != 0 && Depth < 5; I = I->Next, Depth++) + for (FetchItem *I = Queue; I != 0 && Depth < (signed)PipelineDepth; I = I->Next, Depth++) { // Make sure we stick with the same server if (Server->Comp(I->Uri) == false) break; - if (QueueBack == I) Tail = true; if (Tail == true) { - Depth++; QueueBack = I->Next; SendReq(I,Server->Out); continue; @@ -912,6 +958,21 @@ bool HttpMethod::Fetch(FetchItem *) return true; }; /*}}}*/ +// HttpMethod::Configuration - Handle a configuration message /*{{{*/ +// --------------------------------------------------------------------- +/* We stash the desired pipeline depth */ +bool HttpMethod::Configuration(string Message) +{ + if (pkgAcqMethod::Configuration(Message) == false) + return false; + + TimeOut = _config->FindI("Acquire::http::Timeout",TimeOut); + PipelineDepth = _config->FindI("Acquire::http::Pipeline-Depth", + PipelineDepth); + + return true; +} + /*}}}*/ // HttpMethod::Loop - Main loop /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -927,7 +988,7 @@ int HttpMethod::Loop() { if (FailCounter >= 2) { - Fail("Massive Server Brain Damage"); + Fail("Massive Server Brain Damage",true); FailCounter = 0; } @@ -952,10 +1013,16 @@ int HttpMethod::Loop() Server = new ServerState(Queue->Uri,this); } + // Reset the pipeline + if (Server->ServerFd == -1) + QueueBack = Queue; + // Connnect to the host if (Server->Open() == false) { - Fail(); + Fail(true); + delete Server; + Server = 0; continue; } @@ -972,7 +1039,7 @@ int HttpMethod::Loop() case 2: { _error->Error("Bad header Data"); - Fail(); + Fail(true); continue; } @@ -981,7 +1048,7 @@ int HttpMethod::Loop() case 1: { FailCounter++; - _error->DumpErrors(); + _error->Discard(); Server->Close(); continue; }