UNPKG

@remix-run/headers

Version:

A toolkit for working with HTTP headers in JavaScript

99 lines (87 loc) 2.68 kB
import { type HeaderValue } from './header-value.ts' import { quoteEtag } from './utils.ts' /** * Initializer for an `If-Match` header value. */ export interface IfMatchInit { /** * The entity tags to compare against the current entity. */ tags: string[] } /** * The value of an `If-Match` HTTP header. * * [MDN `If-Match` Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Match) * * [HTTP/1.1 Specification](https://datatracker.ietf.org/doc/html/rfc7232#section-3.1) */ export class IfMatch implements HeaderValue, IfMatchInit { tags: string[] = [] /** * @param init A string, array of strings, or object to initialize the header */ constructor(init?: string | string[] | IfMatchInit) { if (init) { if (typeof init === 'string') { this.tags.push(...init.split(/\s*,\s*/).map(quoteEtag)) } else if (Array.isArray(init)) { this.tags.push(...init.map(quoteEtag)) } else { this.tags.push(...init.tags.map(quoteEtag)) } } } /** * Checks if the header contains the given entity tag. * * Note: This method checks only for exact matches and does not consider wildcards. * * @param tag The entity tag to check for * @return `true` if the tag is present in the header, `false` otherwise */ has(tag: string): boolean { return this.tags.includes(quoteEtag(tag)) } /** * Checks if the precondition passes for the given entity tag. * * This method always returns `true` if the `If-Match` header is not present * since the precondition passes regardless of the entity tag being checked. * * Uses strong comparison as per RFC 9110, meaning weak entity tags (prefixed with `W/`) * will never match. * * @param tag The entity tag to check against * @return `true` if the precondition passes, `false` if it fails (should return 412) */ matches(tag: string): boolean { if (this.tags.length === 0) { return true } // Wildcard always matches (regardless of weak/strong) if (this.tags.includes('*')) { return true } let normalizedTag = quoteEtag(tag) // Weak tags never match in If-Match (strong comparison only) if (normalizedTag.startsWith('W/')) { return false } // Only match against strong tags in the header for (let headerTag of this.tags) { if (!headerTag.startsWith('W/') && headerTag === normalizedTag) { return true } } return false } /** * Returns the string representation of the header value. * * @return The header value as a string */ toString() { return this.tags.join(', ') } }