<?xml version="1.0" encoding="utf-8"?>
<!-- 
     draft-rfcxml-general-template-standard-00
  
     This template includes examples of the most commonly used features of RFCXML with comments 
     explaining how to customise them. This template can be quickly turned into an I-D by editing 
     the examples provided. Look for [REPLACE], [REPLACE/DELETE], [CHECK] and edit accordingly.
     Note - 'DELETE' means delete the element or attribute, not just the contents.
     
     Documentation is at https://authors.ietf.org/en/templates-and-schemas
-->
<?xml-model href="rfc7991bis.rnc"?>  <!-- Required for schema validation and schema-aware editing -->
<!-- <?xml-stylesheet type="text/xsl" href="rfc2629.xslt" ?> -->
<!-- This third-party XSLT can be enabled for direct transformations in XML processors, including most browsers -->


<!DOCTYPE rfc [
  <!ENTITY nbsp    "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY nbhy   "&#8209;">
  <!ENTITY wj     "&#8288;">
]>

<rfc
  xmlns:xi="http://www.w3.org/2001/XInclude"
  category="std"
  ipr="trust200902"
  obsoletes=""
  updates=""
  submissionType="IETF"
  xml:lang="en"
  version="3"
  tocInclude="true"
  tocDepth="5"
  symRefs="true"
  sortRefs="true"
  consensus="true"
  docName="draft-power-metadata-expression-language-02"
  > 
   <front>
      <title abbrev="CDNI Metadata Expression Language">CDNI Metadata Expression Language</title>
       <author initials="W." surname="Power" fullname="Will Power">
         <organization>Lumen Technologies</organization>
         <address>
            <postal>
               <street />
               <city />
               <region />
               <code />
               <country>US</country>
            </postal>
            <email>wrpower@gmail.com</email>
         </address>
      </author>
      <author fullname="Glenn Goldstein" initials="G." surname="Goldstein">
         <organization>Lumen Technologies</organization>
         <address>
            <postal>
               <street />
               <city />
               <region />
               <code />
               <country>US</country>
            </postal>
            <email>glenng1215@gmail.com</email>
         </address>
      </author>
      <author fullname="Arnon Warshavsky" initials="A." surname="Warshavsky">
         <organization>Qwilt</organization>
         <address>
            <postal>
               <street />
               <city />
               <region />
               <code />
               <country>Israel</country>
            </postal>
            <email>arnon@qwilt.com</email>
         </address>
      </author>
      <date />
      <workgroup>Content Delivery Networks Interconnection</workgroup>
      <abstract>
         <t>
           This document specifies the syntax and provides usage examples for an expression language to be used within Streaming Video Technology Alliance (SVTA)/Content Delivery Network Interconnection (CDNI) Metadata Interface (MI) objects. The purpose of this expression language is to enable metadata to be applied conditionally (based on aspects of an HTTP request), and to enable Hypertext Transfer Protocol (HTTP) responses to be generated or altered dynamically.
         </t>
      </abstract>
   </front>
<middle>
<section anchor="h.3znysh7">
  <name>Introduction</name>
  <t>The CDNI metadata model defined in <xref target="RFC8006"/> allows metadata to be applied conditionally based on matches to an HTTP request hostname and/or path While this is sufficient for many use cases, the need often arises for configuration metadata (such as caching rules) to be applied conditionally based on matching values of HTTP request headers. Additionally, content delivery networks (CDNs) often need to conditionally modify responses before forwarding them to a client. These modifications typically involve adding, deleting, or modifying HTTP response headers or synthesizing responses. A set of CDNI metadata objects for conditionally applying metadata and modifying responses is defined in the Processing Stages Metadata Specification <xref target="SVTA2032"/>, which requires an expression language to enable the specification of match expressions and synthetically generated values.</t>
  <t>This document specifies the syntax and provides usage examples for an expression language to be used within SVTA/CDNI Metadata Interface (MI) objects, such as those defined within CDNI Metadata Model Extensions <xref target="SVTA2029"/> and its subparts.</t>
