// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef NET_HTTP_HTTP_AUTH_HANDLER_DIGEST_H_
#define NET_HTTP_HTTP_AUTH_HANDLER_DIGEST_H_

#include "net/http/http_auth_handler.h"

// This is needed for the FRIEND_TEST() macro.
#include "testing/gtest/include/gtest/gtest_prod.h"

namespace net {

// Code for handling http digest authentication.
class HttpAuthHandlerDigest : public HttpAuthHandler {
 public:
  virtual std::string GenerateCredentials(const std::wstring& username,
                                          const std::wstring& password,
                                          const HttpRequestInfo* request,
                                          const ProxyInfo* proxy);

 protected:
  virtual bool Init(std::string::const_iterator challenge_begin,
                    std::string::const_iterator challenge_end) {
    nonce_count_ = 0;
    return ParseChallenge(challenge_begin, challenge_end);
  }

 private:
  FRIEND_TEST(HttpAuthHandlerDigestTest, ParseChallenge);
  FRIEND_TEST(HttpAuthHandlerDigestTest, AssembleCredentials);

  // Possible values for the "algorithm" property.
  enum DigestAlgorithm {
    // No algorithm was specified. According to RFC 2617 this means
    // we should default to ALGORITHM_MD5.
    ALGORITHM_UNSPECIFIED,

    // Hashes are run for every request.
    ALGORITHM_MD5,

    // Hash is run only once during the first WWW-Authenticate handshake.
    // (SESS means session).
    ALGORITHM_MD5_SESS,
  };

  // Possible values for "qop" -- may be or-ed together if there were
  // multiple comma separated values.
  enum QualityOfProtection {
    QOP_UNSPECIFIED = 0,
    QOP_AUTH = 1 << 0,
    QOP_AUTH_INT = 1 << 1,
  };

  ~HttpAuthHandlerDigest() {}

  // Parse the challenge, saving the results into this instance.
  // Returns true on success.
  bool ParseChallenge(std::string::const_iterator challenge_begin,
                      std::string::const_iterator challenge_end);

  // Parse an individual property. Returns true on success.
  bool ParseChallengeProperty(const std::string& name,
                              const std::string& value);

  // Generates a random string, to be used for client-nonce.
  static std::string GenerateNonce();

  // Convert enum value back to string.
  static std::string QopToString(int qop);
  static std::string AlgorithmToString(int algorithm);

  // Extract the method and path of the request, as needed by
  // the 'A2' production. (path may be a hostname for proxy).
  void GetRequestMethodAndPath(const HttpRequestInfo* request,
                               const ProxyInfo* proxy,
                               std::string* method,
                               std::string* path) const;

  // Build up  the 'response' production.
  std::string AssembleResponseDigest(const std::string& method,
                                     const std::string& path,
                                     const std::string& username,
                                     const std::string& password,
                                     const std::string& cnonce,
                                     const std::string& nc) const;

  // Build up  the value for (Authorization/Proxy-Authorization).
  std::string AssembleCredentials(const std::string& method,
                                  const std::string& path,
                                  const std::string& username,
                                  const std::string& password,
                                  const std::string& cnonce,
                                  int nonce_count) const;

  // Information parsed from the challenge.
  std::string nonce_;
  std::string domain_;
  std::string opaque_;
  bool stale_;
  DigestAlgorithm algorithm_;
  int qop_; // Bitfield of QualityOfProtection

  int nonce_count_;
};

}  // namespace net

#endif  // NET_HTTP_HTTP_AUTH_HANDLER_DIGEST_H_