redevplugin_worker_sdk/
http.rs1use crate::api;
2use crate::error::{Error, Result};
3use crate::resource::{Handle, IO_FLAG_EOF, MAX_IO_CHUNK_BYTES};
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
7pub struct Header {
8 pub name: String,
9 pub value: String,
10}
11
12#[derive(Debug, Clone, Copy, Default, Serialize)]
13#[serde(rename_all = "snake_case")]
14pub enum RedirectMode {
15 #[default]
16 Follow,
17 Manual,
18 Error,
19}
20
21#[derive(Debug, Clone, Serialize)]
22pub struct HttpRequest {
23 pub connector_id: String,
25 pub method: String,
26 pub url: String,
27 #[serde(default)]
28 pub headers: Vec<Header>,
29 #[serde(default)]
30 pub redirect: RedirectMode,
31 #[serde(default)]
32 #[serde(skip_serializing_if = "Option::is_none")]
33 pub timeout_ms: Option<u32>,
34}
35
36pub type RequestOptions = HttpRequest;
37
38#[derive(Deserialize)]
39struct BeginResult {
40 upload_handle: u64,
41}
42
43#[derive(Deserialize)]
44struct FinishResult {
45 status: u16,
46 #[serde(default)]
47 headers: Vec<Header>,
48 final_url: String,
49 body_handle: u64,
50}
51
52pub struct RequestBody {
53 handle: Handle,
54}
55
56impl RequestBody {
57 pub fn begin(options: HttpRequest) -> Result<Self> {
58 let opened: BeginResult = api::call("net.http.begin", &options)?;
59 Ok(Self {
60 handle: Handle::new(opened.upload_handle)?,
61 })
62 }
63
64 pub fn write_all(&mut self, bytes: &[u8]) -> Result<()> {
65 for chunk in bytes.chunks(MAX_IO_CHUNK_BYTES) {
66 self.handle.write(chunk, 0)?;
67 }
68 Ok(())
69 }
70
71 pub fn finish(mut self) -> Result<Response> {
72 #[derive(Serialize)]
73 struct Arguments {
74 handle: u64,
75 }
76 let finished: FinishResult = api::call(
77 "net.http.finish",
78 &Arguments {
79 handle: self.handle.id(),
80 },
81 )?;
82 self.handle.disarm();
83 Ok(Response {
84 status: finished.status,
85 headers: finished.headers,
86 final_url: finished.final_url,
87 body: ResponseBody {
88 handle: Handle::new(finished.body_handle)?,
89 },
90 })
91 }
92
93 pub fn abort(mut self) -> Result<()> {
94 #[derive(Serialize)]
95 struct Arguments {
96 handle: u64,
97 }
98 let _: serde_json::Value = api::call(
99 "net.http.abort",
100 &Arguments {
101 handle: self.handle.id(),
102 },
103 )?;
104 self.handle.disarm();
105 Ok(())
106 }
107}
108
109pub struct HttpResponse {
110 pub status: u16,
111 pub headers: Vec<Header>,
112 pub final_url: String,
113 pub body: ResponseBody,
114}
115
116pub type Response = HttpResponse;
117
118pub struct ResponseBody {
119 handle: Handle,
120}
121
122impl ResponseBody {
123 pub fn read(&mut self, capacity: usize) -> Result<(Vec<u8>, u32)> {
124 self.handle.read(capacity)
125 }
126
127 pub fn read_all(mut self) -> Result<Vec<u8>> {
128 let mut result = Vec::new();
129 loop {
130 let (chunk, flags) = self.handle.read(MAX_IO_CHUNK_BYTES)?;
131 if chunk.is_empty() && flags & IO_FLAG_EOF == 0 {
132 return Err(Error::internal("HTTP response body made no progress"));
133 }
134 result.extend_from_slice(&chunk);
135 if flags & IO_FLAG_EOF != 0 {
136 self.handle.close()?;
137 return Ok(result);
138 }
139 }
140 }
141
142 pub fn close(mut self) -> Result<()> {
143 self.handle.close()
144 }
145}