aws-samples / amazon-cloudfront-functions

Apache License 2.0
479 stars 78 forks source link

How to make a rewrite? #31

Closed renzit closed 1 year ago

renzit commented 1 year ago

The docs says that is possible to use a rewrite, but there isn't any example on how to achieve that CloudFront Functions Docs

I tried to change the request, in the test tab it works but no in the cloudfront distribution.

Code:

  if (host.startsWith("www.")) {
    host = host.replace("www.", "");
    request.headers.host.value = host;
    return request;

  }

Test in cloudfront Function: Screenshot 2022-11-29 at 11 33 16

Test against distribution URL:

502 ERROR
The request could not be satisfied.
The CloudFront function tried to add, delete, or change a read-only header. We can't connect to the server for this app or website at this time. There might be too much traffic or a configuration error. Try again later, or contact the app or website owner.
If you provide content to customers through CloudFront, you can find steps to troubleshoot and help prevent this error by reviewing the CloudFront documentation.
renzit commented 1 year ago

I ended with this code for all my needs:

function handler(event) {
  var shouldRedirect = false;
  var request = event.request;
  var queryString = queryStringObjectToString(request.querystring);
  var uri = request.uri;
  var regex = /[A-Z]/g;
  var headers = request.headers;
  var host = headers.host.value;
  var last_uri_character = uri.slice(-1);

  // If the URI have a dot we assume is a file and we don't redirect or rewrite
  if (uri.includes(".")) {
    return request;
  }

  // If the URI contains a capital letter, rewrite to the lowercase version
  if (regex.test(uri)) {
    uri = request.uri.toLowerCase();
    request.uri = uri;
  }

  // If the host is www we redirect to the naked domain
  if (host.startsWith("www.")) {
    host = host.replace("www.", "");
    delete headers.host;
    shouldRedirect = true;
  }

  // If the URI ends with a slash, redirect to the non-slash version
  if (last_uri_character !== "/") {
    uri = uri + "/";
    shouldRedirect = true;
  }

  // If we should redirect, do it
  if (shouldRedirect) {
    var url = "https://" + host + uri + queryString;
    var response = {
      statusCode: 301,
      statusDescription: "Permanently Moved",
      headers: { location: { value: url } },
      cookies: request.cookies,
    };
    return response;
  }
  return request;
}

/**
 * @description: Converts an event.request.querystring object back to a query string
 * @date 2022-11-28
 * @param {object} queryStringObject: Query string object as provided by event.request
 * @return {string}:                  A normalised query string in the form ?key1=valn&key2=val2...
 */
function queryStringObjectToString(queryStringObject) {
  // Convert the query string object to an array of entries and reduce to a single string
  return (
    Object.entries(queryStringObject)
      .reduce((p, q) => {
        if (!q[1].multiValue) {
          // Process a single key/value property
          return (p += q[0] + "=" + q[1].value + "&");
        } else {
          // Process multiValue properties. E.g arrays
          return (p +=
            q[1].multiValue.map((v) => q[0] + "=" + v.value).join("&") + "&");
        }
      }, "?")
      // Remove the trailing ampersand
      .slice(0, -1)
  );
}

Thanks.