コード例 #1
0
ファイル: Boundary.java プロジェクト: kaywood/VolleyPlus
  /* package */ Boundary(String boundary) {
    if (TextUtils.isEmpty(boundary)) {
      boundary = generateBoundary();
    }
    this.boundary = boundary;

    final String starting = "--" + boundary + MultipartEntity.CRLF; // $NON-NLS-1$
    final String closing = "--" + boundary + "--" + MultipartEntity.CRLF; // $NON-NLS-1$

    startingBoundary = EncodingUtils.getAsciiBytes(starting);
    closingBoundary = EncodingUtils.getAsciiBytes(closing);
  }
コード例 #2
0
  /**
   * Creates a random cnonce value based on the current time.
   *
   * @return The cnonce value as String.
   * @throws UnsupportedDigestAlgorithmException if MD5 algorithm is not supported.
   */
  public static String createCnonce() {
    String cnonce;

    MessageDigest md5Helper = createMessageDigest("MD5");

    cnonce = Long.toString(System.currentTimeMillis());
    cnonce = encode(md5Helper.digest(EncodingUtils.getAsciiBytes(cnonce)));

    return cnonce;
  }
コード例 #3
0
 void sendToServer(String strMsg) {
   byte[] msg = EncodingUtils.getAsciiBytes(strMsg);
   if (msg.length > buffer.capacity()) // check if buffer long enough
   buffer = ByteBuffer.wrap(msg);
   buffer.clear();
   buffer.put(msg);
   buffer.flip();
   try {
     GlobalData.socketChannel.write(buffer);
   } catch (IOException e) {
     Log.d(TAG, "error on write: " + e.getMessage());
   }
 }
コード例 #4
0
 /**
  * Returns the MIME boundary string that is used to demarcate boundaries of this part. The first
  * call to this method will implicitly create a new boundary string. To create a boundary string
  * first the HttpMethodParams.MULTIPART_BOUNDARY parameter is considered. Otherwise a random one
  * is generated.
  *
  * @return The boundary string of this entity in ASCII encoding.
  */
 protected byte[] getMultipartBoundary() {
   if (multipartBoundary == null) {
     String temp = null;
     if (params != null) {
       temp = (String) params.getParameter(MULTIPART_BOUNDARY);
     }
     if (temp != null) {
       multipartBoundary = EncodingUtils.getAsciiBytes(temp);
     } else {
       multipartBoundary = generateMultipartBoundary();
     }
   }
   return multipartBoundary;
 }
コード例 #5
0
 /**
  * Handles the given exception and generates an HTTP response to be sent back to the client to
  * inform about the exceptional condition encountered in the course of the request processing.
  *
  * @param ex the exception.
  * @param response the HTTP response.
  */
 protected void handleException(final HttpException ex, final HttpResponse response) {
   if (ex instanceof MethodNotSupportedException) {
     response.setStatusCode(HttpStatus.SC_NOT_IMPLEMENTED);
   } else if (ex instanceof UnsupportedHttpVersionException) {
     response.setStatusCode(HttpStatus.SC_HTTP_VERSION_NOT_SUPPORTED);
   } else if (ex instanceof ProtocolException) {
     response.setStatusCode(HttpStatus.SC_BAD_REQUEST);
   } else {
     response.setStatusCode(HttpStatus.SC_INTERNAL_SERVER_ERROR);
   }
   byte[] msg = EncodingUtils.getAsciiBytes(ex.getMessage());
   ByteArrayEntity entity = new ByteArrayEntity(msg);
   entity.setContentType("text/plain; charset=US-ASCII");
   response.setEntity(entity);
 }
コード例 #6
0
  @Test
  public void testDecodingFileWithOffsetAndBufferedSessionData() throws Exception {
    final ReadableByteChannel channel =
        new ReadableByteChannelMock(
            new String[] {"stuff; ", "more stuff; ", "a lot more stuff!"}, Consts.ASCII);

    final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, Consts.ASCII);
    final HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl();
    final IdentityDecoder decoder = new IdentityDecoder(channel, inbuf, metrics);

    final int i = inbuf.fill(channel);
    Assert.assertEquals(7, i);

    final byte[] beginning = EncodingUtils.getAsciiBytes("beginning; ");

    createTempFile();
    RandomAccessFile testfile = new RandomAccessFile(this.tmpfile, "rw");
    try {
      testfile.write(beginning);
    } finally {
      testfile.close();
    }

    testfile = new RandomAccessFile(this.tmpfile, "rw");
    try {
      final FileChannel fchannel = testfile.getChannel();
      long pos = beginning.length;
      while (!decoder.isCompleted()) {
        if (testfile.length() < pos) {
          testfile.setLength(pos);
        }
        final long bytesRead = decoder.transfer(fchannel, pos, 10);
        if (bytesRead > 0) {
          pos += bytesRead;
        }
      }

      // count everything except the initial 7 bytes that went to the session buffer
      Assert.assertEquals(testfile.length() - 7 - beginning.length, metrics.getBytesTransferred());
    } finally {
      testfile.close();
    }

    Assert.assertEquals(
        "beginning; stuff; more stuff; a lot more stuff!",
        CodecTestUtils.readFromFile(this.tmpfile));
  }
コード例 #7
0
ファイル: HttpService.java プロジェクト: eFOIA-12/eFOIA
  protected void handleException(HttpException var1, HttpResponse var2) {
    if (var1 instanceof MethodNotSupportedException) {
      var2.setStatusCode(501);
    } else if (var1 instanceof UnsupportedHttpVersionException) {
      var2.setStatusCode(505);
    } else if (var1 instanceof ProtocolException) {
      var2.setStatusCode(400);
    } else {
      var2.setStatusCode(500);
    }

    String var4 = var1.getMessage();
    String var3 = var4;
    if (var4 == null) {
      var3 = var1.toString();
    }

    ByteArrayEntity var5 = new ByteArrayEntity(EncodingUtils.getAsciiBytes(var3));
    var5.setContentType("text/plain; charset=US-ASCII");
    var2.setEntity(var5);
  }
コード例 #8
0
  /**
   * This test case executes a series of simple POST requests that do not meet the target server
   * expectations.
   */
  @Test
  public void testHttpPostsWithExpectationVerification() throws Exception {

    final int reqNo = 3;

    // Initialize the server-side request handler
    this.server.registerHandler(
        "*",
        new HttpRequestHandler() {

          public void handle(
              final HttpRequest request, final HttpResponse response, final HttpContext context)
              throws HttpException, IOException {

            final StringEntity outgoing = new StringEntity("No content");
            response.setEntity(outgoing);
          }
        });

    this.server.setExpectationVerifier(
        new HttpExpectationVerifier() {

          public void verify(
              final HttpRequest request, final HttpResponse response, final HttpContext context)
              throws HttpException {
            final Header someheader = request.getFirstHeader("Secret");
            if (someheader != null) {
              int secretNumber;
              try {
                secretNumber = Integer.parseInt(someheader.getValue());
              } catch (final NumberFormatException ex) {
                response.setStatusCode(HttpStatus.SC_BAD_REQUEST);
                return;
              }
              if (secretNumber < 2) {
                response.setStatusCode(HttpStatus.SC_EXPECTATION_FAILED);
                final ByteArrayEntity outgoing =
                    new ByteArrayEntity(EncodingUtils.getAsciiBytes("Wrong secret number"));
                response.setEntity(outgoing);
              }
            }
          }
        });

    this.server.start();

    final DefaultBHttpClientConnection conn = client.createConnection();
    final HttpHost host = new HttpHost("localhost", this.server.getPort());

    try {
      for (int r = 0; r < reqNo; r++) {
        if (!conn.isOpen()) {
          client.connect(host, conn);
        }

        final BasicHttpEntityEnclosingRequest post =
            new BasicHttpEntityEnclosingRequest("POST", "/");
        post.addHeader("Secret", Integer.toString(r));
        final ByteArrayEntity outgoing =
            new ByteArrayEntity(EncodingUtils.getAsciiBytes("No content " + r));
        post.setEntity(outgoing);

        final HttpResponse response = this.client.execute(post, host, conn);

        final HttpEntity entity = response.getEntity();
        Assert.assertNotNull(entity);
        EntityUtils.consume(entity);

        if (r < 2) {
          Assert.assertEquals(
              HttpStatus.SC_EXPECTATION_FAILED, response.getStatusLine().getStatusCode());
        } else {
          Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
        }

        if (!this.client.keepAlive(response)) {
          conn.close();
        }
      }
      // Verify the connection metrics
      final HttpConnectionMetrics cm = conn.getMetrics();
      Assert.assertEquals(reqNo, cm.getRequestCount());
      Assert.assertEquals(reqNo, cm.getResponseCount());
    } finally {
      conn.close();
      this.server.shutdown();
    }
  }
