Procházet zdrojové kódy

[ABI break] merge support for http redirects, thanks to
Jeff Licquia and Anthony Towns

Michael Vogt před 17 roky
rodič
revize
15d7e51550

+ 32 - 0
apt-pkg/acquire-method.cc

@@ -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			/*{{{*/
 // AcqMethod::FetchResult::FetchResult - Constructor			/*{{{*/
 // ---------------------------------------------------------------------
 // ---------------------------------------------------------------------
 /* */
 /* */

+ 2 - 0
apt-pkg/acquire-method.h

@@ -84,6 +84,8 @@ class pkgAcqMethod
    void Log(const char *Format,...);
    void Log(const char *Format,...);
    void Status(const char *Format,...);
    void Status(const char *Format,...);
    
    
+   void Redirect(const string &NewURI);
+ 
    int Run(bool Single = false);
    int Run(bool Single = false);
    inline void SetFailExtraMsg(string Msg) {FailExtra = Msg;};
    inline void SetFailExtraMsg(string Msg) {FailExtra = Msg;};
    
    

+ 14 - 0
apt-pkg/acquire-worker.cc

@@ -220,6 +220,20 @@ bool pkgAcquire::Worker::RunMessages()
 	 Status = LookupTag(Message,"Message");
 	 Status = LookupTag(Message,"Message");
 	 break;
 	 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
 	 // 200 URI Start
 	 case 200:
 	 case 200:
 	 {
 	 {

+ 1 - 1
apt-pkg/makefile

@@ -13,7 +13,7 @@ include ../buildlib/defaults.mak
 # methods/makefile - FIXME
 # methods/makefile - FIXME
 LIBRARY=apt-pkg
 LIBRARY=apt-pkg
 LIBEXT=$(GLIBC_VER)$(LIBSTDCPP_VER)
 LIBEXT=$(GLIBC_VER)$(LIBSTDCPP_VER)
-MAJOR=4.6
+MAJOR=4.7
 MINOR=0
 MINOR=0
 SLIBS=$(PTHREADLIB) $(INTLLIBS) -lutil
 SLIBS=$(PTHREADLIB) $(INTLLIBS) -lutil
 APT_DOMAIN:=libapt-pkg$(MAJOR)
 APT_DOMAIN:=libapt-pkg$(MAJOR)

+ 2 - 0
debian/changelog

@@ -35,6 +35,8 @@ apt (0.7.21) UNRELEASED; urgency=low
     - make strings i18n able 
     - make strings i18n able 
   * apt-pkg/contrib/strutl.cc:
   * apt-pkg/contrib/strutl.cc:
     - fix TimeToStr i18n (LP: #289807)
     - fix TimeToStr i18n (LP: #289807)
+  * [ABI break] merge support for http redirects, thanks to
+    Jeff Licquia and Anthony Towns
 
 
   [ Dereck Wonnacott ]
   [ Dereck Wonnacott ]
   * apt-ftparchive might write corrupt Release files (LP: #46439)
   * apt-ftparchive might write corrupt Release files (LP: #46439)

+ 77 - 1
methods/http.cc

@@ -39,6 +39,7 @@
 #include <errno.h>
 #include <errno.h>
 #include <string.h>
 #include <string.h>
 #include <iostream>
 #include <iostream>
+#include <map>
 #include <apti18n.h>
 #include <apti18n.h>
 
 
 // Internet stuff
 // Internet stuff
@@ -57,6 +58,7 @@ int HttpMethod::FailFd = -1;
 time_t HttpMethod::FailTime = 0;
 time_t HttpMethod::FailTime = 0;
 unsigned long PipelineDepth = 10;
 unsigned long PipelineDepth = 10;
 unsigned long TimeOut = 120;
 unsigned long TimeOut = 120;
+bool AllowRedirect = false;
 bool Debug = false;
 bool Debug = false;
 URI Proxy;
 URI Proxy;
 
 
@@ -628,6 +630,12 @@ bool ServerState::HeaderLine(string Line)
       return true;
       return true;
    }
    }
 
 
+   if (stringcasecmp(Tag,"Location:") == 0)
+   {
+      Location = Val;
+      return true;
+   }
+
    return true;
    return true;
 }
 }
 									/*}}}*/
 									/*}}}*/
@@ -900,7 +908,9 @@ bool HttpMethod::ServerDie(ServerState *Srv)
      1 - IMS hit
      1 - IMS hit
      3 - Unrecoverable error 
      3 - Unrecoverable error 
      4 - Error with error content page
      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)
 int HttpMethod::DealWithHeaders(FetchResult &Res,ServerState *Srv)
 {
 {
    // Not Modified
    // Not Modified
@@ -912,6 +922,27 @@ int HttpMethod::DealWithHeaders(FetchResult &Res,ServerState *Srv)
       return 1;
       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
    /* We have a reply we dont handle. This should indicate a perm server
       failure */
       failure */
    if (Srv->Result < 200 || Srv->Result >= 300)
    if (Srv->Result < 200 || Srv->Result >= 300)
@@ -1026,6 +1057,7 @@ bool HttpMethod::Configuration(string Message)
    if (pkgAcqMethod::Configuration(Message) == false)
    if (pkgAcqMethod::Configuration(Message) == false)
       return false;
       return false;
    
    
+   AllowRedirect = _config->FindB("Acquire::http::AllowRedirect",true);
    TimeOut = _config->FindI("Acquire::http::Timeout",TimeOut);
    TimeOut = _config->FindI("Acquire::http::Timeout",TimeOut);
    PipelineDepth = _config->FindI("Acquire::http::Pipeline-Depth",
    PipelineDepth = _config->FindI("Acquire::http::Pipeline-Depth",
 				  PipelineDepth);
 				  PipelineDepth);
@@ -1039,6 +1071,10 @@ bool HttpMethod::Configuration(string Message)
 /* */
 /* */
 int HttpMethod::Loop()
 int HttpMethod::Loop()
 {
 {
+   typedef vector<string> StringVector;
+   typedef vector<string>::iterator StringVectorIterator;
+   map<string, StringVector> Redirected;
+
    signal(SIGTERM,SigTerm);
    signal(SIGTERM,SigTerm);
    signal(SIGINT,SigTerm);
    signal(SIGINT,SigTerm);
    
    
@@ -1225,6 +1261,46 @@ int HttpMethod::Loop()
 	    break;
 	    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:
 	 default:
 	 Fail(_("Internal error"));
 	 Fail(_("Internal error"));
 	 break;
 	 break;

+ 3 - 0
methods/http.h

@@ -99,6 +99,7 @@ struct ServerState
    enum {Chunked,Stream,Closes} Encoding;
    enum {Chunked,Stream,Closes} Encoding;
    enum {Header, Data} State;
    enum {Header, Data} State;
    bool Persistent;
    bool Persistent;
+   string Location;
    
    
    // This is a Persistent attribute of the server itself.
    // This is a Persistent attribute of the server itself.
    bool Pipeline;
    bool Pipeline;
@@ -143,6 +144,8 @@ class HttpMethod : public pkgAcqMethod
    static time_t FailTime;
    static time_t FailTime;
    static void SigTerm(int);
    static void SigTerm(int);
    
    
+   string NextURI;
+   
    public:
    public:
    friend class ServerState;
    friend class ServerState;
 
 

+ 1 - 1
methods/makefile

@@ -7,7 +7,7 @@ include ../buildlib/defaults.mak
 BIN := $(BIN)/methods
 BIN := $(BIN)/methods
 
 
 # FIXME..
 # FIXME..
-LIB_APT_PKG_MAJOR = 4.6
+LIB_APT_PKG_MAJOR = 4.7
 APT_DOMAIN := libapt-pkg$(LIB_APT_PKG_MAJOR)
 APT_DOMAIN := libapt-pkg$(LIB_APT_PKG_MAJOR)
 
 
 # The file method
 # The file method