Skip to content

Commit

Permalink
fix(http): parse readablestream data on fetch request objects
Browse files Browse the repository at this point in the history
  • Loading branch information
ItsChaceD committed Sep 21, 2023
1 parent 687b6b1 commit 3fe0642
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 9 deletions.
50 changes: 47 additions & 3 deletions android/capacitor/src/main/assets/native-bridge.js
Expand Up @@ -64,8 +64,52 @@ var nativeBridge = (function (exports) {
}
return newFormData;
};
const convertBody = async (body) => {
if (body instanceof FormData) {
const convertBody = async (body, contentType) => {
if (body instanceof ReadableStream) {
const reader = body.getReader();
const chunks = [];
while (true) {
const { done, value } = await reader.read();
if (done)
break;
chunks.push(value);
}
const concatenated = new Uint8Array(chunks.reduce((acc, chunk) => acc + chunk.length, 0));
let position = 0;
for (const chunk of chunks) {
concatenated.set(chunk, position);
position += chunk.length;
}
let data = new TextDecoder().decode(concatenated);
let type;
if (contentType === 'application/json') {
try {
data = JSON.parse(data);
}
catch (ignored) {
// ignore
}
type = 'json';
}
else if (contentType === 'multipart/form-data') {
type = 'formData';
}
else if (contentType === null || contentType === void 0 ? void 0 : contentType.startsWith('image')) {
type = 'image';
}
else if (contentType === 'application/octet-stream') {
type = 'binary';
}
else {
type = 'text';
}
return {
data,
type,
headers: { 'Content-Type': contentType || 'application/octet-stream' },
};
}
else if (body instanceof FormData) {
const formData = await convertFormData(body);
const boundary = `${Date.now()}`;
return {
Expand Down Expand Up @@ -434,8 +478,8 @@ var nativeBridge = (function (exports) {
try {
// intercept request & pass to the bridge
const { body, method } = request;
const { data: requestData, type, headers, } = await convertBody(body || undefined);
const optionHeaders = Object.fromEntries(request.headers.entries());
const { data: requestData, type, headers, } = await convertBody((options === null || options === void 0 ? void 0 : options.body) || body || undefined, optionHeaders['Content-Type'] || optionHeaders['content-type']);
const nativeResponse = await cap.nativePromise('CapacitorHttp', 'request', {
url: request.url,
method: method,
Expand Down
51 changes: 48 additions & 3 deletions core/native-bridge.ts
Expand Up @@ -53,8 +53,50 @@ const convertFormData = async (formData: FormData): Promise<any> => {

const convertBody = async (
body: Document | XMLHttpRequestBodyInit | ReadableStream<any> | undefined,
contentType?: string,
): Promise<any> => {
if (body instanceof FormData) {
if (body instanceof ReadableStream) {
const reader = body.getReader();
const chunks: any[] = [];
while (true) {
const { done, value } = await reader.read();
if (done) break;
chunks.push(value);
}
const concatenated = new Uint8Array(
chunks.reduce((acc, chunk) => acc + chunk.length, 0),
);
let position = 0;
for (const chunk of chunks) {
concatenated.set(chunk, position);
position += chunk.length;
}

let data = new TextDecoder().decode(concatenated);
let type;
if (contentType === 'application/json') {
try {
data = JSON.parse(data);
} catch (ignored) {
// ignore
}
type = 'json';
} else if (contentType === 'multipart/form-data') {
type = 'formData';
} else if (contentType?.startsWith('image')) {
type = 'image';
} else if (contentType === 'application/octet-stream') {
type = 'binary';
} else {
type = 'text';
}

return {
data,
type,
headers: { 'Content-Type': contentType || 'application/octet-stream' },
};
} else if (body instanceof FormData) {
const formData = await convertFormData(body);
const boundary = `${Date.now()}`;
return {
Expand Down Expand Up @@ -488,12 +530,15 @@ const initBridge = (w: any): void => {
try {
// intercept request & pass to the bridge
const { body, method } = request;
const optionHeaders = Object.fromEntries(request.headers.entries());
const {
data: requestData,
type,
headers,
} = await convertBody(body || undefined);
const optionHeaders = Object.fromEntries(request.headers.entries());
} = await convertBody(
options?.body || body || undefined,
optionHeaders['Content-Type'] || optionHeaders['content-type'],
);
const nativeResponse: HttpResponse = await cap.nativePromise(
'CapacitorHttp',
'request',
Expand Down
50 changes: 47 additions & 3 deletions ios/Capacitor/Capacitor/assets/native-bridge.js
Expand Up @@ -64,8 +64,52 @@ var nativeBridge = (function (exports) {
}
return newFormData;
};
const convertBody = async (body) => {
if (body instanceof FormData) {
const convertBody = async (body, contentType) => {
if (body instanceof ReadableStream) {
const reader = body.getReader();
const chunks = [];
while (true) {
const { done, value } = await reader.read();
if (done)
break;
chunks.push(value);
}
const concatenated = new Uint8Array(chunks.reduce((acc, chunk) => acc + chunk.length, 0));
let position = 0;
for (const chunk of chunks) {
concatenated.set(chunk, position);
position += chunk.length;
}
let data = new TextDecoder().decode(concatenated);
let type;
if (contentType === 'application/json') {
try {
data = JSON.parse(data);
}
catch (ignored) {
// ignore
}
type = 'json';
}
else if (contentType === 'multipart/form-data') {
type = 'formData';
}
else if (contentType === null || contentType === void 0 ? void 0 : contentType.startsWith('image')) {
type = 'image';
}
else if (contentType === 'application/octet-stream') {
type = 'binary';
}
else {
type = 'text';
}
return {
data,
type,
headers: { 'Content-Type': contentType || 'application/octet-stream' },
};
}
else if (body instanceof FormData) {
const formData = await convertFormData(body);
const boundary = `${Date.now()}`;
return {
Expand Down Expand Up @@ -434,8 +478,8 @@ var nativeBridge = (function (exports) {
try {
// intercept request & pass to the bridge
const { body, method } = request;
const { data: requestData, type, headers, } = await convertBody(body || undefined);
const optionHeaders = Object.fromEntries(request.headers.entries());
const { data: requestData, type, headers, } = await convertBody((options === null || options === void 0 ? void 0 : options.body) || body || undefined, optionHeaders['Content-Type'] || optionHeaders['content-type']);
const nativeResponse = await cap.nativePromise('CapacitorHttp', 'request', {
url: request.url,
method: method,
Expand Down

0 comments on commit 3fe0642

Please sign in to comment.