Показаны сообщения с ярлыком протокол прокси модуля в Golang. Показать все сообщения
Показаны сообщения с ярлыком протокол прокси модуля в Golang. Показать все сообщения

четверг, 4 марта 2021 г.

Модули в Golang: прокси модуля, общение с прокси

Команда go может загружать исходный код модуля и метаданные с прокси-сервера модуля. Переменная среды GOPROXY может использоваться для настройки прокси-серверов, к которым команда go может подключаться и может ли она напрямую взаимодействовать с системами контроля версий. Данные загруженного модуля сохраняются в кеш-памяти модуля. Команда go будет связываться с прокси только тогда, когда ему нужна информация, которой еще нет в кеше.

Предыдущий пост о протоколе GOPROXY описывает запросы, которые могут быть отправлены на сервер GOPROXY. Однако также полезно понимать, когда команда go делает эти запросы. Например, go build выполняется следующим образом:

  • Вычислить список сборки, прочитав файлы go.mod и выполнив выбор минимальной версии (MVS).
  • Прочитать пакеты, указанные в командной строке, и пакеты, которые они импортируют.
  • Если пакет не предоставляется ни одним модулем в списке сборки, найти модуль, который его предоставляет. Добавить требование модуля для последней версии в go.mod и начать заново.
  • Собрать пакеты после того, как все будет загружено.

Когда команда go вычисляет список сборки, она загружает файл go.mod для каждого модуля в графе модулей. Если файла go.mod нет в кеше, команда go загрузит его с прокси с помощью запроса $module/@v/$version.mod (где $module - это путь к модулю, а $version - версия). Эти запросы можно проверить с помощью такого инструмента, как curl. Например, приведенная ниже команда загружает файл go.mod для golang.org/x/mod в версии v0.2.0:

$ curl https://proxy.golang.org/golang.org/x/mod/@v/v0.2.0.mod
module golang.org/x/mod

go 1.12

require (
  golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550
  golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e
  golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898
)

Чтобы загрузить пакет, команде go нужен исходный код модуля, который его предоставляет. Исходный код модуля распространяется в виде файлов .zip, которые извлекаются в кеш модуля. Если в кеше нет .zip файла модуля, команда go загрузит его с помощью запроса $module/@v/$version.zip.

$ curl -O https://proxy.golang.org/golang.org/x/mod/@v/v0.2.0.zip
$ unzip -l v0.2.0.zip | head
Archive:  v0.2.0.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
     1479  00-00-1980 00:00   golang.org/x/mod@v0.2.0/LICENSE
     1303  00-00-1980 00:00   golang.org/x/mod@v0.2.0/PATENTS
      559  00-00-1980 00:00   golang.org/x/mod@v0.2.0/README
       21  00-00-1980 00:00   golang.org/x/mod@v0.2.0/codereview.cfg
      214  00-00-1980 00:00   golang.org/x/mod@v0.2.0/go.mod
     1476  00-00-1980 00:00   golang.org/x/mod@v0.2.0/go.sum
     5224  00-00-1980 00:00   golang.org/x/mod@v0.2.0/gosumcheck/main.go

Обратите внимание, что запросы .mod и .zip разделены, хотя файлы go.mod обычно содержатся в файлах .zip. Команде go может потребоваться загрузить файлы go.mod для многих различных модулей, а файлы .mod намного меньше, чем файлы .zip. Кроме того, если у проекта Go нет файла go.mod, прокси будет обслуживать синтетический файл go.mod, который содержит только директиву module. Синтетические файлы go.mod генерируются командой go при загрузке из системы контроля версий.

Если команде go необходимо загрузить пакет, не предоставленный каким-либо модулем в списке сборки, она попытается найти новый модуль, который его предоставляет. Таким образом, команда go запрашивает информацию о последней версии каждого пути к модулю, который, возможно, может содержать пакет. Например, для пакета golang.org/x/net/html команда go попытается найти последние версии модулей golang.org/x/net/html, golang.org/x/net, golang.org/x/ и golang.org. Фактически существует только golang.org/x/net, который предоставляет этот пакет, поэтому команда go использует последнюю версию этого модуля. Если пакет предоставляет более одного модуля, команда go будет использовать модуль с самым длинным путем.

Когда команда go запрашивает последнюю версию модуля, она сначала отправляет запрос на $module/@v/list. Если список пуст или ни одна из возвращенных версий не может быть использована, он отправляет запрос на $module/@latest. После выбора версии команда go отправляет запрос $module/@v/$version.info для метаданных. Затем она может отправить запросы $module/@v/$version.mod и $module/@v/$version.zip для загрузки файла go.mod и исходного кода.

$ curl https://proxy.golang.org/golang.org/x/mod/@v/list
v0.1.0
v0.2.0

$ curl https://proxy.golang.org/golang.org/x/mod/@v/v0.2.0.info
{"Version":"v0.2.0","Time":"2020-01-02T17:33:45Z"}

После загрузки файла .mod или .zip команда go вычисляет криптографический хеш и проверяет, соответствует ли он хешу в файле go.sum основного модуля. Если хеш отсутствует в go.sum, по умолчанию команда go извлекает его из базы данных контрольных сумм. Если вычисленный хеш не совпадает, команда go сообщает об ошибке безопасности и не устанавливает файл в кеш модуля. Переменные среды GOPRIVATE и GONOSUMDB могут использоваться для отключения запросов к базе данных контрольных сумм для определенных модулей. Переменная среды GOSUMDB также может быть отключена, чтобы полностью отключить запросы к базе данных контрольных сумм. Обратите внимание, что списки версий и метаданные версий, возвращаемые для запросов .info, не аутентифицируются и могут изменяться со временем.


Читайте также:


среда, 3 марта 2021 г.

Модули в Golang: прокси модуля, протокол GOPROXY

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

Успешные ответы HTTP должны иметь код состояния 200 (ОК). Выполняются перенаправления (3xx). Ответы с кодами состояния 4xx и 5xx обрабатываются как ошибки. Коды ошибок 404 (Not Found) и 410 (Gone) указывают на то, что запрошенный модуль или версия недоступны на прокси-сервере, но могут быть найдены в другом месте. Сообщения об ошибках должны иметь тип содержимого text/plain с кодировкой utf-8 или us-ascii.

Команду go можно настроить для связи с прокси-серверами или серверами управления версиями с помощью переменной среды GOPROXY, которая принимает список URL-адресов прокси. Список может включать ключевые слова direct или off. Элементы списка могут быть разделены запятыми (,) или вертикальными чертами (|), которые определяют поведение при возникновении ошибки. Когда за URL-адресом следует запятая, команда go возвращается к более поздним источникам только после ответа 404 (Not Found) или 410 (Gone). Когда за URL-адресом следует вертикальная черта, команда go возвращается к более поздним источникам после любой ошибки, включая ошибки, не относящиеся к HTTP, такие как таймауты. Такое поведение обработки ошибок позволяет прокси-серверу действовать как привратник (gatekeeper) для неизвестных модулей. Например, прокси-сервер может ответить с ошибкой 403 (Forbidden) для модулей, не включенных в утвержденный список.

Ниже указаны запросы, на которые должен отвечать прокси-сервер модуля. Для каждого пути $base - это часть пути URL-адреса прокси, $module - это путь к модулю, а $version - это версия. Например, если URL-адрес прокси - https://example.com/mod, и клиент запрашивает файл go.mod для модуля golang.org/x/text в версии v0.3.2, клиент отправит GET запрос https://example.com/mod/golang.org/x/text/@v/v0.3.2.mod.

Чтобы избежать неоднозначности при обслуживании из файловых систем без учета регистра, элементы $module и $version кодируются с учетом регистра, заменяя каждую прописную букву восклицательным знаком, за которым следует соответствующая строчная буква. Это позволяет хранить на диске модули example.com/M и example.com/m, поскольку первый кодируется как example.com/!m.

Путь $base/$module/@v/list

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

Путь $base/$module/@v/$version.info

Возвращает метаданные в формате JSON о конкретной версии модуля. Ответ должен быть объектом JSON, который соответствует структуре данных Go ниже:

type Info struct {
    Version string    // строка версии
    Time    time.Time // время коммита
}

Поле Version является обязательным и должно содержать действительную каноническую версию. $version в пути запроса не обязательно должна быть той же или даже действительной версией; эта конечная точка может использоваться для поиска версий для имен веток или идентификаторов ревизий. Однако, если $version является канонической версией с основной версией, совместимой с $module, поле Version в успешном ответе должно быть таким же.

Поле Time не является обязательным. Если присутствует, это должна быть строка в формате RFC 3339. Он указывает время, когда версия была создана.

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

Путь $base/$module/@v/$version.mod

Возвращает файл go.mod для конкретной версии модуля. Если у модуля нет файла go.mod в запрошенной версии, должен быть возвращен файл, содержащий только оператор модуля с запрошенным путем к модулю. В противном случае необходимо вернуть исходный немодифицированный файл go.mod.

Путь $base/$module/@v/$version.zip

Возвращает zip-файл, с содержимым определенной версии модуля.

Путь $base/$module/@latest

Возвращает метаданные в формате JSON о последней известной версии модуля в том же формате, что и $base/$module/@v/$version.info. Последняя версия должна быть той версией модуля, которую команда go должна использовать, если $base/$module/@v/list пуст или указанная версия не подходит. Эта конечная точка является необязательной, и прокси-серверы модулей не требуются для ее реализации.

При разрешении последней (latest) версии модуля команда go запросит $base/$module/@v/list, а затем, если подходящие версии не найдены, $base/$module/@latest. Команда go отдает предпочтение в следующем порядке: семантически самая высокая версия релиза, семантически самая высокая предварительная версия и хронологически самая последняя псевдоверсия. В Go 1.12 и ранее команда go считала псевдоверсии в $base/$module/@v/list предварительными версиями, но это уже не так, начиная с Go 1.13.

Прокси-сервер модуля всегда должен обслуживать одно и то же содержимое для успешных ответов на запросы $base/$module/$version.mod и $base/$module/$version.zip. Этот контент криптографически аутентифицируется с использованием файлов go.sum и, по умолчанию, базы данных контрольных сумм.

Команда go кеширует большую часть содержимого, загружаемого с прокси-серверов модуля, в свой кеш модуля в $GOPATH/pkg/mod/cache/download. Даже при загрузке напрямую из систем контроля версий команда go синтезирует явно info, mod и zip файлы и сохраняет их в этом каталоге, как если бы они были загружены непосредственно с прокси-сервера. Макет кеша такой же, как и пространство URL-адресов прокси, поэтому обслуживание $GOPATH/pkg/mod/cache/download на (или копирование на) https://example.com/proxy позволит пользователям получать доступ к версиям кешированных модулей, установив GOPROXY на https://example.com/proxy.


Читайте также:


пятница, 5 июля 2019 г.

Вспомогательные темы инструмента go: протокол прокси модуля

go help goproxy

Команда go по умолчанию загружает модули из систем управления версиями напрямую, как это всегда бывает с go get. Переменная среды GOPROXY позволяет дополнительно контролировать источник загрузки. Если GOPROXY не установлен, является пустой строкой или строкой "direct", при загрузке используется прямое подключение по умолчанию к системам контроля версий. Отключение GOPROXY запрещает загрузку модулей из любого источника. В противном случае ожидается, что GOPROXY будет URL-адресом прокси модуля, и в этом случае команда go извлечет все модули из этого прокси. Независимо от источника модулей, загруженные модули должны соответствовать существующим записям в go.sum.

Прокси модуля Go - это любой веб-сервер, который может отвечать на запросы GET для URL-адресов заданной формы. Запросы не имеют параметров запроса, поэтому даже сайт, обслуживающий фиксированную файловую систему (включая file:/// URL), может быть прокси модуля.

GET-запросы, отправленные на прокси Go модуля:

GET $GOPROXY/<module>/@v/list возвращает список всех известных версий данного модуля, по одной на строку.

GET $GOPROXY/<module>/@v/<version>.info возвращает метаданные в формате JSON об этой версии данного модуля.

GET $GOPROXY/<module>/@v/<version>.mod возвращает файл go.mod для этой версии данного модуля.

GET $GOPROXY/<module>/@v/<version>.zip возвращает zip-архив для этой версии данного модуля.

Чтобы избежать проблем при обслуживании из файловых систем с учетом регистра, элементы <module> и <version> кодируются регистром, заменяя каждую заглавную букву восклицательным знаком, за которым следует соответствующая строчная буква: github.com/Azure кодируется как github.com/!azure.

Метаданные в формате JSON о данном модуле соответствуют этой структуре данных Go, которая может быть расширена в будущем:

type Info struct {
    Version string    // строка версии
    Time    time.Time // время комита
}

Zip-архив для конкретной версии данного модуля - это стандартный zip-файл, содержащий дерево файлов, соответствующее исходному коду модуля и связанным файлам. В архиве используются разделенные косой чертой пути, и каждый путь к файлу в архиве должен начинаться с <module>@<version>/, где модуль и версия подставляются напрямую, а не в регистре. Корень дерева файлов модулей соответствует префиксу <module>@<version>/ в архиве.

Даже при загрузке непосредственно из систем управления версиями команда go синтезирует явно info, mod и zip файлы и сохраняет их в своем локальном кэше, $GOPATH/pkg/mod/cache/download, так же, как если бы она загружала их непосредственно из прокси. Макет кэша такой же, как и у прокси-пространства URL, поэтому обслуживание $GOPATH/pkg/mod/cache/download в (или копирование его) https://example.com/proxy позволит другим пользователям получать доступ к этим версиям кэшированных модулей с GOPROXY=https://example.com/proxy.


Читайте также: