jenkins-bot has submitted this change and it was merged.

Change subject: Better error handling in the ParserService
......................................................................


Better error handling in the ParserService

200b9eae019de50aa770c7fdf2daacb82c9080ce and
5cc3dfb83f6d2741be88a7f38e63f70dc6c63730 introduce some wonkiness.

 * Parse now acts on an error from TemplateRequest right away, instead of
   deferring till after Util.parse.

 * Message wasn't being properly stored in EnvError.

 * A restart flag is added to the errCB because only certain errors
   should invoked a process restart.

 * Removed fetching the default pageinfo when no pagename is supplied.

 * Redirect url is constructed from the prefix and target instead of
   req.path. Ex.

     /en/ -> /en/Main_page?oldid=12345
     /en/test -> /en/Test?oldid=34567

 * Cleans up favicon conditions now that they are supported.

 * html2wt() expects html param to be a string.

Change-Id: I2694f9f968a297f82294a54f1e1b2a75d66725eb
---
M js/api/ParserService.js
M js/lib/mediawiki.DOMPostProcessor.js
M js/lib/mediawiki.parser.environment.js
3 files changed, 77 insertions(+), 70 deletions(-)

Approvals:
  Arlolra: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/js/api/ParserService.js b/js/api/ParserService.js
index 8f0a67d..d6b78fd 100644
--- a/js/api/ParserService.js
+++ b/js/api/ParserService.js
@@ -19,13 +19,14 @@
 
 // global includes
 var express = require('express'),
-       domino = require( 'domino' ),
+       domino = require('domino'),
        jsDiff = require('diff'),
        childProc = require('child_process'),
        spawn = childProc.spawn,
        cluster = require('cluster'),
        fs = require('fs'),
-       path = require('path');
+       path = require('path'),
+       util = require('util');
 
 // local includes
 var mp = '../lib/';
@@ -221,6 +222,7 @@
                        res.send( out, 500 );
                        return;
                }
+               res.setHeader( 'Content-Type', 'text/html; charset=UTF-8' );
                res.write('<html><head>\n');
                res.write('<script type="text/javascript" 
src="/jquery.js"></script><script type="text/javascript" 
src="/scrolling.js"></script><style>ins { background: #ff9191; text-decoration: 
none; } del { background: #99ff7e; text-decoration: none }; </style>\n');
                // Emit base href so all relative urls resolve properly
@@ -275,10 +277,18 @@
        }
 };
 
-function handleCacheRequest (env, req, cb, err, src, cacheErr, cacheSrc) {
-       if (cacheErr) {
+function handleCacheRequest( env, req, res, cb, src, cacheErr, cacheSrc ) {
+       var errorHandlingCB = function ( src, err, doc ) {
+               if ( err ) {
+                       env.errCB( err, true );
+                       return;
+               }
+               cb( req, res, src, doc );
+       };
+
+       if ( cacheErr ) {
                // No luck with the cache request, just proceed as normal.
-               Util.parse(env, cb, err, src);
+               Util.parse(env, errorHandlingCB, null, src);
                return;
        }
        // Extract transclusion and extension content from the DOM
@@ -298,24 +308,14 @@
 
        // pass those expansions into Util.parse to prime the caches.
        //console.log('expansions:', expansions);
-       Util.parse(env, cb, null, src, expansions);
+       Util.parse(env, errorHandlingCB, null, src, expansions);
 }
 
 var parse = function ( env, req, res, cb, err, src_and_metadata ) {
-       var newCb = function ( src, err, doc ) {
-               if ( err !== null ) {
-                       if ( !err.code ) {
-                               err.code = 500;
-                       }
-                       console.error( err.stack || err.toString() );
-                       res.setHeader('Content-Type', 'text/plain; 
charset=UTF-8');
-                       res.send( err.stack || err.toString(), err.code );
-                       return;
-               } else {
-                       res.setHeader('Content-Type', 'text/html; 
charset=UTF-8');
-                       cb( req, res, src, doc );
-               }
-       };
+       if ( err ) {
+               env.errCB( err, true );
+               return;
+       }
 
        // Set the source
        env.setPageSrcInfo( src_and_metadata );
@@ -324,7 +324,7 @@
        // env.page.meta.revision.parentid has the predecessor oldid
 
        // See if we can reuse transclusion or extension expansions.
-       if (!err && env.conf.parsoid.parsoidCacheURI &&
+       if (env.conf.parsoid.parsoidCacheURI &&
                        // And don't parse twice for recursive parsoid requests
                        ! req.headers['x-parsoid-request'])
        {
@@ -339,9 +339,9 @@
                        cacheRequest = new libtr.ParsoidCacheRequest(env,
                                env.page.meta.title, cacheID);
                cacheRequest.once('src',
-                               handleCacheRequest.bind(null, env, req, newCb, 
err, env.page.src));
+                               handleCacheRequest.bind(null, env, req, res, 
cb, env.page.src));
        } else {
-               handleCacheRequest(env, req, newCb, err, env.page.src, 
"Recursive request", null);
+               handleCacheRequest(env, req, res, cb, env.page.src, "Recursive 
request", null);
        }
 };
 
@@ -374,23 +374,31 @@
        res.end('</body></html>');
 });
 
-function ParserError( msg, stack, code ) {
-       Error.call( this, msg );
+function EnvError( message, stack, code, restart ) {
+       this.message = message;
        this.stack = stack;
        this.code = code;
+       this.restart = restart;
 }
 
+util.inherits( EnvError, Error );
+EnvError.prototype.name = "EnvError";
+
 function errorHandler( err, req, res, next ) {
-       if ( !(err instanceof ParserError) ) {
+       if ( !(err instanceof EnvError) ) {
                return next( err );
        }
 
-       console.error( 'ERROR in ' + res.locals.iwp + ':' + res.locals.pageName 
+ ':\n' + err.message );
-       console.error( "Stack trace: " + err.stack );
+       res.setHeader( 'Content-Type', 'text/plain; charset=UTF-8' );
        res.send( err.stack, err.code );
 
-       // Force a clean restart of this worker
-       process.exit( 1 );
+       console.error( 'ERROR in ' + res.locals.iwp + ':' + res.locals.pageName 
);
+       console.error( 'Stack trace: ' + err.stack );
+
+       if ( err.restart ) {
+               // Force a clean restart of this worker
+               process.exit( 1 );
+       }
 }
 
 app.use( errorHandler );
@@ -409,11 +417,12 @@
 
 function parserEnvMw( req, res, next ) {
        MWParserEnvironment.getParserEnv( parsoidConfig, null, res.locals.iwp, 
res.locals.pageName, req.headers.cookie, function ( err, env ) {
-               env.errCB = function ( e ) {
-                       e = new ParserError(
+               env.errCB = function ( e, dontRestart ) {
+                       e = new EnvError(
                                e.message,
                                e.stack || e.toString(),
-                               e.code || 500
+                               e.code || 500,
+                               !dontRestart  // default to restarting
                        );
                        next( e );
                };
@@ -485,16 +494,11 @@
 // Round-trip article testing
 app.get( new RegExp('/_rt/(' + getInterwikiRE() + ')/(.*)'), interParams, 
parserEnvMw, function(req, res) {
        var env = res.locals.env;
-       req.connection.setTimeout(300 * 1000);
-
-       if ( env.page.name === 'favicon.ico' ) {
-               res.send( 'no favicon yet..', 404 );
-               return;
-       }
-
        var target = env.resolveTitle( env.normalizeTitle( env.page.name ), '' 
);
 
+       req.connection.setTimeout(300 * 1000);
        console.log('starting parsing of ' + target);
+
        var oldid = null;
        if ( req.query.oldid ) {
                oldid = req.query.oldid;
@@ -507,11 +511,6 @@
 // simulation
 app.get( new RegExp('/_rtve/(' + getInterwikiRE() + ')/(.*)'), interParams, 
parserEnvMw, function(req, res) {
        var env = res.locals.env;
-       if ( env.page.name === 'favicon.ico' ) {
-               res.send( 'no favicon yet..', 404 );
-               return;
-       }
-
        var target = env.resolveTitle( env.normalizeTitle( env.page.name ), '' 
);
 
        console.log('starting parsing of ' + target);
@@ -533,11 +532,6 @@
 // Round-trip article testing with selser over re-parsed HTML.
 app.get( new RegExp('/_rtselser/(' + getInterwikiRE() + ')/(.*)'), 
interParams, parserEnvMw, function (req, res) {
        var env = res.locals.env;
-       if ( env.page.name === 'favicon.ico' ) {
-               res.send( 'no favicon yet..', 404 );
-               return;
-       }
-
        var target = env.resolveTitle( env.normalizeTitle( env.page.name ), '' 
);
 
        console.log( 'starting parsing of ' + target );
@@ -620,20 +614,25 @@
        var tmpCb, oldid = null;
        if ( wt ) {
                wt = wt.replace( /\r/g, '' );
+
+               // clear default page name
+               if ( !res.locals.pageName ) {
+                       env.page.name = '';
+               }
+
+               var parser = Util.getParserPipeline( env, 
'text/x-mediawiki/full' );
+               parser.on( 'document', function ( document ) {
+                       // Don't cache requests when wt is set in case somebody 
uses
+                       // GET for wikitext parsing
+                       res.setHeader( 'Cache-Control', 
'private,no-cache,s-maxage=0' );
+                       sendRes( req.body.body ? document.body : document );
+               });
+
                tmpCb = function ( err, src_and_metadata ) {
                        if ( err ) {
-                               env.errCB( err );
+                               env.errCB( err, true );
                                return;
                        }
-
-                       var parser = Util.getParserPipeline( env, 
'text/x-mediawiki/full' );
-                       parser.on( 'document', function ( document ) {
-                               res.setHeader( 'Content-Type', 'text/html; 
charset=UTF-8' );
-                               // Don't cache requests when wt is set in case 
somebody uses
-                               // GET for wikitext parsing
-                               res.setHeader( 'Cache-Control', 
'private,no-cache,s-maxage=0' );
-                               sendRes( req.body.body ? document.body : 
document );
-                       });
 
                        // Set the source
                        env.setPageSrcInfo( src_and_metadata );
@@ -641,10 +640,17 @@
                        try {
                                parser.processToplevelDoc( wt );
                        } catch ( e ) {
-                               env.errCB( e );
+                               env.errCB( e, true );
                                return;
                        }
                };
+
+               if ( !res.locals.pageName ) {
+                       // no pageName supplied; don't fetch the page source
+                       tmpCb( null, wt );
+                       return;
+               }
+
        } else {
                if ( req.query.oldid ) {
                        oldid = req.query.oldid;
@@ -662,7 +668,7 @@
                        res.setHeader( 'Cache-Control', 
'private,no-cache,s-maxage=0' );
                        tmpCb = function ( err, src_and_metadata ) {
                                if ( err ) {
-                                       env.errCB( err );
+                                       env.errCB( err, true );
                                        return;
                                }
 
@@ -670,7 +676,11 @@
                                env.setPageSrcInfo( src_and_metadata );
 
                                // Redirect to oldid
-                               res.redirect( req.path + "?oldid=" + 
env.page.meta.revision.revid );
+                               var url = [ "", prefix,
+                                       encodeURIComponent( target ) +
+                                       "?oldid=" + env.page.meta.revision.revid
+                               ].join( "/" );
+                               res.redirect( url );
                                console.warn( "redirected " + prefix + ':' + 
target + " to revision " + env.page.meta.revision.revid );
                        };
                }
@@ -682,6 +692,7 @@
        function sendRes( doc ) {
                var out = DU.serializeNode( doc );
                res.setHeader( 'X-Parsoid-Performance', 
env.getPerformanceHeader() );
+               res.setHeader( 'Content-Type', 'text/html; charset=UTF-8' );
                res.end( out );
                console.warn( "completed parsing of " + prefix + ':' + target + 
" in " + env.performance.duration + " ms" );
        }
@@ -689,8 +700,6 @@
 
 // Regular article parsing
 app.get( new RegExp( '/(' + getInterwikiRE() + ')/(.*)' ), interParams, 
parserEnvMw, function(req, res) {
-       var env = res.locals.env;
-
        // TODO gwicke: re-enable this when actually using Varnish
        //if (/only-if-cached/.test(req.headers['cache-control'])) {
        //      res.send( 'Clearly not cached since this request reached 
Parsoid. Please fix Varnish.',
@@ -703,14 +712,12 @@
 
 // Regular article serialization using POST
 app.post( new RegExp( '/(' + getInterwikiRE() + ')/(.*)' ), interParams, 
parserEnvMw, function ( req, res ) {
-
        // parse html or wt
        if ( req.body.wt ) {
                wt2html( req, res, req.body.wt );
        } else {
-               html2wt( req, res, req.body.html ? req.body.html : 
req.body.content );
+               html2wt( req, res, req.body.html || req.body.content || '' );
        }
-
 });
 
 
diff --git a/js/lib/mediawiki.DOMPostProcessor.js 
b/js/lib/mediawiki.DOMPostProcessor.js
index 179e4f7..8f4379a 100644
--- a/js/lib/mediawiki.DOMPostProcessor.js
+++ b/js/lib/mediawiki.DOMPostProcessor.js
@@ -292,7 +292,7 @@
                // this is a workaround for a bug in domino 1.0.9
                appendToHead( document, 'title' );
        }
-       document.title = env.page.meta.title;
+       document.title = env.page.meta.title || '';
 
        // Hack: Add a base href element to the head element of the HTML DOM so
        // that our relative links resolve fine when the DOM is viewed directly
diff --git a/js/lib/mediawiki.parser.environment.js 
b/js/lib/mediawiki.parser.environment.js
index 6d20872..c8821e2 100644
--- a/js/lib/mediawiki.parser.environment.js
+++ b/js/lib/mediawiki.parser.environment.js
@@ -66,7 +66,7 @@
 var MWParserEnvironment = function ( parsoidConfig, wikiConfig ) {
        // page information
        this.page = {
-               name: 'Main Page',
+               name: 'Main_Page',
                relativeLinkPrefix: '',
                id: null,
                src: null,

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

Gerrit-MessageType: merged
Gerrit-Change-Id: I2694f9f968a297f82294a54f1e1b2a75d66725eb
Gerrit-PatchSet: 8
Gerrit-Project: mediawiki/extensions/Parsoid
Gerrit-Branch: master
Gerrit-Owner: Arlolra <[email protected]>
Gerrit-Reviewer: Arlolra <[email protected]>
Gerrit-Reviewer: GWicke <[email protected]>
Gerrit-Reviewer: Werdna <[email protected]>
Gerrit-Reviewer: jenkins-bot

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

Reply via email to