コード例 #9
0
/**
 * Implements a request entity suitable for an HTTP multipart POST method.
 *
 * <p>The HTTP multipart POST method is defined in section 3.3 of <a
 * href="http://www.ietf.org/rfc/rfc1867.txt">RFC1867</a>:
 *
 * <blockquote>
 *
 * The media-type multipart/form-data follows the rules of all multipart MIME data streams as
 * outlined in RFC 1521. The multipart/form-data contains a series of parts. Each part is expected
 * to contain a content-disposition header where the value is "form-data" and a name attribute
 * specifies the field name within the form, e.g., 'content-disposition: form-data; name="xxxxx"',
 * where xxxxx is the field name corresponding to that field. Field names originally in non-ASCII
 * character sets may be encoded using the method outlined in RFC 1522.
 *
 * </blockquote>
 *
 * <p>This entity is designed to be used in conjunction with the {@link org.apache.http.HttpRequest}
 * to provide multipart posts. Example usage:
 *
 * <pre>
 *  File f = new File("/path/fileToUpload.txt");
 *  HttpRequest request = new HttpRequest("http://host/some_path");
 *  Part[] parts = {
 *      new StringPart("param_name", "value"),
 *      new FilePart(f.getName(), f)
 *  };
 *  filePost.setEntity(
 *      new MultipartRequestEntity(parts, filePost.getParams())
 *      );
 *  HttpClient client = new HttpClient();
 *  int status = client.executeMethod(filePost);
 * </pre>
 *
 * @since 3.0
 */
public class MultipartEntity extends AbstractHttpEntity {

  //    private static final Log log = LogFactory.getLog(MultipartEntity.class);

  /** The Content-Type for multipart/form-data. */
  private static final String MULTIPART_FORM_CONTENT_TYPE = "multipart/form-data";

  /**
   * Sets the value to use as the multipart boundary.
   *
   * <p>This parameter expects a value if type {@link String}.
   */
  public static final String MULTIPART_BOUNDARY = "http.method.multipart.boundary";

  /** The pool of ASCII chars to be used for generating a multipart boundary. */
  private static byte[] MULTIPART_CHARS =
      EncodingUtils.getAsciiBytes(
          "-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");

  /** Generates a random multipart boundary string. */
  public static byte[] generateMultipartBoundary() {
    Random rand = new Random();
    byte[] bytes = new byte[rand.nextInt(11) + 30]; // a random size from 30 to 40
    for (int i = 0; i < bytes.length; i++) {
      bytes[i] = MULTIPART_CHARS[rand.nextInt(MULTIPART_CHARS.length)];
    }
    return bytes;
  }

  /** The MIME parts as set by the constructor */
  protected Part[] parts;

  private byte[] multipartBoundary;

  private HttpParams params;

  private boolean contentConsumed = false;

  /**
   * Creates a new multipart entity containing the given parts.
   *
   * @param parts The parts to include.
   * @param params The params of the HttpMethod using this entity.
   */
  public MultipartEntity(Part[] parts, HttpParams params) {
    if (parts == null) {
      throw new IllegalArgumentException("parts cannot be null");
    }
    if (params == null) {
      throw new IllegalArgumentException("params cannot be null");
    }
    this.parts = parts;
    this.params = params;
  }

  public MultipartEntity(Part[] parts) {
    setContentType(MULTIPART_FORM_CONTENT_TYPE);
    if (parts == null) {
      throw new IllegalArgumentException("parts cannot be null");
    }
    this.parts = parts;
    this.params = null;
  }

  /**
   * Returns the MIME boundary string that is used to demarcate boundaries of this part. The first
   * call to this method will implicitly create a new boundary string. To create a boundary string
   * first the HttpMethodParams.MULTIPART_BOUNDARY parameter is considered. Otherwise a random one
   * is generated.
   *
   * @return The boundary string of this entity in ASCII encoding.
   */
  protected byte[] getMultipartBoundary() {
    if (multipartBoundary == null) {
      String temp = null;
      if (params != null) {
        temp = (String) params.getParameter(MULTIPART_BOUNDARY);
      }
      if (temp != null) {
        multipartBoundary = EncodingUtils.getAsciiBytes(temp);
      } else {
        multipartBoundary = generateMultipartBoundary();
      }
    }
    return multipartBoundary;
  }