</section><section anchor="requirements" title="Requirements">
<t>The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in <xref target="RFC2119"/>.</t>
</section><section anchor="h.whuucahungsa">
  <name>Expression Usage In CDNI Metadata Model</name>
  <t>The CDNI Metadata Expression Language (MEL) provides a syntax with a rich set of variables, operators, and built-in functions to facilitate two key use cases within the CDNI metadata model:</t>
  <ul>
    <li>
      <t>Match Expressions - Expressions that evaluate to a Boolean value are used  to dynamically determine if metadata should be applied based on evaluation of aspects of an inbound HTTP request (matching to a header value, for example). </t>
    </li>
    <li>
      <t>Value Expressions - Enable the dynamic construction of a value to be used in scenarios such as constructing a cache key, setting an HTTP response header or status code, rewriting a request Uniform Resource Identifier (URI), or dynamically generating a response body.</t>
    </li>
  </ul>
  <t>Refer to the Processing Stages Metadata Specification <xref target="SVTA2032"/> for example usage of both match expressions and value expressions within the Processing Stages Model.</t>
  <t>Refer to the Cache Control Metadata Specification <xref target="SVTA2033"/> for example usage of Value Expressions to dynamically generate cache keys.</t>
</section><section anchor="h.tqf15c2ukqae">
  <name>Expression Syntax BNF</name>
  <figure>
    <sourcecode><![CDATA[<list>                ::= "[" "]" | "[" <expr_list> "]" 
<expr_list>           ::= <expr> | <expr_list> "," <expr>
<expr>                ::= <identifier> "=" <expr> | <function_call> | 
                          <expr> <operator> <expr> |
                          <prefix_op> <expr> | <literal>

<function_call>       ::= <function_name> "(" ")" | 
                          <function_name> "(" <expr_list> ")" 

<operator>            ::= <logic_operator> | <math_operator> |
                          <bit_operator> | <string_operator> |
                          <comparison_operator> | <regex_operator> |
                          <glob_operator> | <ip_operator>

<prefix_op>           ::= "+" | "-" | "!" | "~"

<literal>             ::= NUMBER | STRING | "true" | "false" | "nil"

<logic_operator>      ::= "and" | "or" 

<math_operator>       ::= "+" | "-" | "*" | "/" | "%"

<bit_operator>        ::= "|" | "&" | "~" | "<<" | ">>"

<string_operator>     ::= "."

<comparison_operator> ::= "==" | "!=" | ">" | "<" | "<=" | ">=" 

<regex_operator>      ::= "regexmatch" | "~=" | "regexmatchi" |
                          "!regexmatch" | "!regexmatchi" 

<glob_operator>       ::= "globmatch" | "*=" | "globmatchi" |
                          "%*=" | "!globmatch" | "!*=" |
                          "!globmatchi" | "!%*="

<ip_operator>         ::= "ipmatch" | "!ipmatch"

<function_name>       ::= "integer" | "real" | "string" | "boolean" | 
                          "upper" | "lower" |
                          "match" | "match_replace" | "add_query" |  
                          "add_query_multi" | "remove_query" | 
                          "remove_query_multi" |
                          "path_element" | "path_elements"

<identifier>          ::= <alpha_char> <identifier_word> |
                          "_" <identifier_word>

<identifier_word>     ::= <identifier_char> |
                          <identifier_char> <identifier_word>

<identifier_char>     ::= <alpha_numeric> | "." | "-" | "_" | "#"

<alpha_numeric>       ::= <alpha_char> | <digit>

<alpha_char>          ::= "a-z" | "A-Z" 

<digit>               ::= "0" | "1" | "2" | "3" | "4" |
                          "5" | "6" | "7" | "8" | "9"

]]></sourcecode>
  </figure>
</section><section anchor="h.gltdh8cxh4q3">
  <name>Core Variables</name>
  <t>The expression language supports two namespaces of core variables, each with a distinct prefix:</t>
  <ul>
    <li>
      <t>req.        Prefix for accessing attributes of the HTTP request object</t>
    </li>
    <li>
      <t>resp.        Prefix for accessing attributes of the HTTP response object</t>
    </li>
  </ul>
  <table>
    <thead>
      <tr>
        <th>Variable</th>
        <th>Meaning</th>
        <th>Type</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>req.h.&lt;name&gt;</td>
        <td>Request header &lt;name&gt;</td>
        <td>String</td>
      </tr>
      <tr>
        <td>req.uri</td>
        <td>Request URI (includes query string and fragment identifier, if any)</td>
        <td>String</td>
      </tr>
      <tr>
        <td>req.uri.path</td>
        <td>Request URI path</td>
        <td>String</td>
      </tr>
      <tr>
        <td>req.uri.pathquery</td>
        <td>Request path and query string</td>
        <td>String</td>
      </tr>
      <tr>
        <td>req.uri.query</td>
        <td>Request query string</td>
        <td>String</td>
      </tr>
      <tr>
        <td>req.uri.query.&lt;key&gt;</td>
        <td>Request query string value associated with &lt;key&gt;. If the key is not present in the uri, nil is returned. If the key is present with no value, as in "a=", then an empty string is returned.</td>
        <td>String</td>
      </tr>
      <tr>
        <td>req.uri.querykv.&lt;key&gt;</td>
        <td>Request query string key and value associated with &lt;key&gt;, returned as a single String exactly as-is from the request url.For example, when used with a uri containing a query string "key=xxx", expression would return the string "key=xxx". When used with a uri containing a query string "key=", expression would return the string "key=".</td>
        <td>String</td>
      </tr>
      <tr>
        <td>req.method</td>
        <td>Request HTTP method (GET, POST, etc.)</td>
        <td>String</td>
      </tr>
      <tr>
        <td>req.scheme</td>
        <td>Request scheme (http or https)</td>
        <td>String</td>
      </tr>
      <tr>
        <td>req.clientip</td>
        <td>IP address of the client that made the request. Note: IPv6 addresses MUST NOT be enclosed in square brackets [].</td>
        <td>String</td>
      </tr>
      <tr>
        <td>req.clientport</td>
        <td>Request port number </td>
        <td>Unsigned </td>
      </tr>
      <tr>
        <td>resp.h.&lt;name&gt;</td>
        <td>Response header &lt;name&gt;</td>
        <td>String</td>
      </tr>
      <tr>
        <td>resp.status</td>
        <td>Response status code</td>
        <td>Unsigned </td>
      </tr>
    </tbody>
  </table>
</section><section anchor="h.o2btv2kp34lv">
  <name>Operators And Keywords</name>
  <table>
    <thead>
      <tr>
        <th>Operator</th>
        <th>Type</th>
        <th>Result Type</th>
        <th>Meaning</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>==</td>
        <td>infix</td>
        <td>Boolean</td>
        <td>Equality test</td>
      </tr>
      <tr>
        <td>!=</td>
        <td>infix</td>
        <td>Boolean</td>
        <td>Inequality test</td>
      </tr>
      <tr>
        <td>!</td>
        <td>infix</td>
        <td>Boolean</td>
        <td>Logical NOT operator</td>
      </tr>
      <tr>
        <td>&gt; </td>
        <td>infix</td>
        <td>Boolean</td>
        <td>Greater than test</td>
      </tr>
      <tr>
        <td>&lt; </td>
        <td>infix</td>
        <td>Boolean</td>
        <td>Less than test</td>
      </tr>
      <tr>
        <td>&gt;=</td>
        <td>infix</td>
        <td>Boolean</td>
        <td>Greater than or equal test</td>
      </tr>
      <tr>
        <td>&lt;=</td>
        <td>infix</td>
        <td>Boolean</td>
        <td>Less than or equal</td>
      </tr>
      <tr>
        <td>*=</td>
        <td>infix</td>
        <td>Boolean</td>
        <td>Glob style match</td>
      </tr>
      <tr>
        <td>~=</td>
        <td>infix</td>
        <td>Boolean</td>
        <td>Regular expression match (see <xref target="PCRE"/> for details on PCRE RegEx matching)</td>
      </tr>
      <tr>
        <td>ipmatch</td>
        <td>infix</td>
        <td>Boolean</td>
        <td>Match against IP address or CIDR (IPv4 and IPv6). For an example IP address of '10.2.3.4', matching against '10.2.3.0/24' would return true, while matching against '10.2.3.5' would return false.</td>
      </tr>
      <tr>
        <td>+</td>
        <td>infix</td>
        <td>Numeric</td>
        <td>Addition</td>
      </tr>
      <tr>
        <td>-</td>
        <td>infix</td>
        <td>Numeric</td>
        <td>Subtraction</td>
      </tr>
      <tr>
        <td>*</td>
        <td>infix</td>
        <td>Numeric</td>
        <td>Multiplication</td>
      </tr>
      <tr>
        <td>/</td>
        <td>infix</td>
        <td>Numeric</td>
        <td>Division</td>
      </tr>
      <tr>
        <td>%</td>
        <td>infix</td>
        <td>Unsigned or Integer</td>
        <td>Modulus</td>
      </tr>
      <tr>
        <td>.</td>
        <td>infix</td>
        <td>String</td>
        <td>Concatenation. Note: There MUST be at least 1 space before/after the dot operator.</td>
      </tr>
      <tr>
        <td>? :</td>
        <td>ternary</td>
        <td>*</td>
        <td>Conditional operator: &lt;e&gt; ? &lt;v1&gt; : &lt;v2&gt;Evaluates &lt;v1&gt; if &lt;e&gt; is true, &lt;v2&gt; otherwise.</td>
      </tr>
      <tr>
        <td>( )</td>
        <td>grouping</td>
        <td> </td>
        <td>Used to override precedence and used for function calls.</td>
      </tr>
    </tbody>
  </table>
  <table>
    <thead>
      <tr>
        <th>Keyword</th>
        <th>Meaning</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>and</td>
        <td>Logical AND</td>
      </tr>
      <tr>
        <td>or</td>
        <td>Logical OR</td>
      </tr>
      <tr>
        <td>not</td>
        <td>Logical NOT (see also the "!" operator)</td>
      </tr>
      <tr>
        <td>nil</td>
        <td>No value (distinct from empty value)</td>
      </tr>
      <tr>
        <td>true</td>
        <td>Boolean constant: true</td>
      </tr>
      <tr>
        <td>false</td>
        <td>Boolean constant: false</td>
      </tr>
    </tbody>
  </table>
