diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 478a4ea..b10a27e 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -52,6 +52,9 @@ dirs = "5.0" # Pattern matching for folder filters glob = "0.3" +# URL encoding for document IDs +urlencoding = "2.1" + [dev-dependencies] # Testing utilities tokio-test = "0.4" diff --git a/rust/src/couch.rs b/rust/src/couch.rs index 2987472..881dc99 100644 --- a/rust/src/couch.rs +++ b/rust/src/couch.rs @@ -187,7 +187,8 @@ impl CouchClient { } self.retry_operation("store_mail_document", || async { - let url = format!("{}/{}/{}", self.base_url, db_name, doc_id); + let encoded_doc_id = urlencoding::encode(&doc_id); + let url = format!("{}/{}/{}", self.base_url, db_name, encoded_doc_id); let mut request = self.client.put(&url).json(&document); if let Some((username, password)) = &self.auth { @@ -229,7 +230,9 @@ impl CouchClient { let rev = doc_response.ok_or_else(|| anyhow!("Document {} not found", doc_id))?; // Upload the attachment - let url = format!("{}/{}/{}/{}?rev={}", self.base_url, db_name, doc_id, attachment_name, rev); + let encoded_doc_id = urlencoding::encode(doc_id); + let encoded_attachment_name = urlencoding::encode(attachment_name); + let url = format!("{}/{}/{}/{}?rev={}", self.base_url, db_name, encoded_doc_id, encoded_attachment_name, rev); let mut request = self.client .put(&url) .header("Content-Type", content_type) @@ -255,7 +258,8 @@ impl CouchClient { /// Get document revision async fn get_document_rev(&self, db_name: &str, doc_id: &str) -> Result> { - let url = format!("{}/{}/{}", self.base_url, db_name, doc_id); + let encoded_doc_id = urlencoding::encode(doc_id); + let url = format!("{}/{}/{}", self.base_url, db_name, encoded_doc_id); let mut request = self.client.get(&url); if let Some((username, password)) = &self.auth { @@ -287,7 +291,8 @@ impl CouchClient { metadata_to_store.rev = existing.rev; } - let url = format!("{}/{}/{}", self.base_url, db_name, doc_id); + let encoded_doc_id = urlencoding::encode(doc_id); + let url = format!("{}/{}/{}", self.base_url, db_name, encoded_doc_id); let mut request = self.client.put(&url).json(&metadata_to_store); if let Some((username, password)) = &self.auth { @@ -311,7 +316,8 @@ impl CouchClient { /// Get sync metadata for a mailbox pub async fn get_sync_metadata(&self, db_name: &str, mailbox: &str) -> Result { let doc_id = format!("sync_metadata_{}", mailbox); - let url = format!("{}/{}/{}", self.base_url, db_name, doc_id); + let encoded_doc_id = urlencoding::encode(&doc_id); + let url = format!("{}/{}/{}", self.base_url, db_name, encoded_doc_id); let mut request = self.client.get(&url); if let Some((username, password)) = &self.auth { @@ -337,7 +343,8 @@ impl CouchClient { /// Check if a document exists pub async fn document_exists(&self, db_name: &str, doc_id: &str) -> Result { - let url = format!("{}/{}/{}", self.base_url, db_name, doc_id); + let encoded_doc_id = urlencoding::encode(doc_id); + let url = format!("{}/{}/{}", self.base_url, db_name, encoded_doc_id); let mut request = self.client.head(&url); if let Some((username, password)) = &self.auth { @@ -414,7 +421,8 @@ impl CouchClient { /// Delete a document (used in sync mode for deleted messages) pub async fn delete_document(&self, db_name: &str, doc_id: &str) -> Result<()> { // First get the document to get its revision - let url = format!("{}/{}/{}", self.base_url, db_name, doc_id); + let encoded_doc_id = urlencoding::encode(doc_id); + let url = format!("{}/{}/{}", self.base_url, db_name, encoded_doc_id); let mut request = self.client.get(&url); if let Some((username, password)) = &self.auth { @@ -431,8 +439,8 @@ impl CouchClient { let rev = doc["_rev"].as_str() .ok_or_else(|| anyhow!("Document {} has no _rev field", doc_id))?; - // Now delete the document - let delete_url = format!("{}/{}/{}?rev={}", self.base_url, db_name, doc_id, rev); + // Now delete the document + let delete_url = format!("{}/{}/{}?rev={}", self.base_url, db_name, encoded_doc_id, rev); let mut delete_request = self.client.delete(&delete_url); if let Some((username, password)) = &self.auth {