Spec-Zone.ru › HTTP

Серверы прокси и туннелирование: файл PAC автоконфигурации прокси

Файл автоконфигурации прокси (PAC)

Файл автоконфигурации прокси (PAC) — это функция JavaScript, определяющая, будут ли запросы веб-браузера (HTTP, HTTPS и FTP) отправляться напрямую к месту назначения или перенаправляться на веб-сервер прокси. Функция JavaScript в файле PAC определяет функцию:

Синтаксис

function FindProxyForURL(url, host) {
  // …
}

Параметры

url

URL, к которому осуществляется доступ. Путь и компонент запроса https:// URL удаляются. В Chrome (версии с 52 по 73) это можно отключить, установив PacHttpsUrlStrippingEnabled на false в политике или запустив с флагом командной строки --unsafe-pac-url (в Chrome 74 работает только флаг, а начиная с 75 отключить удаление пути нельзя; начиная с Chrome 81 удаление пути не применяется к HTTP-URL, но есть интерес к изменению этого поведения в соответствии с HTTPS); в Firefox, предпочтение network.proxy.autoconfig_url.include_path.

host

Имя хоста, извлечённое из URL. Это только для удобства; это та же строка, что и между :// и первым : или / после него. Номер порта в этом параметре не включён. Он может быть извлечён из URL при необходимости.

Описание

Возвращает строку, описывающую конфигурацию. Формат этой строки определён в разделе формат возвращаемого значения ниже.

Формат возвращаемого значения

  • Функция JavaScript возвращает одну строку
  • Если строка равна null, прокси использовать не нужно
  • Строка может содержать любое количество следующих строительных блоков, разделённых точкой с запятой:
DIRECT

Подключения должны осуществляться напрямую, без использования прокси-серверов

PROXY host:port

Следует использовать указанный прокси-сервер

SOCKS host:port

Следует использовать указанный сервер SOCKS

Недавние версии Firefox также поддерживают:

HTTP host:port

Следует использовать указанный прокси-сервер

HTTPS host:port

Следует использовать указанный прокси-сервер HTTPS

SOCKS4 host:port, SOCKS5 host:port

Следует использовать указанный сервер SOCKS (с указанной версией SOCK)

Если задано несколько значений, разделённых точкой с запятой, то будет использоваться значение, стоящее левее, до тех пор, пока Firefox не сможет установить подключение к прокси. В этом случае будет использоваться следующее значение и т. д.

Браузер автоматически повторит попытку подключения к ранее не ответившему прокси-серверу через 30 минут. Дополнительные попытки будут предприниматься с добавлением 30 минут к интервалу между попытками.

Если все прокси-серверы недоступны и не было указано опции DIRECT, браузер спросит, следует ли временно игнорировать прокси и пытаться подключиться напрямую. Через 20 минут браузер спросит, следует ли повторить попытку подключения к прокси, задавая вопрос вновь через дополнительные 40 минут. Запросы будут продолжаться, добавляя 20 минут к интервалу между запросами.

Примеры

PROXY w3proxy.netscape.com:8080; PROXY mozilla.netscape.com:8081

Основной прокси — w3proxy:8080; если он недоступен, переходить к использованию mozilla:8081, пока основной прокси не станет доступен снова.

PROXY w3proxy.netscape.com:8080; PROXY mozilla.netscape.com:8081; DIRECT

То же самое, что и выше, но если оба прокси недоступны, автоматически начинать прямые подключения. (В первом примере выше, Netscape потребует подтверждения пользователя для осуществления прямых подключений; в этом случае вмешательства пользователя не требуется.)

PROXY w3proxy.netscape.com:8080; SOCKS socks:1080

Использовать SOCKS, если основной прокси недоступен.

Файл автоконфигурации следует сохранить в файле с расширением .pac: proxy.pac.

И тип MIME должен быть установлен на application/x-ns-proxy-autoconfig.

Далее необходимо настроить сервер для сопоставления расширения .pac с типом MIME.

Примечание:

  • Функция JavaScript всегда должна сохраняться в отдельном файле, но не должна быть встроена в файл HTML или любой другой файл.
  • Примеры в конце этого документа полные. Дополнительный синтаксис для сохранения в файл и использования не нужен. (Конечно, JavaScript необходимо изменить, чтобы отразить домен вашего сайта и/или подсети.)

Предопределённые функции и среда

Эти функции могут быть использованы при создании файла PAC:

  • Условия на основе имени хоста
    • isPlainHostName()
    • dnsDomainIs()
    • localHostOrDomainIs()
    • isResolvable()
    • isInNet()
  • Вспомогательные функции
    • dnsResolve()
    • convert_addr()
    • myIpAddress()
    • dnsDomainLevels()
  • Условия на основе URL/имени хоста
    • shExpMatch()
  • Условия на основе времени
    • weekdayRange()
    • dateRange()
    • timeRange()
  • Утилита регистрации
    • alert()
  • Была определена одна ассоциативная таблица (объект), поскольку на момент написания кода JavaScript не было возможности определить её самостоятельно:
    • ProxyConfig.bindings Устаревшая

Примечание: pactester (часть пакета pacparser) использовался для тестирования следующих примеров синтаксиса.

  • Файл PAC назван proxy.pac
  • Командная строка: pactester -p ~/pacparser-master/tests/proxy.pac -u http://www.mozilla.org (передаёт параметр host www.mozilla.org и параметр url http://www.mozilla.org)

isPlainHostName()

Синтаксис

isPlainHostName(host)

Параметры

host

Имя хоста из URL (без номера порта).

Описание

Возвращает true, если в имени хоста нет доменного имени (нет точек).

Примеры

isPlainHostName("www.mozilla.org") // false
isPlainHostName("www") // true

dnsDomainIs()

Синтаксис

dnsDomainIs(host, domain)

Параметры

host

Имя хоста из URL.

domain

Доменное имя для проверки имени хоста.

Описание

Возвращает true, если домен имени хоста соответствует заданному.

Примеры

dnsDomainIs("www.mozilla.org", ".mozilla.org") // true
dnsDomainIs("www", ".mozilla.org") // false

localHostOrDomainIs()

Синтаксис

localHostOrDomainIs(host, hostdom)

Параметры

host

Имя хоста из URL.

hostdom

Полное доменное имя для сравнения.

Описание

Возвращает true, если имя хоста точно соответствует указанному имени хоста или если в имени хоста нет доменной части, но неопределённое имя хоста совпадает.

Примеры

localHostOrDomainIs("www.mozilla.org", "www.mozilla.org")  // true (exact match)
localHostOrDomainIs("www", "www.mozilla.org")              // true (hostname match, domain not specified)
localHostOrDomainIs("www.google.com", "www.mozilla.org")   // false (domain name mismatch)
localHostOrDomainIs("home.mozilla.org", "www.mozilla.org") // false (hostname mismatch)

isResolvable()

Синтаксис

isResolvable(host)

Параметры

host

Имя хоста из URL.

Пытается разрешить имя хоста. Возвращает true, если успешно.

Примеры

isResolvable("www.mozilla.org") // true

isInNet()

Синтаксис

isInNet(host, pattern, mask)

Параметры

host

Имя хоста DNS или IP-адрес. Если передано имя хоста, эта функция преобразует его в IP-адрес.

pattern

Шаблон IP-адреса в формате, разделённом точками.

mask

Маска для шаблона IP-адреса, указывающая, какие части IP-адреса должны совпадать с шаблоном. 0 означает игнорирование, 255 означает совпадение.

Возвращает true, если и только если IP-адрес хоста соответствует заданному шаблону IP-адреса.

Указание шаблона и маски осуществляется так же, как и при конфигурации SOCKS.

Примеры

function alertEval(str) {
  alert(`${str} is ${eval(str)}`);
}
function FindProxyForURL(url, host) {
  alertEval('isInNet(host, "63.245.213.24", "255.255.255.255")');
  // "PAC-alert: isInNet(host, "63.245.213.24", "255.255.255.255") is true"
}

dnsResolve()

dnsResolve(host)

Параметры

host

Имя хоста для разрешения.

Разрешает данное имя хоста DNS в IP-адрес и возвращает его в формате, разделённом точками, в виде строки.

Пример

dnsResolve("www.mozilla.org"); // returns the string "104.16.41.2"
END_OF_DOCUMENT_MARKER

convert_addr()

Синтаксис

convert_addr(ipaddr)

Параметры

ipaddr

Любой адресс, записанный точками, например, IP-адрес или маска.

Соединяет четыре байта, разделенные точками, в одно 4-байтовое слово и преобразует его в десятичное значение.

Пример

convert_addr("104.16.41.2"); // returns the decimal number 1745889538

myIpAddress()

Синтаксис

myIpAddress()

Параметры

(нет)

Возвращаемое значение

Возвращает IP-адрес сервера машины, на которой запущен Firefox, в виде строки в формате целого числа, разделённого точками.

Предупреждение: myIpAddress() возвращает тот же IP-адрес, что и адрес сервера, возвращаемый nslookup localhost на машине Linux. Он не возвращает публичный IP-адрес.

Пример

myIpAddress() //returns the string "127.0.1.1" if you were running Firefox on that localhost

dnsDomainLevels()

Синтаксис

dnsDomainLevels(host)

Параметры

host

— имя хоста из URL.

Возвращает количество (целое число) уровней доменных имен DNS (количество точек) в имени хоста.

Примеры

dnsDomainLevels("www");             // 0
dnsDomainLevels("mozilla.org");     // 1
dnsDomainLevels("www.mozilla.org"); // 2

shExpMatch()

Синтаксис

shExpMatch(str, shexp)

Параметры

str

— любая строка для сравнения (например, URL или имя хоста).

shexp

— оболочка выражения для сравнения.

Возвращает true, если строка соответствует указанному выражению оболочки.

Поддержка конкретного синтаксиса выражений оболочки варьируется в разных браузерах: * (соответствие любому количеству символов) и ? (соответствие одному символу) всегда поддерживаются, в то время как [characters] и [^characters] дополнительно поддерживаются некоторыми реализациями (включая Firefox).

Примечание: Если клиент поддерживает, JavaScript-регулярные выражения обычно предоставляют более мощный и согласованный способ сопоставления шаблонов URL (и других строк).

Примеры

shExpMatch("http://home.netscape.com/people/ari/index.html", "*/ari/*"); // returns true
shExpMatch("http://home.netscape.com/people/montulli/index.html", "*/ari/*"); // returns false

weekdayRange()

Синтаксис

weekdayRange(wd1, wd2, [gmt])

Примечание: (До Firefox 49) wd1 должен быть меньше wd2, если вы хотите, чтобы функция оценивала эти параметры как диапазон. См. предупреждение ниже.

Параметры

wd1 и wd2

Одно из упорядоченных строковых значений дней недели: "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"

gmt

Строка "GMT" или отсутствует.

Только первый параметр обязателен. Второй, третий или оба могут быть опущены.

Если присутствует только один параметр, функция возвращает значение true для дня недели, который представляет этот параметр. Если строка "GMT" указана как второй параметр, время рассматривается по Гринвичу. В противном случае оно предполагается по местному времени.

Если оба параметра wd1 и wd1 определены, условие истинно, если текущий день недели находится между этими двумя упорядоченными днями недели. Границы включительно, но границы упорядочены. Если параметр "GMT" указан, время рассматривается по Гринвичу. В противном случае используется местное время.

Предупреждение: Порядок дней имеет значение. До Firefox 49, weekdayRange("SUN", "SAT") всегда оценивалось как true. Теперь weekdayRange("WED", "SUN") будет оцениваться как true только если текущий день - среда или воскресенье.

Примеры

weekdayRange("MON", "FRI");        // returns true Monday through Friday (local timezone)
weekdayRange("MON", "FRI", "GMT"); // returns true Monday through Friday (GMT timezone)
weekdayRange("SAT");               // returns true on Saturdays local time
weekdayRange("SAT", "GMT");        // returns true on Saturdays GMT time
weekdayRange("FRI", "MON");        // returns true Friday and Monday only (note, order does matter!)

dateRange()

Синтаксис

dateRange(<day> | <month> | <year>, [gmt])  // ambiguity is resolved by assuming year is greater than 31
dateRange(<day1>, <day2>, [gmt])
dateRange(<month1>, <month2>, [gmt])
dateRange(<year1>, <year2>, [gmt])
dateRange(<day1>, <month1>, <day2>, <month2>, [gmt])
dateRange(<month1>, <year1>, <month2>, <year2>, [gmt])
dateRange(<day1>, <month1>, <year1>, <day2>, <month2>, <year2>, [gmt])

Примечание: (До Firefox 49) day1 должен быть меньше day2, month1 должен быть меньше month2, а year1 должен быть меньше year2, если вы хотите, чтобы функция оценивала эти параметры как диапазон. См. предупреждение ниже.

Параметры

день

Упорядоченный день месяца от 1 до 31 (в виде целого числа).

1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31
месяц

Одно из упорядоченных значений месяцев ниже.

"JAN"|"FEB"|"MAR"|"APR"|"MAY"|"JUN"|"JUL"|"AUG"|"SEP"|"OCT"|"NOV"|"DEC"
год

Упорядоченное полное целое число года. Например, 2016 (не 16).

gmt

Строка "GMT", которая устанавливает сравнение времени по Гринвичу, или отсутствует. Если не указано, время рассматривается по местному времени.

Если задано только одно значение (из каждой категории: день, месяц, год), функция возвращает истинное значение только для дней, которые соответствуют этому значению. Если заданы оба значения, результат истинный между этими временами, включая границы, но границы упорядочены.

Предупреждение: Порядок дней, месяцев и годов имеет значение; До Firefox 49, dateRange("JAN", "DEC") всегда оценивался как true. Теперь dateRange("DEC", "JAN") будет истинным только если текущий месяц - декабрь или январь.

Примеры

dateRange(1);            // returns true on the first day of each month, local timezone
dateRange(1, "GMT")      // returns true on the first day of each month, GMT timezone
dateRange(1, 15);        // returns true on the first half of each month
dateRange(24, "DEC");    // returns true on 24th of December each year
dateRange("JAN", "MAR"); // returns true on the first quarter of the year

dateRange(1, "JUN", 15, "AUG");
// returns true from June 1st until August 15th, each year
// (including June 1st and August 15th)

dateRange(1, "JUN", 1995, 15, "AUG", 1995);
// returns true from June 1st, 1995, until August 15th, same year

dateRange("OCT", 1995, "MAR", 1996);
// returns true from October 1995 until March 1996
// (including the entire month of October 1995 and March 1996)

dateRange(1995);
// returns true during the entire year of 1995

dateRange(1995, 1997);
// returns true from beginning of year 1995 until the end of year 1997

timeRange()

Синтаксис

// The full range of expansions is analogous to dateRange.
timeRange(<hour1>, <min1>, <sec1>, <hour2>, <min2>, <sec2>, [gmt])

Примечание: (До Firefox 49) категория час1, мин1, сек1 должна быть меньше категории час2, мин2, сек2, если вы хотите, чтобы функция оценивала эти параметры как диапазон. См. предупреждение ниже.

Параметры

час

Часы от 0 до 23. (0 — полночь, 23 — 11 вечера).

минуты

Минуты от 0 до 59.

секунды

Секунды от 0 до 59.

gmt

Строка "GMT" для времени Гринвича или не указана для местного времени.

Если задано только одно значение (из каждой категории: час, минута, секунда), функция возвращает истинное значение только в те моменты времени, которые соответствуют этому значению. Если заданы оба значения, результат истинный между этими временами, включая границы, но границы упорядочены.

Предупреждение: Порядок часов, минут, секунд имеет значение; До Firefox 49, timeRange(0, 23) всегда оценивался как истинный. Теперь timeRange(23, 0) будет истинным только если текущий час — 23:00 или полночь.

Примеры

timerange(12);                // returns true from noon to 1pm
timerange(12, 13);            // returns true from noon to 1pm
timerange(12, "GMT");         // returns true from noon to 1pm, in GMT timezone
timerange(9, 17);             // returns true from 9am to 5pm
timerange(8, 30, 17, 0);      // returns true from 8:30am to 5:00pm
timerange(0, 0, 0, 0, 0, 30); // returns true between midnight and 30 seconds past midnight

alert()

Синтаксис

alert(message)

Параметры

сообщение

Строка для записи

Записывает сообщение в консоль браузера.

Примеры

