restfront

package
v0.7.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 27, 2026 License: AGPL-3.0 Imports: 14 Imported by: 0

Documentation

Overview

Package restfront — собственный REST-фронт службы: два мультиплексора на двух слушателях, публичный и внутренний.

Предмет

Пока служба стоит за краем платформы, её HTTP-поверхность принадлежит краю: маршруты объявлены аннотациями контракта, а поднимает их чужое дерево. Вынесенная отдельным продуктом, служба края не имеет BY CONSTRUCTION — и её REST обязан существовать сам.

Почему фронтов ДВА, а не один с разбором пути

Раздельность есть свойство СОКЕТА, а не содержимого запроса. Один слушатель, решающий «этот путь внутренний, а этот нет», делает принадлежность маршрута фронту решением, принимаемым на каждом запросе. Требование «внутреннее не публикуется наружу» проверяемо ровно тогда, когда «не опубликован» значит «недосягаем»: это доказуемо снаружи одним обращением, а не чтением условия.

Почему регистрация ТОЛЬКО через собственный адрес

Все звенья, решающие о вызывающем и о доступе к объекту, — перехватчики СЛУШАТЕЛЯ. Внутрипроцессная форма регистрации зовёт реализацию напрямую, поэтому запрос, пришедший по HTTP, обслуживался бы иначе, чем тот же запрос по gRPC: два пути к одному обработчику с разными решениями по дороге. REST и gRPC обязаны отвечать ОДНИМ звеном на один вопрос, а единственный способ это обеспечить — общий слушатель.

Обработчик ошибок вызова: один свой ответ, остальное — умолчание

Отображение кода отказа в HTTP-статус делает библиотека, и множество производимых статусов задаёт она: вызывающему не приходится знать, через какую поверхность он пришёл. Свой обработчик ошибок вызова у фронта есть (stepup.go), но рендерит он ОДИН ответ — указание повысить уровень (решение Р11 приёмки уровня уверенности, kaname#511): `401`, тело края побайтово и вызов RFC 9470 с параметрами уровня, приехавшими хвостом ответа слушателя. Код указания — `UNAUTHENTICATED`, то есть `401` и у умолчания: таблица статусов приёмки не меняется ни одной строкой. Всё прочее уходит умолчанию дословно.

Прежняя редакция этого абзаца обосновывала отсутствие обработчика тем, что множество статусов «совпадает у обеих HTTP-поверхностей платформы». Для отдельно поставленной службы это оказалось НЕВЕРНО, и неверно наблюдаемо: на промах глагола фронт отвечал 501, а эндпоинт выдачи токена — 405 (задача kacho#2493).

Форма отказа на неверный ГЛАГОЛ — одна на обе HTTP-поверхности службы

Фронт и полоса входа отвечают на «путь есть, метод не тот» одной формой (задача #261, решение R36 п. 3): `405`, `{"code":12,"message":"method not allowed","details":[]}` и заголовок `Allow` с методами, которые путь обслуживает. Это решение продукта, а не умолчание: библиотека переводит промах глагола в `Unimplemented`, то есть в 501, и «не реализовано» уводит клиента с дороги — он идёт заводить задачу вместо того, чтобы сменить глагол (задача kacho#2493). Сведение живёт в обработчике ошибок МАРШРУТИЗАЦИИ (mux.go), который судит промах глагола и отображения кодов отказа не трогает.

Перечень `Allow` не выписан: его отвечает маршрутизатор фронта на вопрос о каждом методе HTTP, и обработчики при этом не исполняются (mux.go, allowedMethods). Код `12` — тот, что производит маршрутизатор, и тот же отдаёт полоса входа, поэтому клиент, ключующийся на `code`, читает один класс отказа одинаково по любому адресу службы.

Index

Constants

View Source
const AuthenticationChallenge = "Bearer"

AuthenticationChallenge — ЕДИНСТВЕННОЕ значение подсказки.

Голая схема, без кода ошибки: RFC 6750 §3.1 прямо говорит, что запросу БЕЗ сведений об аутентификации код ошибки прилагать не следует. Отсюда и второе, более важное свойство — подсказка одинакова на ОБЕИХ полосах отказа аутентификации, поэтому по ней нельзя отличить «не предъявлял» от «предъявил негодное», и оракулом она не является.

Экспортировано затем, чтобы проба утверждала ЕГО, а не свою копию.

View Source
const TextMethodNotAllowed = "method not allowed"

TextMethodNotAllowed — текст отказа на неверный метод: дословно тот, которым отвечает полоса входа службы (задача #261, решение R36 п. 3).

Variables

This section is empty.

Functions

func DialTarget

func DialTarget(listenAddr string) string

DialTarget переводит адрес ПРИВЯЗКИ слушателя в адрес, по которому до него дозваниваются из этого же процесса.

Почему это не одно и то же

«0.0.0.0» и «[::]» — не адреса машины, а указание «принимать на всех интерфейсах». Как цель соединения они неопределённы: часть систем резолвит их в петлю молча, часть отказывает, и поведение фронта зависело бы от того, где он поднят. Пустой хост (форма «:9090») неопределён ровно так же.

Перевод сделан ЯВНО, потому что цена неявного здесь не отказ, а расхождение стендов: на одном фронт работает, на другом — нет, и причина не видна ни в одном файле.

Порт сохраняется как есть: фронт идёт к СВОЕМУ слушателю, и другого порта у него быть не может.

func NewInternal

func NewInternal(ctx context.Context, grpcAddr string, opts []grpc.DialOption, admit Admission) (http.Handler, error)

NewInternal собирает внутренний REST-фронт службы.

Отдельный мультиплексор на отдельном слушателе, а не разбор пути на общем: принадлежность маршрута фронту обязана быть свойством того, куда вообще можно дозвониться, а не решением, принимаемым на каждом запросе.

Допуск предъявителя — ЗДЕСЬ, а не у слушателя (SEC-1017-1)

Слушатель видит пиром сам фронт, а не того, кто пришёл к фронту: личность предъявителя HTTP знает только рукопожатие фронта. Обработчик, сужающий довод по личности вызывающего (внутренний Check плоскости данных, kaname#987), на хопе её не видит, — и решать, кого пускать, может только фронт. admit задаёт корень (`authzguard.InternalFrontAdmission`); пустой допуск — отказ сборки, а не «пускать всех»: молчание значило бы ровно прежнюю дыру.

Отказ рендерится обработчиком ошибок мультиплексора — той же формой, что отказ слушателя: `403`, `{"code":7,"message":"permission denied","details":[]}`.

func NewPublic

func NewPublic(ctx context.Context, grpcAddr string, opts []grpc.DialOption) (http.Handler, error)

NewPublic собирает публичный REST-фронт службы.

grpcAddr — адрес СОБСТВЕННОГО публичного gRPC-слушателя. Через него и только через него идёт каждый запрос фронта: все звенья, решающие о вызывающем и о доступе к объекту, суть перехватчики слушателя, и внутрипроцессная регистрация обошла бы их все.

Types

type Admission added in v0.7.0

type Admission func(*tls.ConnectionState) bool

Admission — допуск предъявителя внутреннего фронта по состоянию его рукопожатия. Ложь — отказ `PermissionDenied` до вызова слушателя.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL