Can't stop worker redirect from loop -- pls help!

Hi,

I have been working on a worker to map by country and then redirect to the intended target. I swear I have this written correctly, but the worker keeps redirecting too many times.

What am I doing wrong? Please help! Thanks! Code:

addEventListener('fetch', event => {
  event.respondWith(mapCountry(event.request))
})
async function mapCountry(request) {
  let url = new URL(request.url)
  //Redirect to language based on country
  let country = request.headers.get('CF-IpCountry')
  //English
  if (country == 'GB','AU','CA','US','NZ','AG','AI','AQ','AS','BB','BM','BS','BW','BZ','CC','CK','CX','DM','FJ','FK','FM','GD','GG','GH','GI','GM','GS','GU','GY','HM','IE','IM','IO','JE','JM','KI','KN','KY','LC','LR','LS','MP','MS','MW','NA','NG','PN','SB','SH','SL','SS','SZ','TO','TT','TV','UG','UM','VC','VG','VI','ZA','ZM','ZW') {
    return Response.redirect(request.url + '/en/', 301);
  }
  //Arabic
  if (country == 'AE','JO','KM','KW','LB','LY','MR','OM','PS','QA','SA','SD','SO','SY','TN','YE') {
    return Response.redirect(request.url + '/ar/', 301);
  }
  //Bulgrian
  if (country == 'BG') {
    return Response.redirect(request.url + '/bg/', 301);
  }
  //Everyone else gets English as default
  return Response.redirect(request.url + '/en/', 301);
}

I think you might need the test I added inline:

  /* check if this request has already been redirected properly */
  if (REDIRECT_TEST) {
    return new Response(...)
  }

I’m not sure what the REDIRECT_TEST should be, but I’m sure there’s either a header check you can do, or, worst case, you can path.match(/\(en|bg|ar\)/) which isn’t necessarily the valid regex, but you get the idea.

hth,

Jason.

Actually, thinking a bit more about this, why are you adding the round-trip of a redirect at all? Why not just do a rewrite? e.g.:

  if (country == 'BG') {
    return fetch(request.url + '/bg/', ...)
  }

Hey @jason28 thanks for reply! I had actually tried the rewrite first and was getting the redirect loop. I think now that this whole issue has been caused by the language provider that I use. They also act as a reverse proxy. I’m going to offload the languages to subdomains and see if that works better. Greatly appreciate your help!

1 Like

So it seems I was able to get it working. However, it doesn’t seem like the IP isn’t getting passed. So, every user is seeing English. I VPN’d into Bulgaria and was not directed to BG. Any thoughts? Thanks!

addEventListener('fetch', event => {
  event.respondWith(mapCountry(event.request))
})
function mapCountry(request) {
  let url = new URL(request.url)
  //Redirect to language based on country
  let country = request.headers.get('CF-IpCountry')
  //English
  if (country == 'GB','AU','CA','US','NZ','AG','AI','AQ','AS','BB','BM','BS','BW','BZ','CC','CK','CX','DM','FJ','FK','FM','GD','GG','GH','GI','GM','GS','GU','GY','HM','IE','IM','IO','JE','JM','KI','KN','KY','LC','LR','LS','MP','MS','MW','NA','NG','PN','SB','SH','SL','SS','SZ','TO','TT','TV','UG','UM','VC','VG','VI','ZA','ZM','ZW') {
    return fetch(request.url + 'en');
  }
  //Arabic
  if (country == 'AE','JO','KM','KW','LB','LY','MR','OM','PS','QA','SA','SD','SO','SY','TN','YE') {
    return fetch(request.url + 'ar');
  }
  //Bulgrian
  if (country == 'BG') {
    return fetch(request.url + 'bg');
  }
}

Hmm, it seems I had tunnel vision when I was looking at the code for the redirect loop. I failed to see what is possibly a glaring error. Is this valid JS?

  if (country == 'AE','JO','KM','KW','LB','LY','MR','OM','PS','QA','SA','SD','SO','SY','TN','YE') {
    return fetch(request.url + 'ar');
  }

You also don’t have a fall-through when those if() branches don’t match… Personally, I would do a switch fall-through here:

/* ... */
var langUrl = null;
if (request.url.match(/\/$/))
  langUrl = request.url;
else
  langUrl = request.url + '/';

switch (country) {
  case 'AE':
  case 'JO':
  case 'KM':
  case 'KW':
    /* TODO: insert the rest of the Arabic country codes here ... */
    langUrl += 'ar';
    break;
  case 'BG':
    langUrl += 'bg';
    break;
  default:
    /* anything we didn't match gets English by default */
    langUrl += 'en';
    break;
}

return fetch(langUrl);

I’ve not tried to run this, so there’s definitely an error or three in there. It might be a new angle to try though…

EDIT: Ok, I ran it real quick in the playground, as well as your code. Your conditionals are matching everything, so your return fetch(request.url + 'en') is the first thing to answer. YOu can see that iif you replace each of your return fetch with console.log. Give the switch / case code a try, it worked from my end. At least, it modified the URL as expected when I forced different country codes.

I have noticed that it works, but doesn’t change the physical address. This then causes other issues. Is there some way I can apply window.location.href to this so it will physically redirect to the URL in the browser? Thanks!