mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-10-03 05:43:50 +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 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) {
|
// Special handling for headers
|
||||||
if (
|
if (init1.headers || init2.headers) {
|
||||||
typeof a[key as unknown as keyof T] === 'object'
|
const headers1 = init1.headers ? normalizeHeaders(init1.headers) : {};
|
||||||
&& a[key as unknown as keyof T] !== null
|
const headers2 = init2.headers ? normalizeHeaders(init2.headers) : {};
|
||||||
&& typeof b[key] === 'object'
|
|
||||||
&& b[key] !== null
|
const mergedHeaders = { ...headers1 };
|
||||||
) {
|
|
||||||
result[key] = mergeObjectsDeeply(
|
// For each header in headers2, check if a case-insensitive match exists in mergedHeaders
|
||||||
a[key as unknown as keyof T] as object,
|
Object.entries(headers2).forEach(([key2, value2]) => {
|
||||||
b[key],
|
const existingKey = Object.keys(mergedHeaders).find(
|
||||||
) as (T & S)[Extract<keyof S, string>];
|
key1 => key1.toLowerCase() === key2.toLowerCase(),
|
||||||
} else {
|
);
|
||||||
result[key] = b[key] as (T & S)[Extract<keyof S, string>];
|
|
||||||
}
|
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 (
|
export const retriedFetch = async (
|
||||||
|
|||||||
+3
-3
@@ -12,7 +12,7 @@ import {
|
|||||||
binarySearchLessOrEqual,
|
binarySearchLessOrEqual,
|
||||||
closedIntervalsOverlap,
|
closedIntervalsOverlap,
|
||||||
MaybePromise,
|
MaybePromise,
|
||||||
mergeObjectsDeeply,
|
mergeRequestInit,
|
||||||
promiseWithResolvers,
|
promiseWithResolvers,
|
||||||
retriedFetch,
|
retriedFetch,
|
||||||
toDataView,
|
toDataView,
|
||||||
@@ -326,7 +326,7 @@ export class UrlSource extends Source {
|
|||||||
const abortController = new AbortController();
|
const abortController = new AbortController();
|
||||||
const response = await retriedFetch(
|
const response = await retriedFetch(
|
||||||
this._url,
|
this._url,
|
||||||
mergeObjectsDeeply(this._options.requestInit ?? {}, {
|
mergeRequestInit(this._options.requestInit ?? {}, {
|
||||||
headers: {
|
headers: {
|
||||||
// We could also send a non-range request to request the same bytes (all of them), but doing it like
|
// 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
|
// 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();
|
abortController = new AbortController();
|
||||||
response = await retriedFetch(
|
response = await retriedFetch(
|
||||||
this._url,
|
this._url,
|
||||||
mergeObjectsDeeply(this._options.requestInit ?? {}, {
|
mergeRequestInit(this._options.requestInit ?? {}, {
|
||||||
headers: {
|
headers: {
|
||||||
Range: `bytes=${worker.currentPos}-`,
|
Range: `bytes=${worker.currentPos}-`,
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user