1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
//! This module contains the trait for items that can be filtered by Inbound Filters, plus
//! the implementation for [`Event`].
use url::Url;

use relay_event_schema::protocol::{
    Csp, Event, EventType, Exception, LogEntry, Replay, Span, Values,
};

/// A data item to which filters can be applied.
pub trait Filterable {
    /// The CSP report contained in the item. Only for CSP reports.
    fn csp(&self) -> Option<&Csp>;

    /// The exception values of the item. Only for error events.
    fn exceptions(&self) -> Option<&Values<Exception>>;

    /// The IP address of the client that sent the data.
    fn ip_addr(&self) -> Option<&str>;

    /// The logentry message. Only for error events.
    fn logentry(&self) -> Option<&LogEntry>;

    /// The release string of the data item.
    fn release(&self) -> Option<&str>;

    /// The transaction name. Only for transaction events.
    fn transaction(&self) -> Option<&str>;

    /// The URL from which the request originates. Used for localhost filtering.
    fn url(&self) -> Option<Url>;

    /// The user agent of the client that sent the data.
    fn user_agent(&self) -> Option<&str>;
}

impl Filterable for Event {
    fn csp(&self) -> Option<&Csp> {
        if self.ty.value() != Some(&EventType::Csp) {
            return None;
        }
        self.csp.value()
    }

    fn exceptions(&self) -> Option<&Values<Exception>> {
        self.exceptions.value()
    }

    fn ip_addr(&self) -> Option<&str> {
        let user = self.user.value()?;
        Some(user.ip_address.value()?.as_ref())
    }

    fn logentry(&self) -> Option<&LogEntry> {
        self.logentry.value()
    }

    fn release(&self) -> Option<&str> {
        self.release.as_str()
    }

    fn transaction(&self) -> Option<&str> {
        if self.ty.value() != Some(&EventType::Transaction) {
            return None;
        }
        self.transaction.as_str()
    }

    fn url(&self) -> Option<Url> {
        let url_str = self.request.value()?.url.value()?;
        Url::parse(url_str).ok()
    }

    fn user_agent(&self) -> Option<&str> {
        self.user_agent()
    }
}

impl Filterable for Replay {
    fn csp(&self) -> Option<&Csp> {
        None
    }

    fn exceptions(&self) -> Option<&Values<Exception>> {
        None
    }

    fn ip_addr(&self) -> Option<&str> {
        let user = self.user.value()?;
        Some(user.ip_address.value()?.as_ref())
    }

    fn logentry(&self) -> Option<&LogEntry> {
        None
    }

    fn release(&self) -> Option<&str> {
        self.release.as_str()
    }

    fn transaction(&self) -> Option<&str> {
        None
    }

    fn url(&self) -> Option<Url> {
        let url_str = self.request.value()?.url.value()?;
        Url::parse(url_str).ok()
    }

    fn user_agent(&self) -> Option<&str> {
        self.user_agent()
    }
}

impl Filterable for Span {
    fn csp(&self) -> Option<&Csp> {
        // Only for events.
        None
    }

    fn exceptions(&self) -> Option<&Values<Exception>> {
        // Only for events.
        None
    }

    fn ip_addr(&self) -> Option<&str> {
        self.data.value()?.client_address.as_str()
    }

    fn logentry(&self) -> Option<&LogEntry> {
        // Only for events.
        None
    }

    fn release(&self) -> Option<&str> {
        self.data.value()?.release.as_str()
    }

    fn transaction(&self) -> Option<&str> {
        self.data.value()?.segment_name.as_str()
    }

    fn url(&self) -> Option<Url> {
        let url_str = self.data.value()?.url_full.as_str()?;
        Url::parse(url_str).ok()
    }

    fn user_agent(&self) -> Option<&str> {
        self.data.value()?.user_agent_original.as_str()
    }
}