  /** Returns <code>true</code> if all parts are repeatable, <code>false</code> otherwise. */
  public boolean isRepeatable() {
    for (int i = 0; i < parts.length; i++) {
      if (!parts[i].isRepeatable()) {
        return false;
      }
    }
    return true;
  }

  /* (non-Javadoc)
   */
  public void writeTo(OutputStream out) throws IOException {
    //    	if (out != null) {
    //    		android.util.Log.v("multipartEntity", "out != null");
    //    	}
    Part.sendParts(out, parts, getMultipartBoundary());
  }
  /* (non-Javadoc)
   * @see org.apache.commons.http.AbstractHttpEntity.#getContentType()
   */
  @Override
  public Header getContentType() {
    StringBuffer buffer = new StringBuffer(MULTIPART_FORM_CONTENT_TYPE);
    buffer.append("; boundary=");
    buffer.append(EncodingUtils.getAsciiString(getMultipartBoundary()));
    return new BasicHeader(HTTP.CONTENT_TYPE, buffer.toString());
  }

  /* (non-Javadoc)
   */
  public long getContentLength() {
    try {
      return Part.getLengthOfParts(parts, getMultipartBoundary());
    } catch (Exception e) {
      //           log.error("An exception occurred while getting the length of the parts", e);
      return 0;
    }
  }

  public InputStream getContent() throws IOException, IllegalStateException {
    if (!isRepeatable() && this.contentConsumed) {
      throw new IllegalStateException("Content has been consumed");
    }
    this.contentConsumed = true;

    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    Part.sendParts(baos, this.parts, this.multipartBoundary);
    ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
    return bais;
  }

