Skip to content
Merged
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
3 changes: 2 additions & 1 deletion src/bun_core/Global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,8 @@ pub mod features {
pub fn yaml_parse_inc() {
YAML_PARSE.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
}
/// parsers crate calls `bun_core::analytics::Features::xml_parse_inc()`.
/// Bumped by the `Bun.XML` API and `.xml` imports (not by internal users
/// of the parser, such as the S3 client).
#[inline]
pub fn xml_parse_inc() {
XML_PARSE.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
Expand Down
1 change: 1 addition & 0 deletions src/bundler/ParseTask.rs
Original file line number Diff line number Diff line change
Expand Up @@ -847,6 +847,7 @@ pub mod parse_worker {
let _trace = perf::trace("Bundler.ParseXML");
let mut temp_log = Log::init();
let result = (|| -> core::result::Result<JSAst<'static>, AnyError> {
bun_core::analytics::Features::xml_parse_inc();
Comment thread
coderabbitai[bot] marked this conversation as resolved.
let rows: Expr = bun_parsers::xml::XML::parse(
source,
&mut temp_log,
Expand Down
1 change: 1 addition & 0 deletions src/bundler/transpiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1875,6 +1875,7 @@ fn parse_data_loader<'a>(
compact: true,
encoding: bun_parsers::xml::InputEncoding::File,
};
bun_core::analytics::Features::xml_parse_inc();
match bun_parsers::xml::XML::parse(source, log, arena, options) {
Ok(e) => e,
Err(_) => return None,
Expand Down
1 change: 0 additions & 1 deletion src/parsers/xml.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ impl XML {
bump: &'a Bump,
options: Options,
) -> crate::Result<Expr> {
bun_core::analytics::Features::xml_parse_inc();
let mut tape = Tape::new_in(bump, core::mem::size_of_val(contents));
Comment thread
claude[bot] marked this conversation as resolved.
// SAFETY: see `Tape::object_from`.
unsafe { tape.tape.as_mut() }.encoding = if U::WIDE {
Expand Down
1 change: 1 addition & 0 deletions src/runtime/api/XMLObject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ pub(crate) fn parse(global: &JSGlobalObject, frame: &CallFrame) -> JsResult<JSVa
super::SourceEncoding::Latin1Text => xml::InputEncoding::Latin1,
super::SourceEncoding::Utf16Text => xml::InputEncoding::Text,
};
bun_core::analytics::Features::xml_parse_inc();
let mut result = if source_encoding == super::SourceEncoding::Utf16Text {
// The scaffold hands the string's code units over as bytes.
let units: &[u16] = bytemuck::cast_slice(&source.contents);
Expand Down
4 changes: 4 additions & 0 deletions src/runtime/webcore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,9 @@ pub mod __s3_multipart;
#[doc(hidden)]
#[path = "webcore/s3/simple_request.rs"]
pub mod __s3_simple_request;
#[doc(hidden)]
#[path = "webcore/s3/xml_response.rs"]
pub mod __s3_xml_response;
pub mod s3 {
pub use super::multipart_options_impl as multipart_options;
pub use super::multipart_options_impl::MultiPartUploadOptions;
Expand All @@ -339,6 +342,7 @@ pub mod s3 {
pub use super::__s3_list_objects as list_objects;
pub use super::__s3_multipart as multipart;
pub use super::__s3_simple_request as simple_request;
pub(crate) use super::__s3_xml_response as xml_response;
pub use multipart::MultiPartUpload;
}

Expand Down
112 changes: 44 additions & 68 deletions src/runtime/webcore/s3/download_stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ use core::ffi::c_void;
use core::ptr::NonNull;
use core::sync::atomic::{AtomicBool, AtomicU64, Ordering};

use bun_core::{MutableString, strings};
use bun_core::MutableString;
use bun_event_loop::ConcurrentTask::{AutoDeinit, ConcurrentTask};
use bun_event_loop::{TaskTag, Taskable, task_tag};
use bun_http::{AsyncHTTP, HTTPClientResult, Headers, Signals};
use bun_io::KeepAlive;
use bun_s3_signing::credentials::SignResult;
use bun_s3_signing::error::S3Error;

use crate::webcore::s3::xml_response;
use bun_threading::Mutex;

bun_core::declare_scope!(S3, hidden);
Expand Down Expand Up @@ -67,86 +69,60 @@ impl S3HttpDownloadStreamingTask {

fn report_progress(&mut self, state: State) {
let has_more = state.has_more();
let mut err: Option<S3Error> = None;
let failed = match state.status_code() {
200 | 204 | 206 => state.request_error() != 0,
_ => true,
};

// reshaped for borrowck — `code`/`message` borrow from
// `self.reported_response_buffer`, so we compute the chunk after the
// borrow scope ends rather than inside the labeled block.
let chunk: MutableString = 'brk: {
if failed {
if !has_more {
let mut _has_body_code = false;
let mut _has_body_message = false;

let mut code: &[u8] = b"UnknownError";
let mut message: &[u8] = b"an unexpected error has occurred";
if let Some(req_err) = self.request_error {
code = req_err.name().as_bytes();
_has_body_code = true;
} else {
let bytes = self.reported_response_buffer.list.as_slice();
if !bytes.is_empty() {
message = bytes;

if let Some(start) = strings::index_of(bytes, b"<Code>") {
let value_start = start + b"<Code>".len();
if let Some(end) =
strings::index_of(&bytes[value_start..], b"</Code>")
{
code = &bytes[value_start..value_start + end];
_has_body_code = true;
}
}
if let Some(start) = strings::index_of(bytes, b"<Message>") {
let value_start = start + b"<Message>".len();
if let Some(end) =
strings::index_of(&bytes[value_start..], b"</Message>")
{
message = &bytes[value_start..value_start + end];
_has_body_message = true;
}
}
}
}

// `code`/`message` borrow `self.reported_response_buffer`;
// the callback consumes them before any reset/deinit.
err = Some(S3Error { code, message });
}
break 'brk MutableString::default();
} else {
// `core::mem::take` transfers ownership of the buffer, leaving an
// empty MutableString behind.
let buffer = core::mem::take(&mut self.reported_response_buffer);
break 'brk buffer;
}
};
bun_core::scoped_log!(
S3,
"reportProgres failed: {} has_more: {} len: {}",
failed,
has_more,
chunk.len()
self.reported_response_buffer.list.len()
);

if failed {
if !has_more {
(self.callback)(&chunk, false, err, self.callback_context.as_ptr().cast());
if has_more {
return;
}
} else {
// dont report empty chunks if we have more data to read
if !has_more || chunk.len() > 0 {
(self.callback)(
&chunk,
has_more,
None,
self.callback_context.as_ptr().cast(),
);
self.reported_response_buffer.reset();
let empty = MutableString::default();
let mut code: &[u8] = b"UnknownError";
let mut message: &[u8] = b"an unexpected error has occurred";
let parsed;
if let Some(req_err) = self.request_error {
code = req_err.name().as_bytes();
} else {
let bytes = self.reported_response_buffer.list.as_slice();
if !bytes.is_empty() {
message = bytes;
}
parsed = xml_response::parse_error(bytes);
if let Some(error) = &parsed {
code = error.code.as_deref().unwrap_or(code);
message = error.message.as_deref().unwrap_or(message);
}
}
(self.callback)(
&empty,
false,
Some(S3Error { code, message }),
self.callback_context.as_ptr().cast(),
);
return;
}

// dont report empty chunks if we have more data to read
if !has_more || self.reported_response_buffer.list.len() > 0 {
// `core::mem::take` transfers ownership of the buffer, leaving an
// empty MutableString behind.
let chunk = core::mem::take(&mut self.reported_response_buffer);
(self.callback)(
&chunk,
has_more,
None,
self.callback_context.as_ptr().cast(),
);
self.reported_response_buffer.reset();
}
}

Expand Down
Loading