</section><section anchor="h.ni4lit9ptgcz">
  <name>Built-In Functions</name>
  <t>To enable the types of expressions typically used in content delivery scenarios to evaluate and generate or modify HTTP headers, the following set of built-in functions are defined to facilitate format conversions, matching, and query string management. Any dCDN that advertises support for a metadata property that leverages MEL MUST provide implementations of these built-in functions.</t>
  <section anchor="h.a564hgfpaduv">
    <name>Type Conversions</name>
    <table>
      <thead>
        <tr>
          <th>Function</th>
          <th>Action</th>
          <th>Argument(s)</th>
          <th>Returns</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>integer(e)</td>
          <td>Converts expression to integer.</td>
          <td>1</td>
          <td>integer</td>
        </tr>
        <tr>
          <td>real(e)</td>
          <td>Converts expression to real.</td>
          <td>1</td>
          <td>real</td>
        </tr>
        <tr>
          <td>string(e)</td>
          <td>Converts expression to string.</td>
          <td>1</td>
          <td>string</td>
        </tr>
        <tr>
          <td>boolean(e)</td>
          <td>Converts expression to Boolean.</td>
          <td>1</td>
          <td>Boolean</td>
        </tr>
      </tbody>
    </table>
    <t>The following table summarizes the return values of type conversion functions when presented with edge-case input values:</t>
    <table>
      <thead>
        <tr>
          <th>Function</th>
          <th>non-zero numeric input</th>
          <th>nil input </th>
          <th>non-numeric string input</th>
          <th>numeric zero input</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>integer(e)</td>
          <td>integer</td>
          <td>0</td>
          <td>0</td>
          <td>0</td>
        </tr>
        <tr>
          <td>real(e)</td>
          <td>real</td>
          <td>0</td>
          <td>0</td>
          <td>0</td>
        </tr>
        <tr>
          <td>string(e)</td>
          <td>string</td>
          <td>'nil'</td>
          <td>string</td>
          <td>'0'</td>
        </tr>
        <tr>
          <td>boolean(e)</td>
          <td>true</td>
          <td>false</td>
          <td>true</td>
          <td>false</td>
        </tr>
      </tbody>
    </table>
  </section>
  <section anchor="h.c8ya8nld0n2g">
    <name>String Conversions</name>
    <table>
      <thead>
        <tr>
          <th>Function</th>
          <th>Action</th>
          <th>Argument(s)</th>
          <th>Returns</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>upper(e)</td>
          <td>Converts a string to uppercase. Useful for case-insensitive comparisons.</td>
          <td>1</td>
          <td>string</td>
        </tr>
        <tr>
          <td>lower(e)</td>
          <td>Converts a string to lowercase. Useful for case-insensitive comparisons.</td>
          <td>1</td>
          <td>string</td>
        </tr>
      </tbody>
    </table>
  </section>
  <section anchor="h.hz4mk74cwao0">
    <name>Convenience Functions</name>
    <table>
      <thead>
        <tr>
          <th>Function</th>
          <th>Action</th>
          <th>Args</th>
          <th>Returns</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>match(string Input, string Match)</td>
          <td>Regular expression 'Match' is applied to Input and the matching element (if any) is returned. An empty string is returned if there is no match.See <xref target="PCRE"/> for details on PCRE RegEx matching.</td>
          <td>2</td>
          <td>string</td>
        </tr>
        <tr>
          <td>match_replace(string Input, string Match, string Replace)</td>
          <td>Regular expression 'Match' is applied to the Input argument and replaced with the Replace argument upon successful match. It returns the updated (replaced) version of Input.</td>
          <td>3</td>
          <td>string</td>
        </tr>
        <tr>
          <td>add_query(string Input, string q, string v)</td>
          <td>Add query string element q with value v to the Input string. If v is nil, just add the query string element q. The query element q and value v MUST conform to the format defined in <xref target="RFC3986"/>.</td>
          <td>2</td>
          <td>string</td>
        </tr>
        <tr>
          <td>add_query_multi(string input, string qvs)</td>
          <td>Add all the query value elements from qvs to the input string. For example, if qvs = "k1=v1, k2=v2, k3=v3"), parameters k1, k2, k3 and associated values would be added to input.If a qvs element only has a key but no value, the existing value of that key will be kept.</td>
          <td>2</td>
          <td>string</td>
        </tr>
        <tr>
          <td>remove_query(string Input, string q)</td>
          <td>Remove all occurrences of query string element q from the Input string.</td>
          <td>2</td>
          <td>string</td>
        </tr>
        <tr>
          <td>remove_query_multi(string input, string qs)</td>
          <td>Remove all occurrences of the query string elements referenced in parameter qs from the input string. For example, if qs= "k1, k2, k3", all occurrences of k1, k2, k3 would be removed from input.</td>
          <td>2</td>
          <td>string</td>
        </tr>
        <tr>
          <td>keep_query_multi(string input, string qs)</td>
          <td>Remove all query string elements from input except for the elements referenced in parameter qs. For example, if qs = "k1, k2, k3", all query string elements would be removed from input except for k1, k2, k3.</td>
          <td>2</td>
          <td>string</td>
        </tr>
        <tr>
          <td>path_element(string Input, integer n)</td>
          <td>Return the path element n from Input. -1 returns the last element.</td>
          <td>2</td>
          <td>string</td>
        </tr>
        <tr>
          <td>path_elements(string Input, integer n, integer m)</td>
          <td>Return the path elements from position n to m.</td>
          <td>3</td>
          <td>string</td>
        </tr>
      </tbody>
    </table>
  </section>
