Gergő Tisza has uploaded a new change for review. ( 
https://gerrit.wikimedia.org/r/390938 )

Change subject: Add string length limits
......................................................................

Add string length limits

Adds two new ApiBase::getAllowedParams() keys:
PARAM_MAX_BYTES and PARAM_MAX_CHARS, to set a length
limit for a (string-like) parameter.

This makes it easy to document and enforce database
field length limits (where relying on the database
would either result in unfriendly error messages or
silent truncation, depending on DB settings) and
also exposes them in structured form so API clients
can verify the length without doing roundtrips.

Change-Id: I2e784972d7e11cad79fdef887bbcde297dbd9ce0
---
M includes/api/ApiBase.php
M includes/api/ApiHelp.php
M includes/api/ApiParamInfo.php
M includes/api/i18n/en.json
M includes/api/i18n/qqq.json
5 files changed, 58 insertions(+), 3 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core 
refs/changes/38/390938/1

diff --git a/includes/api/ApiBase.php b/includes/api/ApiBase.php
index 80aeff5..5f6583a 100644
--- a/includes/api/ApiBase.php
+++ b/includes/api/ApiBase.php
@@ -217,6 +217,18 @@
         */
        const PARAM_ISMULTI_LIMIT2 = 22;
 
+       /**
+        * (integer) Maximum length of a string in bytes.
+        * @since 1.31
+        */
+       const PARAM_MAX_BYTES = 23;
+
+       /**
+        * (integer) Maximum length of a string in characters.
+        * @since 1.31
+        */
+       const PARAM_MAX_CHARS = 24;
+
        /**@}*/
 
        const ALL_DEFAULT_STRING = '*';
@@ -1173,9 +1185,9 @@
                        );
                }
 