  public boolean isStreaming() {
    return false;
  }
}
コード例 #10
0
ファイル: DigestScheme.java プロジェクト: yeins/vietspider
  /**
   * Creates digest-response header as defined in RFC2617.
   *
   * @param credentials User credentials
   * @return The digest-response as String.
   */
  private Header createDigestHeader(final Credentials credentials) throws AuthenticationException {
    String uri = getParameter("uri");
    String realm = getParameter("realm");
    String nonce = getParameter("nonce");
    String opaque = getParameter("opaque");
    String method = getParameter("methodname");
    String algorithm = getParameter("algorithm");
    if (uri == null) {
      throw new IllegalStateException("URI may not be null");
    }
    if (realm == null) {
      throw new IllegalStateException("Realm may not be null");
    }
    if (nonce == null) {
      throw new IllegalStateException("Nonce may not be null");
    }

    // TODO: add support for QOP_INT
    int qop = QOP_UNKNOWN;
    String qoplist = getParameter("qop");
    if (qoplist != null) {
      StringTokenizer tok = new StringTokenizer(qoplist, ",");
      while (tok.hasMoreTokens()) {
        String variant = tok.nextToken().trim();
        if (variant.equals("auth")) {
          qop = QOP_AUTH;
          break;
        }
      }
    } else {
      qop = QOP_MISSING;
    }

    if (qop == QOP_UNKNOWN) {
      throw new AuthenticationException("None of the qop methods is supported: " + qoplist);
    }

    // If an algorithm is not specified, default to MD5.
    if (algorithm == null) {
      algorithm = "MD5";
    }
    // If an charset is not specified, default to ISO-8859-1.
    String charset = getParameter("charset");
    if (charset == null) {
      charset = "ISO-8859-1";
    }

    String digAlg = algorithm;
    if (digAlg.equalsIgnoreCase("MD5-sess")) {
      digAlg = "MD5";
    }

    MessageDigest digester;
    try {
      digester = createMessageDigest(digAlg);
    } catch (UnsupportedDigestAlgorithmException ex) {
      throw new AuthenticationException("Unsuppported digest algorithm: " + digAlg);
    }

    String uname = credentials.getUserPrincipal().getName();
    String pwd = credentials.getPassword();

    if (nonce.equals(this.lastNonce)) {
      nounceCount++;
    } else {
      nounceCount = 1;
      cnonce = null;
      lastNonce = nonce;
    }
    StringBuilder sb = new StringBuilder(256);
    Formatter formatter = new Formatter(sb, Locale.US);
    formatter.format("%08x", nounceCount);
    String nc = sb.toString();

    if (cnonce == null) {
      cnonce = createCnonce();
    }

    a1 = null;
    a2 = null;
    // 3.2.2.2: Calculating digest
    if (algorithm.equalsIgnoreCase("MD5-sess")) {
      // H( unq(username-value) ":" unq(realm-value) ":" passwd )
      //      ":" unq(nonce-value)
      //      ":" unq(cnonce-value)

      // calculated one per session
      sb.setLength(0);
      sb.append(uname).append(':').append(realm).append(':').append(pwd);
      String checksum = encode(digester.digest(EncodingUtils.getBytes(sb.toString(), charset)));
      sb.setLength(0);
      sb.append(checksum).append(':').append(nonce).append(':').append(cnonce);
      a1 = sb.toString();
    } else {
      // unq(username-value) ":" unq(realm-value) ":" passwd
      sb.setLength(0);
      sb.append(uname).append(':').append(realm).append(':').append(pwd);
      a1 = sb.toString();
    }

    String hasha1 = encode(digester.digest(EncodingUtils.getBytes(a1, charset)));

    if (qop == QOP_AUTH) {
      // Method ":" digest-uri-value
      a2 = method + ':' + uri;
    } else if (qop == QOP_AUTH_INT) {
      // Method ":" digest-uri-value ":" H(entity-body)
      // TODO: calculate entity hash if entity is repeatable
      throw new AuthenticationException("qop-int method is not suppported");
    } else {
      a2 = method + ':' + uri;
    }

    String hasha2 = encode(digester.digest(EncodingUtils.getBytes(a2, charset)));

    // 3.2.2.1

    String digestValue;
    if (qop == QOP_MISSING) {
      sb.setLength(0);
      sb.append(hasha1).append(':').append(nonce).append(':').append(hasha2);
      digestValue = sb.toString();
    } else {
      sb.setLength(0);
      sb.append(hasha1)
          .append(':')
          .append(nonce)
          .append(':')
          .append(nc)
          .append(':')
          .append(cnonce)
          .append(':')
          .append(qop == QOP_AUTH_INT ? "auth-int" : "auth")
          .append(':')
          .append(hasha2);
      digestValue = sb.toString();
    }

    String digest = encode(digester.digest(EncodingUtils.getAsciiBytes(digestValue)));

    CharArrayBuffer buffer = new CharArrayBuffer(128);
    if (isProxy()) {
      buffer.append(AUTH.PROXY_AUTH_RESP);
    } else {
      buffer.append(AUTH.WWW_AUTH_RESP);
    }
    buffer.append(": Digest ");

    List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>(20);
    params.add(new BasicNameValuePair("username", uname));
    params.add(new BasicNameValuePair("realm", realm));
    params.add(new BasicNameValuePair("nonce", nonce));
    params.add(new BasicNameValuePair("uri", uri));
    params.add(new BasicNameValuePair("response", digest));

    if (qop != QOP_MISSING) {
      params.add(new BasicNameValuePair("qop", qop == QOP_AUTH_INT ? "auth-int" : "auth"));
      params.add(new BasicNameValuePair("nc", nc));
      params.add(new BasicNameValuePair("cnonce", cnonce));
    }
    if (algorithm != null) {
      params.add(new BasicNameValuePair("algorithm", algorithm));
    }
    if (opaque != null) {
      params.add(new BasicNameValuePair("opaque", opaque));
    }

    for (int i = 0; i < params.size(); i++) {
      BasicNameValuePair param = params.get(i);
      if (i > 0) {
        buffer.append(", ");
      }
      boolean noQuotes = "nc".equals(param.getName()) || "qop".equals(param.getName());
      BasicHeaderValueFormatter.DEFAULT.formatNameValuePair(buffer, param, !noQuotes);
    }
    return new BufferedHeader(buffer);
  }
