@@ -11,9 +11,10 @@ import type { IncomingMessage } from 'node:http'
1111
1212import debug from './debug.ts'
1313import type { Qs } from './qs.ts'
14- import { encodeUrl } from './helpers.ts'
14+ import { encodeUrl , getPreviousUrl } from './helpers.ts'
1515import type { Router } from './router/main.ts'
1616import type { HttpResponse } from './response.ts'
17+ import type { ResponseConfig } from './types/response.ts'
1718import type {
1819 RoutesList ,
1920 LookupList ,
@@ -22,6 +23,7 @@ import type {
2223 RouteBuilderArguments ,
2324} from './types/url_builder.ts'
2425import { safeDecodeURI } from './utils.ts'
26+ import Macroable from '@poppinss/macroable'
2527
2628/**
2729 * Provides a fluent API for constructing HTTP redirect responses.
@@ -45,7 +47,13 @@ import { safeDecodeURI } from './utils.ts'
4547 * .toPath('/dashboard')
4648 * ```
4749 */
48- export class Redirect {
50+ export class Redirect extends Macroable {
51+ /**
52+ * Array of allowed hosts for referrer-based redirects.
53+ * When empty, only the request's own host is allowed.
54+ */
55+ allowedHosts : string [ ]
56+
4957 /**
5058 * Flag indicating whether to forward the existing query string from the current request
5159 */
@@ -87,12 +95,22 @@ export class Redirect {
8795 * @param response - AdonisJS response instance
8896 * @param router - AdonisJS router instance
8997 * @param qs - Query string parser instance
98+ * @param config - Redirect configuration
9099 */
91- constructor ( request : IncomingMessage , response : HttpResponse , router : Router , qs : Qs ) {
100+ constructor (
101+ request : IncomingMessage ,
102+ response : HttpResponse ,
103+ router : Router ,
104+ qs : Qs ,
105+ config : ResponseConfig [ 'redirect' ]
106+ ) {
107+ super ( )
92108 this . #request = request
93109 this . #response = response
94110 this . #router = router
95111 this . #qs = qs
112+ this . allowedHosts = config . allowedHosts
113+ this . #forwardQueryString = config . forwardQueryString
96114 }
97115
98116 /**
@@ -113,12 +131,17 @@ export class Redirect {
113131 }
114132
115133 /**
116- * Extracts and returns the referrer URL from request headers
117- * @returns {string } The referrer URL or '/' if not found
134+ * Returns the previous URL for redirect back. By default reads
135+ * the `Referer` header and validates the host.
136+ *
137+ * Since `Redirect` extends `Macroable`, this method can be overridden
138+ * to implement custom logic such as session-based previous URL
139+ * resolution.
140+ *
141+ * @param fallback - URL to return when no valid previous URL is found
118142 */
119- #getReferrerUrl( ) : string {
120- let url = this . #request. headers [ 'referer' ] || this . #request. headers [ 'referrer' ] || '/'
121- return Array . isArray ( url ) ? url [ 0 ] : url
143+ getPreviousUrl ( fallback : string ) : string {
144+ return getPreviousUrl ( this . #request. headers , this . allowedHosts , fallback )
122145 }
123146
124147 /**
@@ -157,6 +180,23 @@ export class Redirect {
157180 * ```
158181 */
159182 withQs ( ) : this
183+ /**
184+ * Enables or disables query string forwarding from the current request.
185+ *
186+ * Use this overload to explicitly control query string forwarding,
187+ * especially useful when `forwardQueryString` is enabled by default
188+ * in the redirect config and you want to disable it for a specific redirect.
189+ *
190+ * @param forward - Whether to forward the query string
191+ * @returns The Redirect instance for method chaining
192+ *
193+ * @example
194+ * ```ts
195+ * // Disable query string forwarding for this redirect
196+ * response.redirect().withQs(false).toPath('/dashboard')
197+ * ```
198+ */
199+ withQs ( forward : boolean ) : this
160200 /**
161201 * Adds multiple query string parameters to the redirect URL
162202 *
@@ -190,12 +230,17 @@ export class Redirect {
190230 * ```
191231 */
192232 withQs ( name : string , value : any ) : this
193- withQs ( name ?: Record < string , any > | string , value ?: any ) : this {
233+ withQs ( name ?: Record < string , any > | string | boolean , value ?: any ) : this {
194234 if ( typeof name === 'undefined' ) {
195235 this . #forwardQueryString = true
196236 return this
197237 }
198238
239+ if ( typeof name === 'boolean' ) {
240+ this . #forwardQueryString = name
241+ return this
242+ }
243+
199244 if ( typeof name === 'string' ) {
200245 this . #queryString[ name ] = value
201246 return this
@@ -206,20 +251,21 @@ export class Redirect {
206251 }
207252
208253 /**
209- * Redirects to the previous path using the Referer header
210- * Falls back to '/' if no referrer is found
254+ * Redirects to the previous URL resolved via `getPreviousUrl`.
255+ *
256+ * @param fallback - URL to redirect to when no valid previous URL is found
211257 */
212- back ( ) {
258+ back ( fallback : string = '/' ) {
213259 let query : Record < string , any > = { }
214260
215- const referrerUrl = this . #getReferrerUrl ( )
216- const url = safeDecodeURI ( referrerUrl , false )
261+ const previousUrl = this . getPreviousUrl ( fallback )
262+ const url = safeDecodeURI ( previousUrl , false )
217263
218- debug ( 'referrer url "%s"' , referrerUrl )
219- debug ( 'referrer base url "%s"' , url . pathname )
264+ debug ( 'previous url "%s"' , previousUrl )
265+ debug ( 'previous base url "%s"' , url . pathname )
220266
221267 /**
222- * Parse query string from the referrer url
268+ * Parse query string from the previous url
223269 */
224270 if ( this . #forwardQueryString) {
225271 query = this . #qs. parse ( url . query || '' )
0 commit comments