tracker/docs/frontend.md
2022-01-15 13:03:41 -05:00

5.3 KiB

Frontends

A Frontend is a component of Chihaya that serves a BitTorrent tracker on one protocol. The frontend accepts, parses and sanitizes requests, passes them to the Logic and writes responses to Clients.

This documentation first gives a high-level overview of Frontends and later goes into implementation specifics. Users of Chihaya are expected to just read the first part - developers should read both.

Functionality

A Frontend serves one protocol, for example HTTP (BEP 3) or UDP (BEP 15). It listens for requests and usually answers each of them with one response, a basic overview of the control flow is:

  1. Read the request.
  2. Parse the request.
  3. Have the Logic handle the request. This calls a series of PreHooks.
  4. Send a response to the Client.
  5. Process the request and response through PostHooks.

Available Frontends

Chihaya ships with frontends for HTTP(S) and UDP. The HTTP frontend uses Go's http package. The UDP frontend implements both old-opentracker-style IPv6 and the IPv6 support specified in BEP 15. The advantage of the old opentracker style is that it contains a usable IPv6 ip field, to enable IP overrides in announces.

Implementing a Frontend

This part is intended for developers.

Implementation Specifics

A frontend should serve only one protocol. It may serve that protocol on multiple transports or networks, if applicable. An example of that is the http Frontend, operating both on HTTP and HTTPS.

The typical control flow of handling announces, in more detail, is:

  1. Read the request.
  2. Parse the request, if invalid go to 9.
  3. Validate/sanitize the request, if invalid go to 9.
  4. If the request is protocol-specific, handle, respond, and go to 8.
  5. Pass the request to the TrackerLogic's HandleAnnounce or HandleScrape method, if an error is returned go to 9.
  6. Send the response to the Client.
  7. Pass the request and response to the TrackerLogic's AfterAnnounce or AfterScrape method.
  8. Finish, accept next request.
  9. For invalid requests or errors during processing: Send an error response to the client. This step may be skipped for suspected denial-of-service attacks. The error response may contain information about the cause of the error. Only errors where the Client is at fault should be explained, internal server errors should be returned without explanation. Then finish, and accept the next request.

Configuration

The frontend must be configurable using a single, exported struct. The struct must have YAML annotations. The struct must implement log.Fielder to be logged on startup.

Metrics

Frontends may provide runtime metrics, such as the number of requests or their duration. Metrics must be reported using Prometheus.

A frontend should provide at least the following metrics:

  • The number of valid and invalid requests handled
  • The average time it takes to handle a single request. This request timing should be made optional using a config entry.

Requests should be separated by type, i.e. Scrapes, Announces, and other protocol-specific requests. If the frontend serves multiple transports or networks, metrics for them should be separable.

It is recommended to publish one Prometheus HistogramVec with:

  • A name like chihaya_PROTOCOL_response_duration_milliseconds
  • A value holding the duration in milliseconds of the reported request
  • Labels for:
    • action (= announce, scrape, ...)
    • address_family (= Unknown, IPv4, IPv6, ...), if applicable
    • error (= A textual representation of the error encountered during processing.) Because error is expected to hold the textual representation of any error that occurred during the request, great care must be taken to ensure all error messages are static. error must not contain any information directly taken from the request, e.g. the value of an invalid parameter. This would cause this dimension of prometheus to explode, which slows down prometheus clients and reporters.

Error Handling

Frontends should return bittorrent.ClientErrors to the Client. Frontends must not return errors that are not a bittorrent.ClientError to the Client. A message like internal server error should be used instead.

Request Sanitization

The TrackerLogic expects sanitized requests in order to function properly.

The bittorrent package provides the SanitizeAnnounce and SanitizeScrape functions to sanitize Announces and Scrapes, respectively. This is the minimal required sanitization, every AnnounceRequest and ScrapeRequest must be sanitized this way.

Note that the AnnounceRequest struct contains booleans of the form XProvided, where X denotes an optional parameter of the BitTorrent protocol. These should be set according to the values received by the Client.

Contexts

All methods of the TrackerLogic interface expect a context.Context as a parameter. After a request is handled by HandleAnnounce without errors, the populated context returned must be used to call AfterAnnounce. The same applies to Scrapes. This way, a PreHook can communicate with a PostHook by setting a context value.