@Override
  public void formatResponse(
      ChallengeWriter cw,
      ChallengeResponse challenge,
      Request request,
      Series<Header> httpHeaders) {

    if (challenge.getIdentifier() != null) {
      cw.appendQuotedChallengeParameter("username", challenge.getIdentifier());
    }

    if (challenge.getRealm() != null) {
      cw.appendQuotedChallengeParameter("realm", challenge.getRealm());
    }

    if (challenge.getServerNonce() != null) {
      cw.appendQuotedChallengeParameter("nonce", challenge.getServerNonce());
    }

    if (challenge.getDigestRef() != null) {
      challenge.setDigestRef(new Reference(request.getResourceRef().getPath()));
      cw.appendQuotedChallengeParameter("uri", challenge.getDigestRef().toString());
    }

    char[] responseDigest = formatResponseDigest(challenge, request);

    if (responseDigest != null) {
      cw.appendQuotedChallengeParameter("response", new String(responseDigest));
    }

    if ((challenge.getDigestAlgorithm() != null)
        && !Digest.ALGORITHM_MD5.equals(challenge.getDigestAlgorithm())) {
      cw.appendChallengeParameter("algorithm", challenge.getDigestAlgorithm());
    }

    if (challenge.getClientNonce() != null) {
      cw.appendQuotedChallengeParameter("cnonce", challenge.getClientNonce());
    }

    if (challenge.getOpaque() != null) {
      cw.appendQuotedChallengeParameter("opaque", challenge.getOpaque());
    }

    if (challenge.getQuality() != null) {
      cw.appendChallengeParameter("qop", challenge.getQuality());
    }

    if ((challenge.getQuality() != null) && (challenge.getServerNounceCount() > 0)) {
      cw.appendChallengeParameter("nc", challenge.getServerNounceCountAsHex());
    }

    for (Parameter param : challenge.getParameters()) {
      if (HeaderUtils.isToken(param.getValue())) {
        cw.appendChallengeParameter(param);
      } else {
        cw.appendQuotedChallengeParameter(param);
      }
    }
  }
  @Override
  public void formatRequest(
      ChallengeWriter cw, ChallengeRequest challenge, Response response, Series<Header> httpHeaders)
      throws IOException {

    if (challenge.getRealm() != null) {
      cw.appendQuotedChallengeParameter("realm", challenge.getRealm());
    }

    if (!challenge.getDomainRefs().isEmpty()) {
      cw.append(", domain=\"");

      for (int i = 0; i < challenge.getDomainRefs().size(); i++) {
        if (i > 0) {
          cw.append(' ');
        }

        cw.append(challenge.getDomainRefs().get(i).toString());
      }

      cw.append('"');
    }

    if (challenge.getServerNonce() != null) {
      cw.appendQuotedChallengeParameter("nonce", challenge.getServerNonce());
    }

    if (challenge.getOpaque() != null) {
      cw.appendQuotedChallengeParameter("opaque", challenge.getOpaque());
    }

    if (challenge.isStale()) {
      cw.appendChallengeParameter("stale", "true");
    }

    if (challenge.getDigestAlgorithm() != null) {
      cw.appendChallengeParameter("algorithm", challenge.getDigestAlgorithm());
    }

    if (!challenge.getQualityOptions().isEmpty()) {
      cw.append(", qop=\"");

      for (int i = 0; i < challenge.getQualityOptions().size(); i++) {
        if (i > 0) {
          cw.append(',');
        }

        cw.appendToken(challenge.getQualityOptions().get(i).toString());
      }

      cw.append('"');
    }

    for (Parameter param : challenge.getParameters()) {
      if (HeaderUtils.isToken(param.getValue())) {
        cw.appendChallengeParameter(param);
      } else {
        cw.appendQuotedChallengeParameter(param);
      }
    }
  }