alert(`${host} = ${dnsResolve(host)}`);            // logs the host name and its IP address
alert("Error: shouldn't reach this clause.");      // log a simple message

Пример 1

Использование прокси для всего, кроме локальных хостов

Примечание: Поскольку все последующие примеры очень специфичны, они не были протестированы.

Все хосты, которые не являются полностью квалифицированными или находятся в локальном домене, будут подключены напрямую. Всё остальное будет проходить через w3proxy.mozilla.org:8080. Если прокси выходит из строя, соединения автоматически становятся прямыми:

function FindProxyForURL(url, host) {
  if (isPlainHostName(host) || dnsDomainIs(host, ".mozilla.org")) {
    return "DIRECT";
  } else {
    return "PROXY w3proxy.mozilla.org:8080; DIRECT";
  }
}

Примечание: Это самый простой и эффективный файл автоконфигурации для случаев, когда есть только один прокси.

Пример 2

Как выше, но использовать прокси для локальных серверов, которые находятся за пределами брандмауэра

Если существуют хосты (например, основной веб-сервер), которые относятся к локальному домену, но находятся за пределами брандмауэра и доступны только через прокси-сервер, эти исключения можно обработать с помощью функции localHostOrDomainIs():

function FindProxyForURL(url, host) {
  if (
    (isPlainHostName(host) || dnsDomainIs(host, ".mozilla.org")) &&
    !localHostOrDomainIs(host, "www.mozilla.org") &&
    !localHostOrDomainIs(host, "merchant.mozilla.org")
  ) {
    return "DIRECT";
  } else {
    return "PROXY w3proxy.mozilla.org:8080; DIRECT";
  }
}

В приведённом примере прокси будет использоваться для всего, кроме локальных хостов в домене mozilla.org, с дополнительным исключением, что хосты www.mozilla.org и merchant.mozilla.org будут проходить через прокси.

Примечание: Порядок вышеуказанных исключений для повышения эффективности: localHostOrDomainIs() функции выполняются только для URL-адресов, которые находятся в локальном домене, а не для каждого URL-адреса. Обращайте внимание на скобки вокруг выражения или перед выражением и, чтобы добиться вышеупомянутого эффективного поведения.

Пример 3

Использовать прокси только если хост нельзя разрешить

Этот пример будет работать в среде, где внутренний DNS-сервер настроен таким образом, что он может разрешать только имена внутренних хостов, а цель состоит в том, чтобы использовать прокси только для хостов, которые невозможно разрешить:

function FindProxyForURL(url, host) {
  if (isResolvable(host)) {
    return "DIRECT";
  }
  return "PROXY proxy.mydomain.com:8080";
}

Вышеуказанное требует обращения к DNS каждый раз; его можно сгруппировать разумно с другими правилами, чтобы DNS обращались только в том случае, если другие правила не дают результата:

function FindProxyForURL(url, host) {
  if (
    isPlainHostName(host) ||
    dnsDomainIs(host, ".mydomain.com") ||
    isResolvable(host)
  ) {
    return "DIRECT";
  }
  return "PROXY proxy.mydomain.com:8080";
}

Пример 4

END_OF_DOCUMENT_MARKER

Основанные на подсетях решения

В этом примере все хосты в заданном подсети подключены напрямую, остальные — через прокси:

function FindProxyForURL(url, host) {
  if (isInNet(host, "198.95.0.0", "255.255.0.0")) {
    return "DIRECT";
  }
  return "PROXY proxy.mydomain.com:8080";
}

Опять же, использование DNS-сервера в примере выше можно минимизировать, добавив избыточные правила в начале:

function FindProxyForURL(url, host) {
  if (
    isPlainHostName(host) ||
    dnsDomainIs(host, ".mydomain.com") ||
    isInNet(host, "198.95.0.0", "255.255.0.0")
  ) {
    return "DIRECT";
  } else {
    return "PROXY proxy.mydomain.com:8080";
  }
}

Пример 5

Распределение нагрузки/маршрутизация на основе шаблонов URL

