]> git.saurik.com Git - apt.git/commitdiff
[ABI break] merge support for http redirects, thanks to
authorMichael Vogt <michael.vogt@ubuntu.com>
Fri, 30 Jan 2009 19:55:20 +0000 (20:55 +0100)
committerMichael Vogt <michael.vogt@ubuntu.com>
Fri, 30 Jan 2009 19:55:20 +0000 (20:55 +0100)
Jeff Licquia and Anthony Towns

apt-pkg/acquire-method.cc
apt-pkg/acquire-method.h
apt-pkg/acquire-worker.cc
apt-pkg/makefile
debian/changelog
methods/http.cc
methods/http.h
methods/makefile

index bc29417f776e9d3b5db93b7d3fedf0229c2094e6..acf1156dcd75162187314d385d1b0524bb94ec9a 100644 (file)
@@ -447,6 +447,38 @@ void pkgAcqMethod::Status(const char *Format,...)
 }
                                                                        /*}}}*/
 
+// AcqMethod::Redirect - Send a redirect message                       /*{{{*/
+// ---------------------------------------------------------------------
+/* This method sends the redirect message and also manipulates the queue
+   to keep the pipeline synchronized. */
+void pkgAcqMethod::Redirect(const string &NewURI)
+{
+   string CurrentURI = "<UNKNOWN>";
+   if (Queue != 0)
+      CurrentURI = Queue->Uri;
+   char S[1024];
+   snprintf(S, sizeof(S)-50, "103 Redirect\nURI: %s\nNew-URI: %s\n\n",
+         CurrentURI.c_str(), NewURI.c_str());
+
+   if (write(STDOUT_FILENO,S,strlen(S)) != (ssize_t)strlen(S))
+      exit(100);
+
+   // Change the URI for the request.
+   Queue->Uri = NewURI;
+
+   /* To keep the pipeline synchronized, move the current request to
+      the end of the queue, past the end of the current pipeline. */
+   FetchItem *I;
+   for (I = Queue; I->Next != 0; I = I->Next) ;
+   I->Next = Queue;
+   Queue = Queue->Next;
+   I->Next->Next = 0;
+   if (QueueBack == 0)
+      QueueBack = I->Next;
+}
+                                                                        /*}}}*/
+
 // AcqMethod::FetchResult::FetchResult - Constructor                   /*{{{*/
 // ---------------------------------------------------------------------
 /* */
index e02eab01859e25cff57849660d532fdb26dc8f46..fab77e66469dd8139b19041c7a2fd341f44b7521 100644 (file)
@@ -84,6 +84,8 @@ class pkgAcqMethod
    void Log(const char *Format,...);
    void Status(const char *Format,...);
    
+   void Redirect(const string &NewURI);
    int Run(bool Single = false);
    inline void SetFailExtraMsg(string Msg) {FailExtra = Msg;};
    
index 1a754dae905cd3f8aa6e49076ed07c7098be3e65..78c68737c32f4d3aef1a37de6314e6b4cfd4d3e8 100644 (file)
@@ -220,6 +220,20 @@ bool pkgAcquire::Worker::RunMessages()
         Status = LookupTag(Message,"Message");
         break;
            
