[tor-commits] [ooni-probe/master] Also record all the redirects
art at torproject.org
art at torproject.org
Mon May 30 16:28:33 UTC 2016
commit 8a745093ecd27240053b7e251de46eb4c303df6f
Author: Arturo Filastò <arturo at filasto.net>
Date: Mon Apr 18 18:45:29 2016 +0200
Also record all the redirects
* Add monkey patch for bug in twisted RedirectAgent: https://twistedmatrix.com/trac/ticket/8265
---
ooni/templates/httpt.py | 22 ++++++++++++++--------
ooni/utils/trueheaders.py | 42 +++++++++++++++++++++++++++++++++++++++++-
2 files changed, 55 insertions(+), 9 deletions(-)
diff --git a/ooni/templates/httpt.py b/ooni/templates/httpt.py
index 2b280f0..2a17f5b 100644
--- a/ooni/templates/httpt.py
+++ b/ooni/templates/httpt.py
@@ -7,6 +7,7 @@ from twisted.web.client import readBody, PartialDownloadError
from twisted.internet import reactor
from twisted.internet.endpoints import TCP4ClientEndpoint
from ooni.utils.trueheaders import TrueHeadersAgent, TrueHeadersSOCKS5Agent
+from ooni.utils.trueheaders import FixedRedirectAgent
from ooni.nettest import NetTestCase
from ooni.utils import log, base64Dict
@@ -37,8 +38,15 @@ class StreamListener(StreamListenerMixin):
log.err("Tor Exit ip detection failed")
+def _representHeaders(headers):
+ represented_headers = {}
+ for name, value in headers.getAllRawHeaders():
+ represented_headers[name] = value[0]
+ return represented_headers
def _representBody(body):
+ if not body:
+ return body
# XXX perhaps add support for decoding gzip in the future.
body = body.replace('\0', '')
decoded = False
@@ -115,9 +123,8 @@ class HTTPTest(NetTestCase):
if self.followRedirects:
try:
- from twisted.web.client import RedirectAgent
- self.control_agent = RedirectAgent(self.control_agent)
- self.agent = RedirectAgent(self.agent)
+ self.control_agent = FixedRedirectAgent(self.control_agent)
+ self.agent = FixedRedirectAgent(self.agent)
self.report['agent'] = 'redirect'
except:
log.err("Warning! You are running an old version of twisted"\
@@ -147,11 +154,10 @@ class HTTPTest(NetTestCase):
failure (instance): An instance of :class:twisted.internet.failure.Failure
"""
- def _representHeaders(headers):
- represented_headers = {}
- for name, value in headers.getAllRawHeaders():
- represented_headers[name] = value[0]
- return represented_headers
+ if response and response.previousResponse:
+ self.addToReport(request, response.previousResponse,
+ response_body=None,
+ failure_string=None)
log.debug("Adding %s to report" % request)
request_headers = TrueHeaders(request['headers'])
diff --git a/ooni/utils/trueheaders.py b/ooni/utils/trueheaders.py
index d5aa206..a5b2fe3 100644
--- a/ooni/utils/trueheaders.py
+++ b/ooni/utils/trueheaders.py
@@ -7,9 +7,14 @@
import itertools
from copy import copy
-from twisted.web import client, _newclient, http_headers
+from twisted.python.failure import Failure
+
+from twisted.web import client, _newclient, http_headers, error
+
from twisted.web._newclient import RequestNotSent, RequestGenerationFailed
from twisted.web._newclient import TransportProxyProducer, STATUS
+from twisted.web._newclient import ResponseFailed
+
from twisted.internet import reactor
from twisted.internet.defer import Deferred, fail, maybeDeferred, failure
@@ -179,3 +184,38 @@ class TrueHeadersSOCKS5Agent(SOCKS5Agent):
self._wrappedAgent._pool = pool
else:
self._pool = pool
+
+class FixedRedirectAgent(client.BrowserLikeRedirectAgent):
+ """
+ This is a redirect agent with this patch manually applied:
+ https://twistedmatrix.com/trac/ticket/8265
+ """
+ def _handleRedirect(self, response, method, uri, headers, redirectCount):
+ """
+ Handle a redirect response, checking the number of redirects already
+ followed, and extracting the location header fields.
+
+ This is pathed to fix a bug in infinite redirect loop.
+ """
+ if redirectCount >= self._redirectLimit:
+ err = error.InfiniteRedirection(
+ response.code,
+ b'Infinite redirection detected',
+ location=uri)
+ raise ResponseFailed([Failure(err)], response)
+ locationHeaders = response.headers.getRawHeaders(b'location', [])
+ if not locationHeaders:
+ err = error.RedirectWithNoLocation(
+ response.code, b'No location header field', uri)
+ raise ResponseFailed([Failure(err)], response)
+ location = self._resolveLocation(response.request.absoluteURI, locationHeaders[0])
+ deferred = self._agent.request(method, location, headers)
+
+ def _chainResponse(newResponse):
+ newResponse.setPreviousResponse(response)
+ return newResponse
+
+ deferred.addCallback(_chainResponse)
+ # This is the fix to properly handle redirects
+ return deferred.addCallback(
+ self._handleResponse, method, uri, headers, redirectCount + 1)
More information about the tor-commits
mailing list