Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redirect middleware plugin causes MIDDLEWARE_INVOCATION_TIMEOUT error when ANY request has large number of query params #2004

Open
chrissnyder2337 opened this issue Dec 17, 2024 · 2 comments
Labels

Comments

@chrissnyder2337
Copy link

Describe the Bug

Redirect middleware plugin causes MIDDLEWARE_INVOCATION_TIMEOUT errors when large number of query parameters are included in the request's url. 8 or 9ish.

Having this many query parameters is quite normal in modern web applications, and the number of query parameters should not have any performance impact on every single request.

Possible Issue:

I think the isPermutedQueryMatch defined in https://github.com/Sitecore/jss/blob/dev/packages/sitecore-jss-nextjs/src/middleware/redirects-middleware.ts is causing issues. The isPermutedQueryMatch method generates all permutations of query parameters to test them against regex patterns. When the query string contains many parameters, the number of permutations grows factorially (n!). This can result in an enormous number of permutations and significantly slow down the processing.

Example:

  • For 5 parameters, there are 120 permutations.
  • For 10 parameters, there are 3,628,800 permutations.

To Reproduce

  1. Add and publish a redirect map to sitecore so the redirect middleware plugin's code runs. It does not matter what it is as long as one exists and is published.a redirects to /b works fine.
  2. Visit any valid non-redirected, or redirected path on the site but with many query parameters. (https://example.com?1=1&2=2&3=3&4=4&5=5&6=6&7=7&8=8&9=9&10=10).
  3. Note that the request takes a long time. And when hosted on Vercel a MIDDLEWARE_INVOCATION_TIMEOUT error is expereinced.

Expected Behavior

The redirect plugin does not cause excessive computation and does not cause MIDDLEWARE_INVOCATION_TIMEOUT errors.

Possible Fix

Handle query parameters better and fix the logic and performance of the redirect middleware plugin.

Provide environment information

  • Sitecore Version: XM Cloud
  • JSS Version: 22.1.3
  • Browser Name and version: N/A
  • Operating System and version (desktop or mobile): N/A
  • Link to your project (if available):
@chrissnyder2337 chrissnyder2337 changed the title Redirect middleware plugin causes MIDDLEWARE_INVOCATION_TIMEOUT errors when large number of query parameters. Redirect middleware plugin causes MIDDLEWARE_INVOCATION_TIMEOUT error when ANY request has large number of query params Dec 17, 2024
@yavorsk
Copy link
Contributor

yavorsk commented Dec 17, 2024

Hi @chrissnyder2337 thanks for the detailed submission!
We know about this problem and we are currently working to resolve it.

@chrissnyder2337
Copy link
Author

chrissnyder2337 commented Dec 17, 2024

As a temporary workaround, but not ideal, to avoid people from getting 504 MIDDLEWARE_INVOCATION_TIMEOUT errors whenever requests have many query parameters, disable the redirect plugin from running at all if there are more than 7 5 params on the url.

NOTE That this workaround prevents redirects from happening at all if the url the person is visiting with has many params (like utm and marketing parameters)

in src/lib/middleware/plugins/redirects.ts

import { NextRequest, NextResponse } from 'next/server';
import { RedirectsMiddleware } from '@sitecore-jss/sitecore-jss-nextjs/middleware';
import { MiddlewarePlugin } from '..';
import { debug } from '@sitecore-jss/sitecore-jss-nextjs/middleware';
import { siteResolver } from 'lib/site-resolver';
import clientFactory from 'lib/graphql-client-factory';

class RedirectsPlugin implements MiddlewarePlugin {
  private redirectsMiddleware: RedirectsMiddleware;
  order = 0;

  constructor() {
    this.redirectsMiddleware = new RedirectsMiddleware({
      // Client factory implementation
      clientFactory,
      // These are all the locales you support in your application.
      // These should match those in your next.config.js (i18n.locales).
      locales: ['en', 'es'],
      // This function determines if a route should be excluded from RedirectsMiddleware.
      // Certain paths are ignored by default (e.g. Next.js API routes), but you may wish to exclude more.
      // This is an important performance consideration since Next.js Edge middleware runs on every request.
      excludeRoute: () => false,
      // This function determines if the middleware should be turned off.
      // By default, it is disabled while in development mode.
      disabled: () => process.env.NODE_ENV === 'development',
      // Site resolver implementation
      siteResolver,
    });
  }
  /**
   * exec async method - to find coincidence in url.pathname and redirects of site
   * @param req<NextRequest>
   * @returns Promise<NextResponse>
   */
  async exec(req: NextRequest, res?: NextResponse): Promise<NextResponse> {
    // This is a temporary workaround to bypass this plugin when there are more than 5ish query parameters which causes a MIDDLEWARE_INVOCATION_TIMEOUT error.
    // This should be removed once this is fixed in sitecore JSS.
    if ([...req.nextUrl.searchParams.entries()].length > 5) {
      debug.redirects(
        '(temp workaround) bypassing JSS redirect plugin due to more than 5 search params'
      );
      return res || NextResponse.next();
    }

    return this.redirectsMiddleware.getHandler()(req, res);
  }
}

export const redirectsPlugin = new RedirectsPlugin();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants