Skip to content

Commit

Permalink
Merge 0ddc43c into 618895c
Browse files Browse the repository at this point in the history
  • Loading branch information
wemeetagain authored Nov 2, 2023
2 parents 618895c + 0ddc43c commit 42f5045
Show file tree
Hide file tree
Showing 7 changed files with 1,172 additions and 2 deletions.
Empty file added packages/api/src/fetch.ts
Empty file.
2 changes: 2 additions & 0 deletions packages/api/src/utils/acceptHeader.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// TODO: file can be deleted once all API definitions are updated

import {ResponseFormat} from "../interfaces.js";

enum MediaType {
Expand Down
2 changes: 1 addition & 1 deletion packages/api/src/utils/client/httpClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ export class HttpClient implements IHttpClient {
}
}

function isAbortedError(e: Error): boolean {
export function isAbortedError(e: Error): boolean {
return isFetchError(e) && e.type === "aborted";
}

Expand Down
110 changes: 110 additions & 0 deletions packages/api/src/utils/headers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import {toBase64} from "@lodestar/utils";
import {OptionalRequestInit} from "./sszTest.js";

export enum MediaType {
json = "application/json",
ssz = "application/octet-stream",
}

export const supportedMediaTypes = Object.values(MediaType);

function isSupportedMediaType(mediaType: string | null): mediaType is MediaType {
return mediaType !== null && supportedMediaTypes.includes(mediaType as MediaType);
}

export function parseContentTypeHeader(contentType?: string): MediaType | null {
if (!contentType) {
return null;
}

const mediaType = contentType.split(";", 1)[0].trim().toLowerCase();

return isSupportedMediaType(mediaType) ? mediaType : null;
}

export function parseAcceptHeader(accept?: string): MediaType | null {
if (!accept) {
return null;
}

// Respect Quality Values per RFC-9110
// Acceptable mime-types are comma separated with optional whitespace
return accept
.toLowerCase()
.split(",")
.map((x) => x.trim())
.reduce(
(best: [number, MediaType | null], current: string): [number, MediaType | null] => {
// An optional `;` delimiter is used to separate the mime-type from the weight
// Normalize here, using 1 as the default qvalue
const quality = current.includes(";") ? current.split(";") : [current, "q=1"];

const mediaType = quality[0].trim();

// If the mime type isn't acceptable, move on to the next entry
if (!isSupportedMediaType(mediaType)) {
return best;
}

// Otherwise, the portion after the semicolon has optional whitespace and the constant prefix "q="
const weight = quality[1].trim();
if (!weight.startsWith("q=")) {
// If the format is invalid simply move on to the next entry
return best;
}

const qvalue = +weight.replace("q=", "");
if (isNaN(qvalue) || qvalue > 1 || qvalue <= 0) {
// If we can't convert the qvalue to a valid number, move on
return best;
}

if (qvalue < best[0]) {
// This mime type is not preferred
return best;
}

// This mime type is preferred
return [qvalue, mediaType];
},
[0, null]
)[1];
}

export function setAuthorizationHeader(url: URL, headers: Headers, {bearerToken}: OptionalRequestInit): void {
if (bearerToken && !headers.has("Authorization")) {
headers.set("Authorization", `Bearer ${bearerToken}`);
}
if (url.username || url.password) {
if (!headers.has("Authorization")) {
headers.set("Authorization", `Basic ${toBase64(`${url.username}:${url.password}`)}`);
}
// Remove the username and password from the URL
url.username = "";
url.password = "";
}
}

export function mergeHeaders(a: HeadersInit | undefined, b: HeadersInit | undefined): Headers {
if (!a) {
return new Headers(b);
}
const headers = new Headers(a);
if (!b) {
return headers;
}
if (Array.isArray(b)) {
for (const [key, value] of b) {
headers.set(key, value);
}
} else if (b instanceof Headers) {
for (const [key, value] of b as unknown as Iterable<[string, string]>) {
headers.set(key, value);
}
} else {
for (const [key, value] of Object.entries(b)) {
headers.set(key, value);
}
}
return headers;
}
Loading

0 comments on commit 42f5045

Please sign in to comment.