// Copyright (c) 2016 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_SPDY_SPDY_FRAMER_DECODER_ADAPTER_H_
#define NET_SPDY_SPDY_FRAMER_DECODER_ADAPTER_H_

#include <stddef.h>

#include <memory>

#include "base/strings/string_piece.h"
#include "net/spdy/hpack/hpack_header_table.h"
#include "net/spdy/spdy_alt_svc_wire_format.h"
#include "net/spdy/spdy_framer.h"
#include "net/spdy/spdy_headers_handler_interface.h"
#include "net/spdy/spdy_protocol.h"

namespace net {

// Abstract base class for an HTTP/2 decoder to be called from SpdyFramer.
class SpdyFramerDecoderAdapter {
 public:
  SpdyFramerDecoderAdapter();
  virtual ~SpdyFramerDecoderAdapter();

  // Set callbacks to be called from the framer.  A visitor must be set, or
  // else the framer will likely crash.  It is acceptable for the visitor
  // to do nothing.  If this is called multiple times, only the last visitor
  // will be used.
  virtual void set_visitor(SpdyFramerVisitorInterface* visitor);
  SpdyFramerVisitorInterface* visitor() const { return visitor_; }

  // Set debug callbacks to be called from the framer. The debug visitor is
  // completely optional and need not be set in order for normal operation.
  // If this is called multiple times, only the last visitor will be used.
  virtual void set_debug_visitor(
      SpdyFramerDebugVisitorInterface* debug_visitor);
  SpdyFramerDebugVisitorInterface* debug_visitor() const {
    return debug_visitor_;
  }

  // Set debug callbacks to be called from the HPACK decoder.
  virtual void SetDecoderHeaderTableDebugVisitor(
      std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor) = 0;

  // Sets whether or not ProcessInput returns after finishing a frame, or
  // continues processing additional frames. Normally ProcessInput processes
  // all input, but this method enables the caller (and visitor) to work with
  // a single frame at a time (or that portion of the frame which is provided
  // as input). Reset() does not change the value of this flag.
  virtual void set_process_single_input_frame(bool v);
  bool process_single_input_frame() const {
    return process_single_input_frame_;
  }

  // Decode the |len| bytes of encoded HTTP/2 starting at |*data|. Returns the
  // number of bytes consumed. It is safe to pass more bytes in than may be
  // consumed.
  virtual size_t ProcessInput(const char* data, size_t len) = 0;

  // Reset the decoder (used just for tests at this time).
  virtual void Reset() = 0;

  // Current state of the decoder.
  virtual SpdyFramer::SpdyState state() const = 0;

  // Current error code (NO_ERROR if state != ERROR).
  virtual SpdyFramer::SpdyError error_code() const = 0;

  // Did the most recently decoded frame header appear to be the start of an
  // HTTP/1.1 (or earlier) response? Used to detect if a backend/server that
  // we sent a request to, responded with an HTTP/1.1 response?
  virtual bool probable_http_response() const = 0;

 private:
  SpdyFramerVisitorInterface* visitor_ = nullptr;
  SpdyFramerDebugVisitorInterface* debug_visitor_ = nullptr;
  bool process_single_input_frame_ = false;
};

// Create an instance of NestedSpdyFramerDecoder, which implements
// SpdyFramerDecoderAdapter, delegating to a SpdyFramer instance that will
// actually perform the decoding (when requested via ProcessInput). This allows
// us to test the SpdyFramerDecoderAdapter mechanism without changing the type
// of decoder that is used.
std::unique_ptr<SpdyFramerDecoderAdapter> CreateNestedSpdyFramerDecoder(
    SpdyFramer* outer);

// SpdyFramerVisitorInterface::OnError needs the original SpdyFramer* to
// pass to the visitor (really a listener). This implementation takes care of
// that while passing along all other calls unmodified.
class SpdyFramerVisitorAdapter : public SpdyFramerVisitorInterface {
 public:
  SpdyFramerVisitorAdapter(SpdyFramerVisitorInterface* visitor,
                           SpdyFramer* framer)
      : visitor_(visitor), framer_(framer) {}
  ~SpdyFramerVisitorAdapter() override {}
  // The visitor needs the original SpdyFramer, not the SpdyFramerDecoderAdapter
  // instance.
  void OnError(SpdyFramer* framer) override;
  void OnDataFrameHeader(SpdyStreamId stream_id,
                         size_t length,
                         bool fin) override;
  void OnStreamFrameData(SpdyStreamId stream_id,
                         const char* data,
                         size_t len) override;
  void OnStreamEnd(SpdyStreamId stream_id) override;
  void OnStreamPadding(SpdyStreamId stream_id, size_t len) override;
  SpdyHeadersHandlerInterface* OnHeaderFrameStart(
      SpdyStreamId stream_id) override;
  void OnHeaderFrameEnd(SpdyStreamId stream_id, bool end_headers) override;
  void OnSynStream(SpdyStreamId stream_id,
                   SpdyStreamId associated_stream_id,
                   SpdyPriority priority,
                   bool fin,
                   bool unidirectional) override;
  void OnSynReply(SpdyStreamId stream_id, bool fin) override;
  void OnRstStream(SpdyStreamId stream_id, SpdyRstStreamStatus status) override;
  void OnSetting(SpdySettingsIds id, uint8_t flags, uint32_t value) override;
  void OnPing(SpdyPingId unique_id, bool is_ack) override;
  void OnSettings(bool clear_persisted) override;
  void OnSettingsAck() override;
  void OnSettingsEnd() override;
  void OnGoAway(SpdyStreamId last_accepted_stream_id,
                SpdyGoAwayStatus status) override;
  void OnHeaders(SpdyStreamId stream_id,
                 bool has_priority,
                 int weight,
                 SpdyStreamId parent_stream_id,
                 bool exclusive,
                 bool fin,
                 bool end) override;
  void OnWindowUpdate(SpdyStreamId stream_id, int delta_window_size) override;
  bool OnGoAwayFrameData(const char* goaway_data, size_t len) override;
  bool OnRstStreamFrameData(const char* rst_stream_data, size_t len) override;
  void OnBlocked(SpdyStreamId stream_id) override;
  void OnPushPromise(SpdyStreamId stream_id,
                     SpdyStreamId promised_stream_id,
                     bool end) override;
  void OnContinuation(SpdyStreamId stream_id, bool end) override;
  void OnPriority(SpdyStreamId stream_id,
                  SpdyStreamId parent_id,
                  int weight,
                  bool exclusive) override;
  void OnAltSvc(SpdyStreamId stream_id,
                base::StringPiece origin,
                const SpdyAltSvcWireFormat::AlternativeServiceVector&
                    altsvc_vector) override;
  bool OnUnknownFrame(SpdyStreamId stream_id, int frame_type) override;

 protected:
  SpdyFramerVisitorInterface* visitor() const { return visitor_; }
  SpdyFramer* framer() const { return framer_; }

 private:
  SpdyFramerVisitorInterface* const visitor_;
  SpdyFramer* const framer_;
};

}  // namespace net

#endif  // NET_SPDY_SPDY_FRAMER_DECODER_ADAPTER_H_
