diff --git a/lib/src/protocol/kawa_h1/answers.rs b/lib/src/protocol/kawa_h1/answers.rs
index f589a972a..3c7318f61 100644
--- a/lib/src/protocol/kawa_h1/answers.rs
+++ b/lib/src/protocol/kawa_h1/answers.rs
@@ -369,12 +369,38 @@ Sozu-Id: %REQUEST_ID\r
{
\"route\": \"%ROUTE\",
\"request_id\": \"%REQUEST_ID\",
+ \"parsing_phase\": \"%PHASE\",
+ \"successfully_parsed\": %SUCCESSFULLY_PARSED,
+ \"partially_parsed\": %PARTIALLY_PARSED,
+ \"invalid\": %INVALID,
+
}
-
Request could not be parsed. Parser stopped at phase: %PHASE.
-Diagnostic: %MESSAGE
-Further details:
-%DETAILS
+Request could not be parsed.
+%MESSAGE
+
+
While parsing %PHASE, this was reported as invalid:
+
+
+
+
+
",
)
}
@@ -480,12 +506,38 @@ Sozu-Id: %REQUEST_ID\r
\"request_id\": \"%REQUEST_ID\",
\"cluster_id\": \"%CLUSTER_ID\",
\"backend_id\": \"%BACKEND_ID\",
+ \"parsing_phase\": \"%PHASE\",
+ \"successfully_parsed\": \"%SUCCESSFULLY_PARSED\",
+ \"partially_parsed\": \"%PARTIALLY_PARSED\",
+ \"invalid\": \"%INVALID\",
+
}
-Response could not be parsed. Parser stopped at phase: %PHASE.
-Diagnostic: %MESSAGE
-Further details:
-%DETAILS
+Response could not be parsed.
+%MESSAGE
+
+
While parsing %PHASE, this was reported as invalid:
+
+
+
+
+
",
)
}
@@ -641,11 +693,23 @@ impl HttpAnswers {
valid_in_header: false,
typ: ReplacementType::VariableOnce(0),
};
- let details = TemplateVariable {
- name: "DETAILS",
+ let successfully_parsed = TemplateVariable {
+ name: "SUCCESSFULLY_PARSED",
valid_in_body: true,
valid_in_header: false,
- typ: ReplacementType::VariableOnce(0),
+ typ: ReplacementType::Variable(0),
+ };
+ let partially_parsed = TemplateVariable {
+ name: "PARTIALLY_PARSED",
+ valid_in_body: true,
+ valid_in_header: false,
+ typ: ReplacementType::Variable(0),
+ };
+ let invalid = TemplateVariable {
+ name: "INVALID",
+ valid_in_body: true,
+ valid_in_header: false,
+ typ: ReplacementType::Variable(0),
};
match status {
@@ -657,7 +721,7 @@ impl HttpAnswers {
400 => Template::new(
400,
answer,
- &[length, route, request_id, message, phase, details],
+ &[length, route, request_id, message, phase, successfully_parsed, partially_parsed, invalid],
),
401 => Template::new(
401,
@@ -682,7 +746,7 @@ impl HttpAnswers {
502 => Template::new(
502,
answer,
- &[length, route, request_id, cluster_id, backend_id, message, phase, details],
+ &[length, route, request_id, cluster_id, backend_id, message, phase, successfully_parsed, partially_parsed, invalid],
),
503 => Template::new(
503,
@@ -806,10 +870,19 @@ impl HttpAnswers {
DefaultAnswer::Answer400 {
message,
phase,
- details,
+ successfully_parsed,
+ partially_parsed,
+ invalid,
} => {
- variables = vec![route.into(), request_id.into(), phase_to_vec(phase)];
- variables_once = vec![message.into(), details.into()];
+ variables = vec![
+ route.into(),
+ request_id.into(),
+ phase_to_vec(phase),
+ successfully_parsed.into(),
+ partially_parsed.into(),
+ invalid.into(),
+ ];
+ variables_once = vec![message.into()];
&self.listener_answers.answer_400
}
DefaultAnswer::Answer401 {} => {
@@ -844,7 +917,9 @@ impl HttpAnswers {
DefaultAnswer::Answer502 {
message,
phase,
- details,
+ successfully_parsed,
+ partially_parsed,
+ invalid,
} => {
variables = vec![
route.into(),
@@ -852,8 +927,11 @@ impl HttpAnswers {
cluster_id.unwrap_or_default().into(),
backend_id.unwrap_or_default().into(),
phase_to_vec(phase),
+ successfully_parsed.into(),
+ partially_parsed.into(),
+ invalid.into(),
];
- variables_once = vec![message.into(), details.into()];
+ variables_once = vec![message.into()];
&self.listener_answers.answer_502
}
DefaultAnswer::Answer503 { message } => {
diff --git a/lib/src/protocol/kawa_h1/diagnostics.rs b/lib/src/protocol/kawa_h1/diagnostics.rs
index be9fcd431..2408cf30c 100644
--- a/lib/src/protocol/kawa_h1/diagnostics.rs
+++ b/lib/src/protocol/kawa_h1/diagnostics.rs
@@ -9,7 +9,7 @@ const CHARSET: &str = "all characters are LATIN-1 (no UTF-8 allowed)";
#[cfg(not(feature = "tolerant-http1-parser"))]
const CHARSET: &str = "all characters are UASCII (no UTF-8 allowed)";
-fn hex_dump(buffer: &[u8], window: usize, start: usize, end: usize) -> String {
+fn hex_and_ascii_dump(buffer: &[u8], window: usize, start: usize, end: usize) -> String {
let mut result = String::with_capacity(window * 4 * 2 + 10);
if end - start <= window {
let slice = &buffer[start..end];
@@ -36,11 +36,41 @@ fn hex_dump(buffer: &[u8], window: usize, start: usize, end: usize) -> String {
result
}
+fn hex_dump(buffer: &[u8], window: usize, start: usize, end: usize) -> String {
+ let mut result = String::with_capacity(window * 3 + 10);
+ result.push('\"');
+ if end - start <= window {
+ let slice = &buffer[start..end];
+ for (i, c) in slice.iter().enumerate() {
+ let _ = write!(result, "{c:02x}");
+ if i < slice.len() - 1 {
+ result.push(' ');
+ }
+ }
+ } else {
+ let half = window / 2;
+ let slice1 = &buffer[start..start + half - 1];
+ let slice2 = &buffer[end - half + 1..end];
+ for c in slice1 {
+ let _ = write!(result, "{c:02x} ");
+ }
+ result.push_str("... ");
+ for (i, c) in slice2.iter().enumerate() {
+ let _ = write!(result, "{c:02x}");
+ if i < slice2.len() - 1 {
+ result.push(' ');
+ }
+ }
+ }
+ result.push('\"');
+ result
+}
+
pub fn diagnostic_400_502(
marker: ParsingPhaseMarker,
kind: ParsingErrorKind,
kawa: &GenericHttpStream,
-) -> (String, String) {
+) -> (String, String, String, String) {
match kind {
ParsingErrorKind::Consuming { index } => {
let message = match marker {
@@ -55,52 +85,47 @@ pub fn diagnostic_400_502(
} else {
"trailer"
};
- if let Some(Block::Header(Pair { key, .. })) = kawa.blocks.back() {
- format!(
- "A {marker} is invalid, make sure {CHARSET}. Last valid {marker} is: {:?}.",
- String::from_utf8_lossy(key.data(kawa.storage.buffer())),
- )
- } else {
- format!("The first {marker} is invalid, make sure {CHARSET}.")
- }
+ format!("A {marker} is invalid, make sure {CHARSET}.")
+ // if let Some(Block::Header(Pair { key, .. })) = kawa.blocks.back() {
+ // format!(
+ // "A {marker} is invalid, make sure {CHARSET}. Last valid {marker} is: {:?}.",
+ // String::from_utf8_lossy(key.data(kawa.storage.buffer())),
+ // )
+ // } else {
+ // format!("The first {marker} is invalid, make sure {CHARSET}.")
+ // }
}
ParsingPhaseMarker::Cookies => {
- if kawa.detached.jar.len() > 1 {
- let Pair { key, .. } = &kawa.detached.jar[kawa.detached.jar.len() - 2];
- format!(
- "A cookie is invalid, make sure {CHARSET}. Last valid cookie is: {:?}.",
- String::from_utf8_lossy(key.data(kawa.storage.buffer())),
- )
- } else {
- format!("The first cookie is invalid, make sure {CHARSET}.")
- }
+ // if kawa.detached.jar.len() > 1 {
+ // let Pair { key, .. } = &kawa.detached.jar[kawa.detached.jar.len() - 2];
+ // format!(
+ // "A cookie is invalid, make sure {CHARSET}. Last valid cookie is: {:?}.",
+ // String::from_utf8_lossy(key.data(kawa.storage.buffer())),
+ // )
+ // } else {
+ // format!("The first cookie is invalid, make sure {CHARSET}.")
+ // }
+ format!("A cookie is invalid, make sure {CHARSET}.")
}
ParsingPhaseMarker::Body
| ParsingPhaseMarker::Chunks
| ParsingPhaseMarker::Terminated
| ParsingPhaseMarker::Error => {
- format!("Parsing phase {marker:?} should not produce 400 error.")
+ format!("The parser stopped in an unexpected phase.")
+ // format!("Parsing phase {marker:?} should not produce 400 error.")
}
};
let buffer = kawa.storage.buffer();
- let details = format!(
- "\
-Parsed successfully:
-{}
-Partially parsed (valid):
-{}
-Invalid:
-{}",
- hex_dump(buffer, 32, kawa.storage.start, kawa.storage.head),
- hex_dump(buffer, 32, kawa.storage.head, index as usize),
- hex_dump(buffer, 32, index as usize, kawa.storage.end),
- );
- (message, details)
+ let successfully_parsed = hex_dump(buffer, 32, kawa.storage.start, kawa.storage.head);
+ let partially_parsed = hex_dump(buffer, 32, kawa.storage.head, index as usize);
+ let invalid = hex_dump(buffer, 32, index as usize, kawa.storage.end);
+ (message, successfully_parsed, partially_parsed, invalid)
}
ParsingErrorKind::Processing { message } => (
- "The request was successfully parsed but presents inconsistent or invalid values."
- .into(),
- message.to_owned(),
+ format!("The request was successfully parsed but presents inconsistent or invalid values: {message}"),
+ String::from("null"),
+ String::from("null"),
+ String::from("null"),
),
}
}
diff --git a/lib/src/protocol/kawa_h1/mod.rs b/lib/src/protocol/kawa_h1/mod.rs
index 797981776..6be38f579 100644
--- a/lib/src/protocol/kawa_h1/mod.rs
+++ b/lib/src/protocol/kawa_h1/mod.rs
@@ -81,7 +81,9 @@ pub enum DefaultAnswer {
Answer400 {
message: String,
phase: kawa::ParsingPhaseMarker,
- details: String,
+ successfully_parsed: String,
+ partially_parsed: String,
+ invalid: String,
},
Answer401 {},
Answer404 {},
@@ -96,7 +98,9 @@ pub enum DefaultAnswer {
Answer502 {
message: String,
phase: kawa::ParsingPhaseMarker,
- details: String,
+ successfully_parsed: String,
+ partially_parsed: String,
+ invalid: String,
},
Answer503 {
message: String,
@@ -445,11 +449,14 @@ impl Http Http Http tuple,
Err(cluster_error) => {
self.set_answer(DefaultAnswer::Answer400 {
- phase: self.request_stream.parsing_phase.marker(),
- details: cluster_error.to_string(),
message: "Could not extract the route after connection started, this should not happen.".into(),
+ phase: self.request_stream.parsing_phase.marker(),
+ successfully_parsed: String::from("null"),
+ partially_parsed: String::from("null"),
+ invalid: String::from("null"),
});
return Err(cluster_error);
}