'Fetch a URL, optionally caching for a specified time.
Args:
url: The URL to retrieve
post_data:
A dict of (str, unicode) key/value pairs.  If set, POST will be used.
parameters:
A dict whose key/value pairs should encoded and added
to the query string. [OPTIONAL]
no_cache: If true, overrides the cache on the current request
Returns:
A string containing the body of the response.'

def _FetchUrl(self, url, post_data=None, parameters=None, no_cache=None):

    extra_params = {}
    if self._default_params:
        extra_params.update(self._default_params)
    if parameters:
        extra_params.update(parameters)
    url = self._BuildUrl(url, extra_params=extra_params)
    opener = self._GetOpener(url, username=self._username, password=self._password)
    encoded_post_data = self._EncodePostData(post_data)
    if (encoded_post_data or no_cache or (not self._cache) or (not self._cache_timeout)):
        url_data = opener.open(url, encoded_post_data).read()
        opener.close()
    else:
        if self._username:
            key = ((self._username + ':') + url)
        else:
            key = url
        last_cached = self._cache.GetCachedTime(key)
        if ((not last_cached) or (time.time() >= (last_cached + self._cache_timeout))):
            url_data = opener.open(url, encoded_post_data).read()
            opener.close()
            self._cache.Set(key, url_data)
        else:
            url_data = self._cache.Get(key)
    return url_data
