Summary

  • RFC 2389 added FEAT so an FTP client could discover documented extensions without trying every command, and OPTS so it could choose supported behaviour for a later command.
  • A conforming positive feature list was complete for documented extensions, but an unrecognized FEAT reply did not prove absence; older servers could support pre-FEAT extensions without knowing how to list them.
  • Capability advertisement, option acceptance, authentication, authorization, command completion and observed transfer outcome remained separate receipts.

The dangerous way to ask a harmless question

An FTP client in the 1990s could know the base protocol and still know too little about the server in front of it. New commands and mechanisms had appeared after RFC 959. Implementations did not adopt them at the same time. A client therefore faced a practical question before it could use an extension: does this server understand it?

The obvious test was to issue the command. That was also the wrong abstraction. A command is an attempt to do something, not a neutral inquiry about what might be possible. RFC 2389 observed that trying extensions one after another wasted exchanges and could produce an effect the client did not want. Discovery by execution confused knowledge with action.

FEAT created a read-before-act boundary. The client sent one word with no argument. A server that recognized the command could return a structured inventory of extension features. The client could compare that inventory with what it understood before invoking any of them. This was thin coordination: a common envelope for capability labels, while every extension retained its own semantics.

The distinction looks small because the wire exchange is small. It changed the location of uncertainty. The client no longer had to turn every question into a trial operation. It could acquire a bounded statement first and decide locally what to do with it.

One leading space carried protocol structure

RFC 2389 made the successful inventory machine-readable. A nonempty response began with a multiline 211- reply. Each feature occupied its own line and began with exactly one space. A final 211 End closed the list. The leading space was not decorative indentation: it ensured that a feature line could not be mistaken for the terminating reply.

The first line remained free-form text. The feature lines did not. A feature label could name a command, but it did not have to. Parameters after the label belonged to the later specification that defined that extension. The order meant nothing, and a server did not have to return the same order twice.

That grammar protected evolution. A client was required to tolerate feature labels it did not know. An unknown label was not a malformed reply; it was evidence that the server implemented something defined after the client was written. The client could ignore what it could not interpret and still use the common subset. Protocol growth did not require old software to pretend that new information was an error.

FEAT itself was absent from the inventory. A reply other than 500 or 502 demonstrated support for the discovery command. OPTS was also omitted because RFC 2389 required every FEAT implementation to implement it. The list described extensions, not every fact the client could already infer from the exchange.

The answer was complete in only one direction

The most interesting part of RFC 2389 was its asymmetry.

If a server implemented FEAT, it had to list every properly documented FTP extension it supported beyond RFC 959 and RFC 2389. A client receiving a conforming list could treat the listed set as the server’s complete extension inventory. A missing extension in that successful response meant the server did not support it.

But a server that did not recognize FEAT returned the ordinary 500 or 502 unknown-command reply. That error did not mean it lacked all extensions. Some extensions had been deployed before the inventory mechanism existed. An older server might understand one of them while having no way to answer FEAT. The client could still need to test that older extension individually.

Even “no features” had this compatibility shadow. A server that understood FEAT but implemented no extensions should return a one-line 211 response. RFC 2389 nevertheless allowed 500 or 502, because to the client the two situations were practically indistinguishable.

The result was a one-sided closure rule. A valid positive inventory narrowed uncertainty strongly. Failure to obtain the inventory left history unresolved. That is a more honest design than making silence carry information it cannot reliably contain.

OPTS selected behaviour; it did not execute the work

Discovery alone did not solve variation within an extension. OPTS let a client request the desired behaviour for a later target command. The defining specification for that target supplied the option syntax and effect. RFC 2389 supplied only the common envelope and reply classes.

A 200 reply meant that the server recognized the target command and found the supplied options appropriate. A 501 reply described a permanent problem: repeating the same request later without changing state would still fail. A 451 reply described a temporary server condition that might clear.

The timing matters. OPTS configured what a subsequent command should do. It did not say that the subsequent command had been issued, authorized or completed. An option receipt could be valid while the later operation failed because a pathname did not exist, credentials lacked permission, resources were unavailable or the data connection broke.

RFC 3659 made this separation concrete. Its MLST feature line could advertise which file facts the server supported and mark default facts with an asterisk. OPTS MLST then selected which facts later MLST and MLSD replies should return. The RFC warned that some non-default facts might be expensive for the server to generate. Availability, default selection, client choice and actual listing remained different states.

A TLS label was not a protected session

RFC 4217 later used the same mechanism for FTP over TLS. A FEAT-capable server supporting the security extension advertised AUTH TLS, PBSZ and PROT. Those lines told the client which negotiation path was available. They did not create that path.

The client still had to send AUTH TLS; the server had to accept it with 234; the TLS exchange had to complete; protection parameters had to be set; certificate identity and policy had to be evaluated; and any required FTP user authentication still had to succeed. The feature label was the first receipt in a chain, not a compressed substitute for the chain.

That distinction also limits what can be inferred from a captured inventory. AUTH TLS says the server claims support for the mechanism in that context. It does not prove that a particular certificate is valid, that the user is authorized, that data protection will be selected or that any file will move.

RFC 7151 supplied another example. A server supporting the virtual-host HOST command had to advertise HOST. Yet choosing a virtual host could change the authentication environment, and certificate-name matching remained separate. A capability name exposed a door. It did not decide who could pass through it.

The registry kept names apart, not winners above losers

As FTP extensions multiplied, RFC 5797 created the IANA FTP Commands and Extensions registry. Its purpose was to reduce command and feature-name collisions and the ambiguity those collisions would create. The registry recorded commands, FEAT codes, descriptions, command types, conformance expectations and references.

The document explicitly denied a broader authority: registration was not proof that an extension was “approved.” An extension could qualify through a permanent public specification or through implementation in generally available client and server systems. Historic entries remained visible to prevent reuse. Placeholder codes reserved useful names but were not meant to appear in FEAT responses.

That is the same discipline at a different layer. The registry says which label refers to which documented mechanism. The server says which mechanisms it supports. The option exchange says which behaviour it accepted. Authentication and policy say what this user may do. The command reply says what happened at the control layer. The data connection and resulting file state say whether the intended transfer occurred.

No one record deserves promotion into all the others.

Disclosure was useful precisely because it was bounded

RFC 2389 acknowledged that a feature inventory could reveal server capabilities and permit further deductions. Without FEAT, a determined observer could probe commands individually, although the pattern might be more visible in logs. The authors did not regard the difference as serious enough to remove the mechanism.

That was a trade: disclose a bounded capability surface so compatible clients could behave predictably, while leaving each extension responsible for its own security. The alternative was not secrecy. It was noisier discovery by action.

The operational lesson is not that every service should publish everything. It is that discovery needs an explicit scope. A capability inventory should expose enough for safe selection, use stable names, tolerate unfamiliar additions and avoid claiming more than it knows. Local systems should still decide identity, policy, resource use and effects when the action occurs.

RFC 2389 did not make FTP extensions self-executing. It made the question “what can you speak?” answerable before “will you do this for me?” The Internet grew through exactly such separations: minimum common syntax, local interpretation, voluntary use and proof supplied by the running exchange.

Sources