Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
273 changes: 138 additions & 135 deletions src/android/binding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,157 +97,160 @@ fn handle_request(
is_document_start_script_enabled: jboolean,
) -> JniResult<jobject> {
let webview_id = env.get_string(&webview_id)?;
let webview_id = webview_id.to_str().ok().unwrap_or_default();
let webview_id = webview_id.to_str().unwrap_or_default();

if let Some(handler) = REQUEST_HANDLER.lock().unwrap().get(webview_id) {
#[cfg(feature = "tracing")]
let span =
tracing::info_span!(parent: None, "wry::custom_protocol::handle", uri = tracing::field::Empty).entered();

let mut request_builder = Request::builder();
let request_handlers = REQUEST_HANDLER.lock().unwrap();
let Some(handler) = request_handlers.get(webview_id) else {
return Ok(*JObject::null());
};

let uri = env
.call_method(&request, "getUrl", "()Landroid/net/Uri;", &[])?
.l()?;
let url: JString = env
.call_method(&uri, "toString", "()Ljava/lang/String;", &[])?
.l()?
.into();
let url = env.get_string(&url)?.to_string_lossy().to_string();
#[cfg(feature = "tracing")]
let span =
tracing::info_span!(parent: None, "wry::custom_protocol::handle", uri = tracing::field::Empty)
.entered();

let mut request_builder = Request::builder();

let uri = env
.call_method(&request, "getUrl", "()Landroid/net/Uri;", &[])?
.l()?;
let url: JString = env
.call_method(&uri, "toString", "()Ljava/lang/String;", &[])?
.l()?
.into();
let url = env.get_string(&url)?.to_string_lossy().to_string();

#[cfg(feature = "tracing")]
span.record("uri", &url);

request_builder = request_builder.uri(&url);

let method = env
.call_method(&request, "getMethod", "()Ljava/lang/String;", &[])?
.l()
.map(JString::from)?;
request_builder = request_builder.method(
env
.get_string(&method)?
.to_string_lossy()
.to_string()
.as_str(),
);

#[cfg(feature = "tracing")]
span.record("uri", &url);

request_builder = request_builder.uri(&url);

let method = env
.call_method(&request, "getMethod", "()Ljava/lang/String;", &[])?
.l()
.map(JString::from)?;
request_builder = request_builder.method(
env
.get_string(&method)?
.to_string_lossy()
.to_string()
.as_str(),
);
let request_headers = env
.call_method(request, "getRequestHeaders", "()Ljava/util/Map;", &[])?
.l()?;
let request_headers = JMap::from_env(env, &request_headers)?;
let mut iter = request_headers.iter(env)?;
while let Some((header, value)) = iter.next(env)? {
let header = JString::from(header);
let value = JString::from(value);
let header = env.get_string(&header)?;
let value = env.get_string(&value)?;
if let (Ok(header), Ok(value)) = (
HeaderName::from_bytes(header.to_bytes()),
HeaderValue::from_bytes(value.to_bytes()),
) {
request_builder = request_builder.header(header, value);
}
}

let request_headers = env
.call_method(request, "getRequestHeaders", "()Ljava/util/Map;", &[])?
.l()?;
let request_headers = JMap::from_env(env, &request_headers)?;
let mut iter = request_headers.iter(env)?;
while let Some((header, value)) = iter.next(env)? {
let header = JString::from(header);
let value = JString::from(value);
let header = env.get_string(&header)?;
let value = env.get_string(&value)?;
if let (Ok(header), Ok(value)) = (
HeaderName::from_bytes(header.to_bytes()),
HeaderValue::from_bytes(value.to_bytes()),
) {
request_builder = request_builder.header(header, value);
}
let final_request = match request_builder.body(Vec::new()) {
Ok(req) => req,
Err(_e) => {
#[cfg(feature = "tracing")]
tracing::warn!("Failed to build response: {_e}");
return Ok(*JObject::null());
}
};

let final_request = match request_builder.body(Vec::new()) {
Ok(req) => req,
Err(_e) => {
#[cfg(feature = "tracing")]
tracing::warn!("Failed to build response: {_e}");
return Ok(*JObject::null());
}
};
let response = {
#[cfg(feature = "tracing")]
let _span = tracing::info_span!("wry::custom_protocol::call_handler").entered();
(handler.handler)(
webview_id,
final_request,
is_document_start_script_enabled != 0,
)
};
let Some(response) = response else {
return Ok(*JObject::null());
};
let status = response.status();
let status_code = status.as_u16() as i32;
let status_err = if status_code < 100 {
Some("Status code can't be less than 100")
} else if status_code > 599 {
Some("statusCode can't be greater than 599.")
} else if status_code > 299 && status_code < 400 {
Some("statusCode can't be in the [300, 399] range.")
} else {
None
};
if let Some(_err) = status_err {
#[cfg(feature = "tracing")]
tracing::warn!("{_err}");
return Ok(*JObject::null());
}

let response = {
#[cfg(feature = "tracing")]
let _span = tracing::info_span!("wry::custom_protocol::call_handler").entered();
(handler.handler)(
webview_id,
final_request,
is_document_start_script_enabled != 0,
)
};
if let Some(response) = response {
let status = response.status();
let status_code = status.as_u16() as i32;
let status_err = if status_code < 100 {
Some("Status code can't be less than 100")
} else if status_code > 599 {
Some("statusCode can't be greater than 599.")
} else if status_code > 299 && status_code < 400 {
Some("statusCode can't be in the [300, 399] range.")
} else {
None
};
if let Some(_err) = status_err {
#[cfg(feature = "tracing")]
tracing::warn!("{_err}");
return Ok(*JObject::null());
let reason_phrase = status.canonical_reason().unwrap_or("OK");
let (mime_type, encoding) = if let Some(content_type) = response.headers().get(CONTENT_TYPE) {
let content_type = content_type.to_str().unwrap().trim();
let mut s = content_type.split(';');
let mime_type = s.next().unwrap().trim();
let mut encoding = None;
for token in s {
let token = token.trim();
if token.starts_with("charset=") {
encoding.replace(token.split('=').nth(1).unwrap());
break;
}

let reason_phrase = status.canonical_reason().unwrap_or("OK");
let (mime_type, encoding) = if let Some(content_type) = response.headers().get(CONTENT_TYPE) {
let content_type = content_type.to_str().unwrap().trim();
let mut s = content_type.split(';');
let mime_type = s.next().unwrap().trim();
let mut encoding = None;
for token in s {
let token = token.trim();
if token.starts_with("charset=") {
encoding.replace(token.split('=').nth(1).unwrap());
break;
}
}
(
env.new_string(mime_type)?,
if let Some(encoding) = encoding {
env.new_string(encoding)?
} else {
JString::default()
},
)
}
(
env.new_string(mime_type)?,
if let Some(encoding) = encoding {
env.new_string(encoding)?
} else {
(JString::default(), JString::default())
};
JString::default()
},
)
} else {
(JString::default(), JString::default())
};

let headers = response.headers();
let obj = env.new_object("java/util/HashMap", "()V", &[])?;
let response_headers = {
let headers_map = JMap::from_env(env, &obj)?;
for (name, value) in headers.iter() {
// WebResourceResponse will automatically generate Content-Type and
// Content-Length headers so we should skip them to avoid duplication.
if name == CONTENT_TYPE || name == CONTENT_LENGTH {
continue;
}
let key = env.new_string(name)?;
let value = env.new_string(value.to_str().unwrap_or_default())?;
headers_map.put(env, &key, &value)?;
}
headers_map
};
let headers = response.headers();
let obj = env.new_object("java/util/HashMap", "()V", &[])?;
let response_headers = {
let headers_map = JMap::from_env(env, &obj)?;
for (name, value) in headers.iter() {
// WebResourceResponse will automatically generate Content-Type and
// Content-Length headers so we should skip them to avoid duplication.
if name == CONTENT_TYPE || name == CONTENT_LENGTH {
continue;
}
let key = env.new_string(name)?;
let value = env.new_string(value.to_str().unwrap_or_default())?;
headers_map.put(env, &key, &value)?;
}
headers_map
};

let bytes = response.body();
let bytes = response.body();

let byte_array_input_stream = env.find_class("java/io/ByteArrayInputStream")?;
let byte_array = env.byte_array_from_slice(bytes)?;
let stream = env.new_object(byte_array_input_stream, "([B)V", &[(&byte_array).into()])?;
let byte_array_input_stream = env.find_class("java/io/ByteArrayInputStream")?;
let byte_array = env.byte_array_from_slice(bytes)?;
let stream = env.new_object(byte_array_input_stream, "([B)V", &[(&byte_array).into()])?;

let reason_phrase = env.new_string(reason_phrase)?;
let reason_phrase = env.new_string(reason_phrase)?;

let web_resource_response_class = env.find_class("android/webkit/WebResourceResponse")?;
let web_resource_response = env.new_object(
let web_resource_response_class = env.find_class("android/webkit/WebResourceResponse")?;
let web_resource_response = env.new_object(
web_resource_response_class,
"(Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/util/Map;Ljava/io/InputStream;)V",
&[(&mime_type).into(), (&encoding).into(), status_code.into(), (&reason_phrase).into(), (&response_headers).into(), (&stream).into()],
)?;

return Ok(*web_resource_response);
}
}

Ok(*JObject::null())
Ok(*web_resource_response)
}

#[allow(non_snake_case)]
Expand Down Expand Up @@ -338,7 +341,7 @@ pub unsafe fn shouldOverride(
let Ok(webview_id) = env.get_string(&webview_id) else {
return false.into();
};
let webview_id = webview_id.to_str().ok().unwrap_or_default();
let webview_id = webview_id.to_str().unwrap_or_default();

URL_LOADING_OVERRIDE
.lock()
Expand Down Expand Up @@ -426,7 +429,7 @@ pub unsafe fn withAssetLoader(mut env: JNIEnv, _: JClass, webview_id: JString) -
let Ok(webview_id) = env.get_string(&webview_id) else {
return false.into();
};
let webview_id = webview_id.to_str().ok().unwrap_or_default();
let webview_id = webview_id.to_str().unwrap_or_default();
(*WITH_ASSET_LOADER
.lock()
.unwrap()
Expand All @@ -440,7 +443,7 @@ pub unsafe fn assetLoaderDomain(mut env: JNIEnv, _: JClass, webview_id: JString)
let Ok(webview_id) = env.get_string(&webview_id) else {
return env.new_string("wry.assets").unwrap().as_raw();
};
let webview_id = webview_id.to_str().ok().unwrap_or_default();
let webview_id = webview_id.to_str().unwrap_or_default();
if let Some(domain) = ASSET_LOADER_DOMAIN.lock().unwrap().get(webview_id) {
env.new_string(domain).unwrap().as_raw()
} else {
Expand Down
Loading
Loading