I'm trying to parse this JSON CSP Record being submitted via POST
directly by the browser into a nested struct:
{"csp-report":{"document-uri":"http://localhost:8000/demo/","referrer":"","violated-directive":"img-src","effective-directive":"img-src","original-policy":"default-src 'self'; report-uri /.well-known/csp-violation","disposition":"report","blocked-uri":"https://www.google.com/logos/doodles/2020/googles-22nd-birthday-6753651837108550-law.gif","line-number":47,"source-file":"http://localhost:8000/demo/","status-code":200,"script-sample":""}}
The following headers are sent:
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7
Cache-Control: no-cache
Connection: keep-alive
Content-Length: 442
Content-Type: application/csp-report
Host: localhost:8000
Origin: http://localhost:8000
Pragma: no-cache
Referer: http://localhost:8000/demo/
Sec-Fetch-Dest: report
Sec-Fetch-Mode: no-cors
Sec-Fetch-Site: same-origin
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36
I followed the Rocket JSON data guide, but the request generates an Unprocessable Entity (422)
and I don't know why.
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "kebab-case")]
#[serde(deny_unknown_fields)]
struct Report {
#[serde(with = "serde_with::json::nested")]
csp_report: ReportBody,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "kebab-case")]
#[serde(deny_unknown_fields)]
struct ReportBody {
blocked_uri: String,
disposition: String,
document_uri: String,
effective_directive: String,
line_number: u128,
original_policy: String,
referrer: String,
script_sample: String,
source_file: String,
status_code: u16,
violated_directive: String,
}
#[post(
"/.well-known/csp-violation",
format = "application/csp-report",
data = "<_report>"
)]
fn record(_report: Json<Report>) -> Status {
Status::NoContent
}
fn main() {
rocket::ignite().mount("/", routes![record]).launch();
}
My guess is that it's due to the header Content-Type: application/csp-report
which I can't change, because the browser sends the report automatically.
JSON from rocket_contrib is a convenience, but not essential. You can still parse the JSON yourself from the raw body data with serde (following example is done with async Rocket). This may bypass any issues with headers: