/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
//! Support for crash report creation and upload. //! //! Upload currently uses the system libcurl or curl binary rather than a rust network stack (as //! curl is more mature, albeit the code to interact with it must be a bit more careful).
#[cfg(mock)]
mock_key! { /// The outer Result is for CrashReport::send(), the inner is for CrashReporterSender::finish(). pubstruct MockReport => Box<dynFn(&CrashReport) -> std::io::Result<std::io::Result<String>> + Send + Sync>
}
/// A crash report to upload. /// /// Post a multipart form payload to the report URL. /// /// The form data contains: /// | name | filename | content | mime | /// ==================================== /// | `extra` | `extra.json` | extra json object | `application/json`| /// | `upload_file_minidump` | dump file name | dump file contents | derived (probably application/binary) | /// if present: /// | `memory_report` | memory file name | memory file contents | derived (probably gzipped json) | pubstruct CrashReport<'a> { pub extra: &'a serde_json::Value, pub dump_file: &'a Path, pub memory_file: Option<&'a Path>, pub url: &'a str,
}
let extra_json_data; if request.is_none() { letmut extra = self.extra.clone(); // Bug 2021130: If ProcessType is main (it always should be, because we only send // reports for main process crashes), remove the annotation. Socorro expects main // processes to not have the ProcessType annotation. // // This is mostly a workaround; ideally Socorro would change to accept a ProcessType of // "main" (see bug 2021204). if extra["ProcessType"].as_str() == Some("main") {
extra.as_object_mut().unwrap().remove("ProcessType");
}
extra_json_data = serde_json::to_string(&extra)?;
request = Some(http::RequestBuilder::MimePost { parts }.build(self.url)?);
}
let response = request.unwrap().send()?; let response = String::from_utf8_lossy(&response).into_owned();
log::debug!("received response from sending report: {:?}", &*response);
Ok(Response::parse(response))
}
}
/// A parsed response from submitting a crash report. #[derive(Default, Debug)] pubstruct Response { pub crash_id: Option<String>, pub stop_sending_reports_for: Option<String>, pub view_url: Option<String>, pub discarded: bool,
}
impl Response { /// Parse a server response. /// /// The response should be newline-separated `<key>=<value>` pairs. fn parse<S: AsRef<str>>(response: S) -> Self { letmut ret = Self::default(); // Fields may be omitted, and parsing is best-effort but will not produce any errors (just // a default Response struct). for line in response.as_ref().lines() { iflet Some((key, value)) = line.split_once('=') { match key { "StopSendingReportsFor" => {
ret.stop_sending_reports_for = Some(value.to_owned())
} "Discarded" => ret.discarded = true, "CrashID" => ret.crash_id = Some(value.to_owned()), "ViewURL" => ret.view_url = Some(value.to_owned()),
_ => (),
}
}
}
ret
}
}
#[cfg(test)] mod test { usesuper::*; usecrate::std::mock;
#[test] fn report_http() { for memory_file in [None, Some(Path::new("minidump.memory.gz"))] { let report = CrashReport {
extra: &serde_json::json! {{ "Foo": "Bar"
}},
dump_file: Path::new("minidump.dmp"),
memory_file,
url: "reports.example.com".as_ref(),
};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.