1
1
import { next } from "@vercel/edge" ;
2
2
import { ipAddress } from "@vercel/functions" ;
3
3
import * as redirectionio from "@redirection.io/redirectionio" ;
4
+ import { NextResponse } from "next/server" ;
4
5
const REDIRECTIONIO_TOKEN = process . env . REDIRECTIONIO_TOKEN || "" ;
5
6
const REDIRECTIONIO_INSTANCE_NAME = process . env . REDIRECTIONIO_INSTANCE_NAME || "redirection-io-vercel-middleware" ;
6
7
const REDIRECTIONIO_VERSION = "redirection-io-vercel-middleware/0.3.12" ;
@@ -10,6 +11,8 @@ const REDIRECTIONIO_ADD_HEADER_RULE_IDS = process.env.REDIRECTIONIO_ADD_HEADER_R
10
11
const REDIRECTIONIO_TIMEOUT = process . env . REDIRECTIONIO_TIMEOUT ? parseInt ( process . env . REDIRECTIONIO_TIMEOUT , 10 ) : 500 ;
11
12
const DEFAULT_CONFIG = {
12
13
matcherRegex : "^/((?!api/|_next/|_static/|_vercel|[\\w-]+\\.\\w+).*)$" ,
14
+ mode : "full" ,
15
+ logged : true ,
13
16
} ;
14
17
export const createRedirectionIoMiddleware = ( config ) => {
15
18
return async ( request , context ) => {
@@ -22,10 +25,8 @@ export const createRedirectionIoMiddleware = (config) => {
22
25
return next ( ) ;
23
26
}
24
27
// Avoid infinite loop
25
- if (
26
- request . headers . get ( "x-redirectionio-middleware" ) === "true" ||
27
- request . headers . get ( "User-Agent" ) === "Vercel Edge Functions"
28
- ) {
28
+ if ( request . headers . get ( "x-redirectionio-middleware" ) === "true" ||
29
+ request . headers . get ( "User-Agent" ) === "Vercel Edge Functions" ) {
29
30
return next ( ) ;
30
31
}
31
32
const body = request . body ? await request . arrayBuffer ( ) : null ;
@@ -41,13 +42,17 @@ export const createRedirectionIoMiddleware = (config) => {
41
42
}
42
43
middlewareRequest = middlewareResponseToRequest ( middlewareRequest , response , body ) ;
43
44
}
44
- return handler ( middlewareRequest , context , async ( request , useFetch ) => {
45
+ return handler ( middlewareRequest , context , config , async ( request , useFetch ) => {
45
46
let response = null ;
46
47
if ( config . nextMiddleware ) {
47
48
response = await config . nextMiddleware ( request , context ) ;
48
49
if ( response . status !== 200 ) {
49
50
return response ;
50
51
}
52
+ // If light mode, only return the response
53
+ if ( config . mode === "light" ) {
54
+ return response ;
55
+ }
51
56
request = middlewareResponseToRequest ( request , response , body ) ;
52
57
}
53
58
if ( ! useFetch ) {
@@ -71,7 +76,7 @@ export const createRedirectionIoMiddleware = (config) => {
71
76
} ;
72
77
const defaultMiddleware = createRedirectionIoMiddleware ( { } ) ;
73
78
export default defaultMiddleware ;
74
- async function handler ( request , context , fetchResponse ) {
79
+ async function handler ( request , context , config , fetchResponse ) {
75
80
if ( ! REDIRECTIONIO_TOKEN ) {
76
81
console . warn ( "No REDIRECTIONIO_TOKEN environment variable found. Skipping redirection.io middleware." ) ;
77
82
return fetchResponse ( request , false ) ;
@@ -87,14 +92,18 @@ async function handler(request, context, fetchResponse) {
87
92
} ) ;
88
93
const url = new URL ( request . url ) ;
89
94
const location = response . headers . get ( "Location" ) ;
90
- if ( location && location . startsWith ( "/" ) ) {
95
+ const hasLocation = location && location . startsWith ( "/" ) ;
96
+ if ( hasLocation ) {
91
97
response . headers . set ( "Location" , url . origin + location ) ;
92
98
}
93
- context . waitUntil (
94
- ( async function ( ) {
99
+ if ( config . logged ) {
100
+ context . waitUntil ( ( async function ( ) {
95
101
await log ( response , backendStatusCode , redirectionIORequest , startTimestamp , action , ip ) ;
96
- } ) ( ) ,
97
- ) ;
102
+ } ) ( ) ) ;
103
+ }
104
+ if ( config . mode === "light" && hasLocation ) {
105
+ return NextResponse . redirect ( url . origin + location , response . status ) ;
106
+ }
98
107
return response ;
99
108
}
100
109
function splitSetCookies ( cookiesString ) {
@@ -137,12 +146,14 @@ function splitSetCookies(cookiesString) {
137
146
pos = nextStart ;
138
147
cookiesStrings . push ( cookiesString . substring ( start , lastComma ) ) ;
139
148
start = pos ;
140
- } else {
149
+ }
150
+ else {
141
151
// in param ',' or param separator ';',
142
152
// we continue from that comma
143
153
pos = lastComma + 1 ;
144
154
}
145
- } else {
155
+ }
156
+ else {
146
157
pos += 1 ;
147
158
}
148
159
}
@@ -154,12 +165,7 @@ function splitSetCookies(cookiesString) {
154
165
}
155
166
function createRedirectionIORequest ( request , ip ) {
156
167
const urlObject = new URL ( request . url ) ;
157
- const redirectionioRequest = new redirectionio . Request (
158
- urlObject . pathname + urlObject . search ,
159
- urlObject . host ,
160
- urlObject . protocol . replace ( ":" , "" ) ,
161
- request . method ,
162
- ) ;
168
+ const redirectionioRequest = new redirectionio . Request ( urlObject . pathname + urlObject . search , urlObject . host , urlObject . protocol . replace ( ":" , "" ) , request . method ) ;
163
169
request . headers . forEach ( ( value , key ) => {
164
170
redirectionioRequest . add_header ( key , value ) ;
165
171
} ) ;
@@ -195,7 +201,7 @@ function middlewareResponseToRequest(originalRequest, response, body) {
195
201
}
196
202
async function fetchRedirectionIOAction ( redirectionIORequest ) {
197
203
try {
198
- const response = await Promise . race ( [
204
+ const response = ( await Promise . race ( [
199
205
fetch ( "https://agent.redirection.io/" + REDIRECTIONIO_TOKEN + "/action" , {
200
206
method : "POST" ,
201
207
body : redirectionIORequest . serialize ( ) . toString ( ) ,
@@ -206,13 +212,14 @@ async function fetchRedirectionIOAction(redirectionIORequest) {
206
212
cache : "no-store" ,
207
213
} ) ,
208
214
new Promise ( ( _ , reject ) => setTimeout ( ( ) => reject ( new Error ( "Timeout" ) ) , REDIRECTIONIO_TIMEOUT ) ) ,
209
- ] ) ;
215
+ ] ) ) ;
210
216
const actionStr = await response . text ( ) ;
211
217
if ( actionStr === "" ) {
212
218
return redirectionio . Action . empty ( ) ;
213
219
}
214
220
return new redirectionio . Action ( actionStr ) ;
215
- } catch ( e ) {
221
+ }
222
+ catch ( e ) {
216
223
console . error ( e ) ;
217
224
return redirectionio . Action . empty ( ) ;
218
225
}
@@ -224,7 +231,8 @@ async function proxy(request, action, fetchResponse) {
224
231
let response ;
225
232
if ( statusCodeBeforeResponse === 0 ) {
226
233
response = await fetchResponse ( request , true ) ;
227
- } else {
234
+ }
235
+ else {
228
236
response = new Response ( "" , {
229
237
status : Number ( statusCodeBeforeResponse ) ,
230
238
} ) ;
@@ -242,7 +250,8 @@ async function proxy(request, action, fetchResponse) {
242
250
for ( const cookie of cookies ) {
243
251
headerMap . add_header ( "set-cookie" , cookie ) ;
244
252
}
245
- } else {
253
+ }
254
+ else {
246
255
headerMap . add_header ( key , value ) ;
247
256
}
248
257
} ) ;
@@ -268,7 +277,8 @@ async function proxy(request, action, fetchResponse) {
268
277
const { readable, writable } = new TransformStream ( ) ;
269
278
createBodyFilter ( response . body , writable , bodyFilter ) ;
270
279
return [ new Response ( readable , response ) , backendStatusCode ] ;
271
- } catch ( err ) {
280
+ }
281
+ catch ( err ) {
272
282
console . error ( err ) ;
273
283
const response = await fetchResponse ( request , true ) ;
274
284
return [ response , response . status ] ;
@@ -315,15 +325,7 @@ async function log(response, backendStatusCode, redirectionioRequest, startTimes
315
325
return ;
316
326
}
317
327
try {
318
- const logAsJson = redirectionio . create_log_in_json (
319
- redirectionioRequest ,
320
- response . status ,
321
- responseHeaderMap ,
322
- action ,
323
- "vercel-edge-middleware/" + REDIRECTIONIO_VERSION ,
324
- BigInt ( startTimestamp ) ,
325
- clientIP ?? "" ,
326
- ) ;
328
+ const logAsJson = redirectionio . create_log_in_json ( redirectionioRequest , response . status , responseHeaderMap , action , "vercel-edge-middleware/" + REDIRECTIONIO_VERSION , BigInt ( startTimestamp ) , clientIP ?? "" ) ;
327
329
return await fetch ( "https://agent.redirection.io/" + REDIRECTIONIO_TOKEN + "/log" , {
328
330
method : "POST" ,
329
331
body : logAsJson ,
@@ -333,7 +335,8 @@ async function log(response, backendStatusCode, redirectionioRequest, startTimes
333
335
} ,
334
336
cache : "no-store" ,
335
337
} ) ;
336
- } catch ( err ) {
338
+ }
339
+ catch ( err ) {
337
340
console . error ( err ) ;
338
341
}
339
342
}
0 commit comments