Repository: honojs/hono
File: src/request.ts (TypeScript)

Code before:
 * - Pass requests to external services after validation
 *
 * @param req - The HonoRequest object to clone
 * @returns A Promise that resolves to a new Request object with the same properties
 *
 * @example
 * ```ts
 * // Clone after consuming the body (e.g., after validation)
 * app.post('/forward',
 *   validator('json', (data) => data),
 *   async (c) => {
 *     const validated = c.req.valid('json')
 *     // Body has been consumed, but cloneRawRequest still works
 *     const clonedReq = await cloneRawRequest(c.req)
 *     return fetch('http://backend-service.com', clonedReq)
 *   }
 * )
 * ```
 */
export const cloneRawRequest = async (req: HonoRequest): Promise<Request> => {
  if (!req.raw.bodyUsed) {
    return req.raw.clone()
  }

  return new Request(req.raw.url, {
    method: req.raw.method,
    headers: req.raw.headers,
    body: await req.blob(),
  })
}

export class HonoRequest<P extends string = '/', I extends Input['out'] = {}> {
  /**
   * `.raw` can get the raw Request object.
   *
   * @see {@link https://hono.dev/docs/api/request#raw}
   *
   * @example
   * ```ts
   * // For Cloudflare Workers
   * app.post('/', async (c) => {
   *   const metadata = c.req.raw.cf?.hostMetadata?
   *   ...
   * })
   * ```
   */
  raw: Request

  #validatedData: { [K in keyof ValidationTargets]?: {} } // Short name of validatedData
  #matchResult: Result<[unknown, RouterRoute]>
  routeIndex: number = 0

Review comment (security):
Should we copy other properties, such as `credentials`, `mode`, and `single`?

```ts
// all properties
new Request(req.raw.url, {
  method: req.raw.method,
  headers: req.raw.headers,
  body: await req.blob(),
  mode: req.raw.mode,
  credentials: req.raw.credentials,
  cache: req.raw.cache,
  redirect: req.raw.redirect,
  referrer: req.raw.referrer,
  referrerPolicy: req.raw.referrerPolicy,
  integrity: req.raw.integrity,
  keepalive: req.raw.keepalive,
})
```

@kamaal111 @usualoma What do you think of this?

Code after:
   *
   * @see {@link https://hono.dev/docs/api/request#raw}
   *
   * @example
   * ```ts
   * // For Cloudflare Workers
   * app.post('/', async (c) => {
   *   const metadata = c.req.raw.cf?.hostMetadata?
   *   ...
   * })
   * ```
   */
  raw: Request

  #validatedData: { [K in keyof ValidationTargets]?: {} } // Short name of validatedData
  #matchResult: Result<[unknown, RouterRoute]>
  routeIndex: number = 0
  /**
   * `.path` can get the pathname of the request.
   *
   * @see {@link https://hono.dev/docs/api/request#path}
   *
   * @example
   * ```ts
   * app.get('/about/me', (c) => {
   *   const pathname = c.req.path // `/about/me`
   * })
   * ```
   */
  path: string
  bodyCache: BodyCache = {}

  constructor(
    request: Request,
    path: string = '/',
    matchResult: Result<[unknown, RouterRoute]> = [[]]
  ) {
    this.raw = request
    this.path = path
    this.#matchResult = matchResult
    this.#validatedData = {}
  }

  /**
   * `.req.param()` gets the path parameters.
   *
   * @see {@link https://hono.dev/docs/api/routing#path-parameter}
   *
   * @example
   * ```ts
   * const name = c.req.param('name')