-
Notifications
You must be signed in to change notification settings - Fork 115
fix(multipart): Use correct discard reasons #5950
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 6 commits
c055532
d4025f1
1a20b80
aa1370c
6f358f8
eeb45a7
6751950
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,13 +17,12 @@ use serde::Deserialize; | |
|
|
||
| use crate::envelope::{ | ||
| AttachmentPlaceholder, AttachmentType, ContentType, Envelope, EnvelopeError, Item, ItemType, | ||
| ManagedItems, | ||
| Items, | ||
| }; | ||
| use crate::extractors::RequestMeta; | ||
| use crate::managed::{Managed, Rejected}; | ||
| use crate::service::ServiceState; | ||
| use crate::services::buffer::{ProjectKeyPair, PushError}; | ||
| use crate::services::outcome::{DiscardItemType, DiscardReason, Outcome, TrackOutcome}; | ||
| use crate::services::outcome::{DiscardItemType, DiscardReason, Outcome}; | ||
| use crate::services::processor::{BucketSource, MetricData, ProcessMetrics}; | ||
| use crate::services::upload::{Create, Stream, Upload}; | ||
| use crate::statsd::{RelayCounters, RelayDistributions}; | ||
|
|
@@ -125,6 +124,29 @@ pub enum BadStoreRequest { | |
| ObjectstoreUploadFailed, | ||
| } | ||
|
|
||
| impl BadStoreRequest { | ||
| pub fn to_outcome(&self) -> Option<Outcome> { | ||
| let discard_reason = match self { | ||
| Self::InvalidCompressionContainer(_) => DiscardReason::InvalidCompression, | ||
| Self::InvalidMinidump => DiscardReason::InvalidMinidump, | ||
| #[cfg(sentry)] | ||
| Self::InvalidProsperodump => DiscardReason::InvalidProsperodump, | ||
| Self::MissingMinidump => DiscardReason::MissingMinidumpUpload, | ||
| #[cfg(sentry)] | ||
| Self::MissingProsperodump => DiscardReason::MissingProsperodumpUpload, | ||
| Self::Overflow(item_type) => DiscardReason::TooLarge(*item_type), | ||
| _ => DiscardReason::Internal, | ||
| }; | ||
| Some(Outcome::Invalid(discard_reason)) | ||
| } | ||
| } | ||
|
elramen marked this conversation as resolved.
elramen marked this conversation as resolved.
Comment on lines
+127
to
+142
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not a blocker, but converting BadStoreRequest to a DiscardReason seems backward to me. It would be better to make the functions that currently return BadStoreRequest return a DiscardReason instead, and make that to a
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree, and maybe we don't need BadStoreRequest at all. But changing all the functions that return BadStoreRequest seems out of scope for this PR. |
||
|
|
||
| impl From<Rejected<BadStoreRequest>> for BadStoreRequest { | ||
| fn from(rejected: Rejected<BadStoreRequest>) -> Self { | ||
| rejected.into_inner() | ||
| } | ||
| } | ||
|
|
||
| impl From<BytesRejection> for BadStoreRequest { | ||
| fn from(value: BytesRejection) -> Self { | ||
| match value { | ||
|
|
@@ -292,7 +314,7 @@ pub fn event_id_from_formdata(data: &[u8]) -> Result<Option<EventId>, BadStoreRe | |
| /// | ||
| /// Extracting the event id from chunked formdata fields on the Minidump endpoint (`sentry__1`, | ||
| /// `sentry__2`, ...) is not supported. In this case, `None` is returned. | ||
| pub fn event_id_from_items(items: &ManagedItems) -> Result<Option<EventId>, BadStoreRequest> { | ||
| pub fn event_id_from_items(items: &Items) -> Result<Option<EventId>, BadStoreRequest> { | ||
| if let Some(item) = items.iter().find(|item| item.ty() == &ItemType::Event) | ||
| && let Some(event_id) = event_id_from_json(&item.payload())? | ||
| { | ||
|
|
@@ -575,27 +597,6 @@ where | |
| Some(item) | ||
| } | ||
|
|
||
| pub fn managed_items_to_envelope( | ||
| items: ManagedItems, | ||
| meta: RequestMeta, | ||
| outcome_aggregator: &Addr<TrackOutcome>, | ||
| event_id: EventId, | ||
| ) -> Managed<Box<Envelope>> { | ||
| let envelope = Envelope::from_request(Some(event_id), meta); | ||
| let mut envelope = Managed::from_envelope(envelope, outcome_aggregator.clone()); | ||
| let mut has_event = false; | ||
| for item in items { | ||
| envelope.merge_with(item, |envelope, item, records| { | ||
| if !has_event && item.creates_event() { | ||
| records.modify_by(DataCategory::Error, 1); | ||
| has_event = true; | ||
| } | ||
| envelope.add_item(item); | ||
| }); | ||
| } | ||
| envelope | ||
| } | ||
|
|
||
| #[derive(Debug)] | ||
| pub struct TextResponse(pub Option<EventId>); | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -24,7 +24,7 @@ use crate::endpoints::common::{self, BadStoreRequest, TextResponse, upload_to_ob | |||||
| use crate::envelope::ContentType::Minidump; | ||||||
| use crate::envelope::{AttachmentType, Envelope, Item, ItemType}; | ||||||
| use crate::extractors::{RawContentType, RequestMeta}; | ||||||
| use crate::managed::Managed; | ||||||
| use crate::managed::{Managed, ManagedResult}; | ||||||
| use crate::middlewares; | ||||||
| use crate::service::ServiceState; | ||||||
| use crate::services::outcome::{DiscardAttachmentType, DiscardItemType, DiscardReason, Outcome}; | ||||||
|
|
@@ -119,9 +119,8 @@ fn decode_minidump(minidump_data: Bytes, max_size: usize) -> Result<Bytes, BadSt | |||||
| match run_decoder(decoder) { | ||||||
| Ok(decoded) => { | ||||||
| if decoded.len() > max_size { | ||||||
| return Err(BadStoreRequest::Overflow(DiscardItemType::Attachment( | ||||||
| DiscardAttachmentType::Minidump, | ||||||
| ))); | ||||||
| let item_type = DiscardItemType::Attachment(DiscardAttachmentType::Minidump); | ||||||
| return Err(BadStoreRequest::Overflow(item_type)); | ||||||
|
elramen marked this conversation as resolved.
|
||||||
| } | ||||||
| Ok(Bytes::from(decoded)) | ||||||
| } | ||||||
|
|
@@ -280,36 +279,37 @@ async fn multipart_to_envelope( | |||||
| ) | ||||||
| .await?; | ||||||
|
|
||||||
| let minidump_item = items | ||||||
| .iter_mut() | ||||||
| .find(|item| item.attachment_type() == Some(AttachmentType::Minidump)) | ||||||
| .ok_or(BadStoreRequest::MissingMinidump)?; | ||||||
| let minidump_idx = items | ||||||
| .iter() | ||||||
| .position(|item| item.attachment_type() == Some(AttachmentType::Minidump)) | ||||||
| .ok_or(BadStoreRequest::MissingMinidump) | ||||||
| .reject(&items)?; | ||||||
|
|
||||||
| // Doing these operations does not make sense if we already streamed the minidump to objectstore. | ||||||
| if !minidump_item.is_attachment_ref() { | ||||||
| let payload = minidump_item.payload(); | ||||||
| if !items[minidump_idx].is_attachment_ref() { | ||||||
|
elramen marked this conversation as resolved.
|
||||||
| let payload = items[minidump_idx].payload(); | ||||||
| let payload = extract_embedded_minidump(payload.clone()) | ||||||
| .await? | ||||||
| .unwrap_or(payload); | ||||||
| let payload = decode_minidump(payload, config.max_attachment_size())?; | ||||||
| let payload = decode_minidump(payload, config.max_attachment_size()).reject(&items)?; | ||||||
|
|
||||||
| minidump_item.modify(|inner, records| { | ||||||
| inner.set_payload(Minidump, payload); | ||||||
| records.lenient(DataCategory::Attachment); | ||||||
| }); | ||||||
|
|
||||||
| validate_minidump(&minidump_item.payload())?; | ||||||
| validate_minidump(&payload).reject(&items)?; | ||||||
|
|
||||||
| minidump_item.modify(|inner, _| { | ||||||
| if let Some(minidump_filename) = inner.filename() { | ||||||
| inner.set_filename(remove_container_extension(minidump_filename).to_owned()) | ||||||
| items.modify(|items, records| { | ||||||
| let minidump_item = &mut items[minidump_idx]; | ||||||
| minidump_item.set_payload(Minidump, payload); | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not related to this PR, but I noticed it: we always qualify enum variants:
Suggested change
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm confused, is qualifying something we should or shouldn't do?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Our convention is to always use the qualified path, that is |
||||||
| records.lenient(DataCategory::Attachment); // decoding the minidump changes its size | ||||||
| if let Some(minidump_filename) = minidump_item.filename() { | ||||||
| minidump_item.set_filename(remove_container_extension(minidump_filename).to_owned()) | ||||||
| } | ||||||
| }); | ||||||
| } | ||||||
|
|
||||||
| let event_id = common::event_id_from_items(&items)?.unwrap_or_else(EventId::new); | ||||||
| let envelope = | ||||||
| common::managed_items_to_envelope(items, meta, state.outcome_aggregator(), event_id); | ||||||
| let envelope = items.map(|items, records| { | ||||||
| records.modify_by(DataCategory::Error, 1); | ||||||
| Box::new(Envelope::from_request(Some(event_id), meta).with_items(items)) | ||||||
| }); | ||||||
| Ok(envelope) | ||||||
| } | ||||||
|
|
||||||
|
|
@@ -396,7 +396,6 @@ async fn raw_minidump_to_envelope( | |||||
| item.set_filename(MINIDUMP_FILE_NAME); | ||||||
| item.set_attachment_type(AttachmentType::Minidump); | ||||||
| let mut item = Managed::with_meta_from_request_meta(&meta, state.outcome_aggregator(), item); | ||||||
|
|
||||||
| if let Some(upload_context) = upload_context | ||||||
| && matches!(upload_context.upload_minidumps, UploadDecision::Upload) | ||||||
| { | ||||||
|
|
@@ -415,20 +414,19 @@ async fn raw_minidump_to_envelope( | |||||
| let decoded_payload = decode_minidump( | ||||||
| request.extract().await?, | ||||||
| state.config().max_attachment_size(), | ||||||
| )?; | ||||||
| ) | ||||||
| .reject(&item)?; | ||||||
| validate_minidump(&decoded_payload).reject(&item)?; | ||||||
| item.modify(|inner, records| { | ||||||
| inner.set_payload(Minidump, decoded_payload); | ||||||
| records.lenient(DataCategory::Attachment); // decoding the minidump changes its size | ||||||
| }); | ||||||
| validate_minidump(&item.payload())?; | ||||||
|
elramen marked this conversation as resolved.
|
||||||
| }; | ||||||
|
|
||||||
| // Create an envelope with a random event id. | ||||||
| let envelope = Envelope::from_request(Some(EventId::new()), meta); | ||||||
| let mut envelope = Managed::from_envelope(envelope, state.outcome_aggregator().clone()); | ||||||
| envelope.merge_with(item, |envelope, item, records| { | ||||||
| let envelope = item.map(|item, records| { | ||||||
| records.modify_by(DataCategory::Error, 1); | ||||||
| envelope.add_item(item); | ||||||
| Box::new(Envelope::from_request(Some(EventId::new()), meta).with_items(vec![item])) | ||||||
| }); | ||||||
| Ok(envelope) | ||||||
| } | ||||||
|
|
||||||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Steered away from a common envelope-creation function because of the complexity of keeping records correct in all cases. Opened #5949 to address this