Этот пример более сложный. Существует четыре (4) прокси-сервера; один из них — резервный, горячий, для всех остальных, поэтому, если любой из оставшихся трёх выйдет из строя, четвёртый возьмёт на себя его функции. Кроме того, три оставшихся прокси-сервера распределяют нагрузку на основе шаблонов URL, что повышает эффективность кэширования (на трёх серверах хранится только один экземпляр любого документа, в отличие от одного экземпляра на каждом из них). Распределение нагрузки выполняется следующим образом:

Прокси Назначение
#1 Домен .com
#2 Домен .edu
#3 Все другие домены
#4 Горячий резерв

Все локальные обращения должны быть прямыми. Все прокси-серверы работают на порту 8080 (это не обязательно, можно просто изменить порт, но необходимо внести изменения в конфигурацию с обеих сторон). Обратите внимание, как строки могут быть конкатенированы с помощью оператора + в JavaScript.

function FindProxyForURL(url, host) {
  if (isPlainHostName(host) || dnsDomainIs(host, ".mydomain.com")) {
    return "DIRECT";
  } else if (shExpMatch(host, "*.com")) {
    return "PROXY proxy1.mydomain.com:8080; PROXY proxy4.mydomain.com:8080";
  } else if (shExpMatch(host, "*.edu")) {
    return "PROXY proxy2.mydomain.com:8080; PROXY proxy4.mydomain.com:8080";
  } else {
    return "PROXY proxy3.mydomain.com:8080; PROXY proxy4.mydomain.com:8080";
  }
}

Пример 6

Установка прокси для определённого протокола

Большая часть стандартной функциональности JavaScript доступна для использования в функции FindProxyForURL(). В качестве примера, для установки разных прокси на основе протокола можно использовать функцию startsWith():

function FindProxyForURL(url, host) {
  if (url.startsWith("http:")) {
    return "PROXY http-proxy.mydomain.com:8080";
  } else if (url.startsWith("ftp:")) {
    return "PROXY ftp-proxy.mydomain.com:8080";
  } else if (url.startsWith("gopher:")) {
    return "PROXY gopher-proxy.mydomain.com:8080";
  } else if (url.startsWith("https:") || url.startsWith("snews:")) {
    return "PROXY security-proxy.mydomain.com:8080";
  }
  return "DIRECT";
}

Примечание: То же самое можно сделать с помощью функции shExpMatch(), описанной ранее.

Например:

if (shExpMatch(url, "http:*")) {
  return "PROXY http-proxy.mydomain.com:8080";
}

Примечание: Файл автоконфигурации может быть выведен скриптом CGI. Это полезно, например, когда файл автоконфигурации работает по-разному в зависимости от IP-адреса клиента (переменная окружения REMOTE_ADDR в CGI).

Использование функций isInNet(), isResolvable() и dnsResolve() следует рассматривать с осторожностью, так как они требуют обращения к DNS-серверу. Все остальные функции, связанные с автоконфигурацией, представляют собой простые функции сопоставления строк, которые не требуют использования DNS-сервера. Если используется прокси, прокси выполнит свой поиск DNS, что удвоит нагрузку на DNS-сервер. Большинство времени эти функции не являются необходимыми для достижения желаемого результата.

История и реализация

Автоконфигурация прокси была введена в Netscape Navigator 2.0 в конце 1990-х годов, одновременно с введением JavaScript. Открытый исходный код Netscape в конечном итоге привел к появлению самого Firefox.

Самая «оригинальная» реализация PAC и её JavaScript-библиотек, следовательно, nsProxyAutoConfig.js встречается в ранних версиях Firefox. Эти утилиты встречаются во многих других системах с открытым исходным кодом, включая Chromium. Позже Firefox интегрировал файл в ProxyAutoConfig.cpp как C++ строковый литерал. Для выделения его в отдельный файл достаточно скопировать фрагмент в JavaScript с директивой console.log для его печати.

Microsoft в целом разработала свою собственную реализацию. Раньше у них были некоторые проблемы с их библиотеками, но большинство из них сейчас решены. Они определили некоторые новые функции с суффиксом «Ex» вокруг частей обработки адресов для поддержки IPv6. Эта функция поддерживается Chromium, но пока не поддерживается Firefox (bugzilla #558253).

© 2005–2022 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Proxy_servers_and_tunneling/Proxy_Auto-Configuration_PAC_file

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API