diff options
author | Michael Vogt <michael.vogt@ubuntu.com> | 2009-01-30 20:55:20 +0100 |
---|---|---|
committer | Michael Vogt <michael.vogt@ubuntu.com> | 2009-01-30 20:55:20 +0100 |
commit | 15d7e51550327bf49b95372f84bd0de4e896e7d7 (patch) | |
tree | 06e4ff4732fd8984da57a95c324f5109e47eb73d /methods/http.cc | |
parent | f814fbf4f2c78e3b9ceeeaba3cb93ed0ebbc7943 (diff) |
[ABI break] merge support for http redirects, thanks to
Jeff Licquia and Anthony Towns
Diffstat (limited to 'methods/http.cc')
-rw-r--r-- | methods/http.cc | 78 |
1 files changed, 77 insertions, 1 deletions
diff --git a/methods/http.cc b/methods/http.cc index b3c791fa0..1bf798da4 100644 --- a/methods/http.cc +++ b/methods/http.cc @@ -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; |