cockpit_web_response_negotiation (const gchar *path,
                                  GHashTable *existing,
                                  const gchar *language,
                                  gchar **actual,
                                  GError **error)
{
  gchar *base = NULL;
  const gchar *ext;
  gchar *dot;
  gchar *name = NULL;
  GBytes *bytes = NULL;
  GError *local_error = NULL;
  gchar *locale = NULL;
  gchar *shorter = NULL;
  gchar *lang = NULL;
  gchar *lang_region = NULL;

  gint i;

  if (language)
      locale = cockpit_locale_from_language (language, NULL, &shorter);

  ext = find_extension (path);
  if (ext)
    {
      base = g_strndup (path, ext - path);
    }
  else
    {
      ext = "";
      base = g_strdup (path);
    }

  while (!bytes)
    {
      /* For a request for a file named "base.ext" and locale "lang_REGION", We try the following variants, in
         order, and serve the first that is found:

           base.lang_REGION.ext
           base.lang_REGION.ext.gz
           base.lang.ext
           base.lang.ext.gz
           base.ext
           base.min.ext
           base.ext.gz
           base.ext.min.gz

         If no locale is requested, or a locale without region, those variants are left out by starting
         further down in the list.

         If none of the variants are found, and the base of the file name has internal dots, these internal
         extensions are dropped one by one from the right.  For example, for a file named "foo.bar.js", we
         first try "foo.bar" with extension ".js", and then "foo" with extension ".js".
      */

      if (locale && shorter && g_strcmp0 (locale, shorter) != 0) {
        lang = shorter;
        lang_region = locale;
        i = 0;
      } else if (locale) {
        lang = locale;
        i = 2;
      } else {
        i = 4;
      }

      for (; i < 8; i++)
        {
          g_free (name);
          switch (i)
            {
            case 0:
              name = g_strconcat (base, ".", lang_region, ext, NULL);
              break;
            case 1:
              name = g_strconcat (base, ".", lang_region, ext, ".gz", NULL);
              break;
            case 2:
              name = g_strconcat (base, ".", lang, ext, NULL);
              break;
            case 3:
              name = g_strconcat (base, ".", lang, ext, ".gz", NULL);
              break;
            case 4:
              name = g_strconcat (base, ext, NULL);
              break;
            case 5:
              name = g_strconcat (base, ".min", ext, NULL);
              break;
            case 6:
              name = g_strconcat (base, ext, ".gz", NULL);
              break;
            case 7:
              name = g_strconcat (base, ".min", ext, ".gz", NULL);
              break;
            default:
              g_assert_not_reached ();
            }

          if (existing)
            {
              if (!g_hash_table_lookup (existing, name))
                continue;
            }

          bytes = load_file (name, &local_error);
          if (bytes)
            break;
          if (local_error)
            goto out;
        }

      /* Pop one level off the file name */
      dot = (gchar *)find_extension (base);
      if (!dot)
        break;

      dot[0] = '\0';
    }

out:
  if (local_error)
    g_propagate_error (error, local_error);
  if (bytes && name && actual)
    {
      *actual = name;
      name = NULL;
    }
  g_free (name);
  g_free (base);
  g_free (locale);
  g_free (shorter);
  return bytes;
}