I'm creating my own frontend client to upload videos to a video hosting service. According to the API docs, I am to POST a multipart/form:
curl -X POST \
-H "Key: YOUR_KEY" \
-F "file=@hello_world.mp4" \
https://muse.ai/api/files/upload
I could setup my client to be allowed to make that cross origin request, however, the request requires a secret API key, so I need my server to proxy the request on behalf of my client.
As minimally follows:
use actix_web::{Error, HttpResponse, client::Client, error, web, HttpRequest};
use std::env;
pub async fn upload_video(req: HttpRequest, payload: web::Payload) -> Result<HttpResponse, Error> {
let muse_api_key = match env::var("MUSE_AI") {
Ok(token) => token,
Err(e) => {
return Err(error::ErrorInternalServerError(e));
}
};
let client = Client::default();
let mut forward_req_resp = client
.request_from("https://muse.ai/api/files/upload", req.head())
.header("key", muse_api_key)
.send_stream(payload)
.await?;
let mut client_resp = HttpResponse::build(forward_req_resp.status());
Ok(client_resp.body(forward_req_resp.body().await?))
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(move || {
App::new()
.service(
web::scope("/video")
.service(
web::resource("/upload").route(web::post().to(upload_video)),
)
)
})
.bind("127.0.0.1:8001")?
.run()
.await
}
Prior to wiring up my frontend, I'm testing with cURL:
curl -v -X POST -F "file=@/path/to/sintel_trailer-720p.mp4" 127.0.0.1:8001/video/upload
Resulting output:
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 8001 (#0)
> POST /video/upload HTTP/1.1
> Host: 127.0.0.1:8001
> User-Agent: curl/7.64.1
> Accept: */*
> Content-Length: 7608419
> Content-Type: multipart/form-data; boundary=------------------------076c45bb618a62c2
> Expect: 100-continue
>
< HTTP/1.1 100 Continue
< HTTP/1.1 400 Bad Request
< content-length: 40
< content-type: text/plain; charset=utf-8
< set-cookie: actix-session=3JVldgobuv9nv6zE9uV%2F1i0slQMHlV384rXzc9BWwRE%3D%7B%7D; HttpOnly; Path=/
< date: Mon, 01 Feb 2021 07:32:14 GMT
* HTTP error before end of send, stop sending
<
* Closing connection 0
protocol error: not a result of an error%
I've tried of a few variants, maybe one of which is notable: Adding the following to top of handler function:
let mut bytes = web::BytesMut::new();
while let Some(item) = payload.next().await {
bytes.extend_from_slice(&item?);
}
Then changing ClientRequestBuilding from .request_from
to:
.post("https://muse.ai/api/files/upload")
This results in: { error: "missing_file"}
.