def OpenURL(self, url, verify_cb=lambda x: True, data=None,
              request_opts=None):
    """Get the requested URL.

    Note that we do not have any concept of timing here - we try to connect
    through all proxies as fast as possible until one works. Timing and poll
    frequency is left to the calling code.

    Args:
      url: The URL to fetch
      verify_cb: An optional callback which can be used to validate the URL. It
        receives the HTTPObject and return True if this seems OK, False
        otherwise. For example, if we are behind a captive portal we might
        receive invalid object even though HTTP status is 200.
      data: If specified, we POST this data to the server.
      request_opts: A dict containing optional headers.

    Returns:
      An HTTPObject instance or None if a connection could not be made.
    """
    # Start checking the proxy from the last value found.
    tries = 0
    last_error = 500

    while tries < len(self.proxies):
      proxy_index = self.last_proxy_index % len(self.proxies)
      proxy = self.proxies[proxy_index]
      try:
        proxydict = {}
        if proxy:
          proxydict["http"] = proxy
          proxydict["https"] = proxy

        proxy_support = urllib2.ProxyHandler(proxydict)
        opener = urllib2.build_opener(proxy_support)
        urllib2.install_opener(opener)

        request_opts = (request_opts or {}).copy()
        request_opts["Cache-Control"] = "no-cache"
        request = urllib2.Request(url, data, request_opts)

        duration, handle = self._RetryRequest(request)
        data = handle.read()

        result = HTTPObject(url=url, data=data, proxy=proxy, code=200,
                            duration=duration)

        if not verify_cb(result):
          raise urllib2.HTTPError(url=url, code=500, msg="Data not verified.",
                                  hdrs=[], fp=handle)

        # The last connection worked.
        self.consecutive_connection_errors = 0
        return result

      except urllib2.HTTPError as e:
        # Especially trap a 406 error message - it means the client needs to
        # enroll.
        if e.code == 406:
          # A 406 is not considered an error as the frontend is reachable. If we
          # considered it as an error the client would be unable to send the
          # enrollment request since connection errors disable message draining.
          self.consecutive_connection_errors = 0
          return HTTPObject(code=406)

        # Try the next proxy
        self.last_proxy_index = proxy_index + 1
        tries += 1
        last_error = e.code

      except urllib2.URLError as e:
        # Try the next proxy
        self.last_proxy_index = proxy_index + 1
        tries += 1
        last_error = 500

    # We failed to connect at all here.
    return HTTPObject(code=last_error)
dataset/ETHPy150Open google/grr/grr/client/comms.py/HTTPManager.OpenURL/original