</section><section anchor="h.w3gg1c7i822n">
  <name>User-Defined Variables</name>
  <t>In addition to the core variable namespaces that address HTTP request and response objects (req. and resp.), MEL supports user-defined variables that can be referenced via the following prefix:</t>
  <ul>
    <li>
      <t>var. Prefix for accessing user-defined variables set via MI.SetVariable</t>
    </li>
  </ul>
  <t>A user defined variable is available for access in MEL expressions from the moment it is assigned, throughout the duration of the transaction. If a user variable is accessed before it has been set, it returns the value of nil.</t>
  <section anchor="h.r4qi147wzq20">
    <name>MI.SetVariable</name>
    <t>MI.SetVariable is a GenericMetadata object that allows one to set user-defined variables that can be accessed from MEL. Variables set via this mechanism can be accessed in matching and value construction expressions using a var. prefix before the variable name.  Note: Variable names MUST be string literals.</t>
    <t>Property: variable-name</t>
    <ul>
      <li>
        <t>Description: The name of the variable.</t>
      </li>
      <li>
        <t>Type: String. Alphanumeric with both uppercase and lowercase characters; the property MUST start with a letter.</t>
      </li>
      <li>
        <t>Mandatory-to-Specify: Yes</t>
      </li>
    </ul>
    <t>Property: variable-value</t>
    <ul>
      <li>
        <t>Description: The string representation of the value to set for the user-defined variable.</t>
      </li>
      <li>
        <t>Type: String, either the static value or a MEL expression, determined by the value-is-expression property.</t>
      </li>
      <li>
        <t>Mandatory-to-Specify: Yes</t>
      </li>
    </ul>
    <t>Property: value-is-expression</t>
    <ul>
      <li>
        <t>Description: A flag to signal whether the value is a static string literal or a MEL expression that needs to be dynamically evaluated.</t>
      </li>
      <li>
        <t>Type: Boolean</t>
      </li>
      <li>
        <t>Mandatory-to-Specify: No. The default is "False", indicating that the value is a string literal and does not need to be evaluated.</t>
      </li>
    </ul>
    <t>The following example illustrates the setting of a user-defined variable whose value is a MEL expression suffixed by a static literal string:</t>
    <figure>
      <sourcecode><![CDATA[{
  "generic-metadata-type": "MI.SetVariable",
  "generic-metadata-value": {
    "variable-name": "myvar",
    "variable-value": "req.h.host . 'is my host from player'"
    "value-is-expression": true
  }
}]]></sourcecode>
    </figure>
    <t>The following example illustrates the setting of a user-defined variable whose value is another user-defined variable suffixed by a static literal string:</t>
    <figure>
      <sourcecode><![CDATA[{
  "generic-metadata-type": "MI.SetVariable",
  "generic-metadata-value": {
    "variable-name": "myvar1",
    "variable-value": "req.host . 'is my host from player'"
    "value-is-expression": true
  }
}
{
  "generic-metadata-type": "MI.SetVariable",
  "generic-metadata-value": {
    "variable-name": "myvar2",
    "variable-value": "var.myvar1 . 'and forwarded to Origin'"
    "value-is-expression": true
  }
}]]></sourcecode>
    </figure>
  </section>
