@@ -34,7 +34,7 @@ impl HttpClient for WasmClient {
34
34
35
35
fn send ( & self , req : Request ) -> BoxFuture < ' static , Result < Response , Self :: Error > > {
36
36
let fut = Box :: pin ( async move {
37
- let req = fetch:: new ( req. method ( ) , req . url ( ) ) ;
37
+ let req: fetch :: Request = fetch:: Request :: new ( req) ? ;
38
38
let mut res = req. send ( ) . await ?;
39
39
40
40
let body = res. body_bytes ( ) ;
@@ -56,7 +56,6 @@ impl HttpClient for WasmClient {
56
56
}
57
57
}
58
58
59
- // This type e
60
59
struct InnerFuture {
61
60
fut : Pin < Box < dyn Future < Output = Result < Response , io:: Error > > + ' static > > ,
62
61
}
@@ -77,6 +76,8 @@ impl Future for InnerFuture {
77
76
}
78
77
79
78
mod fetch {
79
+ use futures_util:: io:: AsyncReadExt ;
80
+ use http:: request:: Parts ;
80
81
use js_sys:: { Array , ArrayBuffer , Reflect , Uint8Array } ;
81
82
use wasm_bindgen:: JsCast ;
82
83
use wasm_bindgen_futures:: JsFuture ;
@@ -85,27 +86,75 @@ mod fetch {
85
86
86
87
use std:: io;
87
88
use std:: iter:: { IntoIterator , Iterator } ;
89
+ use std:: pin:: Pin ;
88
90
89
91
/// Create a new fetch request.
90
- pub ( crate ) fn new ( method : impl AsRef < str > , url : impl AsRef < str > ) -> Request {
91
- Request :: new ( method, url)
92
- }
93
92
94
93
/// An HTTP Fetch Request.
95
94
pub ( crate ) struct Request {
96
95
init : RequestInit ,
97
96
url : String ,
97
+ _body_buf : Pin < Vec < u8 > > ,
98
98
}
99
99
100
100
impl Request {
101
101
/// Create a new instance.
102
- pub ( crate ) fn new ( method : impl AsRef < str > , url : impl AsRef < str > ) -> Self {
102
+ pub ( crate ) fn new ( req : super :: Request ) -> Result < Self , io:: Error > {
103
+ let (
104
+ Parts {
105
+ method,
106
+ uri,
107
+ headers,
108
+ ..
109
+ } ,
110
+ mut body,
111
+ ) = req. into_parts ( ) ;
112
+
113
+ //create a fetch request initaliser
103
114
let mut init = web_sys:: RequestInit :: new ( ) ;
115
+
116
+ //set the fetch method
104
117
init. method ( method. as_ref ( ) ) ;
105
- Self {
106
- init,
107
- url : url. as_ref ( ) . to_owned ( ) ,
118
+
119
+ //add any fetch headers
120
+ let init_headers = web_sys:: Headers :: new ( ) . unwrap ( ) ;
121
+ for ( name, value) in headers. iter ( ) {
122
+ init_headers
123
+ . append ( name. as_str ( ) , value. to_str ( ) . unwrap ( ) )
124
+ . map_err ( |_| {
125
+ io:: Error :: new (
126
+ io:: ErrorKind :: Other ,
127
+ format ! (
128
+ "could not add header: {} = {}" ,
129
+ name. as_str( ) ,
130
+ value. to_str( ) . expect( "could not stringify header value" )
131
+ ) ,
132
+ )
133
+ } ) ?;
134
+ }
135
+ init. headers ( & init_headers) ;
136
+
137
+ //convert the body into a uint8 array
138
+ // needs to be pinned and retained inside the Request because the Uint8Array passed to
139
+ // js is just a portal into WASM linear memory, and if the underlying data is moved the
140
+ // js ref will become silently invalid
141
+ let mut body_buf = Vec :: with_capacity ( 1024 ) ;
142
+ futures:: executor:: block_on ( body. read_to_end ( & mut body_buf) ) . map_err ( |_| {
143
+ io:: Error :: new ( io:: ErrorKind :: Other , "could not read body into a buffer" )
144
+ } ) ?;
145
+ let body_pinned = Pin :: new ( body_buf) ;
146
+ if body_pinned. len ( ) > 0 {
147
+ unsafe {
148
+ let uint_8_array = js_sys:: Uint8Array :: view ( & body_pinned) ;
149
+ init. body ( Some ( & uint_8_array) ) ;
150
+ }
108
151
}
152
+
153
+ Ok ( Self {
154
+ init,
155
+ url : uri. to_string ( ) ,
156
+ _body_buf : body_pinned,
157
+ } )
109
158
}
110
159
111
160
/// Submit a request
0 commit comments