mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-09-27 02:43:48 +02:00
Properly merge different forms of headers in UrlSource (#126)
This commit is contained in:
+50
-17
@@ -519,26 +519,59 @@ export const SECOND_TO_MICROSECOND_FACTOR = 1e6 * (1 + Number.EPSILON);
|
||||
*/
|
||||
export type SetRequired<T, K extends keyof T> = T & Required<Pick<T, K>>;
|
||||
|
||||
export const mergeObjectsDeeply = <T extends object, S extends object>(a: T, b: S): T & S => {
|
||||
const result = { ...a } as T & S;
|
||||
/**
|
||||
* Merges two RequestInit objects with special handling for headers.
|
||||
* Headers are merged case-insensitively, but original casing is preserved.
|
||||
* init2 headers take precedence and will override case-insensitive matches from init1.
|
||||
*/
|
||||
export const mergeRequestInit = (init1: RequestInit, init2: RequestInit): RequestInit => {
|
||||
const merged: RequestInit = { ...init1, ...init2 };
|
||||
|
||||
for (const key in b) {
|
||||
if (
|
||||
typeof a[key as unknown as keyof T] === 'object'
|
||||
&& a[key as unknown as keyof T] !== null
|
||||
&& typeof b[key] === 'object'
|
||||
&& b[key] !== null
|
||||
) {
|
||||
result[key] = mergeObjectsDeeply(
|
||||
a[key as unknown as keyof T] as object,
|
||||
b[key],
|
||||
) as (T & S)[Extract<keyof S, string>];
|
||||
} else {
|
||||
result[key] = b[key] as (T & S)[Extract<keyof S, string>];
|
||||
}
|
||||
// Special handling for headers
|
||||
if (init1.headers || init2.headers) {
|
||||
const headers1 = init1.headers ? normalizeHeaders(init1.headers) : {};
|
||||
const headers2 = init2.headers ? normalizeHeaders(init2.headers) : {};
|
||||
|
||||
const mergedHeaders = { ...headers1 };
|
||||
|
||||
// For each header in headers2, check if a case-insensitive match exists in mergedHeaders
|
||||
Object.entries(headers2).forEach(([key2, value2]) => {
|
||||
const existingKey = Object.keys(mergedHeaders).find(
|
||||
key1 => key1.toLowerCase() === key2.toLowerCase(),
|
||||
);
|
||||
|
||||
if (existingKey) {
|
||||
delete mergedHeaders[existingKey];
|
||||
}
|
||||
|
||||
mergedHeaders[key2] = value2;
|
||||
});
|
||||
|
||||
merged.headers = mergedHeaders;
|
||||
}
|
||||
|
||||
return result;
|
||||
return merged;
|
||||
};
|
||||
|
||||
/** Normalizes HeadersInit to a Record<string, string> format. */
|
||||
const normalizeHeaders = (headers: HeadersInit): Record<string, string> => {
|
||||
if (headers instanceof Headers) {
|
||||
const result: Record<string, string> = {};
|
||||
headers.forEach((value, key) => {
|
||||
result[key] = value;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
if (Array.isArray(headers)) {
|
||||
const result: Record<string, string> = {};
|
||||
headers.forEach(([key, value]) => {
|
||||
result[key] = value;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
return headers;
|
||||
};
|
||||
|
||||
export const retriedFetch = async (
|
||||
|
||||
+3
-3
@@ -12,7 +12,7 @@ import {
|
||||
binarySearchLessOrEqual,
|
||||
closedIntervalsOverlap,
|
||||
MaybePromise,
|
||||
mergeObjectsDeeply,
|
||||
mergeRequestInit,
|
||||
promiseWithResolvers,
|
||||
retriedFetch,
|
||||
toDataView,
|
||||
@@ -326,7 +326,7 @@ export class UrlSource extends Source {
|
||||
const abortController = new AbortController();
|
||||
const response = await retriedFetch(
|
||||
this._url,
|
||||
mergeObjectsDeeply(this._options.requestInit ?? {}, {
|
||||
mergeRequestInit(this._options.requestInit ?? {}, {
|
||||
headers: {
|
||||
// We could also send a non-range request to request the same bytes (all of them), but doing it like
|
||||
// this is an easy way to check if the server supports range requests in the first place
|
||||
@@ -393,7 +393,7 @@ export class UrlSource extends Source {
|
||||
abortController = new AbortController();
|
||||
response = await retriedFetch(
|
||||
this._url,
|
||||
mergeObjectsDeeply(this._options.requestInit ?? {}, {
|
||||
mergeRequestInit(this._options.requestInit ?? {}, {
|
||||
headers: {
|
||||
Range: `bytes=${worker.currentPos}-`,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user