feat: support redirects for a list of header paths (#7411)
* add country code to meta tag * use blocked paths header * proper types * add test * Update functions/components/metaTagInjector.ts Co-authored-by: Zach Pomerantz <zzmp@uniswap.org> * Update functions/components/metaTagInjector.ts Co-authored-by: Zach Pomerantz <zzmp@uniswap.org> * Update src/pages/App.tsx Co-authored-by: Zach Pomerantz <zzmp@uniswap.org> * pr suggestions * skip failing e2e * revert test change * take file from main --------- Co-authored-by: Zach Pomerantz <zzmp@uniswap.org>
This commit is contained in:
parent
3ced65b8a4
commit
e6519a7dd1
@ -11,7 +11,7 @@ export const onRequest: PagesFunction = async ({ request, next }) => {
|
|||||||
}
|
}
|
||||||
const res = next()
|
const res = next()
|
||||||
try {
|
try {
|
||||||
return new HTMLRewriter().on('head', new MetaTagInjector(data)).transform(await res)
|
return new HTMLRewriter().on('head', new MetaTagInjector(data, request)).transform(await res)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,15 @@ test('should append meta tag to element', () => {
|
|||||||
} as unknown as Element
|
} as unknown as Element
|
||||||
const property = 'property'
|
const property = 'property'
|
||||||
const content = 'content'
|
const content = 'content'
|
||||||
const injector = new MetaTagInjector({
|
const injector = new MetaTagInjector(
|
||||||
|
{
|
||||||
title: 'test',
|
title: 'test',
|
||||||
url: 'testUrl',
|
url: 'testUrl',
|
||||||
image: 'testImage',
|
image: 'testImage',
|
||||||
description: 'testDescription',
|
description: 'testDescription',
|
||||||
})
|
},
|
||||||
|
new Request('http://localhost')
|
||||||
|
)
|
||||||
injector.append(element, property, content)
|
injector.append(element, property, content)
|
||||||
expect(element.append).toHaveBeenCalledWith(`<meta property="${property}" content="${content}"/>`, { html: true })
|
expect(element.append).toHaveBeenCalledWith(`<meta property="${property}" content="${content}"/>`, { html: true })
|
||||||
|
|
||||||
@ -36,3 +39,22 @@ test('should append meta tag to element', () => {
|
|||||||
|
|
||||||
expect(element.append).toHaveBeenCalledTimes(13)
|
expect(element.append).toHaveBeenCalledTimes(13)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('should pass through header blocked paths', () => {
|
||||||
|
const element = {
|
||||||
|
append: jest.fn(),
|
||||||
|
} as unknown as Element
|
||||||
|
const request = new Request('http://localhost')
|
||||||
|
request.headers.set('x-blocked-paths', '/')
|
||||||
|
const injector = new MetaTagInjector(
|
||||||
|
{
|
||||||
|
title: 'test',
|
||||||
|
url: 'testUrl',
|
||||||
|
image: 'testImage',
|
||||||
|
description: 'testDescription',
|
||||||
|
},
|
||||||
|
request
|
||||||
|
)
|
||||||
|
injector.element(element)
|
||||||
|
expect(element.append).toHaveBeenCalledWith(`<meta property="x:blocked-paths" content="/"/>`, { html: true })
|
||||||
|
})
|
||||||
|
@ -10,7 +10,7 @@ type MetaTagInjectorInput = {
|
|||||||
* to inject meta tags into the <head> of an HTML document.
|
* to inject meta tags into the <head> of an HTML document.
|
||||||
*/
|
*/
|
||||||
export class MetaTagInjector implements HTMLRewriterElementContentHandlers {
|
export class MetaTagInjector implements HTMLRewriterElementContentHandlers {
|
||||||
constructor(private input: MetaTagInjectorInput) {}
|
constructor(private input: MetaTagInjectorInput, private request: Request) {}
|
||||||
|
|
||||||
append(element: Element, property: string, content: string) {
|
append(element: Element, property: string, content: string) {
|
||||||
element.append(`<meta property="${property}" content="${content}"/>`, { html: true })
|
element.append(`<meta property="${property}" content="${content}"/>`, { html: true })
|
||||||
@ -38,5 +38,10 @@ export class MetaTagInjector implements HTMLRewriterElementContentHandlers {
|
|||||||
this.append(element, 'twitter:image', this.input.image)
|
this.append(element, 'twitter:image', this.input.image)
|
||||||
this.append(element, 'twitter:image:alt', this.input.title)
|
this.append(element, 'twitter:image:alt', this.input.title)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const blockedPaths = this.request.headers.get('x-blocked-paths')
|
||||||
|
if (blockedPaths) {
|
||||||
|
this.append(element, 'x:blocked-paths', blockedPaths)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ export const onRequest: PagesFunction = async ({ params, request, next }) => {
|
|||||||
const { index } = params
|
const { index } = params
|
||||||
const collectionAddress = index[0]?.toString()
|
const collectionAddress = index[0]?.toString()
|
||||||
const tokenId = index[1]?.toString()
|
const tokenId = index[1]?.toString()
|
||||||
return getMetadataRequest(res, request.url, () => getAsset(collectionAddress, tokenId, request.url))
|
return getMetadataRequest(res, request, () => getAsset(collectionAddress, tokenId, request.url))
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ export const onRequest: PagesFunction = async ({ params, request, next }) => {
|
|||||||
try {
|
try {
|
||||||
const { index } = params
|
const { index } = params
|
||||||
const collectionAddress = index?.toString()
|
const collectionAddress = index?.toString()
|
||||||
return getMetadataRequest(res, request.url, () => getCollection(collectionAddress, request.url))
|
return getMetadataRequest(res, request, () => getCollection(collectionAddress, request.url))
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ export const onRequest: PagesFunction = async ({ params, request, next }) => {
|
|||||||
if (!tokenAddress) {
|
if (!tokenAddress) {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
return getMetadataRequest(res, request.url, () => getToken(networkName, tokenAddress, request.url))
|
return getMetadataRequest(res, request, () => getToken(networkName, tokenAddress, request.url))
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
@ -4,13 +4,13 @@ import { Data } from './cache'
|
|||||||
|
|
||||||
export async function getMetadataRequest(
|
export async function getMetadataRequest(
|
||||||
res: Promise<Response>,
|
res: Promise<Response>,
|
||||||
url: string,
|
request: Request,
|
||||||
getData: () => Promise<Data | undefined>
|
getData: () => Promise<Data | undefined>
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
const cachedData = await getRequest(url, getData, (data): data is Data => true)
|
const cachedData = await getRequest(request.url, getData, (data): data is Data => true)
|
||||||
if (cachedData) {
|
if (cachedData) {
|
||||||
return new HTMLRewriter().on('head', new MetaTagInjector(cachedData)).transform(await res)
|
return new HTMLRewriter().on('head', new MetaTagInjector(cachedData, request)).transform(await res)
|
||||||
} else {
|
} else {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
@ -162,6 +162,12 @@ export default function App() {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const blockedPaths = document.querySelector('meta[name="x:blocked-paths"]')?.getAttribute('content')?.split(',')
|
||||||
|
const shouldBlockPath = blockedPaths?.includes(pathname) ?? false
|
||||||
|
if (shouldBlockPath && pathname !== '/swap') {
|
||||||
|
return <Navigate to="/swap" replace />
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
<DarkModeQueryParamReader />
|
<DarkModeQueryParamReader />
|
||||||
|
Loading…
Reference in New Issue
Block a user