Skip to content

Commit

Permalink
merg
Browse files Browse the repository at this point in the history
  • Loading branch information
velzie committed Oct 20, 2024
2 parents bdf5fd4 + 6fc4730 commit c063a45
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 67 deletions.
1 change: 1 addition & 0 deletions rewriter/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions rewriter/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ oxc_syntax = "0.20.0"
rand = "0.8.5"
serde = "1.0.204"
serde-wasm-bindgen = "0.6.5"
thiserror = "1.0.64"
url = "2.5.2"
wasm-bindgen = "0.2.92"
web-sys = { version = "0.3.72", features = ["Url"] }
Expand Down
138 changes: 89 additions & 49 deletions rewriter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,79 +4,119 @@ use std::{panic, str::FromStr};

use js_sys::{Function, Object, Reflect};
use rewrite::{rewrite, Config, EncodeFn};
use thiserror::Error;
use url::Url;
use wasm_bindgen::{prelude::*, throw_str};
use wasm_bindgen::prelude::*;

#[derive(Debug, Error)]
pub enum RewriterError {
#[error("JS: {0}")]
Js(String),
#[error("URL parse error: {0}")]
Url(#[from] url::ParseError),

#[error("{0} was not {1}")]
Not(String, &'static str),
#[error("❗❗❗ ❗❗❗ REWRITER OFFSET OOB FAIL ❗❗❗ ❗❗❗")]
Oob,
}

impl From<JsValue> for RewriterError {
fn from(value: JsValue) -> Self {
Self::Js(format!("{:?}", value))
}
}

impl From<RewriterError> for JsValue {
fn from(value: RewriterError) -> Self {
JsError::from(value).into()
}
}

impl RewriterError {
fn not_str(x: &str, obj: &JsValue) -> Self {
Self::Not(format!("{:?} in {:?}", x, obj), "string")
}

fn not_fn(obj: JsValue) -> Self {
Self::Not(format!("{:?}", obj), "function")
}

fn not_bool(obj: &JsValue) -> Self {
Self::Not(format!("{:?}", obj), "bool")
}
}

pub type Result<T> = std::result::Result<T, RewriterError>;

#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = console)]
fn log(s: &str);
fn error(s: &str);
}

#[wasm_bindgen]
pub fn init() {
panic::set_hook(Box::new(console_error_panic_hook::hook));
}

fn create_encode_function(encode: JsValue) -> EncodeFn {
let Ok(encode) = encode.dyn_into::<Function>() else {
throw_str("invalid encode function");
};
fn create_encode_function(encode: JsValue) -> Result<EncodeFn> {
let encode = encode.dyn_into::<Function>()?;

Box::new(move |str| {
Ok(Box::new(move |str| {
encode
.call1(&JsValue::NULL, &str.into())
.unwrap()
.as_string()
.unwrap()
.to_string()
})
}))
}

fn get_obj(obj: &JsValue, k: &str) -> JsValue {
Reflect::get(obj, &k.into()).unwrap()
fn get_obj(obj: &JsValue, k: &str) -> Result<JsValue> {
Ok(Reflect::get(obj, &k.into())?)
}

fn get_str(obj: &JsValue, k: &str) -> String {
Reflect::get(obj, &k.into()).unwrap().as_string().unwrap()
fn get_str(obj: &JsValue, k: &str) -> Result<String> {
Reflect::get(obj, &k.into())?
.as_string()
.ok_or_else(|| RewriterError::not_str(k, obj))
}

fn get_flag(scramjet: &Object, url: &str, flag: &str) -> bool {
let fenabled = get_obj(scramjet, "flagEnabled")
fn get_flag(scramjet: &Object, url: &str, flag: &str) -> Result<bool> {
let fenabled = get_obj(scramjet, "flagEnabled")?
.dyn_into::<Function>()
.unwrap();
fenabled
.call2(
&JsValue::NULL,
&flag.into(),
&web_sys::Url::new(url).expect("invalid url").into(),
)
.expect("error in flagEnabled")
.as_bool()
.expect("not bool returned from flagEnabled")
.map_err(RewriterError::not_fn)?;
let ret = fenabled.call2(
&JsValue::NULL,
&flag.into(),
&web_sys::Url::new(url).expect("invalid url").into(),
)?;

ret.as_bool().ok_or_else(|| RewriterError::not_bool(&ret))
}

fn get_config(scramjet: &Object, url: &str) -> Config {
let codec = &get_obj(scramjet, "codec");
let config = &get_obj(scramjet, "config");
let globals = &get_obj(config, "globals");

Config {
prefix: get_str(config, "prefix"),
encode: create_encode_function(get_obj(codec, "encode")),

wrapfn: get_str(globals, "wrapfn"),
importfn: get_str(globals, "importfn"),
rewritefn: get_str(globals, "rewritefn"),
metafn: get_str(globals, "metafn"),
setrealmfn: get_str(globals, "setrealmfn"),
pushsourcemapfn: get_str(globals, "pushsourcemapfn"),

do_sourcemaps: get_flag(scramjet, url, "sourcemaps"),
capture_errors: get_flag(scramjet, url, "captureErrors"),
scramitize: get_flag(scramjet, url, "scramitize"),
strict_rewrites: get_flag(scramjet, url, "strictRewrites"),
}
fn get_config(scramjet: &Object, url: &str) -> Result<Config> {
let codec = &get_obj(scramjet, "codec")?;
let config = &get_obj(scramjet, "config")?;
let globals = &get_obj(config, "globals")?;

Ok(Config {
prefix: get_str(config, "prefix")?,
encode: create_encode_function(get_obj(codec, "encode")?)?,

wrapfn: get_str(globals, "wrapfn")?,
importfn: get_str(globals, "importfn")?,
rewritefn: get_str(globals, "rewritefn")?,
metafn: get_str(globals, "metafn")?,
setrealmfn: get_str(globals, "setrealmfn")?,
pushsourcemapfn: get_str(globals, "pushsourcemapfn")?,

do_sourcemaps: get_flag(scramjet, url, "sourcemaps")?,
capture_errors: get_flag(scramjet, url, "captureErrors")?,
scramitize: get_flag(scramjet, url, "scramitize")?,
strict_rewrites: get_flag(scramjet, url, "strictRewrites")?,
})
}

#[cfg(feature = "drm")]
Expand All @@ -90,17 +130,17 @@ fn drmcheck() -> bool {
}

#[wasm_bindgen]
pub fn rewrite_js(js: &str, url: &str, scramjet: &Object) -> Vec<u8> {
pub fn rewrite_js(js: &str, url: &str, scramjet: &Object) -> Result<Vec<u8>> {
#[cfg(feature = "drm")]
if !drmcheck() {
return Vec::new();
}

rewrite(js, Url::from_str(url).unwrap(), get_config(scramjet, url))
rewrite(js, Url::from_str(url)?, get_config(scramjet, url)?)
}

#[wasm_bindgen]
pub fn rewrite_js_from_arraybuffer(js: &[u8], url: &str, scramjet: &Object) -> Vec<u8> {
pub fn rewrite_js_from_arraybuffer(js: &[u8], url: &str, scramjet: &Object) -> Result<Vec<u8>> {
#[cfg(feature = "drm")]
if !drmcheck() {
return Vec::new();
Expand All @@ -109,5 +149,5 @@ pub fn rewrite_js_from_arraybuffer(js: &[u8], url: &str, scramjet: &Object) -> V
// we know that this is a valid utf-8 string
let js = unsafe { std::str::from_utf8_unchecked(js) };

rewrite(js, Url::from_str(url).unwrap(), get_config(scramjet, url))
rewrite(js, Url::from_str(url)?, get_config(scramjet, url)?)
}
22 changes: 12 additions & 10 deletions rewriter/src/rewrite.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use core::str;
use std::str::from_utf8;

use crate::{error, Result, RewriterError};
use oxc_allocator::Allocator;
use oxc_ast::{
ast::{
Expand Down Expand Up @@ -456,21 +457,20 @@ fn random_string() -> String {
.to_string()
}

pub fn rewrite(js: &str, url: Url, config: Config) -> Vec<u8> {
pub fn rewrite(js: &str, url: Url, config: Config) -> Result<Vec<u8>> {
let allocator = Allocator::default();
let source_type = SourceType::default();
let ret = Parser::new(&allocator, js, source_type).parse();

for error in ret.errors {
for err in ret.errors {
let cloned = js.to_string();
let error = error.with_source_code(cloned);
println!("{error:?}");
let err = err.with_source_code(cloned);
println!("oxc parse error {err:?}");
error(&format!("oxc parse error {err:?}"))
}

let program = ret.program;

// dbg!(&program);

let sourcetag = random_string();

let mut ast_pass = Rewriter {
Expand Down Expand Up @@ -553,7 +553,8 @@ pub fn rewrite(js: &str, url: Url, config: Config) -> Vec<u8> {
);
}

buffer.extend_from_slice(unsafe { js.get_unchecked(offset..start) }.as_bytes());
buffer
.extend_from_slice(js.get(offset..start).ok_or(RewriterError::Oob)?.as_bytes());

buffer.extend_from_slice(text.as_bytes());
offset = end;
Expand Down Expand Up @@ -583,7 +584,8 @@ pub fn rewrite(js: &str, url: Url, config: Config) -> Vec<u8> {
}
JsChange::SourceTag { tagstart } => {
let start = *tagstart as usize;
buffer.extend_from_slice(unsafe { js.get_unchecked(offset..start) }.as_bytes());
buffer
.extend_from_slice(js.get(offset..start).ok_or(RewriterError::Oob)?.as_bytes());

let inject = format!("/*scramtag {} {}*/", start, sourcetag);
buffer.extend_from_slice(inject.as_bytes());
Expand All @@ -602,10 +604,10 @@ pub fn rewrite(js: &str, url: Url, config: Config) -> Vec<u8> {

sourcemap.extend_from_slice(&buffer);

return sourcemap;
return Ok(sourcemap);
}

buffer
Ok(buffer)
}

fn json_escape_string(s: &str) -> String {
Expand Down
41 changes: 33 additions & 8 deletions src/client/shared/caches.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ export default function (client: ScramjetClient, self: typeof globalThis) {

client.Proxy("CacheStorage.prototype.match", {
apply(ctx) {
ctx.args[0] = `${client.url.origin}@${ctx.args[0]}`;
if (typeof ctx.args[0] === "string" || ctx.args[0] instanceof URL) {
ctx.args[0] = rewriteUrl(ctx.args[0].toString(), client.meta);
}
},
});

Expand All @@ -29,45 +31,68 @@ export default function (client: ScramjetClient, self: typeof globalThis) {

client.Proxy("Cache.prototype.add", {
apply(ctx) {
ctx.args[0] = rewriteUrl(ctx.args[0], client.meta);
if (typeof ctx.args[0] === "string" || ctx.args[0] instanceof URL) {
ctx.args[0] = rewriteUrl(ctx.args[0].toString(), client.meta);
}
},
});

client.Proxy("Cache.prototype.addAll", {
apply(ctx) {
for (let i = 0; i < ctx.args[0].length; i++) {
ctx.args[0][i] = rewriteUrl(ctx.args[0][i], client.meta);
if (
typeof ctx.args[0][i] === "string" ||
ctx.args[0][i] instanceof URL
) {
ctx.args[0][i] = rewriteUrl(ctx.args[0][i].toString(), client.meta);
}
}
},
});

client.Proxy("Cache.prototype.put", {
apply(ctx) {
ctx.args[0] = rewriteUrl(ctx.args[0], client.meta);
if (typeof ctx.args[0] === "string" || ctx.args[0] instanceof URL) {
ctx.args[0] = rewriteUrl(ctx.args[0].toString(), client.meta);
}
},
});

client.Proxy("Cache.prototype.match", {
apply(ctx) {
ctx.args[0] = rewriteUrl(ctx.args[0], client.meta);
if (typeof ctx.args[0] === "string" || ctx.args[0] instanceof URL) {
ctx.args[0] = rewriteUrl(ctx.args[0].toString(), client.meta);
}
},
});

client.Proxy("Cache.prototype.matchAll", {
apply(ctx) {
if (ctx.args[0]) ctx.args[0] = rewriteUrl(ctx.args[0], client.meta);
if (
(ctx.args[0] && typeof ctx.args[0] === "string") ||
(ctx.args[0] && ctx.args[0] instanceof URL)
) {
ctx.args[0] = rewriteUrl(ctx.args[0].toString(), client.meta);
}
},
});

client.Proxy("Cache.prototype.keys", {
apply(ctx) {
if (ctx.args[0]) ctx.args[0] = rewriteUrl(ctx.args[0], client.meta);
if (
(ctx.args[0] && typeof ctx.args[0] === "string") ||
(ctx.args[0] && ctx.args[0] instanceof URL)
) {
ctx.args[0] = rewriteUrl(ctx.args[0].toString(), client.meta);
}
},
});

client.Proxy("Cache.prototype.delete", {
apply(ctx) {
ctx.args[0] = rewriteUrl(ctx.args[0], client.meta);
if (typeof ctx.args[0] === "string" || ctx.args[0] instanceof URL) {
ctx.args[0] = rewriteUrl(ctx.args[0].toString(), client.meta);
}
},
});
}

0 comments on commit c063a45

Please sign in to comment.