コード例 #11
0
  /**
   * Creates an MD5 response digest.
   *
   * @return The created digest as string. This will be the response tag's value in the
   *     Authentication HTTP header.
   * @throws AuthenticationException when MD5 is an unsupported algorithm
   */
  private String createDigest(final Credentials credentials) throws AuthenticationException {
    // Collecting required tokens
    String uri = getParameter("uri");
    String realm = getParameter("realm");
    String nonce = getParameter("nonce");
    String method = getParameter("methodname");
    String algorithm = getParameter("algorithm");
    if (uri == null) {
      throw new IllegalStateException("URI may not be null");
    }
    if (realm == null) {
      throw new IllegalStateException("Realm may not be null");
    }
    if (nonce == null) {
      throw new IllegalStateException("Nonce may not be null");
    }
    // If an algorithm is not specified, default to MD5.
    if (algorithm == null) {
      algorithm = "MD5";
    }
    // If an charset is not specified, default to ISO-8859-1.
    String charset = getParameter("charset");
    if (charset == null) {
      charset = "ISO-8859-1";
    }

    if (qopVariant == QOP_AUTH_INT) {
      throw new AuthenticationException("Unsupported qop in HTTP Digest authentication");
    }

    MessageDigest md5Helper = createMessageDigest("MD5");

    String uname = credentials.getUserPrincipal().getName();
    String pwd = credentials.getPassword();

    // 3.2.2.2: Calculating digest
    StringBuilder tmp = new StringBuilder(uname.length() + realm.length() + pwd.length() + 2);
    tmp.append(uname);
    tmp.append(':');
    tmp.append(realm);
    tmp.append(':');
    tmp.append(pwd);
    // unq(username-value) ":" unq(realm-value) ":" passwd
    String a1 = tmp.toString();

    // a1 is suitable for MD5 algorithm
    if (algorithm.equals("MD5-sess")) {
      // H( unq(username-value) ":" unq(realm-value) ":" passwd )
      //      ":" unq(nonce-value)
      //      ":" unq(cnonce-value)

      String cnonce = getCnonce();

      String tmp2 = encode(md5Helper.digest(EncodingUtils.getBytes(a1, charset)));
      StringBuilder tmp3 = new StringBuilder(tmp2.length() + nonce.length() + cnonce.length() + 2);
      tmp3.append(tmp2);
      tmp3.append(':');
      tmp3.append(nonce);
      tmp3.append(':');
      tmp3.append(cnonce);
      a1 = tmp3.toString();
    } else if (!algorithm.equals("MD5")) {
      throw new AuthenticationException("Unhandled algorithm " + algorithm + " requested");
    }
    String md5a1 = encode(md5Helper.digest(EncodingUtils.getBytes(a1, charset)));

    String a2 = null;
    if (qopVariant == QOP_AUTH_INT) {
      // Unhandled qop auth-int
      // we do not have access to the entity-body or its hash
      // TODO: add Method ":" digest-uri-value ":" H(entity-body)
    } else {
      a2 = method + ':' + uri;
    }
    String md5a2 = encode(md5Helper.digest(EncodingUtils.getAsciiBytes(a2)));

    // 3.2.2.1
    String serverDigestValue;
    if (qopVariant == QOP_MISSING) {
      StringBuilder tmp2 = new StringBuilder(md5a1.length() + nonce.length() + md5a2.length());
      tmp2.append(md5a1);
      tmp2.append(':');
      tmp2.append(nonce);
      tmp2.append(':');
      tmp2.append(md5a2);
      serverDigestValue = tmp2.toString();
    } else {
      String qopOption = getQopVariantString();
      String cnonce = getCnonce();

      StringBuilder tmp2 =
          new StringBuilder(
              md5a1.length()
                  + nonce.length()
                  + NC.length()
                  + cnonce.length()
                  + qopOption.length()
                  + md5a2.length()
                  + 5);
      tmp2.append(md5a1);
      tmp2.append(':');
      tmp2.append(nonce);
      tmp2.append(':');
      tmp2.append(NC);
      tmp2.append(':');
      tmp2.append(cnonce);
      tmp2.append(':');
      tmp2.append(qopOption);
      tmp2.append(':');
      tmp2.append(md5a2);
      serverDigestValue = tmp2.toString();
    }

    String serverDigest = encode(md5Helper.digest(EncodingUtils.getAsciiBytes(serverDigestValue)));

    return serverDigest;
  }