</section><section anchor="h.viy7jx5w8cn">
  <name>Error Handling</name>
  <section anchor="h.ll00oos9tk7w">
    <name>Compile-Time Errors</name>
    <t>To ensure reliable service, all CDNI metadata configurations MUST be validated for syntax errors before they are ingested into a dCDN. That is, existing configurations SHOULD be kept as the live running configuration until the new configuration has passed validation. If errors are detected in a new configuration, the configuration MUST be rejected. An HTTP 500 'Internal Server Error' SHOULD be returned with a message that indicates the source of the error (line number and configuration element that caused the error).</t>
    <t>Examples of MEL compile-time errors:</t>
    <ul>
      <li>
        <t>Unknown MEL variable name referenced in an expression</t>
      </li>
      <li>
        <t>Unknown MEL operator, keyword, or functions referenced in an expression</t>
      </li>
      <li>
        <t>Incorrect number of arguments used in a MEL expression operator or function</t>
      </li>
      <li>
        <t>Incorrect type of argument used in a MEL expression operator or function</t>
      </li>
    </ul>
  </section>
  <section anchor="h.aortr883kab6">
    <name>Runtime Errors</name>
    <t>If a runtime error is detected when processing a request, the request SHOULD be terminated, and an HTTP 500 'Internal Server Error' returned to the caller. To avoid security leaks, sensitive information MUST be removed from the error message before it is returned to an external client. In addition to returning the HTTP 500 error, the dCDN SHOULD log additional diagnostic information to assist in troubleshooting.</t>
    <t>Examples of runtime errors:</t>
    <ul>
      <li>
        <t>Failure to allocate memory (or other server resources) when evaluating a MEL expression</t>
      </li>
      <li>
        <t>Incorrect runtime argument type in a MEL expression, such as, trying to convert a non-numeric string to a number</t>
      </li>
    </ul>
  </section>