+         // 103 Redirect
+         case 103:
+         {
+            if (Itm == 0)
+            {
+               _error->Error("Method gave invalid 103 Redirect message");
+               break;
+            }
+            string NewURI = LookupTag(Message,"New-URI",URI.c_str());
+            Itm->URI = NewURI;
+            break;
+         }
+   
         // 200 URI Start
         case 200:
         {
index 1b78c94f687667eb0305fff122070187fce0c348..087f177409aea21afbea679ad0a552a52d1b8ece 100644 (file)
@@ -13,7 +13,7 @@ include ../buildlib/defaults.mak
 # methods/makefile - FIXME
 LIBRARY=apt-pkg
 LIBEXT=$(GLIBC_VER)$(LIBSTDCPP_VER)
-MAJOR=4.6
+MAJOR=4.7
 MINOR=0
 SLIBS=$(PTHREADLIB) $(INTLLIBS) -lutil
 APT_DOMAIN:=libapt-pkg$(MAJOR)
index fea9133ee66ee420f692707b80a8f3cc092cfaed..caef53bafc80f07b156896e47c4d5ffee175e291 100644 (file)
@@ -35,6 +35,8 @@ apt (0.7.21) UNRELEASED; urgency=low
     - make strings i18n able 
   * apt-pkg/contrib/strutl.cc:
     - fix TimeToStr i18n (LP: #289807)
+  * [ABI break] merge support for http redirects, thanks to
+    Jeff Licquia and Anthony Towns
 
   [ Dereck Wonnacott ]
   * apt-ftparchive might write corrupt Release files (LP: #46439)
index b3c791fa0a0e2fd555e81b4361dd7076b08e88bf..1bf798da44a9e02eac0d715186993380bd3146e8 100644 (file)
@@ -39,6 +39,7 @@
 #include <errno.h>
 #include <string.h>
 #include <iostream>
+#include <map>
 #include <apti18n.h>
 
 // Internet stuff
@@ -57,6 +58,7 @@ int HttpMethod::FailFd = -1;
 time_t HttpMethod::FailTime = 0;
 unsigned long PipelineDepth = 10;
 unsigned long TimeOut = 120;
+bool AllowRedirect = false;
 bool Debug = false;
 URI Proxy;
 
@@ -628,6 +630,12 @@ bool ServerState::HeaderLine(string Line)
       return true;
    }
 
+   if (stringcasecmp(Tag,"Location:") == 0)
+   {
+      Location = Val;
+      return true;
+   }
+
    return true;
 }
                                                                        /*}}}*/
@@ -900,7 +908,9 @@ bool HttpMethod::ServerDie(ServerState *Srv)
      1 - IMS hit
      3 - Unrecoverable error 
      4 - Error with error content page
-     5 - Unrecoverable non-server error (close the connection) */
+     5 - Unrecoverable non-server error (close the connection) 
+     6 - Try again with a new or changed URI
+ */
 int HttpMethod::DealWithHeaders(FetchResult &Res,ServerState *Srv)
 {
    // Not Modified
@@ -912,6 +922,27 @@ int HttpMethod::DealWithHeaders(FetchResult &Res,ServerState *Srv)
       return 1;
    }
    
+   /* Redirect
+    *
+    * Note that it is only OK for us to treat all redirection the same
+    * because we *always* use GET, not other HTTP methods.  There are
+    * three redirection codes for which it is not appropriate that we
+    * redirect.  Pass on those codes so the error handling kicks in.
+    */
+   if (AllowRedirect
+       && (Srv->Result > 300 && Srv->Result < 400)
+       && (Srv->Result != 300       // Multiple Choices
+           && Srv->Result != 304    // Not Modified
+           && Srv->Result != 306))  // (Not part of HTTP/1.1, reserved)
+   {
+      if (!Srv->Location.empty())
+      {
+         NextURI = Srv->Location;
+         return 6;
+      }
+      /* else pass through for error message */
+   }
    /* We have a reply we dont handle. This should indicate a perm server
       failure */
    if (Srv->Result < 200 || Srv->Result >= 300)
@@ -1026,6 +1057,7 @@ bool HttpMethod::Configuration(string Message)
    if (pkgAcqMethod::Configuration(Message) == false)
       return false;
    
+   AllowRedirect = _config->FindB("Acquire::http::AllowRedirect",true);
    TimeOut = _config->FindI("Acquire::http::Timeout",TimeOut);
    PipelineDepth = _config->FindI("Acquire::http::Pipeline-Depth",
                                  PipelineDepth);
@@ -1039,6 +1071,10 @@ bool HttpMethod::Configuration(string Message)
 /* */
 int HttpMethod::Loop()
 {
+   typedef vector<string> StringVector;
+   typedef vector<string>::iterator StringVectorIterator;
+   map<string, StringVector> Redirected;
+
    signal(SIGTERM,SigTerm);
    signal(SIGINT,SigTerm);
    
@@ -1225,6 +1261,46 @@ int HttpMethod::Loop()
            break;
         }
         
+         // Try again with a new URL
+         case 6:
+         {
+            // Clear rest of response if there is content
+            if (Server->HaveContent)
+            {
+               File = new FileFd("/dev/null",FileFd::WriteExists);
+               Server->RunData();
+               delete File;
+               File = 0;
+            }
+
+            /* Detect redirect loops.  No more redirects are allowed
+               after the same URI is seen twice in a queue item. */
+            StringVector &R = Redirected[Queue->DestFile];
+            bool StopRedirects = false;
+            if (R.size() == 0)
+               R.push_back(Queue->Uri);
+            else if (R[0] == "STOP" || R.size() > 10)
+               StopRedirects = true;
+            else
+            {
+               for (StringVectorIterator I = R.begin(); I != R.end(); I++)
+                  if (Queue->Uri == *I)
+                  {
+                     R[0] = "STOP";
+                     break;
+                  }
+               R.push_back(Queue->Uri);
+            }
+            if (StopRedirects == false)
+               Redirect(NextURI);
+            else
+               Fail();
+            break;
+         }
+
         default:
         Fail(_("Internal error"));
         break;
index 6753a990122d9ffb556f463157a3a7ba7975ae99..13f02ec77b0b0c3d7560128ed07bd7c938c2ff50 100644 (file)
@@ -99,6 +99,7 @@ struct ServerState
    enum {Chunked,Stream,Closes} Encoding;
    enum {Header, Data} State;
    bool Persistent;
+   string Location;
    
    // This is a Persistent attribute of the server itself.
    bool Pipeline;
@@ -143,6 +144,8 @@ class HttpMethod : public pkgAcqMethod
    static time_t FailTime;
    static void SigTerm(int);
    
+   string NextURI;
+   
    public:
    friend class ServerState;
 
index d9481dbcc30f1cda93597798d856ecdbce3321af..78bdbc96f033a724462f43d8ef96a95cff21a5bb 100644 (file)
@@ -7,7 +7,7 @@ include ../buildlib/defaults.mak
 BIN := $(BIN)/methods
 
 # FIXME..
-LIB_APT_PKG_MAJOR = 4.6
+LIB_APT_PKG_MAJOR = 4.7
 APT_DOMAIN := libapt-pkg$(LIB_APT_PKG_MAJOR)
 
 # The file method