1
#pragma once
2

            
3
#include "envoy/buffer/buffer.h"
4
#include "envoy/event/schedulable_cb.h"
5
#include "envoy/http/header_map.h"
6
#include "envoy/network/address.h"
7
#include "envoy/network/filter.h"
8
#include "envoy/stats/stats_macros.h" // IWYU pragma: keep
9

            
10
#include "source/common/common/logger.h"
11

            
12
#include "cilium/accesslog.h"
13
#include "cilium/api/accesslog.pb.h"
14
#include "cilium/websocket_codec.h"
15
#include "cilium/websocket_config.h"
16

            
17
namespace Envoy {
18
namespace Cilium {
19
namespace WebSocket {
20

            
21
class Instance : public Network::Filter,
22
                 public CodecCallbacks,
23
                 Logger::Loggable<Logger::Id::filter> {
24
public:
25
24
  Instance(const ConfigSharedPtr& config) : config_(config) {}
26

            
27
  // Network::ReadFilter
28
  void initializeReadFilterCallbacks(Network::ReadFilterCallbacks& callbacks) override;
29
  Network::FilterStatus onNewConnection() override;
30
  Network::FilterStatus onData(Buffer::Instance&, bool end_stream) override;
31

            
32
  // Network::WriteFilter
33
24
  void initializeWriteFilterCallbacks(Network::WriteFilterCallbacks& callbacks) override {
34
24
    write_callbacks_ = &callbacks;
35
24
  }
36
  Network::FilterStatus onWrite(Buffer::Instance&, bool end_stream) override;
37

            
38
  // WebSocket::CodecCallbacks
39
727
  const ConfigSharedPtr& config() override { return config_; }
40
11
  void onHandshakeCreated(const Http::RequestHeaderMap& headers) override {
41
11
    log_entry_.updateFromRequest(0, nullptr, headers);
42
11
  }
43
11
  void onHandshakeSent() override { config_->log(log_entry_, ::cilium::EntryType::Request); }
44
  void onHandshakeRequest(const Http::RequestHeaderMap& headers) override;
45
11
  void onHandshakeResponse(const Http::ResponseHeaderMap& headers) override {
46
11
    log_entry_.updateFromResponse(headers, config_->time_source_);
47
11
    config_->log(log_entry_, ::cilium::EntryType::Response);
48
11
  }
49
13
  void onHandshakeResponseSent(const Http::ResponseHeaderMap& headers) override {
50
13
    bool accepted = headers.Status() && headers.getStatusValue() == "101";
51
13
    if (accepted) {
52
12
      config_->log(log_entry_, ::cilium::EntryType::Request);
53
12
    } else {
54
1
      config_->log(log_entry_, ::cilium::EntryType::Denied);
55
1
      config_->stats_.access_denied_.inc();
56
1
    }
57
13
    log_entry_.updateFromResponse(headers, config_->time_source_);
58
13
    config_->log(log_entry_, ::cilium::EntryType::Response);
59
13
  }
60

            
61
  void injectEncoded(Buffer::Instance& data, bool end_stream) override;
62
  void injectDecoded(Buffer::Instance& data, bool end_stream) override;
63

            
64
  void
65
12
  setOriginalDestinationAddress(const Network::Address::InstanceConstSharedPtr& orig_dst) override {
66
12
    callbacks_->connection().connectionInfoSetter().restoreLocalAddress(orig_dst);
67
12
  }
68

            
69
private:
70
  const ConfigSharedPtr config_;
71

            
72
  Network::ReadFilterCallbacks* callbacks_{nullptr};
73
  Network::WriteFilterCallbacks* write_callbacks_{nullptr};
74
  CodecPtr codec_{nullptr};
75
  Event::SchedulableCallbackPtr client_handshake_cb_{nullptr};
76
  Cilium::AccessLog::Entry log_entry_{};
77
};
78

            
79
} // namespace WebSocket
80
} // namespace Cilium
81
} // namespace Envoy