1use std::collections::HashMap;
49
50use base64::Engine as _;
51use prost::Message;
52use serde_json::Value;
53
54#[derive(Debug)]
60pub enum GrpcWebError {
61 MalformedFrame(String),
63 Descriptor(String),
65 MethodNotFound(String),
67 Transcoding(String),
69}
70
71impl std::fmt::Display for GrpcWebError {
72 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
73 match self {
74 GrpcWebError::MalformedFrame(m) => {
75 write!(f, "malformed grpc-web frame: {m}")
76 }
77 GrpcWebError::Descriptor(m) => write!(f, "descriptor error: {m}"),
78 GrpcWebError::MethodNotFound(m) => {
79 write!(f, "method not found in descriptors: {m}")
80 }
81 GrpcWebError::Transcoding(m) => write!(f, "transcoding error: {m}"),
82 }
83 }
84}
85
86impl std::error::Error for GrpcWebError {}
87
88#[derive(Clone, PartialEq, Message)]
104pub struct FileDescriptorSet {
105 #[prost(message, repeated, tag = "1")]
106 pub file: Vec<FileDescriptorProto>,
107}
108
109#[derive(Clone, PartialEq, Message)]
111pub struct FileDescriptorProto {
112 #[prost(string, optional, tag = "1")]
113 pub name: Option<String>,
114 #[prost(string, optional, tag = "2")]
115 pub package: Option<String>,
116 #[prost(message, repeated, tag = "4")]
117 pub message_type: Vec<DescriptorProto>,
118 #[prost(message, repeated, tag = "6")]
119 pub service: Vec<ServiceDescriptorProto>,
120}
121
122#[derive(Clone, PartialEq, Message)]
124pub struct DescriptorProto {
125 #[prost(string, optional, tag = "1")]
126 pub name: Option<String>,
127 #[prost(message, repeated, tag = "2")]
128 pub field: Vec<FieldDescriptorProto>,
129 #[prost(message, repeated, tag = "3")]
130 pub nested_type: Vec<DescriptorProto>,
131 #[prost(message, repeated, tag = "4")]
132 pub enum_type: Vec<EnumDescriptorProto>,
133}
134
135#[derive(Clone, PartialEq, Message)]
137pub struct ServiceDescriptorProto {
138 #[prost(string, optional, tag = "1")]
139 pub name: Option<String>,
140 #[prost(message, repeated, tag = "2")]
141 pub method: Vec<MethodDescriptorProto>,
142}
143
144#[derive(Clone, PartialEq, Message)]
146pub struct MethodDescriptorProto {
147 #[prost(string, optional, tag = "1")]
148 pub name: Option<String>,
149 #[prost(string, optional, tag = "2")]
150 pub input_type: Option<String>,
151 #[prost(string, optional, tag = "3")]
152 pub output_type: Option<String>,
153}
154
155#[derive(Clone, PartialEq, Message)]
157pub struct FieldDescriptorProto {
158 #[prost(string, optional, tag = "1")]
159 pub name: Option<String>,
160 #[prost(string, optional, tag = "10")]
161 pub json_name: Option<String>,
162 #[prost(int32, optional, tag = "3")]
163 pub number: Option<i32>,
164 #[prost(enumeration = "field_label::Label", optional, tag = "4")]
165 pub label: Option<i32>,
166 #[prost(enumeration = "field_type::Type", optional, tag = "5")]
167 pub r#type: Option<i32>,
168 #[prost(string, optional, tag = "6")]
169 pub type_name: Option<String>,
170}
171
172#[derive(Clone, PartialEq, Message)]
174pub struct EnumDescriptorProto {
175 #[prost(string, optional, tag = "1")]
176 pub name: Option<String>,
177 #[prost(message, repeated, tag = "2")]
178 pub value: Vec<EnumValueDescriptorProto>,
179}
180
181#[derive(Clone, PartialEq, Message)]
183pub struct EnumValueDescriptorProto {
184 #[prost(string, optional, tag = "1")]
185 pub name: Option<String>,
186 #[prost(int32, optional, tag = "2")]
187 pub number: Option<i32>,
188}
189
190pub mod field_label {
192 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, prost::Enumeration)]
193 #[repr(i32)]
194 pub enum Label {
195 Optional = 1,
196 Required = 2,
197 Repeated = 3,
198 }
199 pub const OPTIONAL: i32 = 1;
200 pub const REQUIRED: i32 = 2;
201 pub const REPEATED: i32 = 3;
202}
203
204pub mod field_type {
206 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, prost::Enumeration)]
207 #[repr(i32)]
208 pub enum Type {
209 Double = 1,
210 Float = 2,
211 Int64 = 3,
212 Uint64 = 4,
213 Int32 = 5,
214 Fixed64 = 6,
215 Fixed32 = 7,
216 Bool = 8,
217 String = 9,
218 Message = 11,
219 Bytes = 12,
220 Uint32 = 13,
221 Enum = 14,
222 Sfixed32 = 15,
223 Sfixed64 = 16,
224 Sint32 = 17,
225 Sint64 = 18,
226 }
227 pub const DOUBLE: i32 = 1;
228 pub const FLOAT: i32 = 2;
229 pub const INT64: i32 = 3;
230 pub const UINT64: i32 = 4;
231 pub const INT32: i32 = 5;
232 pub const FIXED64: i32 = 6;
233 pub const FIXED32: i32 = 7;
234 pub const BOOL: i32 = 8;
235 pub const STRING: i32 = 9;
236 pub const MESSAGE: i32 = 11;
237 pub const BYTES: i32 = 12;
238 pub const UINT32: i32 = 13;
239 pub const ENUM: i32 = 14;
240 pub const SFIXED32: i32 = 15;
241 pub const SFIXED64: i32 = 16;
242 pub const SINT32: i32 = 17;
243 pub const SINT64: i32 = 18;
244}
245
246const FLAG_DATA: u8 = 0x00;
253const FLAG_TRAILER: u8 = 0x80;
254
255const FRAME_PREFIX_LEN: usize = 5;
258
259pub fn translate_grpc_web_to_grpc(body: &[u8]) -> Result<Vec<u8>, GrpcWebError> {
273 let mut out = Vec::with_capacity(body.len());
274 let mut pos = 0;
275 while pos < body.len() {
276 if pos + FRAME_PREFIX_LEN > body.len() {
277 return Err(GrpcWebError::MalformedFrame(format!(
278 "truncated frame header at offset {pos}"
279 )));
280 }
281 let flag = body[pos];
282 let len = u32::from_be_bytes([body[pos + 1], body[pos + 2], body[pos + 3], body[pos + 4]])
283 as usize;
284 let data_start = pos + FRAME_PREFIX_LEN;
285 let data_end = data_start + len;
286 if data_end > body.len() {
287 return Err(GrpcWebError::MalformedFrame(format!(
288 "frame length {len} exceeds remaining body at offset {pos}"
289 )));
290 }
291 match flag {
292 FLAG_DATA => {
293 out.extend_from_slice(&body[data_start..data_end]);
294 }
295 FLAG_TRAILER => {
296 return Err(GrpcWebError::MalformedFrame(
300 "unexpected trailer frame in request body".to_string(),
301 ));
302 }
303 _ => {
304 return Err(GrpcWebError::MalformedFrame(format!(
305 "unknown frame flag 0x{flag:02x} at offset {pos}"
306 )));
307 }
308 }
309 pos = data_end;
310 }
311 Ok(out)
312}
313
314pub fn translate_grpc_to_grpc_web(body: &[u8], trailers: &[u8]) -> Vec<u8> {
328 let mut out = Vec::with_capacity(body.len() + trailers.len() + FRAME_PREFIX_LEN * 2);
329 out.push(FLAG_DATA);
331 out.extend_from_slice(&(body.len() as u32).to_be_bytes());
332 out.extend_from_slice(body);
333 out.push(FLAG_TRAILER);
335 out.extend_from_slice(&(trailers.len() as u32).to_be_bytes());
336 out.extend_from_slice(trailers);
337 out
338}
339
340pub fn translate_grpc_to_grpc_web_data_chunk(chunk: &[u8]) -> Vec<u8> {
345 let mut out = Vec::with_capacity(chunk.len() + FRAME_PREFIX_LEN);
346 out.push(FLAG_DATA);
347 out.extend_from_slice(&(chunk.len() as u32).to_be_bytes());
348 out.extend_from_slice(chunk);
349 out
350}
351
352pub fn translate_grpc_trailers_to_grpc_web(trailers: &[u8]) -> Vec<u8> {
355 let mut out = Vec::with_capacity(trailers.len() + FRAME_PREFIX_LEN);
356 out.push(FLAG_TRAILER);
357 out.extend_from_slice(&(trailers.len() as u32).to_be_bytes());
358 out.extend_from_slice(trailers);
359 out
360}
361
362pub fn parse_trailers(trailer_bytes: &[u8]) -> HashMap<String, String> {
365 let text = String::from_utf8_lossy(trailer_bytes);
366 let mut map = HashMap::new();
367 for line in text.lines() {
368 if let Some((key, value)) = line.split_once(':') {
369 map.insert(key.trim().to_string(), value.trim().to_string());
370 }
371 }
372 map
373}
374
375pub fn build_trailers(trailers: &HashMap<String, String>) -> Vec<u8> {
378 let mut out = String::new();
379 for (key, value) in trailers {
380 out.push_str(key);
381 out.push_str(": ");
382 out.push_str(value);
383 out.push('\n');
384 }
385 out.into_bytes()
386}
387
388#[derive(Debug, Clone)]
396pub struct LoadedDescriptor {
397 pub bytes: Vec<u8>,
400 pub package: String,
402 pub service: String,
404}
405
406#[derive(Debug, Clone)]
409pub struct MethodInfo {
410 pub full_path: String,
412 pub request_type: String,
414 pub response_type: String,
416}
417
418pub struct GrpcTranscoder {
429 methods: HashMap<String, MethodInfo>,
431 descriptors: Vec<LoadedDescriptor>,
433}
434
435impl std::fmt::Debug for GrpcTranscoder {
436 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
437 f.debug_struct("GrpcTranscoder")
438 .field("methods", &self.methods)
439 .field("descriptor_count", &self.descriptors.len())
440 .finish()
441 }
442}
443
444impl GrpcTranscoder {
445 pub fn from_descriptors(descriptors: Vec<LoadedDescriptor>) -> Result<Self, GrpcWebError> {
449 let mut methods = HashMap::new();
450 for desc in &descriptors {
451 let fds = FileDescriptorSet::decode(&desc.bytes[..]).map_err(|e| {
452 GrpcWebError::Descriptor(format!(
453 "failed to decode FileDescriptorSet for {}/{}: {e}",
454 desc.package, desc.service
455 ))
456 })?;
457 for fd in &fds.file {
458 let pkg = fd.package.as_deref().unwrap_or("");
459 if pkg != desc.package {
460 continue;
461 }
462 for svc in &fd.service {
463 if svc.name.as_deref() != Some(desc.service.as_str()) {
464 continue;
465 }
466 for method in &svc.method {
467 let m_name = method.name.as_deref().unwrap_or("");
468 let full_path =
469 format!("/{}.{}{}{}", desc.package, desc.service, "/", m_name);
470 let request_type = method.input_type.clone().unwrap_or_default();
471 let response_type = method.output_type.clone().unwrap_or_default();
472 methods.insert(
473 full_path.clone(),
474 MethodInfo {
475 full_path,
476 request_type,
477 response_type,
478 },
479 );
480 }
481 }
482 }
483 }
484 Ok(GrpcTranscoder {
485 methods,
486 descriptors,
487 })
488 }
489
490 pub fn method(&self, full_path: &str) -> Option<&MethodInfo> {
493 self.methods.get(full_path)
494 }
495
496 pub fn method_count(&self) -> usize {
498 self.methods.len()
499 }
500
501 pub fn json_to_grpc(&self, method: &str, json: &Value) -> Result<Vec<u8>, GrpcWebError> {
506 let info = self
507 .methods
508 .get(method)
509 .ok_or_else(|| GrpcWebError::MethodNotFound(method.to_string()))?;
510 let fds = self.descriptor_set()?;
511 let msg_desc = resolve_message(&fds, &info.request_type).ok_or_else(|| {
512 GrpcWebError::Descriptor(format!(
513 "request message type {} not found in descriptors",
514 info.request_type
515 ))
516 })?;
517 encode_json_to_proto(json, &msg_desc, &fds).map_err(GrpcWebError::Transcoding)
518 }
519
520 pub fn grpc_to_json(&self, method: &str, proto_bytes: &[u8]) -> Result<Value, GrpcWebError> {
524 let info = self
525 .methods
526 .get(method)
527 .ok_or_else(|| GrpcWebError::MethodNotFound(method.to_string()))?;
528 let fds = self.descriptor_set()?;
529 let msg_desc = resolve_message(&fds, &info.response_type).ok_or_else(|| {
530 GrpcWebError::Descriptor(format!(
531 "response message type {} not found in descriptors",
532 info.response_type
533 ))
534 })?;
535 decode_proto_to_json(proto_bytes, &msg_desc, &fds).map_err(GrpcWebError::Transcoding)
536 }
537
538 fn descriptor_set(&self) -> Result<FileDescriptorSet, GrpcWebError> {
541 let mut all_files = Vec::new();
542 for desc in &self.descriptors {
543 let fds = FileDescriptorSet::decode(&desc.bytes[..]).map_err(|e| {
544 GrpcWebError::Descriptor(format!("failed to decode FileDescriptorSet: {e}"))
545 })?;
546 all_files.extend(fds.file);
547 }
548 Ok(FileDescriptorSet { file: all_files })
549 }
550}
551
552fn resolve_message(fds: &FileDescriptorSet, full_name: &str) -> Option<DescriptorProto> {
560 let name = full_name.strip_prefix('.').unwrap_or(full_name);
563 for fd in &fds.file {
566 let prefix = fd.package.as_deref().unwrap_or("");
567 let prefix = if prefix.is_empty() {
568 String::new()
569 } else {
570 format!("{}.", prefix)
571 };
572 for msg in &fd.message_type {
573 if let Some(found) = find_message_recursive(msg, &prefix, name) {
574 return Some(found);
575 }
576 }
577 }
578 None
579}
580
581fn find_message_recursive(
584 msg: &DescriptorProto,
585 prefix: &str,
586 target: &str,
587) -> Option<DescriptorProto> {
588 let name = msg.name.as_deref().unwrap_or("");
589 let full = format!("{prefix}{name}");
590 if full == target {
591 return Some(msg.clone());
592 }
593 let nested_prefix = format!("{full}.");
594 for nested in &msg.nested_type {
595 if let Some(found) = find_message_recursive(nested, &nested_prefix, target) {
596 return Some(found);
597 }
598 }
599 None
600}
601
602fn encode_json_to_proto(
606 json: &Value,
607 msg_desc: &DescriptorProto,
608 fds: &FileDescriptorSet,
609) -> Result<Vec<u8>, String> {
610 let obj = json
611 .as_object()
612 .ok_or_else(|| "expected a JSON object for a protobuf message".to_string())?;
613 let mut buf = Vec::new();
614 for field in &msg_desc.field {
615 let Some(json_name) = &field.json_name else {
616 continue;
617 };
618 let Some(value) = obj.get(json_name) else {
619 continue;
620 };
621 if value.is_null() {
622 continue;
623 }
624 encode_field(&mut buf, field, value, fds)?;
625 }
626 Ok(buf)
627}
628
629fn encode_field(
631 buf: &mut Vec<u8>,
632 field: &FieldDescriptorProto,
633 value: &Value,
634 fds: &FileDescriptorSet,
635) -> Result<(), String> {
636 let number = field.number.unwrap_or(0) as u32;
637 let label = field.label.unwrap_or(field_label::OPTIONAL);
638 let ty = field.r#type.unwrap_or(field_type::MESSAGE);
639 let is_repeated = label == field_label::REPEATED;
640
641 if is_repeated {
642 let arr = value.as_array().ok_or_else(|| {
643 format!(
644 "field {} expected a JSON array",
645 field.json_name.as_deref().unwrap_or("")
646 )
647 })?;
648 for elem in arr {
649 if elem.is_null() {
650 continue;
651 }
652 encode_single_field(buf, number, ty, field, elem, fds)?;
653 }
654 return Ok(());
655 }
656
657 encode_single_field(buf, number, ty, field, value, fds)
658}
659
660fn encode_single_field(
662 buf: &mut Vec<u8>,
663 number: u32,
664 ty: i32,
665 field: &FieldDescriptorProto,
666 value: &Value,
667 fds: &FileDescriptorSet,
668) -> Result<(), String> {
669 match ty {
670 field_type::STRING => {
671 let s = value
672 .as_str()
673 .ok_or_else(|| format!("field {number} expected a string"))?;
674 let bytes = s.as_bytes();
675 write_tag(buf, number, WIRE_LENGTH_DELIMITED);
676 write_varint(buf, bytes.len() as u64);
677 buf.extend_from_slice(bytes);
678 }
679 field_type::BYTES => {
680 let s = value
681 .as_str()
682 .ok_or_else(|| format!("field {number} expected a base64 string for bytes"))?;
683 let decoded = base64::engine::general_purpose::STANDARD
684 .decode(s)
685 .map_err(|e| format!("field {number} invalid base64: {e}"))?;
686 write_tag(buf, number, WIRE_LENGTH_DELIMITED);
687 write_varint(buf, decoded.len() as u64);
688 buf.extend_from_slice(&decoded);
689 }
690 field_type::BOOL => {
691 let b = value
692 .as_bool()
693 .ok_or_else(|| format!("field {number} expected a bool"))?;
694 write_tag(buf, number, WIRE_VARINT);
695 write_varint(buf, if b { 1u64 } else { 0u64 });
696 }
697 field_type::INT32 | field_type::SINT32 | field_type::SFIXED32 => {
698 let n = value
699 .as_i64()
700 .ok_or_else(|| format!("field {number} expected an integer"))?
701 as i32;
702 write_tag(buf, number, WIRE_VARINT);
703 write_varint(buf, n as u32 as u64);
704 }
705 field_type::INT64 | field_type::SINT64 | field_type::SFIXED64 => {
706 let n = value
707 .as_i64()
708 .ok_or_else(|| format!("field {number} expected an integer"))?;
709 write_tag(buf, number, WIRE_VARINT);
710 write_varint(buf, n as u64);
711 }
712 field_type::UINT32 | field_type::FIXED32 => {
713 let n = value
714 .as_u64()
715 .ok_or_else(|| format!("field {number} expected a non-negative integer"))?
716 as u32;
717 write_tag(buf, number, WIRE_VARINT);
718 write_varint(buf, n as u64);
719 }
720 field_type::UINT64 | field_type::FIXED64 => {
721 let n = value
722 .as_u64()
723 .ok_or_else(|| format!("field {number} expected a non-negative integer"))?;
724 write_tag(buf, number, WIRE_VARINT);
725 write_varint(buf, n);
726 }
727 field_type::FLOAT => {
728 let f = value
729 .as_f64()
730 .ok_or_else(|| format!("field {number} expected a number"))?
731 as f32;
732 write_tag(buf, number, WIRE_32BIT);
733 buf.extend_from_slice(&f.to_le_bytes());
734 }
735 field_type::DOUBLE => {
736 let f = value
737 .as_f64()
738 .ok_or_else(|| format!("field {number} expected a number"))?;
739 write_tag(buf, number, WIRE_64BIT);
740 buf.extend_from_slice(&f.to_le_bytes());
741 }
742 field_type::ENUM => {
743 let n = if let Some(i) = value.as_i64() {
744 i as i32
745 } else if let Some(s) = value.as_str() {
746 let _ = s;
749 return Err(format!(
750 "field {number} enum-by-name encoding not supported; \
751 use the integer value"
752 ));
753 } else {
754 return Err(format!(
755 "field {number} expected an integer or string for enum"
756 ));
757 };
758 write_tag(buf, number, WIRE_VARINT);
759 write_varint(buf, n as u32 as u64);
760 }
761 field_type::MESSAGE => {
762 let type_name = field
763 .type_name
764 .as_deref()
765 .ok_or_else(|| format!("field {number} message type missing"))?;
766 let nested = resolve_message(fds, type_name)
767 .ok_or_else(|| format!("field {number} message type {type_name} not found"))?;
768 let sub = encode_json_to_proto(value, &nested, fds)?;
769 write_tag(buf, number, WIRE_LENGTH_DELIMITED);
770 write_varint(buf, sub.len() as u64);
771 buf.extend_from_slice(&sub);
772 }
773 _ => {
774 return Err(format!("field {number} type {ty} not supported"));
775 }
776 }
777 Ok(())
778}
779
780fn decode_proto_to_json(
784 proto: &[u8],
785 msg_desc: &DescriptorProto,
786 fds: &FileDescriptorSet,
787) -> Result<Value, String> {
788 let mut obj = serde_json::Map::new();
789 let mut pos = 0;
790 while pos < proto.len() {
791 let (tag, tag_len) =
792 read_varint(&proto[pos..]).ok_or_else(|| "truncated varint tag".to_string())?;
793 pos += tag_len;
794 let field_number = (tag >> 3) as u32;
795 let wire_type = (tag & 0x07) as u8;
796
797 let field = msg_desc
798 .field
799 .iter()
800 .find(|f| f.number.unwrap_or(0) as u32 == field_number);
801 let json_name = field
802 .and_then(|f| f.json_name.clone())
803 .unwrap_or_else(|| format!("field{field_number}"));
804
805 let (value, consumed) = decode_field(&proto[pos..], wire_type, field, fds)?;
806 pos += consumed;
807
808 if let Some(existing) = obj.get(&json_name) {
810 if let Some(arr) = existing.as_array() {
811 let mut arr = arr.clone();
812 arr.push(value);
813 obj.insert(json_name, Value::Array(arr));
814 } else {
815 let arr = vec![existing.clone(), value];
817 obj.insert(json_name, Value::Array(arr));
818 }
819 } else {
820 obj.insert(json_name, value);
821 }
822 }
823 Ok(Value::Object(obj))
824}
825
826fn decode_field(
828 buf: &[u8],
829 wire_type: u8,
830 field: Option<&FieldDescriptorProto>,
831 fds: &FileDescriptorSet,
832) -> Result<(Value, usize), String> {
833 let ty = field.and_then(|f| f.r#type).unwrap_or(field_type::MESSAGE);
834
835 match wire_type {
836 WIRE_VARINT => {
837 let (v, len) = read_varint(buf).ok_or_else(|| "truncated varint".to_string())?;
838 let value = match ty {
839 field_type::BOOL => Value::Bool(v != 0),
840 field_type::INT32 | field_type::SINT32 | field_type::SFIXED32 => {
841 Value::Number((v as u32 as i32 as i64).into())
842 }
843 field_type::INT64 | field_type::SINT64 | field_type::SFIXED64 => {
844 Value::Number((v as i64).into())
845 }
846 field_type::UINT32 | field_type::FIXED32 => Value::Number((v as u32 as u64).into()),
847 field_type::UINT64 | field_type::FIXED64 => Value::Number(v.into()),
848 field_type::ENUM => Value::Number((v as u32 as i32 as i64).into()),
849 _ => Value::Number(v.into()),
850 };
851 Ok((value, len))
852 }
853 WIRE_64BIT => {
854 if buf.len() < 8 {
855 return Err("truncated 64-bit field".to_string());
856 }
857 let bytes: [u8; 8] = buf[..8].try_into().unwrap();
858 let value = match ty {
859 field_type::DOUBLE => serde_json::Number::from_f64(f64::from_le_bytes(bytes))
860 .map(Value::Number)
861 .unwrap_or(Value::Null),
862 field_type::FIXED64 => Value::Number(u64::from_le_bytes(bytes).into()),
863 field_type::SFIXED64 => Value::Number(i64::from_le_bytes(bytes).into()),
864 _ => Value::Null,
865 };
866 Ok((value, 8))
867 }
868 WIRE_LENGTH_DELIMITED => {
869 let (len, len_bytes) =
870 read_varint(buf).ok_or_else(|| "truncated length-delimited length".to_string())?;
871 let len = len as usize;
872 let data_start = len_bytes;
873 let data_end = data_start + len;
874 if data_end > buf.len() {
875 return Err("truncated length-delimited field".to_string());
876 }
877 let data = &buf[data_start..data_end];
878 let value = match ty {
879 field_type::STRING => Value::String(String::from_utf8_lossy(data).into_owned()),
880 field_type::BYTES => {
881 Value::String(base64::engine::general_purpose::STANDARD.encode(data))
882 }
883 field_type::MESSAGE => {
884 let type_name = field
885 .and_then(|f| f.type_name.as_deref())
886 .ok_or_else(|| "message field missing type_name".to_string())?;
887 let nested = resolve_message(fds, type_name)
888 .ok_or_else(|| format!("message type {type_name} not found"))?;
889 decode_proto_to_json(data, &nested, fds)?
890 }
891 _ => {
892 Value::String(String::from_utf8_lossy(data).into_owned())
895 }
896 };
897 Ok((value, data_end))
898 }
899 WIRE_32BIT => {
900 if buf.len() < 4 {
901 return Err("truncated 32-bit field".to_string());
902 }
903 let bytes: [u8; 4] = buf[..4].try_into().unwrap();
904 let value = match ty {
905 field_type::FLOAT => serde_json::Number::from_f64(f32::from_le_bytes(bytes) as f64)
906 .map(Value::Number)
907 .unwrap_or(Value::Null),
908 field_type::FIXED32 => Value::Number(u32::from_le_bytes(bytes).into()),
909 field_type::SFIXED32 => Value::Number(i32::from_le_bytes(bytes).into()),
910 _ => Value::Null,
911 };
912 Ok((value, 4))
913 }
914 _ => Err(format!("unknown wire type {wire_type}")),
915 }
916}
917
918const WIRE_VARINT: u8 = 0;
924const WIRE_64BIT: u8 = 1;
925const WIRE_LENGTH_DELIMITED: u8 = 2;
926const WIRE_32BIT: u8 = 5;
927
928fn write_tag(buf: &mut Vec<u8>, field_number: u32, wire_type: u8) {
930 let tag = ((field_number as u64) << 3) | (wire_type as u64);
931 write_varint(buf, tag);
932}
933
934fn write_varint(buf: &mut Vec<u8>, mut value: u64) {
936 while value >= 0x80 {
937 buf.push((value as u8) | 0x80);
938 value >>= 7;
939 }
940 buf.push(value as u8);
941}
942
943fn read_varint(buf: &[u8]) -> Option<(u64, usize)> {
946 let mut result: u64 = 0;
947 let mut shift = 0;
948 for (i, byte) in buf.iter().enumerate() {
949 result |= ((byte & 0x7f) as u64) << shift;
950 if byte & 0x80 == 0 {
951 return Some((result, i + 1));
952 }
953 shift += 7;
954 if shift >= 64 {
955 return None;
956 }
957 }
958 None
959}
960
961pub mod grpc_code {
967 pub const OK: i32 = 0;
968 pub const CANCELLED: i32 = 1;
969 pub const UNKNOWN: i32 = 2;
970 pub const INVALID_ARGUMENT: i32 = 3;
971 pub const DEADLINE_EXCEEDED: i32 = 4;
972 pub const NOT_FOUND: i32 = 5;
973 pub const ALREADY_EXISTS: i32 = 6;
974 pub const PERMISSION_DENIED: i32 = 7;
975 pub const RESOURCE_EXHAUSTED: i32 = 8;
976 pub const FAILED_PRECONDITION: i32 = 9;
977 pub const ABORTED: i32 = 10;
978 pub const OUT_OF_RANGE: i32 = 11;
979 pub const UNIMPLEMENTED: i32 = 12;
980 pub const INTERNAL: i32 = 13;
981 pub const UNAVAILABLE: i32 = 14;
982 pub const DATA_LOSS: i32 = 15;
983 pub const UNAUTHENTICATED: i32 = 16;
984}
985
986pub fn grpc_status_to_http(status: i32, message: &str) -> (u16, Value) {
990 let http_status = match status {
991 grpc_code::OK => 200,
992 grpc_code::CANCELLED => 499,
993 grpc_code::UNKNOWN => 500,
994 grpc_code::INVALID_ARGUMENT => 400,
995 grpc_code::DEADLINE_EXCEEDED => 504,
996 grpc_code::NOT_FOUND => 404,
997 grpc_code::ALREADY_EXISTS => 409,
998 grpc_code::PERMISSION_DENIED => 403,
999 grpc_code::RESOURCE_EXHAUSTED => 429,
1000 grpc_code::FAILED_PRECONDITION => 400,
1001 grpc_code::ABORTED => 409,
1002 grpc_code::OUT_OF_RANGE => 400,
1003 grpc_code::UNIMPLEMENTED => 501,
1004 grpc_code::INTERNAL => 500,
1005 grpc_code::UNAVAILABLE => 503,
1006 grpc_code::DATA_LOSS => 500,
1007 grpc_code::UNAUTHENTICATED => 401,
1008 _ => 500,
1009 };
1010 let body = serde_json::json!({
1011 "code": status,
1012 "message": message,
1013 "details": [],
1014 });
1015 (http_status, body)
1016}
1017
1018pub fn grpc_status_name(status: i32) -> &'static str {
1020 match status {
1021 grpc_code::OK => "OK",
1022 grpc_code::CANCELLED => "CANCELLED",
1023 grpc_code::UNKNOWN => "UNKNOWN",
1024 grpc_code::INVALID_ARGUMENT => "INVALID_ARGUMENT",
1025 grpc_code::DEADLINE_EXCEEDED => "DEADLINE_EXCEEDED",
1026 grpc_code::NOT_FOUND => "NOT_FOUND",
1027 grpc_code::ALREADY_EXISTS => "ALREADY_EXISTS",
1028 grpc_code::PERMISSION_DENIED => "PERMISSION_DENIED",
1029 grpc_code::RESOURCE_EXHAUSTED => "RESOURCE_EXHAUSTED",
1030 grpc_code::FAILED_PRECONDITION => "FAILED_PRECONDITION",
1031 grpc_code::ABORTED => "ABORTED",
1032 grpc_code::OUT_OF_RANGE => "OUT_OF_RANGE",
1033 grpc_code::UNIMPLEMENTED => "UNIMPLEMENTED",
1034 grpc_code::INTERNAL => "INTERNAL",
1035 grpc_code::UNAVAILABLE => "UNAVAILABLE",
1036 grpc_code::DATA_LOSS => "DATA_LOSS",
1037 grpc_code::UNAUTHENTICATED => "UNAUTHENTICATED",
1038 _ => "UNKNOWN",
1039 }
1040}