1
1
//! http-client implementation for fetch
2
2
3
- use super :: { Body , HttpClient , Request , Response } ;
3
+ use super :: { http_types :: Headers , Body , HttpClient , Request , Response } ;
4
4
5
5
use futures:: future:: BoxFuture ;
6
6
use futures:: prelude:: * ;
@@ -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:: Request = fetch:: Request :: new ( req) ?;
37
+ let req: fetch:: Request = fetch:: Request :: new ( req) . await ?;
38
38
let mut res = req. send ( ) . await ?;
39
39
40
40
let body = res. body_bytes ( ) ;
@@ -77,12 +77,10 @@ impl Future for InnerFuture {
77
77
78
78
mod fetch {
79
79
use futures_util:: io:: AsyncReadExt ;
80
- use http:: request:: Parts ;
81
80
use js_sys:: { Array , ArrayBuffer , Reflect , Uint8Array } ;
82
81
use wasm_bindgen:: JsCast ;
83
82
use wasm_bindgen_futures:: JsFuture ;
84
- use web_sys:: window;
85
- use web_sys:: RequestInit ;
83
+ use web_sys:: { window, RequestInit } ;
86
84
87
85
use std:: io;
88
86
use std:: iter:: { IntoIterator , Iterator } ;
@@ -92,54 +90,28 @@ mod fetch {
92
90
93
91
/// An HTTP Fetch Request.
94
92
pub ( crate ) struct Request {
95
- init : RequestInit ,
96
- url : String ,
93
+ request : web_sys:: Request ,
97
94
_body_buf : Pin < Vec < u8 > > ,
98
95
}
99
96
100
97
impl Request {
101
98
/// Create a new instance.
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
-
99
+ pub ( crate ) async fn new ( mut req : super :: Request ) -> Result < Self , io:: Error > {
113
100
//create a fetch request initaliser
114
- let mut init = web_sys :: RequestInit :: new ( ) ;
101
+ let mut init = RequestInit :: new ( ) ;
115
102
116
103
//set the fetch method
117
- init. method ( method. as_ref ( ) ) ;
104
+ init. method ( req . method ( ) . as_ref ( ) ) ;
118
105
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) ;
106
+ let uri = req. url ( ) . to_string ( ) ;
107
+ let mut body = req. take_body ( ) ;
136
108
137
109
//convert the body into a uint8 array
138
110
// needs to be pinned and retained inside the Request because the Uint8Array passed to
139
111
// js is just a portal into WASM linear memory, and if the underlying data is moved the
140
112
// js ref will become silently invalid
141
113
let mut body_buf = Vec :: with_capacity ( 1024 ) ;
142
- futures :: executor :: block_on ( body. read_to_end ( & mut body_buf) ) . map_err ( |_| {
114
+ body. read_to_end ( & mut body_buf) . await . map_err ( |_| {
143
115
io:: Error :: new ( io:: ErrorKind :: Other , "could not read body into a buffer" )
144
116
} ) ?;
145
117
let body_pinned = Pin :: new ( body_buf) ;
@@ -150,9 +122,29 @@ mod fetch {
150
122
}
151
123
}
152
124
125
+ let request = web_sys:: Request :: new_with_str_and_init ( & uri, & init) . map_err ( |e| {
126
+ io:: Error :: new (
127
+ io:: ErrorKind :: Other ,
128
+ format ! ( "failed to create request: {:?}" , e) ,
129
+ )
130
+ } ) ?;
131
+
132
+ //add any fetch headers
133
+ let headers: & mut super :: Headers = req. as_mut ( ) ;
134
+ for ( name, value) in headers. iter ( ) {
135
+ let name = name. as_str ( ) ;
136
+ let value = value. as_str ( ) ;
137
+
138
+ request. headers ( ) . set ( name, value) . map_err ( |_| {
139
+ io:: Error :: new (
140
+ io:: ErrorKind :: Other ,
141
+ format ! ( "could not add header: {} = {}" , name, value) ,
142
+ )
143
+ } ) ?;
144
+ }
145
+
153
146
Ok ( Self {
154
- init,
155
- url : uri. to_string ( ) ,
147
+ request,
156
148
_body_buf : body_pinned,
157
149
} )
158
150
}
@@ -162,8 +154,7 @@ mod fetch {
162
154
pub ( crate ) async fn send ( self ) -> Result < Response , io:: Error > {
163
155
// Send the request.
164
156
let window = window ( ) . expect ( "A global window object could not be found" ) ;
165
- let request = web_sys:: Request :: new_with_str_and_init ( & self . url , & self . init ) . unwrap ( ) ;
166
- let promise = window. fetch_with_request ( & request) ;
157
+ let promise = window. fetch_with_request ( & self . request ) ;
167
158
let resp = JsFuture :: from ( promise) . await . unwrap ( ) ;
168
159
debug_assert ! ( resp. is_instance_of:: <web_sys:: Response >( ) ) ;
169
160
let res: web_sys:: Response = resp. dyn_into ( ) . unwrap ( ) ;
0 commit comments