C. Scott Ananian has uploaded a new change for review. ( https://gerrit.wikimedia.org/r/402436 )
Change subject: Use Promise.async/yield for lib/api/routes.js ...................................................................... Use Promise.async/yield for lib/api/routes.js Change-Id: If181edf096861e31dc8d5fa20910fb8ab8a511d4 --- M lib/api/apiUtils.js M lib/api/routes.js 2 files changed, 140 insertions(+), 135 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/services/parsoid refs/changes/36/402436/1 diff --git a/lib/api/apiUtils.js b/lib/api/apiUtils.js index 7bf3c76..4071c0b 100644 --- a/lib/api/apiUtils.js +++ b/lib/api/apiUtils.js @@ -166,6 +166,12 @@ env.log('fatal/request', err); }; +apiUtils.errorWrapper = function(env, promiseOrValue) { + return Promise.resolve(promiseOrValue).catch(function(err) { + apiUtils.errorHandler(env, err); + }); +}; + // To support the 'subst' API parameter, we need to prefix each // top-level template with 'subst'. To make sure we do this for the // correct templates, tokenize the starting wikitext and use that to diff --git a/lib/api/routes.js b/lib/api/routes.js index 089dbe5..4a30106 100644 --- a/lib/api/routes.js +++ b/lib/api/routes.js @@ -254,7 +254,7 @@ // Spec'd in https://phabricator.wikimedia.org/T75955 and the API tests. - var wt2html = Promise.method(function(req, res, wt, reuseExpansions) { + var wt2html = Promise.async(function *(req, res, wt, reuseExpansions) { var env = res.locals.env; var opts = res.locals.opts; var oldid = res.locals.oldid; @@ -271,134 +271,132 @@ startTimers.set('wt2html.total', Date.now()); } - var p = Promise.resolve(wt); - if (oldid || typeof wt !== 'string') { // Always fetch the page info if we have an oldid. // Otherwise, if no wt was passed, we need to figure out // the latest revid to which we'll redirect. - p = p.tap(function() { - return TemplateRequest.setPageSrcInfo(env, target, oldid); - }); + yield TemplateRequest.setPageSrcInfo(env, target, oldid); } + // Calling this `wikitext` so that it's easily distinguishable. + // It may be modified by substTopLevelTemplates. + var wikitext; var doSubst = (typeof wt === 'string' && res.locals.subst); if (doSubst) { - p = p.then(function(wikitext) { - return apiUtils.substTopLevelTemplates(env, target, wikitext); - }); + wikitext = yield apiUtils.substTopLevelTemplates(env, target, wt); + } else { + wikitext = wt; } - return p.then(function(wikitext) { - // Calling this `wikitext` so that it's easily distinguishable. - // It may have been modified by substTopLevelTemplates. + // Now that we have a revid, we can redirect + if (typeof wikitext !== 'string' && !oldid) { + return apiUtils.redirectToOldid(req, res); + } - // Now that we have a revid, we can redirect - if (typeof wikitext !== 'string' && !oldid) { - return apiUtils.redirectToOldid(req, res); + // Follow redirects if asked + if (parsoidConfig.devAPI && req.query.follow_redirects) { + // Get localized redirect matching regexp + var reSrc = env.conf.wiki.getMagicWordMatcher('redirect').source; + reSrc = '^[ \\t\\n\\r\\0\\x0b]*' + + reSrc.substring(1, reSrc.length - 1) + // Strip ^ and $ + '[ \\t\\n\\r\\x0c]*(?::[ \\t\\n\\r\\x0c]*)?' + + '\\[\\[([^\\]]+)\\]\\]'; + var re = new RegExp(reSrc, 'i'); + var s = wikitext || env.page.src; + var redirMatch = s.match(re); + if (redirMatch) { + return apiUtils._redirectToPage(redirMatch[2], req, res); } + } - // Follow redirects if asked - if (parsoidConfig.devAPI && req.query.follow_redirects) { - // Get localized redirect matching regexp - var reSrc = env.conf.wiki.getMagicWordMatcher('redirect').source; - reSrc = '^[ \\t\\n\\r\\0\\x0b]*' + - reSrc.substring(1, reSrc.length - 1) + // Strip ^ and $ - '[ \\t\\n\\r\\x0c]*(?::[ \\t\\n\\r\\x0c]*)?' + - '\\[\\[([^\\]]+)\\]\\]'; - var re = new RegExp(reSrc, 'i'); - var s = wikitext || env.page.src; - var redirMatch = s.match(re); - if (redirMatch) { - return apiUtils._redirectToPage(redirMatch[2], req, res); - } + var envOptions = Object.assign({ + pageBundle: pageBundle, + // Set data-parsoid to be discarded, so that the subst'ed + // content is considered new when it comes back. + discardDataParsoid: doSubst, + }, res.locals.envOptions); + + // VE, the only client using body_only property, + // doesn't want section tags when this flag is set. + // (T181226) + if (res.locals.body_only) { + envOptions.wrapSections = false; + } + + if (typeof wikitext === 'string') { + // Don't cache requests when wt is set in case somebody uses + // GET for wikitext parsing + apiUtils.setHeader(res, 'Cache-Control', 'private,no-cache,s-maxage=0'); + + if (metrics) { + metrics.endTiming( + 'wt2html.wt.init', startTimers.get('wt2html.init') + ); + startTimers.set('wt2html.wt.parse', Date.now()); + metrics.timing('wt2html.wt.size.input', wikitext.length); } + } else if (oldid) { + envOptions.pageWithOldid = true; - var envOptions = Object.assign({ - pageBundle: pageBundle, - // Set data-parsoid to be discarded, so that the subst'ed - // content is considered new when it comes back. - discardDataParsoid: doSubst, - }, res.locals.envOptions); - - // VE, the only client using body_only property, - // doesn't want section tags when this flag is set. - // (T181226) - if (res.locals.body_only) { - envOptions.wrapSections = false; - } - - if (typeof wikitext === 'string') { - // Don't cache requests when wt is set in case somebody uses - // GET for wikitext parsing + if (req.headers.cookie) { + // Don't cache requests with a session. apiUtils.setHeader(res, 'Cache-Control', 'private,no-cache,s-maxage=0'); - - if (metrics) { - metrics.endTiming('wt2html.wt.init', - startTimers.get('wt2html.init')); - startTimers.set('wt2html.wt.parse', Date.now()); - metrics.timing('wt2html.wt.size.input', wikitext.length); - } - } else if (oldid) { - envOptions.pageWithOldid = true; - - if (req.headers.cookie) { - // Don't cache requests with a session. - apiUtils.setHeader(res, 'Cache-Control', 'private,no-cache,s-maxage=0'); - } - - // Indicate the MediaWiki revision in a header as well for - // ease of extraction in clients. - apiUtils.setHeader(res, 'content-revision-id', oldid); - - if (metrics) { - metrics.endTiming('wt2html.pageWithOldid.init', - startTimers.get('wt2html.init')); - startTimers.set('wt2html.pageWithOldid.parse', Date.now()); - metrics.timing('wt2html.pageWithOldid.size.input', env.page.src.length); - } - } else { - console.assert(false, 'Should be unreachable'); } - return parse({ - // NOTE: This causes another TemplateRequest but otherwise - // we don't have all the metadata. - input: (typeof wikitext === 'string') ? wikitext : undefined, - mode: 'wt2html', - parsoidOptions: parsoidOptions, - envOptions: envOptions, - oldid: oldid, - contentmodel: opts.contentmodel, - contentVersion: env.contentVersion, - body_only: res.locals.body_only, - cacheConfig: true, - reuseExpansions: reuseExpansions, - }) - .then(function(out) { - if (opts.format === 'lint') { - apiUtils.jsonResponse(res, out.lint); - } else { - apiUtils.wt2htmlRes(env, res, out.html, out.pb, out.contentmodel); - } - var html = out.html; - if (metrics) { - if (startTimers.has('wt2html.wt.parse')) { - metrics.endTiming('wt2html.wt.parse', - startTimers.get('wt2html.wt.parse')); - metrics.timing('wt2html.wt.size.output', html.length); - } else if (startTimers.has('wt2html.pageWithOldid.parse')) { - metrics.endTiming('wt2html.pageWithOldid.parse', - startTimers.get('wt2html.pageWithOldid.parse')); - metrics.timing('wt2html.pageWithOldid.size.output', html.length); - } - metrics.endTiming('wt2html.total', startTimers.get('wt2html.total')); - } - }); + // Indicate the MediaWiki revision in a header as well for + // ease of extraction in clients. + apiUtils.setHeader(res, 'content-revision-id', oldid); + + if (metrics) { + metrics.endTiming( + 'wt2html.pageWithOldid.init', + startTimers.get('wt2html.init') + ); + startTimers.set('wt2html.pageWithOldid.parse', Date.now()); + metrics.timing('wt2html.pageWithOldid.size.input', env.page.src.length); + } + } else { + console.assert(false, 'Should be unreachable'); + } + + var out = yield parse({ + // NOTE: This causes another TemplateRequest but otherwise + // we don't have all the metadata. + input: (typeof wikitext === 'string') ? wikitext : undefined, + mode: 'wt2html', + parsoidOptions: parsoidOptions, + envOptions: envOptions, + oldid: oldid, + contentmodel: opts.contentmodel, + contentVersion: env.contentVersion, + body_only: res.locals.body_only, + cacheConfig: true, + reuseExpansions: reuseExpansions, }); + if (opts.format === 'lint') { + apiUtils.jsonResponse(res, out.lint); + } else { + apiUtils.wt2htmlRes(env, res, out.html, out.pb, out.contentmodel); + } + var html = out.html; + if (metrics) { + if (startTimers.has('wt2html.wt.parse')) { + metrics.endTiming( + 'wt2html.wt.parse', startTimers.get('wt2html.wt.parse') + ); + metrics.timing('wt2html.wt.size.output', html.length); + } else if (startTimers.has('wt2html.pageWithOldid.parse')) { + metrics.endTiming( + 'wt2html.pageWithOldid.parse', + startTimers.get('wt2html.pageWithOldid.parse') + ); + metrics.timing('wt2html.pageWithOldid.size.output', html.length); + } + metrics.endTiming('wt2html.total', startTimers.get('wt2html.total')); + } }); - var html2wt = Promise.method(function(req, res, html) { + var html2wt = Promise.async(function *(req, res, html) { var env = res.locals.env; var opts = res.locals.opts; @@ -517,7 +515,7 @@ selser = { oldtext: oldtext, oldhtml: oldhtml }; } - return parse({ + var out = yield parse({ input: DU.toXML(doc), mode: useSelser ? 'selser' : 'html2wt', parsoidOptions: parsoidOptions, @@ -527,18 +525,19 @@ contentmodel: opts.contentmodel || (opts.original && opts.original.contentmodel), cacheConfig: true, - }) - .then(function(out) { - if (metrics) { - metrics.endTiming('html2wt.total', - startTimers.get('html2wt.total')); - metrics.timing('html2wt.size.output', out.wt.length); - } - apiUtils.plainResponse(res, out.wt, undefined, apiUtils.wikitextContentType(env)); }); + if (metrics) { + metrics.endTiming( + 'html2wt.total', startTimers.get('html2wt.total') + ); + metrics.timing('html2wt.size.output', out.wt.length); + } + apiUtils.plainResponse( + res, out.wt, undefined, apiUtils.wikitextContentType(env) + ); }); - var pb2pb = Promise.method(function(req, res) { + var pb2pb = Promise.async(function *(req, res) { // eslint-disable-line require-yield var env = res.locals.env; var opts = res.locals.opts; @@ -591,15 +590,15 @@ }); // GET requests - routes.v3Get = function(req, res) { + routes.v3Get = Promise.async(function *(req, res) { var opts = res.locals.opts; var env = res.locals.env; - var p; + if (opts.format === 'wikitext') { - var target = env.normalizeAndResolvePageTitle(); - var oldid = res.locals.oldid; - p = TemplateRequest.setPageSrcInfo(env, target, oldid) - .then(function() { + try { + var target = env.normalizeAndResolvePageTitle(); + var oldid = res.locals.oldid; + yield TemplateRequest.setPageSrcInfo(env, target, oldid); if (!oldid) { return apiUtils.redirectToOldid(req, res); } @@ -607,18 +606,19 @@ apiUtils.setHeader(res, 'x-contentmodel', env.page.meta.revision.contentmodel); } apiUtils.plainResponse(res, env.page.src, undefined, apiUtils.wikitextContentType(env)); - }); + } catch (e) { + apiUtils.errorHandler(env, e); + } } else { - p = wt2html(req, res); + return apiUtils.errorWrapper(env, wt2html(req, res)); } - return p.catch(apiUtils.errorHandler.bind(null, env)); - }; + }); // POST requests - routes.v3Post = function(req, res) { + routes.v3Post = Promise.async(function *(req, res) { // eslint-disable-line require-yield var opts = res.locals.opts; var env = res.locals.env; - var p; + if (opts.from === 'wikitext') { // Accept wikitext as a string or object{body,headers} var wikitext = opts.wikitext; @@ -633,7 +633,7 @@ if (typeof wikitext !== 'string' && res.locals.titleMissing) { return apiUtils.fatalRequest(env, 'No title or wikitext was provided.', 400); } - p = wt2html(req, res, wikitext); + return apiUtils.errorWrapper(env, wt2html(req, res, wikitext)); } else { if (opts.format === 'wikitext') { // html is required for serialization @@ -643,13 +643,12 @@ // Accept html as a string or object{body,headers} var html = (typeof opts.html === 'string') ? opts.html : (opts.html.body || ''); - p = html2wt(req, res, html); + return apiUtils.errorWrapper(env, html2wt(req, res, html)); } else { - p = pb2pb(req, res); + return apiUtils.errorWrapper(env, pb2pb(req, res)); } } - return p.catch(apiUtils.errorHandler.bind(null, env)); - }; + }); return routes; }; -- To view, visit https://gerrit.wikimedia.org/r/402436 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: If181edf096861e31dc8d5fa20910fb8ab8a511d4 Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/services/parsoid Gerrit-Branch: master Gerrit-Owner: C. Scott Ananian <canan...@wikimedia.org> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits