Future _authenticate()

in lib/src/http_impl.dart [341:451]


  Future<HttpClientResponse> _authenticate(bool proxyAuth) {
    Future<HttpClientResponse> retry() {
      // Drain body and retry.
      return drain().then((_) {
        return _httpClient
            ._openUrlFromRequest(
                _httpRequest.method, _httpRequest.uri, _httpRequest)
            .then((request) => request.close());
      });
    }

    List<String> authChallenge() {
      return proxyAuth
          ? headers[HttpHeaders.PROXY_AUTHENTICATE]
          : headers[HttpHeaders.WWW_AUTHENTICATE];
    }

    _Credentials findCredentials(_AuthenticationScheme scheme) {
      return proxyAuth
          ? _httpClient._findProxyCredentials(_httpRequest._proxy, scheme)
          : _httpClient._findCredentials(_httpRequest.uri, scheme);
    }

    void removeCredentials(_Credentials cr) {
      if (proxyAuth) {
        _httpClient._removeProxyCredentials(cr);
      } else {
        _httpClient._removeCredentials(cr);
      }
    }

    Future<bool> requestAuthentication(
        _AuthenticationScheme scheme, String realm) {
      if (proxyAuth) {
        if (_httpClient._authenticateProxy == null) {
          return Future.value(false);
        }
        var proxy = _httpRequest._proxy;
        return _httpClient._authenticateProxy(
            proxy.host, proxy.port, scheme.toString(), realm);
      } else {
        if (_httpClient._authenticate == null) {
          return Future.value(false);
        }
        return _httpClient._authenticate(
            _httpRequest.uri, scheme.toString(), realm);
      }
    }

    List<String> challenge = authChallenge();
    assert(challenge != null || challenge.length == 1);
    HeaderValueImpl header =
        HeaderValueImpl.parse(challenge[0], parameterSeparator: ",");
    _AuthenticationScheme scheme =
        _AuthenticationScheme.fromString(header.value);
    String realm = header.parameters["realm"];

    // See if any matching credentials are available.
    _Credentials cr = findCredentials(scheme);
    if (cr != null) {
      // For basic authentication don't retry already used credentials
      // as they must have already been added to the request causing
      // this authenticate response.
      if (cr.scheme == _AuthenticationScheme.BASIC && !cr.used) {
        // Credentials where found, prepare for retrying the request.
        return retry();
      }

      // Digest authentication only supports the MD5 algorithm.
      if (cr.scheme == _AuthenticationScheme.DIGEST &&
          (header.parameters["algorithm"] == null ||
              header.parameters["algorithm"].toLowerCase() == "md5")) {
        if (cr.nonce == null || cr.nonce == header.parameters["nonce"]) {
          // If the nonce is not set then this is the first authenticate
          // response for these credentials. Set up authentication state.
          if (cr.nonce == null) {
            cr
              ..nonce = header.parameters["nonce"]
              ..algorithm = "MD5"
              ..qop = header.parameters["qop"]
              ..nonceCount = 0;
          }
          // Credentials where found, prepare for retrying the request.
          return retry();
        } else if (header.parameters["stale"] != null &&
            header.parameters["stale"].toLowerCase() == "true") {
          // If stale is true retry with new nonce.
          cr.nonce = header.parameters["nonce"];
          // Credentials where found, prepare for retrying the request.
          return retry();
        }
      }
    }

    // Ask for more credentials if none found or the one found has
    // already been used. If it has already been used it must now be
    // invalid and is removed.
    if (cr != null) {
      removeCredentials(cr);
      cr = null;
    }
    return requestAuthentication(scheme, realm).then((credsAvailable) {
      if (credsAvailable) {
        cr = _httpClient._findCredentials(_httpRequest.uri, scheme);
        return retry();
      } else {
        // No credentials available, complete with original response.
        return this;
      }
    });
  }