mirror of
https://github.com/denoland/deno.git
synced 2025-08-04 02:48:24 +00:00
Rename extensions/ directory to ext/ (#11643)
This commit is contained in:
parent
3a69941151
commit
a0285e2eb8
134 changed files with 77 additions and 77 deletions
390
ext/web/lib.rs
Normal file
390
ext/web/lib.rs
Normal file
|
@ -0,0 +1,390 @@
|
|||
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
mod blob;
|
||||
mod message_port;
|
||||
|
||||
use deno_core::error::bad_resource_id;
|
||||
use deno_core::error::range_error;
|
||||
use deno_core::error::type_error;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::include_js_files;
|
||||
use deno_core::op_async;
|
||||
use deno_core::op_sync;
|
||||
use deno_core::url::Url;
|
||||
use deno_core::Extension;
|
||||
use deno_core::OpState;
|
||||
use deno_core::Resource;
|
||||
use deno_core::ResourceId;
|
||||
use deno_core::ZeroCopyBuf;
|
||||
use encoding_rs::CoderResult;
|
||||
use encoding_rs::Decoder;
|
||||
use encoding_rs::DecoderResult;
|
||||
use encoding_rs::Encoding;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use std::borrow::Cow;
|
||||
use std::cell::RefCell;
|
||||
use std::fmt;
|
||||
use std::path::PathBuf;
|
||||
use std::usize;
|
||||
|
||||
use crate::blob::op_blob_create_object_url;
|
||||
use crate::blob::op_blob_create_part;
|
||||
use crate::blob::op_blob_read_part;
|
||||
use crate::blob::op_blob_remove_part;
|
||||
use crate::blob::op_blob_revoke_object_url;
|
||||
use crate::blob::op_blob_slice_part;
|
||||
pub use crate::blob::Blob;
|
||||
pub use crate::blob::BlobPart;
|
||||
pub use crate::blob::BlobStore;
|
||||
pub use crate::blob::InMemoryBlobPart;
|
||||
|
||||
pub use crate::message_port::create_entangled_message_port;
|
||||
use crate::message_port::op_message_port_create_entangled;
|
||||
use crate::message_port::op_message_port_post_message;
|
||||
use crate::message_port::op_message_port_recv_message;
|
||||
pub use crate::message_port::JsMessageData;
|
||||
pub use crate::message_port::MessagePort;
|
||||
|
||||
/// Load and execute the javascript code.
|
||||
pub fn init(blob_store: BlobStore, maybe_location: Option<Url>) -> Extension {
|
||||
Extension::builder()
|
||||
.js(include_js_files!(
|
||||
prefix "deno:ext/web",
|
||||
"00_infra.js",
|
||||
"01_dom_exception.js",
|
||||
"01_mimesniff.js",
|
||||
"02_event.js",
|
||||
"02_structured_clone.js",
|
||||
"03_abort_signal.js",
|
||||
"04_global_interfaces.js",
|
||||
"05_base64.js",
|
||||
"06_streams.js",
|
||||
"08_text_encoding.js",
|
||||
"09_file.js",
|
||||
"10_filereader.js",
|
||||
"11_blob_url.js",
|
||||
"12_location.js",
|
||||
"13_message_port.js",
|
||||
))
|
||||
.ops(vec![
|
||||
("op_base64_decode", op_sync(op_base64_decode)),
|
||||
("op_base64_encode", op_sync(op_base64_encode)),
|
||||
(
|
||||
"op_encoding_normalize_label",
|
||||
op_sync(op_encoding_normalize_label),
|
||||
),
|
||||
("op_encoding_new_decoder", op_sync(op_encoding_new_decoder)),
|
||||
("op_encoding_decode", op_sync(op_encoding_decode)),
|
||||
("op_encoding_encode_into", op_sync(op_encoding_encode_into)),
|
||||
("op_blob_create_part", op_sync(op_blob_create_part)),
|
||||
("op_blob_slice_part", op_sync(op_blob_slice_part)),
|
||||
("op_blob_read_part", op_async(op_blob_read_part)),
|
||||
("op_blob_remove_part", op_sync(op_blob_remove_part)),
|
||||
(
|
||||
"op_blob_create_object_url",
|
||||
op_sync(op_blob_create_object_url),
|
||||
),
|
||||
(
|
||||
"op_blob_revoke_object_url",
|
||||
op_sync(op_blob_revoke_object_url),
|
||||
),
|
||||
(
|
||||
"op_message_port_create_entangled",
|
||||
op_sync(op_message_port_create_entangled),
|
||||
),
|
||||
(
|
||||
"op_message_port_post_message",
|
||||
op_sync(op_message_port_post_message),
|
||||
),
|
||||
(
|
||||
"op_message_port_recv_message",
|
||||
op_async(op_message_port_recv_message),
|
||||
),
|
||||
])
|
||||
.state(move |state| {
|
||||
state.put(blob_store.clone());
|
||||
if let Some(location) = maybe_location.clone() {
|
||||
state.put(Location(location));
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
.build()
|
||||
}
|
||||
|
||||
fn op_base64_decode(
|
||||
_state: &mut OpState,
|
||||
input: String,
|
||||
_: (),
|
||||
) -> Result<ZeroCopyBuf, AnyError> {
|
||||
let mut input: &str = &input.replace(|c| char::is_ascii_whitespace(&c), "");
|
||||
// "If the length of input divides by 4 leaving no remainder, then:
|
||||
// if input ends with one or two U+003D EQUALS SIGN (=) characters,
|
||||
// remove them from input."
|
||||
if input.len() % 4 == 0 {
|
||||
if input.ends_with("==") {
|
||||
input = &input[..input.len() - 2]
|
||||
} else if input.ends_with('=') {
|
||||
input = &input[..input.len() - 1]
|
||||
}
|
||||
}
|
||||
|
||||
// "If the length of input divides by 4 leaving a remainder of 1,
|
||||
// throw an InvalidCharacterError exception and abort these steps."
|
||||
if input.len() % 4 == 1 {
|
||||
return Err(
|
||||
DomExceptionInvalidCharacterError::new("Failed to decode base64.").into(),
|
||||
);
|
||||
}
|
||||
|
||||
if input
|
||||
.chars()
|
||||
.any(|c| c != '+' && c != '/' && !c.is_alphanumeric())
|
||||
{
|
||||
return Err(
|
||||
DomExceptionInvalidCharacterError::new(
|
||||
"Failed to decode base64: invalid character",
|
||||
)
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
||||
let cfg = base64::Config::new(base64::CharacterSet::Standard, true)
|
||||
.decode_allow_trailing_bits(true);
|
||||
let out = base64::decode_config(&input, cfg).map_err(|err| {
|
||||
DomExceptionInvalidCharacterError::new(&format!(
|
||||
"Failed to decode base64: {:?}",
|
||||
err
|
||||
))
|
||||
})?;
|
||||
Ok(ZeroCopyBuf::from(out))
|
||||
}
|
||||
|
||||
fn op_base64_encode(
|
||||
_state: &mut OpState,
|
||||
s: ZeroCopyBuf,
|
||||
_: (),
|
||||
) -> Result<String, AnyError> {
|
||||
let cfg = base64::Config::new(base64::CharacterSet::Standard, true)
|
||||
.decode_allow_trailing_bits(true);
|
||||
let out = base64::encode_config(&s, cfg);
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct DecoderOptions {
|
||||
label: String,
|
||||
ignore_bom: bool,
|
||||
fatal: bool,
|
||||
}
|
||||
|
||||
fn op_encoding_normalize_label(
|
||||
_state: &mut OpState,
|
||||
label: String,
|
||||
_: (),
|
||||
) -> Result<String, AnyError> {
|
||||
let encoding = Encoding::for_label_no_replacement(label.as_bytes())
|
||||
.ok_or_else(|| {
|
||||
range_error(format!(
|
||||
"The encoding label provided ('{}') is invalid.",
|
||||
label
|
||||
))
|
||||
})?;
|
||||
Ok(encoding.name().to_lowercase())
|
||||
}
|
||||
|
||||
fn op_encoding_new_decoder(
|
||||
state: &mut OpState,
|
||||
options: DecoderOptions,
|
||||
_: (),
|
||||
) -> Result<ResourceId, AnyError> {
|
||||
let DecoderOptions {
|
||||
label,
|
||||
fatal,
|
||||
ignore_bom,
|
||||
} = options;
|
||||
|
||||
let encoding = Encoding::for_label(label.as_bytes()).ok_or_else(|| {
|
||||
range_error(format!(
|
||||
"The encoding label provided ('{}') is invalid.",
|
||||
label
|
||||
))
|
||||
})?;
|
||||
|
||||
let decoder = if ignore_bom {
|
||||
encoding.new_decoder_without_bom_handling()
|
||||
} else {
|
||||
encoding.new_decoder_with_bom_removal()
|
||||
};
|
||||
|
||||
let rid = state.resource_table.add(TextDecoderResource {
|
||||
decoder: RefCell::new(decoder),
|
||||
fatal,
|
||||
});
|
||||
|
||||
Ok(rid)
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct DecodeOptions {
|
||||
rid: ResourceId,
|
||||
stream: bool,
|
||||
}
|
||||
|
||||
fn op_encoding_decode(
|
||||
state: &mut OpState,
|
||||
data: ZeroCopyBuf,
|
||||
options: DecodeOptions,
|
||||
) -> Result<String, AnyError> {
|
||||
let DecodeOptions { rid, stream } = options;
|
||||
|
||||
let resource = state
|
||||
.resource_table
|
||||
.get::<TextDecoderResource>(rid)
|
||||
.ok_or_else(bad_resource_id)?;
|
||||
|
||||
let mut decoder = resource.decoder.borrow_mut();
|
||||
let fatal = resource.fatal;
|
||||
|
||||
let max_buffer_length = if fatal {
|
||||
decoder
|
||||
.max_utf8_buffer_length_without_replacement(data.len())
|
||||
.ok_or_else(|| range_error("Value too large to decode."))?
|
||||
} else {
|
||||
decoder
|
||||
.max_utf8_buffer_length(data.len())
|
||||
.ok_or_else(|| range_error("Value too large to decode."))?
|
||||
};
|
||||
|
||||
let mut output = String::with_capacity(max_buffer_length);
|
||||
|
||||
if fatal {
|
||||
let (result, _) =
|
||||
decoder.decode_to_string_without_replacement(&data, &mut output, !stream);
|
||||
match result {
|
||||
DecoderResult::InputEmpty => Ok(output),
|
||||
DecoderResult::OutputFull => {
|
||||
Err(range_error("Provided buffer too small."))
|
||||
}
|
||||
DecoderResult::Malformed(_, _) => {
|
||||
Err(type_error("The encoded data is not valid."))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let (result, _, _) = decoder.decode_to_string(&data, &mut output, !stream);
|
||||
match result {
|
||||
CoderResult::InputEmpty => Ok(output),
|
||||
CoderResult::OutputFull => Err(range_error("Provided buffer too small.")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct TextDecoderResource {
|
||||
decoder: RefCell<Decoder>,
|
||||
fatal: bool,
|
||||
}
|
||||
|
||||
impl Resource for TextDecoderResource {
|
||||
fn name(&self) -> Cow<str> {
|
||||
"textDecoder".into()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct EncodeIntoResult {
|
||||
read: usize,
|
||||
written: usize,
|
||||
}
|
||||
|
||||
fn op_encoding_encode_into(
|
||||
_state: &mut OpState,
|
||||
input: String,
|
||||
mut buffer: ZeroCopyBuf,
|
||||
) -> Result<EncodeIntoResult, AnyError> {
|
||||
// Since `input` is already UTF-8, we can simply find the last UTF-8 code
|
||||
// point boundary from input that fits in `buffer`, and copy the bytes up to
|
||||
// that point.
|
||||
let boundary = if buffer.len() >= input.len() {
|
||||
input.len()
|
||||
} else {
|
||||
let mut boundary = buffer.len();
|
||||
|
||||
// The maximum length of a UTF-8 code point is 4 bytes.
|
||||
for _ in 0..4 {
|
||||
if input.is_char_boundary(boundary) {
|
||||
break;
|
||||
}
|
||||
debug_assert!(boundary > 0);
|
||||
boundary -= 1;
|
||||
}
|
||||
|
||||
debug_assert!(input.is_char_boundary(boundary));
|
||||
boundary
|
||||
};
|
||||
|
||||
buffer[..boundary].copy_from_slice(input[..boundary].as_bytes());
|
||||
|
||||
Ok(EncodeIntoResult {
|
||||
// The `read` output parameter is measured in UTF-16 code units.
|
||||
read: input[..boundary].encode_utf16().count(),
|
||||
written: boundary,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_declaration() -> PathBuf {
|
||||
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("lib.deno_web.d.ts")
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DomExceptionQuotaExceededError {
|
||||
pub msg: String,
|
||||
}
|
||||
|
||||
impl DomExceptionQuotaExceededError {
|
||||
pub fn new(msg: &str) -> Self {
|
||||
DomExceptionQuotaExceededError {
|
||||
msg: msg.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DomExceptionInvalidCharacterError {
|
||||
pub msg: String,
|
||||
}
|
||||
|
||||
impl DomExceptionInvalidCharacterError {
|
||||
pub fn new(msg: &str) -> Self {
|
||||
DomExceptionInvalidCharacterError {
|
||||
msg: msg.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for DomExceptionQuotaExceededError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.pad(&self.msg)
|
||||
}
|
||||
}
|
||||
impl fmt::Display for DomExceptionInvalidCharacterError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.pad(&self.msg)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for DomExceptionQuotaExceededError {}
|
||||
|
||||
impl std::error::Error for DomExceptionInvalidCharacterError {}
|
||||
|
||||
pub fn get_error_class_name(e: &AnyError) -> Option<&'static str> {
|
||||
e.downcast_ref::<DomExceptionQuotaExceededError>()
|
||||
.map(|_| "DOMExceptionQuotaExceededError")
|
||||
.or_else(|| {
|
||||
e.downcast_ref::<DomExceptionInvalidCharacterError>()
|
||||
.map(|_| "DOMExceptionInvalidCharacterError")
|
||||
})
|
||||
}
|
||||
pub struct Location(pub Url);
|
Loading…
Add table
Add a link
Reference in a new issue