summaryrefslogtreecommitdiff
path: root/methods
diff options
context:
space:
mode:
Diffstat (limited to 'methods')
-rw-r--r--methods/http.cc78
-rw-r--r--methods/http.h3
-rw-r--r--methods/makefile2
3 files changed, 81 insertions, 2 deletions
diff --git a/methods/http.cc b/methods/http.cc
index b0fb89fda..44274bd78 100644
--- a/methods/http.cc
+++ b/methods/http.cc
@@ -38,6 +38,7 @@
#include <stdio.h>
#include <errno.h>
#include <string.h>
+#include <map>
#include <apti18n.h>
// Internet stuff
@@ -56,6 +57,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;
@@ -627,6 +629,12 @@ bool ServerState::HeaderLine(string Line)
return true;
}
+ if (stringcasecmp(Tag,"Location:") == 0)
+ {
+ Location = Val;
+ return true;
+ }
+
return true;
}
/*}}}*/
@@ -899,7 +907,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
@@ -911,6 +921,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)
@@ -1028,6 +1059,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);
@@ -1041,6 +1073,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);
@@ -1227,6 +1263,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;
diff --git a/methods/http.h b/methods/http.h
index dec5cd80f..bc076e1f8 100644
--- a/methods/http.h
+++ b/methods/http.h
@@ -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;
@@ -145,6 +146,8 @@ class HttpMethod : public pkgAcqMethod
protected:
virtual bool Fetch(FetchItem *);
+ string NextURI;
+
public:
friend class ServerState;
diff --git a/methods/makefile b/methods/makefile
index 5c4fa82bf..1d022be90 100644
--- a/methods/makefile
+++ b/methods/makefile
@@ -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