sentry_types/protocol/
attachment.rs

1use std::fmt;
2
3use serde::Deserialize;
4
5/// The different types an attachment can have.
6#[derive(Debug, Clone, Eq, PartialEq, Deserialize)]
7pub enum AttachmentType {
8    #[serde(rename = "event.attachment")]
9    /// (default) A standard attachment without special meaning.
10    Attachment,
11    /// A minidump file that creates an error event and is symbolicated. The
12    /// file should start with the `MDMP` magic bytes.
13    #[serde(rename = "event.minidump")]
14    Minidump,
15    /// An Apple crash report file that creates an error event and is symbolicated.
16    #[serde(rename = "event.applecrashreport")]
17    AppleCrashReport,
18    /// An XML file containing UE4 crash meta data. During event ingestion,
19    /// event contexts and extra fields are extracted from this file.
20    #[serde(rename = "unreal.context")]
21    UnrealContext,
22    /// A plain-text log file obtained from UE4 crashes. During event ingestion,
23    /// the last logs are extracted into event breadcrumbs.
24    #[serde(rename = "unreal.logs")]
25    UnrealLogs,
26    /// A custom attachment type with an arbitrary string value.
27    #[serde(untagged)]
28    Custom(String),
29}
30
31impl Default for AttachmentType {
32    fn default() -> Self {
33        Self::Attachment
34    }
35}
36
37impl AttachmentType {
38    /// Gets the string value Sentry expects for the attachment type.
39    pub fn as_str(&self) -> &str {
40        match self {
41            Self::Attachment => "event.attachment",
42            Self::Minidump => "event.minidump",
43            Self::AppleCrashReport => "event.applecrashreport",
44            Self::UnrealContext => "unreal.context",
45            Self::UnrealLogs => "unreal.logs",
46            Self::Custom(s) => s,
47        }
48    }
49}
50
51#[derive(Clone, PartialEq, Default)]
52/// Represents an attachment item.
53pub struct Attachment {
54    /// The actual attachment data.
55    pub buffer: Vec<u8>,
56    /// The filename of the attachment.
57    pub filename: String,
58    /// The Content Type of the attachment
59    pub content_type: Option<String>,
60    /// The special type of this attachment.
61    pub ty: Option<AttachmentType>,
62}
63
64impl Attachment {
65    /// Writes the attachment and its headers to the provided `Writer`.
66    pub fn to_writer<W>(&self, writer: &mut W) -> std::io::Result<()>
67    where
68        W: std::io::Write,
69    {
70        writeln!(
71            writer,
72            r#"{{"type":"attachment","length":{length},"filename":"{filename}","attachment_type":"{at}","content_type":"{ct}"}}"#,
73            filename = self.filename,
74            length = self.buffer.len(),
75            at = self
76                .ty
77                .as_ref()
78                .unwrap_or(&AttachmentType::default())
79                .as_str(),
80            ct = self
81                .content_type
82                .as_ref()
83                .unwrap_or(&"application/octet-stream".to_string())
84        )?;
85
86        writer.write_all(&self.buffer)?;
87        Ok(())
88    }
89}
90
91// Implement Debug manually, otherwise users will be sad when they get a dump
92// of decimal encoded bytes to their console
93impl fmt::Debug for Attachment {
94    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95        f.debug_struct("Attachment")
96            .field("buffer", &self.buffer.len())
97            .field("filename", &self.filename)
98            .field("content_type", &self.content_type)
99            .field("type", &self.ty)
100            .finish()
101    }
102}
103
104#[cfg(test)]
105mod tests {
106    use super::*;
107    use serde_json;
108
109    #[test]
110    fn test_attachment_type_deserialize() {
111        let result: AttachmentType = serde_json::from_str(r#""event.minidump""#).unwrap();
112        assert_eq!(result, AttachmentType::Minidump);
113
114        let result: AttachmentType = serde_json::from_str(r#""my.custom.type""#).unwrap();
115        assert_eq!(result, AttachmentType::Custom("my.custom.type".to_string()));
116    }
117}