// Copyright 2014 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_TOOLS_QUIC_TEST_TOOLS_TEST_TOOLS_HTTP_MESSAGE_H_
#define NET_TOOLS_QUIC_TEST_TOOLS_TEST_TOOLS_HTTP_MESSAGE_H_

#include <string>
#include <vector>

#include "base/strings/string_piece.h"
#include "net/tools/balsa/balsa_enums.h"
#include "net/tools/balsa/balsa_headers.h"

namespace net {
namespace tools {
namespace test {

class HttpConstants {
 public:
  enum Version {
    HTTP_UNKNOWN = 0,
    HTTP_0_9,
    HTTP_1_0,
    HTTP_1_1
  };

  enum Method {
    UNKNOWN_METHOD = 0,
    OPTIONS,
    GET,
    HEAD,
    POST,
    PUT,
    DELETE,
    TRACE,
    CONNECT,

    MKCOL,
    UNLOCK,
  };
};

// Stripped down wrapper class which basically contains headers and a body.
class HTTPMessage {
 public:
  typedef HttpConstants::Version Version;
  typedef HttpConstants::Method Method;

  // Convenient functions to map strings into enums. The string passed in is
  // not assumed to be NULL-terminated.
  static Version StringToVersion(base::StringPiece str);
  static Method StringToMethod(base::StringPiece str);

  static const char* MethodToString(Method method);
  static const char* VersionToString(Version version);

  // Default constructor makes an empty HTTP/1.1 GET request. This is typically
  // used to construct a message that will be Initialize()-ed.
  HTTPMessage();

  // Build a request message
  HTTPMessage(Version version, Method request, const std::string& path);

  virtual ~HTTPMessage();

  const std::string& body() const { return body_; }

  // Adds a header line to the message.
  void AddHeader(const std::string& header, const std::string& value);

  // Removes a header line from the message.
  void RemoveHeader(const std::string& header);

  // A utility function which calls RemoveHeader followed by AddHeader.
  void ReplaceHeader(const std::string& header, const std::string& value);

  // Adds a body and the optional content-length header field (omitted to test
  // read until close test case). To generate a message that has a header field
  // of 0 content-length, call AddBody("", true).
  // Multiple calls to AddBody()/AddChunkedBody() has the effect of overwriting
  // the previous entry without warning.
  void AddBody(const std::string& body, bool add_content_length);

  bool has_complete_message() const { return has_complete_message_; }
  void set_has_complete_message(bool value) { has_complete_message_ = value; }

  // Do some basic http message consistency checks like:
  // - Valid transfer-encoding header
  // - Valid content-length header
  // - Messages we expect to be complete are complete.
  // This check can be disabled by setting skip_message_validation.
  void ValidateMessage() const;

  bool skip_message_validation() const { return skip_message_validation_; }
  void set_skip_message_validation(bool value) {
    skip_message_validation_ = value;
  }

  // Allow direct access to the body string.  This should be used with caution:
  // it will not update the request headers like AddBody and AddChunkedBody do.
  void set_body(const std::string& body) { body_ = body; }

  const BalsaHeaders* headers() const { return &headers_; }
  BalsaHeaders* headers() { return &headers_; }

 protected:
  BalsaHeaders headers_;

  std::string body_;  // the body with chunked framing/gzip compression

  bool is_request_;

  // True if the message should be considered complete during serialization.
  // Used by SPDY and Streamed RPC clients to decide wherever or not
  // to include fin flags and during message validation (if enabled).
  bool has_complete_message_;

  // Allows disabling message validation when creating test messages
  // that are intentionally invalid.
  bool skip_message_validation_;

 private:
  void InitializeFields();

  DISALLOW_COPY_AND_ASSIGN(HTTPMessage);
};

}  // namespace test
}  // namespace tools
}  // namespace net

#endif  // NET_TOOLS_QUIC_TEST_TOOLS_TEST_TOOLS_HTTP_MESSAGE_H_