-               // More validation only when choices were not given
-               // choices were validated in parseMultiValue()
                if ( isset( $value ) ) {
+                       // More validation only when choices were not given
+                       // choices were validated in parseMultiValue()
                        if ( !is_array( $type ) ) {
                                switch ( $type ) {
                                        case 'NULL': // nothing to do
@@ -1285,6 +1297,23 @@
                                $value = array_unique( $value );
                        }
 
+                       if ( in_array( $type, [ 'NULL', 'string', 'text', 
'password' ], true ) ) {
+                               foreach ( (array)$value as $val ) {
+                                       if ( isset( 
$paramSettings[self::PARAM_MAX_BYTES] ) ) {
+                                               if ( strlen( $val ) > 
$paramSettings[self::PARAM_MAX_BYTES] ) {
+                                                       $this->dieWithError( [ 
'apierror-maxbytes', $encParamName,
+                                                               
$paramSettings[self::PARAM_MAX_BYTES] ] );
+                                               }
+                                       }
+                                       if ( isset( 
$paramSettings[self::PARAM_MAX_CHARS] ) ) {
+                                               if ( mb_strlen( $val, 'UTF-8' ) 
> $paramSettings[self::PARAM_MAX_CHARS] ) {
+                                                       $this->dieWithError( [ 
'apierror-maxchars', $encParamName,
+                                                               
$paramSettings[self::PARAM_MAX_CHARS] ] );
+                                               }
+                                       }
+                               }
+                       }
+
                        // Set a warning if a deprecated parameter has been 
passed
                        if ( $deprecated && $value !== false ) {
                                $feature = $encParamName;
diff --git a/includes/api/ApiHelp.php b/includes/api/ApiHelp.php
index 318555a..b0ffdb2 100644
--- a/includes/api/ApiHelp.php
+++ b/includes/api/ApiHelp.php
@@ -528,6 +528,17 @@
                                                                ->parse();
                                                        $hintPipeSeparated = 
false;
                                                } else {
+                                                       if ( in_array( $type, [ 
null, 'string', 'text', 'password' ], true ) ) {
+                                                               if ( isset( 
$settings[self::PARAM_MAX_BYTES] ) ) {
+                                                                       $info[] 
= $context->msg( 'api-help-param-maxbytes' )
+                                                                               
->numParams( $settings[self::PARAM_MAX_BYTES] );
+                                                               }
+                                                               if ( isset( 
$settings[self::PARAM_MAX_CHARS] ) ) {
+                                                                       $info[] 
= $context->msg( 'api-help-param-maxchars' )
+                                                                               
->numParams( $settings[self::PARAM_MAX_CHARS] );
+                                                               }
+                                                       }
+
                                                        switch ( $type ) {
                                                                case 
'submodule':
                                                                        
$groups[] = $name;
@@ -668,7 +679,6 @@
                                                                $info[] = 
$msg->params( $multi ? 2 : 1 )->parse();
                                                        }
                                                }
-
                                                if ( $multi ) {
                                                        $extra = [];
                                                        $lowcount = !empty( 
$settings[ApiBase::PARAM_ISMULTI_LIMIT1] )
diff --git a/includes/api/ApiParamInfo.php b/includes/api/ApiParamInfo.php
index 2fa20a9..674698a 100644
--- a/includes/api/ApiParamInfo.php
+++ b/includes/api/ApiParamInfo.php
@@ -471,6 +471,14 @@
                        if ( !empty( $settings[ApiBase::PARAM_RANGE_ENFORCE] ) 
) {
                                $item['enforcerange'] = true;
                        }
+                       if ( in_array( $item['type'], [ null, 'string', 'text', 
'password' ], true ) ) {
+                               if ( isset( $settings[self::PARAM_MAX_BYTES] ) 
) {
+                                       $item['maxbytes'] = 
$settings[self::PARAM_MAX_BYTES];
+                               }
+                               if ( isset( $settings[self::PARAM_MAX_CHARS] ) 
) {
+                                       $item['maxchars'] = 
$settings[self::PARAM_MAX_CHARS];
+                               }
+                       }
                        if ( !empty( 
$settings[ApiBase::PARAM_DEPRECATED_VALUES] ) ) {
                                $deprecatedValues = array_keys( 
$settings[ApiBase::PARAM_DEPRECATED_VALUES] );
                                if ( is_array( $item['type'] ) ) {
diff --git a/includes/api/i18n/en.json b/includes/api/i18n/en.json
index dbd5451..85f17de 100644
--- a/includes/api/i18n/en.json
+++ b/includes/api/i18n/en.json
@@ -1605,6 +1605,8 @@
        "api-help-param-direction": "In which direction to 
enumerate:\n;newer:List oldest first. Note: $1start has to be before 
$1end.\n;older:List newest first (default). Note: $1start has to be later than 
$1end.",
        "api-help-param-continue": "When more results are available, use this 
to continue.",
        "api-help-param-no-description": "<span class=\"apihelp-empty\">(no 
description)</span>",
+       "api-help-param-maxbytes": "Cannot be longer than $1 
{{PLURAL:$1|byte|bytes}}.",
+       "api-help-param-maxchars": "Cannot be longer than $1 
{{PLURAL:$1|character|characters}}.",
        "api-help-examples": "{{PLURAL:$1|Example|Examples}}:",
        "api-help-permissions": "{{PLURAL:$1|Permission|Permissions}}:",
        "api-help-permissions-granted-to": "{{PLURAL:$1|Granted to}}: $2",
@@ -1710,6 +1712,8 @@
        "apierror-invalidurlparam": "Invalid value for <var>$1urlparam</var> 
(<kbd>$2=$3</kbd>).",
        "apierror-invaliduser": "Invalid username \"$1\".",
        "apierror-invaliduserid": "User ID <var>$1</var> is not valid.",
+       "apierror-maxbytes": "Parameter <var>$1</var> cannot be longer than $2 
{{PLURAL:$2|byte|bytes}}",
+       "apierror-maxchars": "Parameter <var>$1</var> cannot be longer than $2 
{{PLURAL:$2|character|characters}}",
        "apierror-maxlag-generic": "Waiting for a database server: $1 
{{PLURAL:$1|second|seconds}} lagged.",
        "apierror-maxlag": "Waiting for $2: $1 {{PLURAL:$1|second|seconds}} 
lagged.",
        "apierror-mimesearchdisabled": "MIME search is disabled in Miser Mode.",
diff --git a/includes/api/i18n/qqq.json b/includes/api/i18n/qqq.json
index 6aaaac7..3bdf7c6 100644
--- a/includes/api/i18n/qqq.json
+++ b/includes/api/i18n/qqq.json
@@ -1496,6 +1496,8 @@
        "api-help-param-direction": "{{doc-apihelp-param|description=any 
standard \"dir\" parameter|noseealso=1}}",
        "api-help-param-continue": "{{doc-apihelp-param|description=any 
standard \"continue\" parameter, or other parameter with the same 
semantics|noseealso=1}}",
        "api-help-param-no-description": "Displayed on API parameters that lack 
any description",
+       "api-help-param-maxbytes": "Used to display the maximum allowed length 
of a parameter, in bytes.",
+       "api-help-param-maxchars": "Used to display the maximum allowed length 
of a parameter, in characters.",
        "api-help-examples": "Label for the API help examples 
section\n\nParameters:\n* $1 - Number of examples to be 
displayed\n{{Identical|Example}}",
        "api-help-permissions": "Label for the \"permissions\" section in the 
main module's help output.\n\nParameters:\n* $1 - Number of permissions 
displayed\n{{Identical|Permission}}",
        "api-help-permissions-granted-to": "Used to introduce the list of 
groups each permission is assigned to.\n\nParameters:\n* $1 - Number of 
groups\n* $2 - List of group names, comma-separated",
@@ -1599,6 +1601,8 @@
        "apierror-invalidurlparam": "{{doc-apierror}}\n\nParameters:\n* $1 - 
Module parameter prefix, e.g. \"bl\".\n* $2 - Key\n* $3 - Value.",
        "apierror-invaliduser": "{{doc-apierror}}\n\nParameters:\n* $1 - User 
name that is invalid.",
        "apierror-invaliduserid": "{{doc-apierror}}",
+       "apierror-maxbytes": "{{doc-apierror}}\n\nParameters:\n* $1 - Parameter 
name.\n* $2 - Maximum allowed bytes.",
+       "apierror-maxchars": "{{doc-apierror}}\n\nParameters:\n* $1 - Parameter 
name.\n* $2 - Maximum allowed characters.",
        "apierror-maxlag-generic": "{{doc-apierror}}\n\nParameters:\n* $1 - 
Database is lag in seconds.",
        "apierror-maxlag": "{{doc-apierror}}\n\nParameters:\n* $1 - Database 
lag in seconds.\n* $2 - Database server that is lagged.",
        "apierror-mimesearchdisabled": "{{doc-apierror}}",

-- 
To view, visit https://gerrit.wikimedia.org/r/390938
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I2e784972d7e11cad79fdef887bbcde297dbd9ce0
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: GergÅ‘ Tisza <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to