Merge "API: Pretty-printed responses should always use HTTP status 200"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Thu, 10 Nov 2016 21:02:03 +0000 (21:02 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Thu, 10 Nov 2016 21:02:03 +0000 (21:02 +0000)
1  2 
includes/api/ApiMain.php
resources/src/mediawiki.special/mediawiki.special.apisandbox.js

diff --combined includes/api/ApiMain.php
@@@ -572,11 -572,7 +572,7 @@@ class ApiMain extends ApiBase 
  
                $response = $this->getRequest()->response();
                $headerStr = 'MediaWiki-API-Error: ' . $errCode;
-               if ( $e->getCode() === 0 ) {
-                       $response->header( $headerStr );
-               } else {
-                       $response->header( $headerStr, true, $e->getCode() );
-               }
+               $response->header( $headerStr );
  
                // Reset and print just the error message
                ob_clean();
                $this->createErrorPrinter();
  
                try {
-                       $this->printResult( true );
+                       $this->printResult( $e->getCode() );
                } catch ( UsageException $ex ) {
                        // The error printer itself is failing. Try suppressing its request
                        // parameters and redo.
                        $this->mPrinter = null;
                        $this->createErrorPrinter();
                        $this->mPrinter->forceDefaultParams();
-                       $this->printResult( true );
+                       if ( $e->getCode() ) {
+                               $response->statusHeader( 200 ); // Reset in case the fallback doesn't want a non-200
+                       }
+                       $this->printResult( $e->getCode() );
                }
        }
  
         * If the parameter and the header do match, the header is checked against $wgCrossSiteAJAXdomains
         * and $wgCrossSiteAJAXdomainExceptions, and if the origin qualifies, the appropriate CORS
         * headers are set.
 -       * http://www.w3.org/TR/cors/#resource-requests
 -       * http://www.w3.org/TR/cors/#resource-preflight-requests
 +       * https://www.w3.org/TR/cors/#resource-requests
 +       * https://www.w3.org/TR/cors/#resource-preflight-requests
         *
         * @return bool False if the caller should abort (403 case), true otherwise (all other cases)
         */
  
                        $response->header( "Access-Control-Allow-Origin: $allowOrigin" );
                        $response->header( "Access-Control-Allow-Credentials: $allowCredentials" );
 -                      // http://www.w3.org/TR/resource-timing/#timing-allow-origin
 +                      // https://www.w3.org/TR/resource-timing/#timing-allow-origin
                        if ( $allowTiming !== false ) {
                                $response->header( "Timing-Allow-Origin: $allowTiming" );
                        }
                        MWDebug::appendDebugInfoToApiResult( $this->getContext(), $this->getResult() );
  
                        // Print result data
-                       $this->printResult( false );
+                       $this->printResult();
                }
        }
  
        /**
         * Print results using the current printer
         *
-        * @param bool $isError
+        * @param int $httpCode HTTP status code, or 0 to not change
         */
-       protected function printResult( $isError ) {
+       protected function printResult( $httpCode = 0 ) {
                if ( $this->getConfig()->get( 'DebugAPI' ) !== false ) {
                        $this->setWarning( 'SECURITY WARNING: $wgDebugAPI is enabled' );
                }
  
                $printer = $this->mPrinter;
                $printer->initPrinter( false );
+               if ( $httpCode ) {
+                       $printer->setHttpStatus( $httpCode );
+               }
                $printer->execute();
                $printer->closePrinter();
        }
                        },
                        apiCheckValid: function () {
                                var that = this;
 -                              return this.isValid().done( function ( ok ) {
 +                              return this.getValidity().then( function () {
 +                                      return $.Deferred().resolve( true ).promise();
 +                              }, function () {
 +                                      return $.Deferred().resolve( false ).promise();
 +                              } ).done( function ( ok ) {
                                        ok = ok || suppressErrors;
                                        that.setIcon( ok ? null : 'alert' );
                                        that.setIconTitle( ok ? '' : mw.message( 'apisandbox-alert-field' ).plain() );
                },
  
                dateTimeInputWidget: {
 -                      isValid: function () {
 -                              var ok = !Util.apiBool( this.paramInfo.required ) || this.getApiValue() !== '';
 -                              return $.Deferred().resolve( ok ).promise();
 +                      getValidity: function () {
 +                              if ( !Util.apiBool( this.paramInfo.required ) || this.getApiValue() !== '' ) {
 +                                      return $.Deferred().resolve().promise();
 +                              } else {
 +                                      return $.Deferred().reject().promise();
 +                              }
                        }
                },
  
                                        } );
                                        widget.setIcon = widget.input.setIcon.bind( widget.input );
                                        widget.setIconTitle = widget.input.setIconTitle.bind( widget.input );
 -                                      widget.isValid = widget.input.isValid.bind( widget.input );
 +                                      widget.getValidity = widget.input.getValidity.bind( widget.input );
                                        widget.paramInfo = pi;
                                        $.extend( widget, WidgetMethods.textInputWidget );
                                        if ( Util.apiBool( pi.enforcerange ) ) {
                                        } );
                                        widget.setIcon = widget.input.setIcon.bind( widget.input );
                                        widget.setIconTitle = widget.input.setIconTitle.bind( widget.input );
 -                                      widget.isValid = widget.input.isValid.bind( widget.input );
 +                                      widget.getValidity = widget.input.getValidity.bind( widget.input );
                                        widget.input.setValidation( function ( value ) {
                                                return value === 'max' || widget.validateNumber( value );
                                        } );
                                                        if ( data.modules.length ) {
                                                                mw.loader.load( data.modules );
                                                        }
+                                                       if ( data.status && data.status !== 200 ) {
+                                                               $( '<div>' )
+                                                                       .addClass( 'api-pretty-header api-pretty-status' )
+                                                                       .append(
+                                                                               mw.message( 'api-format-prettyprint-status', data.status, data.statustext ).parse()
+                                                                       )
+                                                                       .appendTo( $result );
+                                                       }
                                                        $result.append( Util.parseHTML( data.html ) );
                                                        loadTime = data.time;
                                                } else if ( ( m = data.match( /<pre[ >][\s\S]*<\/pre>/ ) ) ) {