</section><section anchor="h.6shtiqm7rbvp">
  <name>FCI Capabilities</name>
  <t>Since implementing the full MEL specification may be complex and onerous, a mechanism is needed for a dCDN to advertise what portions of the MEL standard it supports (if any). This section introduces the FCI.SupportedMELFeatures object, which can be contained within the Capabilities Advertisement object defined in <xref target="RFC8008"/> section 5, or embedded in an FCI.MetadataExtended object as defined in <xref target="SVTA2041"/>, the SVTA Configuration Interface Metadata Capabilities Specification.</t>
  <t>If FCI.SupportedMELFeatures is provided within an Capabilities Advertisement object and a  FCI.MetadataExtended object for a given footprint, the advertisement within FCI.MetadataExtended MUST take precedence.</t>
  <section anchor="h.my22digf1aha">
    <name>FCI.SupportedMELFeatures</name>
    <t>The FCI.SupportedMELFeatures object is contained in FCI Capabilities advertisements and allows a dCDN to advertise the portions of the MEL specification that it supports. If a capabilities advertisement does not contain a FCI.SupportedMELFeatures or a  FCI.MetadataExtended object with an embedded FCI.SupportedMELFeatures object, the upstream content delivery network (uCDN) MUST assume that the dCDN has support for the full MEL specification.</t>
    <t>Property: keywords</t>
    <ul>
      <li>
        <t>Description: A list of supported keywords.</t>
      </li>
      <li>
        <t>Type: Array</t>
      </li>
      <li>
        <t>Mandatory-to-Specify: No. If not specified, it is assumed to be  empty. </t>
      </li>
      <li>
        <t>Values:  ["and", "or", "not", "nil", "true", "false"]</t>
      </li>
    </ul>
    <t>Property: operators</t>
    <ul>
      <li>
        <t>Description: A list of supported operators.</t>
      </li>
      <li>
        <t>Type: Array</t>
      </li>
      <li>
        <t>Mandatory-to-Specify: No. If not specified, it is assumed to be empty.</t>
      </li>
      <li>
        <t>Values: ["==", "!=", "!", "&gt;", "&lt;", "&gt;=", "&lt;=", "*=", "~=", "+", "-", "*", "/", "%", " . ", "()", "?:", "ipmatch"]</t>
      </li>
    </ul>
    <t>Property: variables</t>
    <ul>
      <li>
        <t>Description: A list of supported variables.</t>
      </li>
      <li>
        <t>Type: Array</t>
      </li>
      <li>
        <t>Mandatory-to-Specify: No. If not specified, it is assumed to be  empty.</t>
      </li>
      <li>
        <t>Values: ["req.h.&lt;name&gt;", "req.uri", "req.uri.path", "req.uri.pathquery", "req.uri.query", "req.uri.query.&lt;key&gt;", "req.uri.querykv.&lt;key&gt;", "req.method", "req.scheme", "resp.h.&lt;name&gt;", "resp.status", "req.clientip", "req.clientport", "var.&lt;user-variable&gt;" ]</t>
      </li>
    </ul>
    <t>Property: built-in-functions</t>
    <ul>
      <li>
        <t>Description: A list of supported built-in function names.</t>
      </li>
      <li>
        <t>Type: Array</t>
      </li>
      <li>
        <t>Mandatory-to-Specify: No. If not specified, it is assumed to be  empty</t>
      </li>
      <li>
        <t>Values:  ["integer", real", "string", "boolean", upper", "lower", "match", "match_replace", "add_query", "remove_query", "path_element", "path_elements", "add_query_multi", "remove_query_multi", "keep_query_multi"]</t>
      </li>
    </ul>
    <t>The following example advertises a subset of MEL support:</t>
    <figure>
      <sourcecode><![CDATA[{
"capabilities": [
    {
      "capability-type": "FCI.SupportedMELFeatures",
      "capability-value": {
        "keywords": ["and", "or", "not", "nil", "true", "false"],
        "operators" : ["==", "!=", "!", ">", "<", ">=",
           "<=", "~=", " . ", "()" ],
        "variables": ["req.h.<name>", "req.uri", "req.uri.path" ],
        "built-in-functions": [ "string", "boolean", "upper",
           "lower", "match", "match_replace", "path_element"]
      }
    }
  ]
}]]></sourcecode>
    </figure>
  </section>
</section><section anchor="h.lxq313q4hogd">
  <name>Informative Examples</name>
  <section anchor="h.xmqh11ice1di">
    <name>MI.ComputedCacheKey</name>
    <t>The following examples illustrate usage of the Metadata Expression Language to dynamically generate cache keys, as specified by the MI.ComputedCacheKey object in the Cache Control Metadata Specification <xref target="SVTA2033"/></t>
    <t>Example setting the cache key to the value of the X-Cache-Key header from the client HTTP request:</t>
    <figure>
      <sourcecode><![CDATA[{
  "generic-metadata-type": "MI.ComputedCacheKey",
  "generic-metadata-value": {
    "expression": "req.h.x-cache-key"
  }
}]]></sourcecode>
    </figure>
    <t>Example setting the cache key to the request URI, forced to lower-case:</t>
    <figure>
      <sourcecode><![CDATA[{
  "generic-metadata-type": "MI.ComputedCacheKey",
  "generic-metadata-value": {
    "expression": "lower(req.uri)"
  }
}]]></sourcecode>
    </figure>
  </section>
  <section anchor="h.qqfs7uxtv5s">
    <name>MI.ExpressionMatch</name>
    <t>The following example illustrates usage of the Metadata Expression Language to create a match expression, as specified by the Processing Stages Metadata Specification <xref target="SVTA2032"/></t>
    <t>In this example, the expression is true if the user-agent (glob) matches '*Safari*' and the referrer equals 'www.x.com'.</t>
    <figure>
      <sourcecode><![CDATA[{
  "generic-metadata-type": "MI.MatchExpression",
  "generic-metadata-value": {
    "expression": "req.h.user-agent *= '*Safari*' and
                   req.h.referer == 'www.x.com'"
  }
}]]></sourcecode>
    </figure>
  </section>
  <section anchor="h.gqxif7x9lipy">
    <name>MI.ResponseTransform</name>
    <t>The following example illustrates usage of the Metadata Expression Language to alter the headers of an HTTP response, as specified by the Processing Stages Metadata Specification <xref target="SVTA2032"/></t>
    <t>An HTTP response is transformed by adding a dynamically constructed header with a value that uses the expression language to concatenate the values of the user-agent and host header.</t>
    <t> </t>
    <figure>
      <sourcecode><![CDATA[{
  "generic-metadata-type": "MI.ResponseTransform",
  "generic-metadata-value": {
    "header-transform": {
      "add": [
        {
          "name": "X-custom-response-header",
          "value": "req.h.user-agent . '-' . req.h.host",
          "value-is-expressions": true
        }
      ]
    }
  }
}]]></sourcecode>
    </figure>
  </section>
