Repository: honojs/hono
File: src/middleware/secure-headers/secure-headers.ts (TypeScript)

Code before:
    await next()
    setHeaders(ctx, headersToSetForReq)

    if (options?.removePoweredBy) {
      ctx.res.headers.delete('X-Powered-By')
    }
  }
}

function getFilteredHeaders(options: SecureHeadersOptions): [string, string][] {
  return Object.entries(HEADERS_MAP)
    .filter(([key]) => options[key as keyof SecureHeadersOptions])
    .map(([key, defaultValue]) => {
      const overrideValue = options[key as keyof SecureHeadersOptions]
      return typeof overrideValue === 'string' ? [defaultValue[0], overrideValue] : defaultValue
    })
}

function getCSPDirectives(
  contentSecurityPolicy: ContentSecurityPolicyOptions
): [SecureHeadersCallback | undefined, string | string[]] {
  const callbacks: ((ctx: Context, values: string[]) => void)[] = []
  const resultValues: string[] = []

  for (const [directive, value] of Object.entries(contentSecurityPolicy)) {
    if (directive === 'reportUri') {
      continue
    }
    const valueArray = Array.isArray(value) ? value : [value]

    valueArray.forEach((value, i) => {
      if (typeof value === 'function') {
        const index = i * 2 + 2 + resultValues.length
        callbacks.push((ctx, values) => {
          values[index] = value(ctx, directive)
        })
      }
    })

    resultValues.push(
      directive.replace(/[A-Z]+(?![a-z])|[A-Z]/g, (match, offset) =>
        offset ? '-' + match.toLowerCase() : match.toLowerCase()
      ),
      ...valueArray.flatMap((value) => [' ', value]),
      '; '
    )
  }
  if (contentSecurityPolicy.reportUri) {
    const uris = Array.isArray(contentSecurityPolicy.reportUri)
      ? contentSecurityPolicy.reportUri
      : [contentSecurityPolicy.reportUri]

Review comment (security):
I realized that this `if (directive === 'reportUri') {}` and `if (contentSecurityPolicy.reportUri) {}` is not necessary, right?

So I think that we can apply this patch:

```diff
diff --git a/src/middleware/secure-headers/secure-headers.ts b/src/middleware/secure-headers/secure-headers.ts
index 55afa21d..cb81a0fd 100644
--- a/src/middleware/secure-headers/secure-headers.ts
+++ b/src/middleware/secure-headers/secure-headers.ts
@@ -244,9 +244,6 @@ function getCSPDirectives(
   const resultValues: string[] = []

   for (const [directive, value] of Object.entries(contentSecurityPolicy)) {
-    if (directive === 'reportUri') {
-      continue
-    }
     const valueArray = Array.isArray(value) ? value : [value]

     valueArray.forEach((value, i) => {
@@ -266,12 +263,6 @@ function getCSPDirectives(
       '; '
     )
   }
-  if (contentSecurityPolicy.reportUri) {
-    const uris = Array.isArray(contentSecurityPolicy.reportUri)
-      ? contentSecurityPolicy.reportUri
-      : [contentSecurityPolicy.reportUri]
-    resultValues.push('report-uri', ' ', uris.join(' '), '; ')
-  }
   resultValues.pop()

   return callbacks.length === 0
```

Code after:
    await next()
    setHeaders(ctx, headersToSetForReq)

    if (options?.removePoweredBy) {
      ctx.res.headers.delete('X-Powered-By')
    }
  }
}

function getFilteredHeaders(options: SecureHeadersOptions): [string, string][] {
  return Object.entries(HEADERS_MAP)
    .filter(([key]) => options[key as keyof SecureHeadersOptions])
    .map(([key, defaultValue]) => {
      const overrideValue = options[key as keyof SecureHeadersOptions]
      return typeof overrideValue === 'string' ? [defaultValue[0], overrideValue] : defaultValue
    })
}

function getCSPDirectives(
  contentSecurityPolicy: ContentSecurityPolicyOptions
): [SecureHeadersCallback | undefined, string | string[]] {
  const callbacks: ((ctx: Context, values: string[]) => void)[] = []
  const resultValues: string[] = []

  for (const [directive, value] of Object.entries(contentSecurityPolicy)) {
    const valueArray = Array.isArray(value) ? value : [value]

    valueArray.forEach((value, i) => {
      if (typeof value === 'function') {
        const index = i * 2 + 2 + resultValues.length
        callbacks.push((ctx, values) => {
          values[index] = value(ctx, directive)
        })
      }
    })

    resultValues.push(
      directive.replace(/[A-Z]+(?![a-z])|[A-Z]/g, (match, offset) =>
        offset ? '-' + match.toLowerCase() : match.toLowerCase()
      ),
      ...valueArray.flatMap((value) => [' ', value]),
      '; '
    )
  }
  resultValues.pop()

  return callbacks.length === 0
    ? [undefined, resultValues.join('')]
    : [
        (ctx, headersToSet) =>
          headersToSet.map((values) => {