@@ -30,12 +30,11 @@ pub enum HttpClientAction {
30
30
} ,
31
31
}
32
32
33
- /// HTTP Request type that can be shared over Wasm boundary to apps.
34
- /// This is the one you send to the `http-client:distro:sys` service.
33
+ /// HTTP Request type contained in [`HttpClientAction::Http`].
35
34
///
36
35
/// BODY is stored in the lazy_load_blob, as bytes
37
36
///
38
- /// TIMEOUT is stored in the message expect_response value
37
+ /// TIMEOUT is stored in the message's `expects_response` value
39
38
#[ derive( Clone , Debug , Serialize , Deserialize ) ]
40
39
pub struct OutgoingHttpRequest {
41
40
/// must parse to [`http::Method`]
@@ -63,32 +62,38 @@ pub enum HttpClientRequest {
63
62
64
63
/// [`crate::Response`] type received from the `http-client:distro:sys` service after
65
64
/// sending a successful [`HttpClientAction`] to it.
66
- #[ derive( Debug , Serialize , Deserialize ) ]
65
+ #[ derive( Clone , Debug , Serialize , Deserialize ) ]
67
66
pub enum HttpClientResponse {
68
67
Http ( HttpResponse ) ,
69
68
WebSocketAck ,
70
69
}
71
70
72
- #[ derive( Error , Debug , Serialize , Deserialize ) ]
71
+ #[ derive( Clone , Debug , Error , Serialize , Deserialize ) ]
73
72
pub enum HttpClientError {
74
73
// HTTP errors
75
- #[ error( "http-client: request is not valid HttpClientRequest: {req}. " ) ]
76
- BadRequest { req : String } ,
77
- #[ error( "http-client: http method not supported: {method}. " ) ]
74
+ #[ error( "request could not be deserialized to valid HttpClientRequest" ) ]
75
+ MalformedRequest ,
76
+ #[ error( "http method not supported: {method}" ) ]
78
77
BadMethod { method : String } ,
79
- #[ error( "http-client: url could not be parsed: {url}. " ) ]
78
+ #[ error( "url could not be parsed: {url}" ) ]
80
79
BadUrl { url : String } ,
81
- #[ error( "http-client: http version not supported: {version}. " ) ]
80
+ #[ error( "http version not supported: {version}" ) ]
82
81
BadVersion { version : String } ,
83
- #[ error( "http-client: failed to execute request {error}." ) ]
84
- RequestFailed { error : String } ,
82
+ #[ error( "client failed to build request: {0}" ) ]
83
+ BuildRequestFailed ( String ) ,
84
+ #[ error( "client failed to execute request: {0}" ) ]
85
+ ExecuteRequestFailed ( String ) ,
85
86
86
87
// WebSocket errors
87
- #[ error( "websocket_client: failed to open connection {url}. " ) ]
88
+ #[ error( "could not open connection to {url}" ) ]
88
89
WsOpenFailed { url : String } ,
89
- #[ error( "websocket_client: failed to send message {req}." ) ]
90
- WsPushFailed { req : String } ,
91
- #[ error( "websocket_client: failed to close connection {channel_id}." ) ]
90
+ #[ error( "sent WebSocket push to unknown channel {channel_id}" ) ]
91
+ WsPushUnknownChannel { channel_id : u32 } ,
92
+ #[ error( "WebSocket push failed because message had no blob attached" ) ]
93
+ WsPushNoBlob ,
94
+ #[ error( "WebSocket push failed because message type was Text, but blob was not a valid UTF-8 string" ) ]
95
+ WsPushBadText ,
96
+ #[ error( "failed to close connection {channel_id} because it was not open" ) ]
92
97
WsCloseFailed { channel_id : u32 } ,
93
98
}
94
99
@@ -141,48 +146,42 @@ pub fn send_request_await_response(
141
146
url : url. to_string ( ) ,
142
147
headers : headers. unwrap_or_default ( ) ,
143
148
} ) )
144
- . map_err ( |e| HttpClientError :: BadRequest {
145
- req : format ! ( "{e:?}" ) ,
146
- } ) ?,
149
+ . map_err ( |_| HttpClientError :: MalformedRequest ) ?,
147
150
)
148
151
. blob_bytes ( body)
149
152
. send_and_await_response ( timeout)
150
153
. unwrap ( ) ;
151
154
let Ok ( Message :: Response { body, .. } ) = res else {
152
- return Err ( HttpClientError :: RequestFailed {
153
- error : "http-client timed out" . to_string ( ) ,
154
- } ) ;
155
+ return Err ( HttpClientError :: ExecuteRequestFailed (
156
+ "http-client timed out" . to_string ( ) ,
157
+ ) ) ;
155
158
} ;
156
159
let resp = match serde_json:: from_slice :: <
157
160
std:: result:: Result < HttpClientResponse , HttpClientError > ,
158
161
> ( & body)
159
162
{
160
163
Ok ( Ok ( HttpClientResponse :: Http ( resp) ) ) => resp,
161
164
Ok ( Ok ( HttpClientResponse :: WebSocketAck ) ) => {
162
- return Err ( HttpClientError :: RequestFailed {
163
- error : "http-client gave unexpected response" . to_string ( ) ,
164
- } )
165
+ return Err ( HttpClientError :: ExecuteRequestFailed (
166
+ "http-client gave unexpected response" . to_string ( ) ,
167
+ ) )
165
168
}
166
169
Ok ( Err ( e) ) => return Err ( e) ,
167
170
Err ( e) => {
168
- return Err ( HttpClientError :: RequestFailed {
169
- error : format ! ( "http-client gave invalid response: {e:?}" ) ,
170
- } )
171
+ return Err ( HttpClientError :: ExecuteRequestFailed ( format ! (
172
+ "http-client gave invalid response: {e:?}"
173
+ ) ) )
171
174
}
172
175
} ;
173
176
let mut http_response = http:: Response :: builder ( )
174
177
. status ( http:: StatusCode :: from_u16 ( resp. status ) . unwrap_or_default ( ) ) ;
175
178
let headers = http_response. headers_mut ( ) . unwrap ( ) ;
176
179
for ( key, value) in & resp. headers {
177
180
let Ok ( key) = http:: header:: HeaderName :: from_str ( key) else {
178
- return Err ( HttpClientError :: RequestFailed {
179
- error : format ! ( "http-client gave invalid header key: {key}" ) ,
180
- } ) ;
181
+ continue ;
181
182
} ;
182
183
let Ok ( value) = http:: header:: HeaderValue :: from_str ( value) else {
183
- return Err ( HttpClientError :: RequestFailed {
184
- error : format ! ( "http-client gave invalid header value: {value}" ) ,
185
- } ) ;
184
+ continue ;
186
185
} ;
187
186
headers. insert ( key, value) ;
188
187
}
0 commit comments