agent-rs icon indicating copy to clipboard operation
agent-rs copied to clipboard

Unable to depend on `ic-utils` for `http_request` interface when targeting Wasm

Open paulyoung opened this issue 3 years ago • 2 comments

I added ic-utils = "0.3.1" to the [dependencies] section of my Cargo.toml file so I could do the following:

use ic_cdk_macros::{query};
use ic_utils::interfaces::http_request::{HttpResponse, HttpRequest};

#[query]
fn http_request(request: HttpRequest) -> HttpResponse {
  ...
}

However, that caused cargo build --target wasm32-unknown-unknown --package <my package> --release to fail.

ic-utils appears to transitively depend on openssl-sys, and apparently the openssl crate doesn't have support for WebAssembly.

I'll probably copy and paste what I need from http_request.rs for now but it would be great if we could depend on a crate from this repo that includes them instead.

paulyoung avatar Jun 05 '21 01:06 paulyoung

In case anyone else is looking to do this, or looking to make a PR, here's some info.

I created a local crate called ic-utils-http-request and copied part of https://docs.rs/crate/ic-utils/0.3.1/source/src/interfaces/http_request.rs there, but I was getting this error:

error: implementation of `ic_cdk::export::candid::de::ArgumentDecoder` is not general enough
    --> src/codebase/src/lib.rs:9:1
     |
9    |   #[query]
     |   ^^^^^^^^ implementation of `ic_cdk::export::candid::de::ArgumentDecoder` is not general enough
     |
    ::: /Users/py/.cargo/registry/src/github.com-1ecc6299db9ec823/candid-0.6.21/src/de.rs:1090:1
     |
1090 | / pub trait ArgumentDecoder<'a>: Sized {
1091 | |     /// Decodes a value of type [Self], modifying the deserializer (values are consumed).
1092 | |     fn decode(de: &mut IDLDeserialize<'a>) -> Result<Self>;
1093 | | }
     | |_- trait `ic_cdk::export::candid::de::ArgumentDecoder` defined here
     |
     = note: `(ic_utils_http_request::HttpRequest<'_>,)` must implement `ic_cdk::export::candid::de::ArgumentDecoder<'0>`, for any lifetime `'0`...
     = note: ...but `(ic_utils_http_request::HttpRequest<'_>,)` actually implements `ic_cdk::export::candid::de::ArgumentDecoder<'1>`, for some specific lifetime `'1`
     = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to previous error; 1 warning emitted

I worked around it by doing the following:

diff --git a/src/ic-utils-http-request/src/lib.rs b/src/ic-utils-http-request/src/lib.rs
index 1b5b6ed..a649e25 100644
--- a/src/ic-utils-http-request/src/lib.rs
+++ b/src/ic-utils-http-request/src/lib.rs
@@ -14,12 +14,12 @@ use ic_cdk::export::candid::{CandidType, Deserialize};
 pub struct HeaderField(pub String, pub String);

 #[derive(CandidType, Deserialize)]
-pub struct HttpRequest<'body> {
+pub struct HttpRequest {
     pub method: String,
     pub url: String,
     pub headers: Vec<HeaderField>,
     #[serde(with = "serde_bytes")]
-    pub body: &'body [u8],
+    pub body: Vec<u8>,
 }

 #[derive(CandidType, Deserialize)]

I suspect I can avoid that by adding a type annotation at the call site (below) but haven't been able to figure that out yet.

#[query]
fn http_request(request: HttpRequest) -> HttpResponse {
   HttpResponse {
       status_code: 200,
       headers: vec![],
       body: request.body.to_vec(),
       streaming_strategy: None,
   }
}

@chenyan-dfinity, do you have any suggestions?

paulyoung avatar Jun 05 '21 03:06 paulyoung

Could be a CDK issue. Not sure if CDK allows deserializing borrowed arguments.

One thing you can try is to use serde_bytes::Bytes instead of &'body [u8] so that the lifetime is hidden.

chenyan-dfinity avatar Jun 05 '21 04:06 chenyan-dfinity