1
#include "source/common/http/user_agent.h"
2

            
3
#include <cstdint>
4
#include <memory>
5
#include <string>
6

            
7
#include "envoy/network/connection.h"
8
#include "envoy/stats/scope.h"
9
#include "envoy/stats/timespan.h"
10

            
11
#include "source/common/http/headers.h"
12
#include "source/common/stats/symbol_table.h"
13
#include "source/common/stats/utility.h"
14

            
15
namespace Envoy {
16
namespace Http {
17

            
18
UserAgentContext::UserAgentContext(Stats::SymbolTable& symbol_table)
19
51402
    : symbol_table_(symbol_table), pool_(symbol_table),
20
51402
      downstream_cx_length_ms_(pool_.add("downstream_cx_length_ms")),
21
51402
      ios_(pool_.add("user_agent.ios")), android_(pool_.add("user_agent.android")),
22
51402
      downstream_cx_total_(pool_.add("downstream_cx_total")),
23
51402
      downstream_cx_destroy_remote_active_rq_(pool_.add("downstream_cx_destroy_remote_active_rq")),
24
51402
      downstream_rq_total_(pool_.add("downstream_rq_total")) {}
25

            
26
22435
void UserAgent::completeConnectionLength(Stats::Timespan& span) {
27
22435
  if (stats_ != nullptr) {
28
2
    stats_->downstream_cx_length_ms_.recordValue(span.elapsed().count());
29
2
  }
30
22435
}
31

            
32
UserAgentStats::UserAgentStats(Stats::StatName prefix, Stats::StatName device, Stats::Scope& scope,
33
                               const UserAgentContext& context)
34
2
    : downstream_cx_total_(Stats::Utility::counterFromElements(
35
2
          scope, {prefix, device, context.downstream_cx_total_})),
36
2
      downstream_cx_destroy_remote_active_rq_(Stats::Utility::counterFromElements(
37
2
          scope, {prefix, device, context.downstream_cx_destroy_remote_active_rq_})),
38
2
      downstream_rq_total_(Stats::Utility::counterFromElements(
39
2
          scope, {prefix, device, context.downstream_rq_total_})),
40
2
      downstream_cx_length_ms_(Stats::Utility::histogramFromElements(
41
2
          scope, {prefix, device, context.downstream_cx_length_ms_},
42
2
          Stats::Histogram::Unit::Milliseconds)) {
43
2
  downstream_cx_total_.inc();
44
2
}
45

            
46
void UserAgent::initializeFromHeaders(const RequestHeaderMap& headers, Stats::StatName prefix,
47
91424
                                      Stats::Scope& scope) {
48
  // We assume that the user-agent is consistent based on the first request.
49
91424
  if (stats_ == nullptr && !initialized_) {
50
19816
    initialized_ = true;
51

            
52
19816
    const absl::string_view user_agent = headers.getUserAgentValue();
53
19816
    if (!user_agent.empty()) {
54
8
      if (user_agent.find("iOS") != absl::string_view::npos) {
55
1
        stats_ = std::make_unique<UserAgentStats>(prefix, context_.ios_, scope, context_);
56
7
      } else if (user_agent.find("android") != absl::string_view::npos) {
57
1
        stats_ = std::make_unique<UserAgentStats>(prefix, context_.android_, scope, context_);
58
1
      }
59
8
    }
60
19816
  }
61
91424
  if (stats_ != nullptr) {
62
3
    stats_->downstream_rq_total_.inc();
63
3
  }
64
91424
}
65

            
66
669
void UserAgent::onConnectionDestroy(Network::ConnectionEvent event, bool active_streams) {
67
669
  if (stats_ != nullptr && active_streams && event == Network::ConnectionEvent::RemoteClose) {
68
1
    stats_->downstream_cx_destroy_remote_active_rq_.inc();
69
1
  }
70
669
}
71

            
72
} // namespace Http
73
} // namespace Envoy