</section><section anchor="Security" title="Security Considerations">
            <t>
            The FCI and MI objects defined in the present document are transferred via the interfaces defined in CDNI <xref target="RFC8006"/> which describes how to secure these interfaces protecting integrity and confidentiality while ensuring the authenticity of the dCDN and uCDN.
            </t>
        </section><section anchor="IANA" title="IANA Considerations">
            <section anchor="IANA.cdni.payload.types" title="CDNI Payload Types">
                <t>This document requests the registration of the following entries under the "CDNI Payload Types" registry hosted by IANA:
                </t>
                <table>
                    <name>CDNI Payload Types</name>
                    <thead>
                        <tr><td>Payload Type</td><td>Specification</td></tr>
                    </thead>
                    <tbody>
                        <tr><td>MI.SetVariable</td><td>RFCthis</td></tr>
                        <tr><td>FCI.SupportedMELFeatures</td><td>RFCthis</td></tr>
                    </tbody>
                 </table>
            </section>
</section><section anchor="Acknowledgements" title="Acknowledgements">
            <t>
                The authors would like to express their gratitude to the members of the Streaming Video Technology Alliance <xref target="SVTA"/> Open Caching Working Group for their guidance / contribution / reviews ...)
            </t>
            <t>Particulary the following people contribute in one or other way to the content of this draft:</t>  
                <ul>
                    <li>Pankaj Chaudhari - Disney Streaming Services</li>
                    <li>Rajeev RK - picoNETS</li>
                    <li>Yoav Gressel - Qwilt</li>
                    <li>Alfonso Siloniz - Telefonica</li>
                    <li>Ben Rosenblum - Vecima</li>
                    </ul>
        </section>
   </middle>
   <back>
      <references title="Normative References">
         <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.2119.xml"/>
         <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.3986.xml"/>
         <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8006.xml"/>
         <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8008.xml"/>
      </references>
      <references title="Informative References">
         <reference anchor="SVTA" target="https://www.svta.org">
            <front>
               <title>Streaming Video Technology Alliance Home Page</title>
               <author><organization>SVTA</organization></author>
               <date />
            </front>
         </reference>
          <reference anchor="PCRE" target="https://www.pcre.org/">
            <front>
               <title>Perl Compatible Regular Expressions</title>
               <author><organization>PCRE</organization></author>
            </front>
         </reference>
         <reference anchor="SVTA2029" target="https://svta.org/documents/SVTA2029">
            <front>
               <title>CDNI Metadata Model Extensions</title>
               <author><organization>SVTA</organization></author>
               <date />
            </front>
         </reference> 
         <reference anchor="SVTA2032" target="https://svta.org/documents/SVTA2032">
            <front>
               <title>Processing Stages Metadata Specification</title>
               <author><organization>SVTA</organization></author>
               <date />
            </front>
         </reference> 
         <reference anchor="SVTA2033" target="https://svta.org/documents/SVTA2033">
            <front>
               <title>Cache Control Metadata</title>
               <author><organization>SVTA</organization></author>
               <date />
            </front>
         </reference>
          <reference anchor="SVTA2041" target="https://svta.org/documents/SVTA2041">
            <front>
               <title>Metadata Capabilities</title>
               <author><organization>SVTA</organization></author>
               <date />
            </front>
         </reference>         

       </references>
   </back>
</rfc>
