mirror of
https://github.com/servo/servo.git
synced 2025-08-05 05:30:08 +01:00
bypass SM for in-memory streams in request bodies, dis-allow other cases in sync XHR
This commit is contained in:
parent
3535dd7412
commit
ad4dea7d84
3 changed files with 75 additions and 19 deletions
|
@ -58,6 +58,7 @@ struct TransmitBodyConnectHandler {
|
||||||
canceller: TaskCanceller,
|
canceller: TaskCanceller,
|
||||||
bytes_sender: Option<IpcSender<Vec<u8>>>,
|
bytes_sender: Option<IpcSender<Vec<u8>>>,
|
||||||
control_sender: IpcSender<BodyChunkRequest>,
|
control_sender: IpcSender<BodyChunkRequest>,
|
||||||
|
in_memory: Option<Vec<u8>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TransmitBodyConnectHandler {
|
impl TransmitBodyConnectHandler {
|
||||||
|
@ -66,6 +67,7 @@ impl TransmitBodyConnectHandler {
|
||||||
task_source: NetworkingTaskSource,
|
task_source: NetworkingTaskSource,
|
||||||
canceller: TaskCanceller,
|
canceller: TaskCanceller,
|
||||||
control_sender: IpcSender<BodyChunkRequest>,
|
control_sender: IpcSender<BodyChunkRequest>,
|
||||||
|
in_memory: Option<Vec<u8>>,
|
||||||
) -> TransmitBodyConnectHandler {
|
) -> TransmitBodyConnectHandler {
|
||||||
TransmitBodyConnectHandler {
|
TransmitBodyConnectHandler {
|
||||||
stream: stream,
|
stream: stream,
|
||||||
|
@ -73,6 +75,7 @@ impl TransmitBodyConnectHandler {
|
||||||
canceller,
|
canceller,
|
||||||
bytes_sender: None,
|
bytes_sender: None,
|
||||||
control_sender,
|
control_sender,
|
||||||
|
in_memory,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,6 +100,12 @@ impl TransmitBodyConnectHandler {
|
||||||
.clone()
|
.clone()
|
||||||
.expect("No bytes sender to transmit chunk.");
|
.expect("No bytes sender to transmit chunk.");
|
||||||
|
|
||||||
|
// In case of the data being in-memory, send everything in one chunk, by-passing SpiderMonkey.
|
||||||
|
if let Some(bytes) = self.in_memory.take() {
|
||||||
|
let _ = bytes_sender.send(bytes);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let _ = self.task_source.queue_with_canceller(
|
let _ = self.task_source.queue_with_canceller(
|
||||||
task!(setup_native_body_promise_handler: move || {
|
task!(setup_native_body_promise_handler: move || {
|
||||||
// Step 1, Let body be request’s body.
|
// Step 1, Let body be request’s body.
|
||||||
|
@ -247,11 +256,15 @@ impl ExtractedBody {
|
||||||
let task_source = global.networking_task_source();
|
let task_source = global.networking_task_source();
|
||||||
let canceller = global.task_canceller(TaskSourceName::Networking);
|
let canceller = global.task_canceller(TaskSourceName::Networking);
|
||||||
|
|
||||||
|
// In case of the data being in-memory, send everything in one chunk, by-passing SM.
|
||||||
|
let in_memory = stream.get_in_memory_bytes();
|
||||||
|
|
||||||
let mut body_handler = TransmitBodyConnectHandler::new(
|
let mut body_handler = TransmitBodyConnectHandler::new(
|
||||||
trusted_stream,
|
trusted_stream,
|
||||||
task_source,
|
task_source,
|
||||||
canceller,
|
canceller,
|
||||||
chunk_request_sender.clone(),
|
chunk_request_sender.clone(),
|
||||||
|
in_memory,
|
||||||
);
|
);
|
||||||
|
|
||||||
ROUTER.add_route(
|
ROUTER.add_route(
|
||||||
|
@ -281,6 +294,11 @@ impl ExtractedBody {
|
||||||
// Also return the stream for this body, which can be used by script to consume it.
|
// Also return the stream for this body, which can be used by script to consume it.
|
||||||
(request_body, stream)
|
(request_body, stream)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Is the data of the stream of this extracted body available in memory?
|
||||||
|
pub fn in_memory(&self) -> bool {
|
||||||
|
self.stream.in_memory()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <https://fetch.spec.whatwg.org/#concept-bodyinit-extract>
|
/// <https://fetch.spec.whatwg.org/#concept-bodyinit-extract>
|
||||||
|
|
|
@ -196,6 +196,21 @@ impl ReadableStream {
|
||||||
.close(cx, handle);
|
.close(cx, handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Does the stream have all data in memory?
|
||||||
|
pub fn in_memory(&self) -> bool {
|
||||||
|
self.external_underlying_source
|
||||||
|
.as_ref()
|
||||||
|
.map(|source| source.in_memory())
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return bytes for synchronous use, if the stream has all data in memory.
|
||||||
|
pub fn get_in_memory_bytes(&self) -> Option<Vec<u8>> {
|
||||||
|
self.external_underlying_source
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|source| source.get_in_memory_bytes())
|
||||||
|
}
|
||||||
|
|
||||||
/// Acquires a reader and locks the stream,
|
/// Acquires a reader and locks the stream,
|
||||||
/// must be done before `read_a_chunk`.
|
/// must be done before `read_a_chunk`.
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
|
@ -372,22 +387,37 @@ struct ExternalUnderlyingSourceController {
|
||||||
buffer: RefCell<Vec<u8>>,
|
buffer: RefCell<Vec<u8>>,
|
||||||
/// Has the stream been closed by native code?
|
/// Has the stream been closed by native code?
|
||||||
closed: Cell<bool>,
|
closed: Cell<bool>,
|
||||||
|
/// Does this stream contains all it's data in memory?
|
||||||
|
in_memory: Cell<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExternalUnderlyingSourceController {
|
impl ExternalUnderlyingSourceController {
|
||||||
fn new(source: ExternalUnderlyingSource) -> ExternalUnderlyingSourceController {
|
fn new(source: ExternalUnderlyingSource) -> ExternalUnderlyingSourceController {
|
||||||
let buffer = match source {
|
let (buffer, in_mem) = match source {
|
||||||
ExternalUnderlyingSource::Blob(size) | ExternalUnderlyingSource::Memory(size) => {
|
ExternalUnderlyingSource::Blob(size) => (Vec::with_capacity(size), false),
|
||||||
Vec::with_capacity(size)
|
ExternalUnderlyingSource::Memory(size) => (Vec::with_capacity(size), true),
|
||||||
},
|
ExternalUnderlyingSource::FetchResponse => (vec![], false),
|
||||||
ExternalUnderlyingSource::FetchResponse => vec![],
|
|
||||||
};
|
};
|
||||||
ExternalUnderlyingSourceController {
|
ExternalUnderlyingSourceController {
|
||||||
buffer: RefCell::new(buffer),
|
buffer: RefCell::new(buffer),
|
||||||
closed: Cell::new(false),
|
closed: Cell::new(false),
|
||||||
|
in_memory: Cell::new(in_mem),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Does the stream have all data in memory?
|
||||||
|
pub fn in_memory(&self) -> bool {
|
||||||
|
self.in_memory.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return bytes synchronously if the stream has all data in memory.
|
||||||
|
pub fn get_in_memory_bytes(&self) -> Option<Vec<u8>> {
|
||||||
|
if self.in_memory.get() {
|
||||||
|
return Some(self.buffer.borrow().clone());
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
/// Signal available bytes if the stream is currently readable.
|
/// Signal available bytes if the stream is currently readable.
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
fn maybe_signal_available_bytes(
|
fn maybe_signal_available_bytes(
|
||||||
|
|
|
@ -580,7 +580,13 @@ impl XMLHttpRequestMethods for XMLHttpRequest {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
Some(DocumentOrBodyInit::Blob(ref b)) => {
|
Some(DocumentOrBodyInit::Blob(ref b)) => {
|
||||||
Some(b.extract(&self.global()).expect("Couldn't extract body."))
|
let extracted_body = b.extract(&self.global()).expect("Couldn't extract body.");
|
||||||
|
if !extracted_body.in_memory() && self.sync.get() {
|
||||||
|
warn!("Sync XHR with not in-memory Blob as body not supported");
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(extracted_body)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
Some(DocumentOrBodyInit::FormData(ref formdata)) => Some(
|
Some(DocumentOrBodyInit::FormData(ref formdata)) => Some(
|
||||||
formdata
|
formdata
|
||||||
|
@ -620,21 +626,23 @@ impl XMLHttpRequestMethods for XMLHttpRequest {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
Some(DocumentOrBodyInit::ReadableStream(ref stream)) => {
|
Some(DocumentOrBodyInit::ReadableStream(ref stream)) => {
|
||||||
// TODO:
|
if self.sync.get() {
|
||||||
// 1. If the keepalive flag is set, then throw a TypeError.
|
warn!("Sync XHR with ReadableStream as body not supported");
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
if stream.is_locked() || stream.is_disturbed() {
|
||||||
|
return Err(Error::Type(
|
||||||
|
"The body's stream is disturbed or locked".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
if stream.is_locked() || stream.is_disturbed() {
|
Some(ExtractedBody {
|
||||||
return Err(Error::Type(
|
stream: stream.clone(),
|
||||||
"The body's stream is disturbed or locked".to_string(),
|
total_bytes: None,
|
||||||
));
|
content_type: None,
|
||||||
|
source: BodySource::Null,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(ExtractedBody {
|
|
||||||
stream: stream.clone(),
|
|
||||||
total_bytes: None,
|
|
||||||
content_type: None,
|
|
||||||
source: BodySource::Null,
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue