// 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 CHROME_BROWSER_SAFE_BROWSING_PROTOCOL_PARSER_H_
#define CHROME_BROWSER_SAFE_BROWSING_PROTOCOL_PARSER_H_
#pragma once

// Parse the data returned from the chunk response.
//
// Based on the SafeBrowsing v2.1 protocol:
// http://code.google.com/p/google-safe-browsing/wiki/Protocolv2Spec
//
// Read the response from a SafeBrowsing request, and parse into useful pieces.
// The protocol is generally line oriented, but can contain binary data in the
// actual chunk responses. The consumer of the protocol data should instantiate
// the parser and call the appropriate parsing function on the data.
//
// Examples of protocol responses:
//
// 1. List identification
//    i:goog-phish-shavar\n
//    <command>:<command_data>\n
//
// 2. Minimum time to wait (seconds) until the next download request can be made
//    n:1200\n
//    <command>:<time_in_seconds>\n
//
// 3. Redirect URL for retrieving a chunk
//    u:cache.googlevideo.com/safebrowsing/rd/goog-phish-shavar_a_1\n
//    <command>:<url>\n
//
// 4. Add and sub chunks
//   a:1:4:523\n...    <-- Add chunk + binary data
//   s:13:4:17\n...    <-- Sub chunk + binary data
//   <chunk_type>:<chunk_number>:<prefix_len>:<chunk_bytes>\n<binary_data>
//
// 5. Add-del and sub-del requests
//    ad:1-4000,5001\n    <-- Add-del
//    sd:1,3,5,7,903\n    <-- Sub-del
//    <command>:<chunk_range>\n


#include <string>
#include <vector>

#include "base/basictypes.h"
#include "chrome/browser/safe_browsing/chunk_range.h"
#include "chrome/browser/safe_browsing/safe_browsing_util.h"


class SafeBrowsingProtocolParser {
 public:
  SafeBrowsingProtocolParser();

  // Parse the response of an update request. Results for chunk deletions (both
  // add-del and sub-del are returned in 'chunk_deletes', and new chunk URLs to
  // download are contained in 'chunk_urls'. The next time the client is allowed
  // to request another update is returned in 'next_update_sec'. If the service
  // wants us to retrieve new MAC keys, 're_key' will be set to true. If we are
  // using MACs to verify responses, the 'key' must be set to the private key
  // returned from the SafeBrowsing servers. 'reset' will be set to true if the
  // SafeBrowsing service wants us to dump our database.
  // Returns 'true'if it was able to decode the chunk properly, 'false' if not
  // decoded properly and the results should be ignored.
  bool ParseUpdate(const char* chunk_data,
                   int chunk_len,
                   const std::string& key,
                   int* next_update_sec,
                   bool* re_key,
                   bool* reset,
                   std::vector<SBChunkDelete>* chunk_deletes,
                   std::vector<ChunkUrl>* chunk_urls);

  // Parse the response from a chunk URL request and returns the hosts/prefixes
  // for adds and subs in "chunks".  Returns 'true' on successful parsing,
  // 'false' otherwise. Any result should be ignored when a parse has failed.
  bool ParseChunk(const std::string& list_name,
                  const char* chunk_data,
                  int chunk_len,
                  const std::string& key,
                  const std::string& mac,
                  bool* re_key,
                  SBChunkList* chunks);

  // Parse the result of a GetHash request, returning the list of full hashes.
  // If we are checking for valid MACs, the caller should populate 'key'.
  bool ParseGetHash(const char* chunk_data,
                    int chunk_len,
                    const std::string& key,
                    bool* re_key,
                    std::vector<SBFullHashResult>* full_hashes);

  // Convert a list of partial hashes into a proper GetHash request.
  void FormatGetHash(const std::vector<SBPrefix>& prefixes,
                     std::string* request);

  // Parse the keys used for subsequent communications with the SafeBrowsing
  // servers. Returns true on successful parse, false on parse error.
  bool ParseNewKey(const char* chunk_data,
                   int chunk_length,
                   std::string* client_key,
                   std::string* wrapped_key);

 private:
  bool ParseAddChunk(const std::string& list_name,
                     const char* data,
                     int data_len,
                     int hash_len,
                     std::deque<SBChunkHost>* hosts);
  bool ParseSubChunk(const std::string& list_name,
                     const char* data,
                     int data_len,
                     int hash_len,
                     std::deque<SBChunkHost>* hosts);

  // Helper functions used by ParseAddChunk and ParseSubChunk.
  static void ReadHostAndPrefixCount(const char** data,
                                     int* remaining,
                                     SBPrefix* host,
                                     int* count);
  static int ReadChunkId(const char** data, int* remaining);
  static bool ReadPrefixes(
      const char** data, int* remaining, SBEntry* entry, int count);

  // The name of the current list
  std::string list_name_;

  DISALLOW_COPY_AND_ASSIGN(SafeBrowsingProtocolParser);
};


#endif  // CHROME_BROWSER_SAFE_BROWSING_PROTOCOL_PARSER_H_