Decode a SQL-literal payload or pass through a bare payload. If the input is single-quoted, strip the outer quotes and unescape doubled quotes (`''` → `'`) per SQL string-literal rules. Reject unterminated quotes rather than silently treating them as bare payloads.
(input: &str)
| 107 | /// quotes (`''` → `'`) per SQL string-literal rules. Reject unterminated |
| 108 | /// quotes rather than silently treating them as bare payloads. |
| 109 | fn parse_payload(input: &str) -> crate::Result<String> { |
| 110 | if input.is_empty() { |
| 111 | return Err(crate::Error::BadRequest { |
| 112 | detail: "PUBLISH TO payload is empty".into(), |
| 113 | }); |
| 114 | } |
| 115 | if !input.starts_with('\'') { |
| 116 | return Ok(input.to_string()); |
| 117 | } |
| 118 | let bytes = input.as_bytes(); |
| 119 | let mut out = String::with_capacity(input.len()); |
| 120 | let mut i = 1; |
| 121 | while i < bytes.len() { |
| 122 | if bytes[i] == b'\'' { |
| 123 | if i + 1 < bytes.len() && bytes[i + 1] == b'\'' { |
| 124 | out.push('\''); |
| 125 | i += 2; |
| 126 | continue; |
| 127 | } |
| 128 | if i + 1 != bytes.len() { |
| 129 | return Err(crate::Error::BadRequest { |
| 130 | detail: "PUBLISH TO payload has trailing tokens after closing quote".into(), |
| 131 | }); |
| 132 | } |
| 133 | return Ok(out); |
| 134 | } |
| 135 | out.push(bytes[i] as char); |
| 136 | i += 1; |
| 137 | } |
| 138 | Err(crate::Error::BadRequest { |
| 139 | detail: "PUBLISH TO payload has unterminated string literal".into(), |
| 140 | }) |
| 141 | } |
| 142 | |
| 143 | #[cfg(test)] |
| 144 | mod tests { |