Page MenuHomePhabricator

Visual Editor + Apache bug. Visual Editor not working when editing or creating a page with : or / characters in the Title. e.g. http://localhost/w/index.php/User:John/Newpage
Closed, ResolvedPublic

Description

Debian 10.5 buster
MediaWiki 1.35.0-rc.2
PHP 7.3.19-1~deb10u1 (apache2handler)
MariaDB 10.4.8-MariaDB-log

When I try to create a page using Visual Editor that has either : or / in the title I get an error: Error contacting the Parsoid/RESTBase server (HTTP 404)

Debugging the warning emitted in file ApiParsoidTrait.php (/extensions/VisualEditor/includes/ApiParsoidTrait.php) line 160 I get the following values (when I try to create /User:John/Testpage):

'code':
404

'trace':
#0 /var/www/html/w/extensions/VisualEditor/includes/ApiVisualEditor.php(67): ApiVisualEditor->requestRestbase(Object(Title), 'POST', 'transform/wikit...', Array)
#1 /var/www/html/w/extensions/VisualEditor/includes/ApiVisualEditor.php(251): ApiVisualEditor->parseWikitextFragment(Object(Title), 'testtext', false, NULL, true)
#2 /var/www/html/w/includes/api/ApiMain.php(1593): ApiVisualEditor->execute()
#3 /var/www/html/w/includes/api/ApiMain.php(529): ApiMain->executeAction()
#4 /var/www/html/w/includes/api/ApiMain.php(500): ApiMain->executeActionWithErrorHandling()
#5 /var/www/html/w/api.php(90): ApiMain->execute()
#6 /var/www/html/w/api.php(45): wfApiMain()
#7 {main}

'response':
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>404 Not Found</title> </head><body> <h1>Not Found</h1> <p>The requested URL was not found on this server.</p> <hr> <address>Apache/2.4.38 (Debian) Server at localhost Port 80</address> </body></html>

'requestPath':
transform/wikitext/to/html/User%3AJohn%2FTestpage

What looks strange to me is this part:

'requestPath': transform/wikitext/to/html/User%3AJohn%2FTestpage

given that some / are sanitized and some are not. So what I did is remove the function urlencode from lines 230 & 250 in file ApiParsoidTrait.php then Visual Editor creates new pages either inside the User namespace or subpages in the Main namespace without problem.

i.e. the use of urlencode there seems to create problems.

Event Timeline

I have pretty much the same configuration, except I use nginx and you use Apache, and I have no issue, neither when I create a page with VE, neither when I edit one existing page. When I create a page, both the standard version with urlencode at lines 230 and 250 in extensions/VisualEditor/includes/ApiParsoidTrait.php, and your version without urlencode work. But when I edit an existing page, only the standard version works, Parsoid says me 404 with your version. Hence the only difference seems to be the webserver.

Can you provide your access logs related to "POST api.php" and "POST rest.php" to check how is encoded your URLs?

Also you can set $wgDebugLogFile = '/tmp/mediawiki.log'; in LocalSettings.php to get verbose logs. Can you provide the headers of the requests from the point of view of MediaWiki (like Start request POST /w/rest.php/…)?

Thanks for testing this Seb35, my results seem strange when compared to your results.

I reverted back to the original version (i.e. no changes to lines 230 and 250 in extensions/VisualEditor/includes/ApiParsoidTrait.php), and setting the $wgDebugLogFile I get the below:

Start request POST /w/api.php
IP: ::1
HTTP HEADERS:
HOST: localhost
CONNECTION: keep-alive
CONTENT-LENGTH: 2059
ACCEPT: application/json, text/javascript, */*; q=0.01
X-REQUESTED-WITH: XMLHttpRequest
USER-AGENT: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36
CONTENT-TYPE: multipart/form-data; boundary=----WebKitFormBoundaryd59bCYTV7xvNev6P
ORIGIN: http://localhost
SEC-FETCH-SITE: same-origin
SEC-FETCH-MODE: cors
SEC-FETCH-DEST: empty
REFERER: http://localhost/w/index.php?title=Main_Page/Newpage2&action=edit
ACCEPT-ENCODING: gzip, deflate, br
ACCEPT-LANGUAGE: en-GB,en-US;q=0.9,en;q=0.8
COOKIE: mediadb_mw__session=802bh4rlvuspd64mnhhutqit0rfcu7j0; mediadb_mw_UserID=10; mediadb_mw_UserName=John; mediadb_mw_Token=fac9c8a3e5c8655486daeea2f275c56d; VEE=visualeditor; UseDC=master; UseCDNCache=false
(end headers)
[localisation] LocalisationCache using store LCStoreDB
[session] SessionManager using store SqlBagOStuff
[DBQuery] Wikimedia\Rdbms\DatabaseMysqlBase::open [0s] localhost: SET group_concat_max_len = 262144, sql_mode = ''
[DBReplication] Wikimedia\Rdbms\LBFactory::getChronologyProtector: request info {
    "IPAddress": "::1",
    "UserAgent": "Mozilla\/5.0 (X11; Linux x86_64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/85.0.4183.83 Safari\/537.36",
    "ChronologyProtection": false,
    "ChronologyPositionIndex": 0,
    "ChronologyClientId": false
}
[DBReplication] Wikimedia\Rdbms\ChronologyProtector::getStartupMasterPositions: client ID is 3ab04fb2a97c6552062fdb96e07fc1de (read)
[DBReplication] Wikimedia\Rdbms\ChronologyProtector::getStartupMasterPositions: key is global:Wikimedia\Rdbms\ChronologyProtector:3ab04fb2a97c6552062fdb96e07fc1de:v2 (read)
[DBConnection] Wikimedia\Rdbms\LoadBalancer::lazyLoadReplicationPositions: executed chronology callback.
[DBConnection] Wikimedia\Rdbms\LoadBalancer::getLocalConnection: opened new connection for 0
User: cache miss for user 10
[DBQuery] Wikimedia\Rdbms\Database::beginIfImplied (User::loadFromDatabase) [0s] localhost: BEGIN
[DBQuery] User::loadFromDatabase [0s] localhost: SELECT  user_id,user_name,user_real_name,user_email,user_touched,user_token,user_email_authenticated,user_email_token,user_email_token_expires,user_registration,user_editcount,user_actor.actor_id  FROM `mw_user` JOIN `mw_actor` `user_actor` ON ((user_actor.actor_user = user_id))   WHERE user_id = 10  LIMIT 1  
[objectcache] fetchOrRegenerate(global:user:id:mediadb-mw_:10): miss, new value computed
[DBQuery] Wikimedia\Rdbms\DatabaseMysqlBase::open [0s] localhost: SET group_concat_max_len = 262144, sql_mode = ''
[DBConnection] Wikimedia\Rdbms\LoadBalancer::getLocalConnection: opened new connection for 0
[DBQuery] SqlBagOStuff::fetchBlobMulti [0s] localhost: SELECT  keyname,value,exptime  FROM `mw_objectcache`    WHERE keyname = 'mediadb-mw_:MWSession:802bh4rlvuspd64mnhhutqit0rfcu7j0'  
[DBQuery] MediaWiki\User\UserGroupManager::getUserGroupMemberships [0s] localhost: SELECT  ug_user,ug_group,ug_expiry  FROM `mw_user_groups`    WHERE ug_user = 10  
[DBQuery] Wikimedia\Rdbms\DatabaseMysqlBase::serverIsReadOnly [0s] localhost: SELECT @@GLOBAL.read_only AS Value
[objectcache] fetchOrRegenerate(global:rdbms-server-readonly:localhost:mediadb:): miss, new value computed
[DBQuery] LinkCache::fetchPageRow [0s] localhost: SELECT  page_id,page_len,page_is_redirect,page_latest,page_restrictions,page_content_model  FROM `mw_page`    WHERE page_namespace = 0 AND page_title = 'Main_Page/Newpage2'  LIMIT 1  
[ContentHandler] Registered handler for wikitext: WikitextContentHandler
Unstubbing $wgLang on call of $wgLang::unstub from ContentHandler->getPageLanguage
[DBQuery] MediaWiki\Revision\RevisionStore::fetchRevisionRowFromConds [0s] localhost: SELECT  rev_id,rev_page,rev_timestamp,rev_minor_edit,rev_deleted,rev_len,rev_parent_id,rev_sha1,comment_rev_comment.comment_text AS `rev_comment_text`,comment_rev_comment.comment_data AS `rev_comment_data`,comment_rev_comment.comment_id AS `rev_comment_cid`,actor_rev_user.actor_user AS `rev_user`,actor_rev_user.actor_name AS `rev_user_text`,temp_rev_user.revactor_actor AS `rev_actor`,page_namespace,page_title,page_id,page_latest,page_is_redirect,page_len,user_name  FROM `mw_revision` JOIN `mw_revision_comment_temp` `temp_rev_comment` ON ((temp_rev_comment.revcomment_rev = rev_id)) JOIN `mw_comment` `comment_rev_comment` ON ((comment_rev_comment.comment_id = temp_rev_comment.revcomment_comment_id)) JOIN `mw_revision_actor_temp` `temp_rev_user` ON ((temp_rev_user.revactor_rev = rev_id)) JOIN `mw_actor` `actor_rev_user` ON ((actor_rev_user.actor_id = temp_rev_user.revactor_actor)) JOIN `mw_page` ON ((page_id = rev_page)) LEFT JOIN `mw_user` ON ((actor_rev_user.actor_user != 0) AND (user_id = actor_rev_user.actor_user))   WHERE page_namespace = 8 AND page_title = 'Gadgets-definition' AND (rev_id=page_latest)  LIMIT 1  
[objectcache] fetchOrRegenerate(mediadb-mw_:gadgets-definition:9:2): miss, new value computed
[UserOptionsManager] Loading options from database
[DBQuery] MediaWiki\User\UserOptionsManager::loadUserOptions [0s] localhost: SELECT  up_property,up_value  FROM `mw_user_properties`    WHERE up_user = 10  
[http] POST: http://localhost/w/rest.php/localhost/v3/transform/html/to/wikitext/Main_Page%2FNewpage2
[VisualEditor] ApiParsoidTrait::requestRestbase: Received HTTP 404 from RESTBase
[MessageCache] MessageCache using store SqlBagOStuff
[DBQuery] LCStoreDB::get [0s] localhost: SELECT  lc_value  FROM `mw_l10n_cache`    WHERE lc_lang = 'en' AND lc_key = 'deps'  LIMIT 1  
[DBQuery] LCStoreDB::get [0s] localhost: SELECT  lc_value  FROM `mw_l10n_cache`    WHERE lc_lang = 'en' AND lc_key = 'list'  LIMIT 1  
[DBQuery] LCStoreDB::get [0s] localhost: SELECT  lc_value  FROM `mw_l10n_cache`    WHERE lc_lang = 'en' AND lc_key = 'preload'  LIMIT 1  
[DBQuery] LCStoreDB::get [0s] localhost: SELECT  lc_value  FROM `mw_l10n_cache`    WHERE lc_lang = 'en' AND lc_key = 'preload'  LIMIT 1  
[DBQuery] LCStoreDB::get [0s] localhost: SELECT  lc_value  FROM `mw_l10n_cache`    WHERE lc_lang = 'en' AND lc_key = 'messages:apierror-visualeditor-docserver-http'  LIMIT 1  
[DBQuery] LCStoreDB::get [0s] localhost: SELECT  lc_value  FROM `mw_l10n_cache`    WHERE lc_lang = 'en' AND lc_key = 'list'  LIMIT 1  
[DBQuery] SqlBagOStuff::fetchBlobMulti [0s] localhost: SELECT  keyname,value,exptime  FROM `mw_objectcache`    WHERE keyname = 'mediadb-mw_:messages:en'  
[DBQuery] SqlBagOStuff::fetchBlobMulti [0s] localhost: SELECT  keyname,value,exptime  FROM `mw_objectcache`    WHERE keyname = 'mediadb-mw_:messages:en:status'  
[DBQuery] SqlBagOStuff::lock [0s] localhost: SELECT GET_LOCK('mediadb-mw_:messages:en', 0) AS lockstatus
[SQLBagOStuff] SqlBagOStuff::lock failed due to timeout for mediadb-mw_:messages:en.
[DBQuery] MessageCache::loadFromDB(en)-big [0s] localhost: SELECT  page_title,page_latest  FROM `mw_page`    WHERE page_is_redirect = 0 AND page_namespace = 8 AND (page_title NOT LIKE '%/%' ESCAPE '`' ) AND (page_len > 10000)  
[DBQuery] MessageCache::loadFromDB(en)-small [0s] localhost: SELECT  /*! STRAIGHT_JOIN */ rev_id,rev_page,rev_timestamp,rev_minor_edit,rev_deleted,rev_len,rev_parent_id,rev_sha1,comment_rev_comment.comment_text AS `rev_comment_text`,comment_rev_comment.comment_data AS `rev_comment_data`,comment_rev_comment.comment_id AS `rev_comment_cid`,actor_rev_user.actor_user AS `rev_user`,actor_rev_user.actor_name AS `rev_user_text`,temp_rev_user.revactor_actor AS `rev_actor`,page_namespace,page_title,page_id,page_latest,page_is_redirect,page_len,user_name  FROM `mw_page` JOIN `mw_revision` ON ((page_id = rev_page)) JOIN `mw_revision_comment_temp` `temp_rev_comment` ON ((temp_rev_comment.revcomment_rev = rev_id)) JOIN `mw_comment` `comment_rev_comment` ON ((comment_rev_comment.comment_id = temp_rev_comment.revcomment_comment_id)) JOIN `mw_revision_actor_temp` `temp_rev_user` ON ((temp_rev_user.revactor_rev = rev_id)) JOIN `mw_actor` `actor_rev_user` ON ((actor_rev_user.actor_id = temp_rev_user.revactor_actor)) LEFT JOIN `mw_user` ON ((actor_rev_user.actor_user != 0) AND (user_id = actor_rev_user.actor_user))   WHERE page_is_redirect = 0 AND page_namespace = 8 AND (page_title NOT LIKE '%/%' ESCAPE '`' ) AND (page_len <= 10000) AND (page_latest = rev_id)  
[DBQuery] MediaWiki\Revision\RevisionStore::loadSlotRecords [0s] localhost: SELECT  slot_revision_id,slot_content_id,slot_origin,slot_role_id,content_size,content_sha1,content_address,content_model  FROM `mw_slots` JOIN `mw_content` ON ((slot_content_id = content_id))   WHERE slot_revision_id = '212'  
[DBQuery] MediaWiki\Storage\NameTableStore::loadTable [0s] localhost: SELECT  role_id AS `id`,role_name AS `name`  FROM `mw_slot_roles`     ORDER BY id 
[objectcache] fetchOrRegenerate(global:NameTableSqlStore:slot_roles:mediadb-mw_): miss, new value computed
[DBQuery] MediaWiki\Storage\NameTableStore::loadTable [0s] localhost: SELECT  model_id AS `id`,model_name AS `name`  FROM `mw_content_models`     ORDER BY id 
[objectcache] fetchOrRegenerate(global:NameTableSqlStore:content_models:mediadb-mw_): miss, new value computed
[DBQuery] MediaWiki\Storage\SqlBlobStore::fetchBlobs [0s] localhost: SELECT  old_id,old_text,old_flags  FROM `mw_text`    WHERE old_id = 207  
[objectcache] fetchOrRegenerate(global:SqlBlobStore-blob:mediadb-mw_:tt%3A207): miss, new value computed
[DBQuery] SqlBagOStuff::updateTable [0.003s] localhost: REPLACE INTO `mw_objectcache` (keyname,value,exptime) VALUES ('mediadb-mw_:messages:en','U��\n�0��>��q t]�6;�&��Md��͂V�ԋ��v޼�|�� Hx�0VMGt,�!�\nX0\n�O���\\�(�\Z{Î�;GV������8������9���?���G�����2�aW�EQ[�\r���Vņ��\'X>����0j\Z����Ѫ��R��Z�x�*���XVoW����.8W\\F\\�&S�~�','20380119031407')
[DBQuery] SqlBagOStuff::unlock [0s] localhost: SELECT RELEASE_LOCK('mediadb-mw_:messages:en') as lockstatus
[MessageCache] MessageCache::load: Loading en... local cache is empty, global cache is expired/volatile, loading from database
ParserFactory: using default preprocessor
[DBQuery] LCStoreDB::get [0s] localhost: SELECT  lc_value  FROM `mw_l10n_cache`    WHERE lc_lang = 'en' AND lc_key = 'magicWords'  LIMIT 1  
[DBQuery] LCStoreDB::get [0s] localhost: SELECT  lc_value  FROM `mw_l10n_cache`    WHERE lc_lang = 'en' AND lc_key = 'namespaceGenderAliases'  LIMIT 1  
[DBQuery] LCStoreDB::get [0s] localhost: SELECT  lc_value  FROM `mw_l10n_cache`    WHERE lc_lang = 'en' AND lc_key = 'linkPrefixExtension'  LIMIT 1  
[DBQuery] LCStoreDB::get [0s] localhost: SELECT  lc_value  FROM `mw_l10n_cache`    WHERE lc_lang = 'en' AND lc_key = 'messages:api-usage-docref'  LIMIT 1  
[DBQuery] LCStoreDB::get [0s] localhost: SELECT  lc_value  FROM `mw_l10n_cache`    WHERE lc_lang = 'en' AND lc_key = 'messages:api-usage-mailinglist-ref'  LIMIT 1  
ApiMain::setCacheMode: setting cache mode private
[DBQuery] MediaWiki::preOutputCommit [0s] localhost: COMMIT
MediaWiki::preOutputCommit: primary transaction round committed
MediaWiki::preOutputCommit: pre-send deferred updates completed
MediaWiki::preOutputCommit: session changes committed
[DBReplication] Wikimedia\Rdbms\ChronologyProtector::storeSessionReplicationPosition: DB 'localhost' touched
[DBReplication] Wikimedia\Rdbms\ChronologyProtector::shutdown: no master positions to save
MediaWiki::preOutputCommit: LBFactory shutdown completed
[cookie] setcookie: "UseDC", "master", "1599130147", "/", "", "", "1", ""
[cookie] setcookie: "UseCDNCache", "false", "1599130147", "/", "", "", "1", ""
User::getBlockedStatus: checking blocked status for John
[DBQuery] Wikimedia\Rdbms\Database::beginIfImplied (MediaWiki\Block\DatabaseBlock::newLoad) [0s] localhost: BEGIN
[DBQuery] MediaWiki\Block\DatabaseBlock::newLoad [0s] localhost: SELECT  ipb_id,ipb_address,ipb_timestamp,ipb_auto,ipb_anon_only,ipb_create_account,ipb_enable_autoblock,ipb_expiry,ipb_deleted,ipb_block_email,ipb_allow_usertalk,ipb_parent_block_id,ipb_sitewide,comment_ipb_reason.comment_text AS `ipb_reason_text`,comment_ipb_reason.comment_data AS `ipb_reason_data`,comment_ipb_reason.comment_id AS `ipb_reason_cid`,actor_ipb_by.actor_user AS `ipb_by`,actor_ipb_by.actor_name AS `ipb_by_text`,ipb_by_actor  FROM `mw_ipblocks` JOIN `mw_comment` `comment_ipb_reason` ON ((comment_ipb_reason.comment_id = ipb_reason_id)) JOIN `mw_actor` `actor_ipb_by` ON ((actor_ipb_by.actor_id = ipb_by_actor))   WHERE ipb_address IN ('John','0:0:0:0:0:0:0:1')  OR ((ipb_range_start  LIKE 'v6-0000%' ESCAPE '`' ) AND (ipb_range_start <= 'v6-00000000000000000000000000000001') AND (ipb_range_end >= 'v6-00000000000000000000000000000001'))  
[DBQuery] MediaWiki::restInPeace [0s] localhost: COMMIT
[DeferredUpdates] DeferredUpdates::run: started MWCallableUpdate_Pingback::schedulePingback #244
[DeferredUpdates] DeferredUpdates::run: ended MWCallableUpdate_Pingback::schedulePingback #244
Request ended normally
[session] Saving all sessions on shutdown
[DBConnection] Wikimedia\Rdbms\LBFactory::destroy: closing connection to database 'localhost'.
[DBConnection] Wikimedia\Rdbms\LBFactory::destroy: closing connection to database 'localhost'.

I tested after installing Apache 2.4.38 with default settings and mod_php7.3 and *I can confirm* the bug when creating a page, and indeed solved by removing the two urlencode in VE code; and I can never edit an existing page, both with and without the two urlencode when there is a slash in the title.

I suspect something like a double-decoding somewhere in the stack, perhaps in mod_php or in Apache, perhaps there is some option to pre-decode percent-encoded URLs incompatible with this part of MediaWiki (given the core MediaWiki understand the URLs provided by Apache to display pages).

It’s really a difference of treatment by core Apache between:

http://localhost/mediawiki-1.35.0-rc.2/rest.php/localhost/v3/page/html/Utilisateur:Seb35/Test7/25?redirect=false&stash=true

which is handled by the rest.php script with an unknown (MediaWiki) handler, i.e. 404 MediaWiki error {"messageTranslations":{"fr":"Le chemin relatif requis (/localhost/v3/page/html/Utilisateur:Seb35/Test7/25) ne correspondait à aucun gestionnaire connu","en":"The requested relative path (/localhost/v3/page/html/Utilisateur:Seb35/Test7/25) did not match any known handler"},"httpCode":404,"httpReason":"Not Found"}

and

http://localhost/mediawiki-1.35.0-rc.2/rest.php/localhost/v3/page/html/Utilisateur%3ASeb35%2FTest7/25?redirect=false&stash=true

which is directly handled by Apache, returning a 404 Apache error with its standard page Not Found - The requested URL was not found on this server. - Apache/2.4.38 (Debian) Server at localhost Port 80

I’m no more accustomed to Apache, but probably it is related to some pathinfo, I tried without success to play with AcceptPathInfo and AllowEncodingSlashed. The second URL is always rejected for me.

Thank you, given this is a confirmed bug using Apache (and editing doesn't work even with the changes proposed), I will install nginx for the time being.

Johnbra renamed this task from Visual Editor not working when : or / characters in the Title. Possible bug? to Visual Editor + Apache bug. Visual Editor not working when editing or creating a page with : or / characters in the Title. e.g. http://localhost/w/index.php/User:John/Newpage.Sep 3 2020, 2:22 PM

I finally found: it works by setting AllowEncodedSlashes NoDecode in the VirtualHost (can also be on but Apache docs say it’s more secure to set to NoDecode). I it also mentionned in Restbase configuration, which has URLs similar to Parsoid.

In my previous tests I set up AllowEncodedSlashes in global config as it should be authorised given the docs, but it seems it had no effect.

@Johnbra: do you want to test or you already switched to nginx?

I had changed to nginx but was having another problem....

Just reinstalled apache, tried it and it works!

Thank you very much for your help

matmarex added a subscriber: matmarex.

@Draceane This task was about an issue that never affected Wikimedia wikis, it's unlikely to be the same as the issue that person ran into. Unfortunately there are several different problems that all result in the same message ("Error contacting the Parsoid/RESTBase server (HTTP 404)").

Your issue is most likely the same as this: T235822: VisualEditor can't save edits (HTTP 404 error) when it was open for more than 24 hours while editing an old revision or after switching from wikitext, although I can't be sure (I tried searching our error logs for cswiki and I can't find anything corresponding to that edit attempt).

If it keeps happening, please open a new task.

This comment was removed by Kachkaev.

So, what do I do if I use shared webhosting and have no access to the Apache Virtual Host configuration files?

There's nothing you can do. If you contact your webhosting's support, maybe they can change the configuration for you.

I've already tried that, they won't do that. So basically I need to rename/move every article that contains a / in its title?

@TheConen you may try configuring $wgVisualEditorRestbaseURL or $wgVisualEditorFullRestbaseURL in your instance as the last resort before renaming the pages. I saw this mentioned in T263928. Haven't tried the approach myself though because setting AllowEncodedSlashes NoDecode was possible in my case.

I just wanted to say that when I downloaded version 1.35 of mediawiki on a debian 10 machine (2 days ago) , it still had this problem, the solution provided where one adds AllowEncodedSlashes NoDecode indeed worked, and for anyone who is not sure how to do this, one must ssh into the host machine, then edit /etc/apache2/sites-enabled/000-default.conf, add that line, and then restart apache.

Good luck o/

I disagree with this task being marked as resolved. This was working fine with the external Parsoid service and got broken in the virtual rest service in 1.35. It does not make sense to me that the web server configuration should be changed to accomodate what I call a bug. Of course, I am interested in seing it fixed properly for IIS (T265614) but I think my point about changing the configuration of the web server to fix it is valid.

I agree with @ti_infotrad here. This should be fixed directly in Parsoid's code. There are people who can't easily touch their web server configuration (most can probably use htaccess, but AllowEncodedSlashes isn't valid there). Furthermore, this is an apache-only solution, if someone else runs into this with a less common websrv, it will be (again) broken for 'em. Can we fix this for real please?

This was working fine with the external Parsoid service

Is it possible to use the external Parsoid service with MW 1.35?

This was working fine with the external Parsoid service

Is it possible to use the external Parsoid service with MW 1.35?

Yes, that is what I have decided to do.

Is it possible to use the external Parsoid service with MW 1.35?

Yes, that is what I have decided to do.

Can you share the recipe?

@Johnywhy, you just need to follow the installation instructions given at https://www.mediawiki.org/wiki/Extension:VisualEditor#Linking_with_Parsoid

Could this method be used to run Parsoid on the same server? The page says

Advanced configurations may wish to run Parsoid on a dedicated host or cluster.
You should change $wgServer to match the non-local host running Parsoid

which sounds different than using the same server.

Absolutely

Le sam. 6 févr. 2021 14 h 54, Johnywhy <no-reply@phabricator.wikimedia.org>
a écrit :

Johnywhy added a comment. View Task
https://phabricator.wikimedia.org/T261921

In T261921#6802427 https://phabricator.wikimedia.org/T261921#6802427,
@ti_infotrad https://phabricator.wikimedia.org/p/ti_infotrad/ wrote:

@Johnywhy https://phabricator.wikimedia.org/p/Johnywhy/, you just need
to follow the installation instructions given at
https://www.mediawiki.org/wiki/Extension:VisualEditor#Linking_with_Parsoid

Could this method be used to run Parsoid on the same server?

*TASK DETAIL*
https://phabricator.wikimedia.org/T261921

*EMAIL PREFERENCES*
https://phabricator.wikimedia.org/settings/panel/emailpreferences/

*To: *Seb35, Johnywhy
*Cc: *Johnywhy, WS-Pieter, Urbanecm, ti_infotrad, cuppajoeman, TheConen,
Scripcat, Kachkaev, matmarex, Seb35, Aklapper, Johnbra, Mohammadmalek554,
keithbrianpadilla, Saimongoltinio, WikimeSteve, ppelberg, marcella,
Revansx, OhKayeSierra, takidelfin, Necroarcano, Robinma, merbst, Wess,
Srdjan, Eevans, Jrf, Husun1297, Hardikj, Ryasmeen, GWicke, Dinoguy1000,
Swainr, ssastry, Arlolra, Ltrlg

Absolutely

Le sam. 6 févr. 2021 14 h 54, Johnywhy <no-reply@phabricator.wikimedia.org>

Could this method be used to run Parsoid on the same server?

Didn't work for me. i'm getting this error when i try to use Visual Editor.

Fatal error: Class MWParsoid\Config\DataAccess contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (Wikimedia\Parsoid\Config\DataAccess::fetchPageContent) in /home/gunsywtx/public_html/extensions/parsoid/extension/src/Config/DataAccess.php on line 37

i'm not uploading the git version (recommended "for developers", i'm trying to make this work with the bundled parsoid, since i'm not a 'developer'.

For development purposes you usually want to use a git checkout of Parsoid
https://www.mediawiki.org/wiki/Parsoid#Linking_a_developer_checkout_of_Parsoid

here's my LocalSettings.php

# PARSOID
$PARSOID_INSTALL_DIR = 'extensions/parsoid'; # bundled copy
#$PARSOID_INSTALL_DIR = '/my/path/to/git/checkout/of/Parsoid';

/* 
// For developers: ensure Parsoid is executed from $PARSOID_INSTALL_DIR,
// (not the version included in mediawiki-core by default)
// Must occur *before* wfLoadExtension()
if ( $PARSOID_INSTALL_DIR !== 'vendor/wikimedia/parsoid' ) {
    AutoLoader::$psr4Namespaces += [
        // Keep this in sync with the "autoload" clause in
        // $PARSOID_INSTALL_DIR/composer.json
        'Wikimedia\\Parsoid\\' => "$PARSOID_INSTALL_DIR/src",
        ];
    }
*/

wfLoadExtension( 'Parsoid', "$PARSOID_INSTALL_DIR/extension.json" );
// wfLoadExtension( 'Parsoid', 'vendor/wikimedia/parsoid/extension.json' );

# Manually configure Parsoid
$wgVisualEditorParsoidAutoConfig = false;
$wgParsoidSettings = [
    'useSelser' => true,
    'rtTestMode' => false,
    'linting' => false,
    ];

$wgVirtualRestConfig['modules']['parsoid'] = [];
// $wgVirtualRestConfig['modules']['parsoid']['forwardCookies'] = false;

$wgVirtualRestConfig['modules']['parsoid'] = array(
    // URL to the Parsoid instance.
    // You should change $wgServer to match the non-local host running Parsoid
    'url' => $wgServer . $wgScriptPath . '/rest.php',
    // Parsoid "domain", see below (optional, rarely needed)
    // 'domain' => 'localhost',
    );

// VISUAL EDITOR
wfLoadExtension( 'VisualEditor' );
$wgGroupPermissions['*']['writeapi'] = true;
$wgRevokePermissions['*']['writeapi'] = false;
# By default, VisualEditor is only enabled for the namespaces "Main", "User", "File" and "Category"
$wgVisualEditorAvailableNamespaces = [
    "Portal" => true,
    "Draft" => true,
    NS_PORTAL_TALK => true,
    NS_DRAFT_TALK => true
    ];

@Johnywhy

// For 1.36-alpha only
wfLoadExtension( 'Parsoid', 'vendor/wikimedia/parsoid/extension.json' );
  • My experience with Parsoid is that, up to now, it has been a node.js based external service since 1.27; this is the way I always installed it and this is the way I am using it with 1.35. Unfortunately, I think you will have to go through the developer page https://www.mediawiki.org/wiki/Parsoid/Developer_Setup and follow the instructions for your platform.

My experience with Parsoid is that, up to now, it has been a node.js based external service since 1.27; this is the way I always installed it and this is the way I am using it with 1.35. Unfortunately, I think you will have to go through the developer page https://www.mediawiki.org/wiki/Parsoid/Developer_Setup and follow the instructions for your platform.

Since MediaWiki 1.35, Parsoid is a PHP based service, bundled with the MediaWiki release. I don't know if you can still use Parsoid/JS in MediaWiki 1.35. There is basically Parsoid/JS and Parsoid/PHP now, with Parsoid/JS only being supported until June 2021, see https://www.mediawiki.org/wiki/Parsoid

MediaWiki 1.36 Alpha also uses Parsoid/PHP, you just have to manually activate it now instead of it being automatically activated like in 1.35 LTS. This is expected to change for the release of 1.36.

! In T261921#6809371, @TheConen wrote:
Since MediaWiki 1.35, Parsoid is a PHP based service

is this the wrong config for 1.35 php parsoid? This is the config that's not working for me, above
https://www.mediawiki.org/wiki/Parsoid#Linking_a_developer_checkout_of_Parsoid

thx

That's for a development checkout of Parsoid from the git repo. For a standard MediaWiki installation, you don't need any configuration except

wfLoadExtension( 'VisualEditor' );

which is usually done automatically.

For a standard MediaWiki installation, you don't need any configuration except

wfLoadExtension( 'VisualEditor' );

which is usually done automatically.

Standard VisualEditor config isn't working on 1.35. That's the exact reason why i'm attempting this alternate config. i thought that was a known issue. i'm on a shared server, with no ability to touch server settings.

Well, it is for me... only thing I have in my config regarding Parsoid/VisualEditor are permissions because I use a semi-private wiki (publicly readable, but not writable). That requires something like this:

if ( !isset( $_SERVER['REMOTE_ADDR'] ) OR $_SERVER['REMOTE_ADDR'] == 'YOUR_IP_HERE' ) {
	$wgGroupPermissions['*']['read'] = true;
	$wgGroupPermissions['*']['edit'] = true;
	$wgGroupPermissions['*']['writeapi'] = true;
}

If VisualEditor is not working at all for you, you are in the wrong bug report.... this bug report is about Visual Editor not working with pages containing /. All other pages should work fine. If that's not the case for you, your problem with VisualEditor lies elsewhere.

If VisualEditor is not working at all for you, you are in the wrong bug report.... this bug report is about Visual Editor not working with pages containing /. All other pages should work fine. If that's not the case for you, your problem with VisualEditor lies elsewhere.

When i click 'Save changes' in Visual Editor, i get the same error described in this thread:

Error contacting the Parsoid/RESTBase server (HTTP 403)

Therefor, it seems reasonable to hope that the solution offered here may solve my issue too.

Are you saying the method described in the instructions cannot work with 1.35? Or just that you think it's unnecessary?

You're getting a 403 error (Forbidden). If you had the problem described in this thread, you would get a 404 error (Not found). 403 errors happen when Parsoid is missing permissions, probably because you are using a semi-private or private wiki. Try the code snippet I mentioned above and have a look at https://www.mediawiki.org/wiki/Extension:VisualEditor#Troubleshooting, https://www.mediawiki.org/wiki/User:Andrujhon/Allow_Parsoid_Server and https://www.mediawiki.org/wiki/Topic:Vv35plp6g16qno0s

The correct bug report for your problem is T265043

Try the code snippet I mentioned above
The correct bug report for your problem is T265043

Thx for that. But i don't know what to put for 'REMOTE_ADDR' or 'YOUR_IP_HERE'. This mw was installed by Softaculous, on a shared host, if that matters. i don't think i have a static IP.

Also, it seems my config for writeapi is good. Not sure about the rest. This page says:

Error contacting the Parsoid/RESTBase server (HTTP 403)
Caused by the 'writeapi' right being revoked (or not granted). Check your LocalSettings.php and remove any overrides for this right. (T265043)

My LocalSettings.php:

## PREVENT ANONYMOUS EDITS, READS, CREATES. 
$wgGroupPermissions['*']['edit'] = false;
$wgGroupPermissions['*']['create'] = false;

// VISUAL EDITOR
wfLoadExtension( 'VisualEditor' );
$wgGroupPermissions['*']['writeapi'] = true;
$wgRevokePermissions['*']['writeapi'] = false;
# By default, VisualEditor is only enabled for the namespaces "Main", "User", "File" and "Category"
$wgVisualEditorAvailableNamespaces = [
    "Portal" => true,
    "Draft" => true,
    NS_PORTAL_TALK => true,
    NS_DRAFT_TALK => true
    ];

Visual Editor needs anonynmous read, edit and writeapi rights. All of these are per default true so you don't need to change anything. Remove everything except

wfLoadExtension( 'VisualEditor' );

from your config and see if that works.
If it does, you can try this:

// VISUAL EDITOR
wfLoadExtension( 'VisualEditor' );

// Permissions for semi-private wiki. 
$wgGroupPermissions['*']['edit'] = false;
$wgGroupPermissions['*']['create'] = false;
//Permissions for Visual Editor
if ( !isset( $_SERVER['REMOTE_ADDR'] ) OR $_SERVER['REMOTE_ADDR'] == '<YOUR_IP_HERE>' ) {
	$wgGroupPermissions['*']['read'] = true;
	$wgGroupPermissions['*']['edit'] = true;
	$wgGroupPermissions['*']['writeapi'] = true;
}

Replace <YOUR_IP_HERE> with the IPv4 or IPv6 address of your server. You may need to try both and see which one works for you.

Remove everything except

wfLoadExtension( 'VisualEditor' );

from your config and see if that works.

Unfortunately, it doesn't. Getting same error on save.
thx!

What happens with this one?

wfLoadExtension( 'VisualEditor' );
$wgGroupPermissions['*']['read'] = true;
$wgGroupPermissions['*']['edit'] = true;
$wgGroupPermissions['*']['writeapi'] = true;

What happens with this one?

wfLoadExtension( 'VisualEditor' );
$wgGroupPermissions['*']['read'] = true;
$wgGroupPermissions['*']['edit'] = true;
$wgGroupPermissions['*']['writeapi'] = true;

Thx for that! But, same error. Note, i'm not using your if ( !isset( $_SERVER... yet. Should i?

i just noticed a conflicting setting. This one is intended to prevent anonymous edits. Might be the issue:
$wgGroupPermissions['*']['edit'] = false; # https://www.mediawiki.org/wiki/Manual:Preventing_access#Simple_private_wiki

but you said to set to true to enable Visual Editor. Does that mean we must allow anon edits if we want to use Visual Editor?:
$wgGroupPermissions['*']['edit'] = true;

Here are some other parts of my LocalSettings.php which might be relevant. I shared relevant links. Protection is rather complicated, and i struggled with it at the time i set up this wiki (3 yrs ago):

# SUPPOSED TO REMOVE THE "PROTECT" TAB FOR THEIR NAMESPACES
# https://www.mediawiki.org/wiki/Manual:$wgNamespaceProtection
$wgNamespaceProtection[NS_PORTAL] = 
$wgNamespaceProtection['NS_FORM'] = 	
$wgNamespaceProtection[NS_PROJECT] =
$wgNamespaceProtection[NS_HELP] =
$wgNamespaceProtection[NS_CATEGORY] =array( 'editprotected' );
/* https://www.mediawiki.org/wiki/Manual:User_rights#List_of_permissions
The above statement means: Users and groups who have 'editprotected' permission shall have write-access to the Form namespace. editprotected makes sense here, cuz:
- Only admins have editprotected by default, and i want to target admins.
- "wgNamespaceProtection" is all about, well, editing something that's protected :)
- saves me the trouble of creating a new protection and applying to admins.
https://www.mediawiki.org/w/index.php?title=Topic:Ua5fqyzhagx3iso8&action=history
https://www.mediawiki.org/w/index.php?title=Topic:Ua5fqyzhagx3iso8&topic_showPostId=ua7het8puwsmpt4y#flow-post-ua7het8puwsmpt4y
*/


## FLOW & ECHO
wfLoadExtension( 'Flow' );
wfLoadExtension( 'Echo' );
$wgNamespaceContentModels[NS_TALK] = 'flow-board';		# MAIN TALK  https://www.mediawiki.org/wiki/Extension_default_namespaces#MediaWiki_Core
$wgNamespaceContentModels[NS_PROJECT_TALK] = 'flow-board';		
$wgNamespaceContentModels[NS_HELP_TALK] = 'flow-board';		
$wgNamespaceContentModels[NS_CATEGORY_TALK] = 'flow-board';		
$wgNamespaceContentModels[107] = 'flow-board';
$wgNamespaceContentModels[NS_DRAFT_TALK] = 'flow-board';		
$wgNamespaceContentModels[NS_PORTAL_TALK] = 'flow-board';	


## APPROVED REVS
wfLoadExtension( 'ApprovedRevs' );
$egApprovedRevsAutomaticApprovals = true;		# allow auto-approval of admin edits. 
$egApprovedRevsEnabledNamespaces[] = NS_DRAFT;	
$egApprovedRevsSelfOwnedNamespaces[] = NS_USER ;


## MODERATION 
wfLoadExtension( 'Moderation' );
$wgModerationTimeToOverrideRejection = 31556952;
$wgModerationNotificationEnable = true;
$wgGroupPermissions['sysop']['moderation'] = true; # Allow sysops to use Special:Moderation
$wgGroupPermissions['sysop']['skip-moderation'] = true; # Allow sysops to skip moderation
$wgGroupPermissions['automoderated']['skip-move-moderation'] = false;
$wgGroupPermissions['sysop']['skip-move-moderation'] = true;
$wgAutoConfirmCount = 10;	
$wgGroupPermissions['autoconfirmed']['skip-move-moderation'] = false;

$wgWhitelistReadRegexp = 
	['/Portal:/', '/ /', '/Draft:/', '/Template:/', '/Category:/',  '/Topic:/', 
	'/MediaWiki:Common.css/', '/MediaWiki:TopicTags.css/', '/Special:AllPages/', '/Special:RecentChanges/', '/Special:RequestAccount/'
	];

but you said to set to true to enable Visual Editor. Does that mean we must allow anon edits if we want to use Visual Editor?:

Yes, Visual Editor needs anonymous access to read, edit and writeapi. That being said, you can still use a private wiki with Visual Editor - the code snippet I gave you (with the if ( !isset( $_SERVER... will enable the necessary permissions for VisualEditor only. However, you must use that code snippet at the end of your LocalSettings.php, otherwise you will overwrite the settings again.

What I want you to do to test if VisualEditor works in general, is to allow anonymous read, edit and writeapi rights on your wiki and then see if VisualEditor works. If it works when you have anonymous rights enabled on your wiki, it is just a matter of putting the right IP address in the code snippet I gave you and putting it at the very end of your LocalSettings.php

Try this at the very end of your LocalSettings.php

wfLoadExtension( 'VisualEditor' );
$wgGroupPermissions['*']['read'] = true;
$wgGroupPermissions['*']['edit'] = true;
$wgGroupPermissions['*']['writeapi'] = true;

If that works, replace it with

// VISUAL EDITOR
wfLoadExtension( 'VisualEditor' );
if ( !isset( $_SERVER['REMOTE_ADDR'] ) OR $_SERVER['REMOTE_ADDR'] == '<YOUR_IP_HERE>' ) {
	$wgGroupPermissions['*']['read'] = true;
	$wgGroupPermissions['*']['edit'] = true;
	$wgGroupPermissions['*']['writeapi'] = true;
}

Visual Editor needs anonymous access to read, edit and writeapi.

With my settings as shown above, Visual Editor is able to read and edit pages. Just cannot save.

Try this at the very end of your LocalSettings.php

wfLoadExtension( 'VisualEditor' );
$wgGroupPermissions['*']['read'] = true;
$wgGroupPermissions['*']['edit'] = true;
$wgGroupPermissions['*']['writeapi'] = true;

ok, i did that, and i removed the ['edit'] = false line.

Still getting same parsoid error on save.

Well, in that case, I'm at my wit's end... sorry ¯\_(ツ)_/¯.

thx for trying!

i don't know if this helps, but with the following config, i don't get the 'Edit' link on the page anymore:

wfLoadExtension( 'VisualEditor' );
if ( !isset( $_SERVER['REMOTE_ADDR'] ) OR $_SERVER['REMOTE_ADDR'] == '199.188.200.217' ) {
	$wgGroupPermissions['*']['read'] = true;
	$wgGroupPermissions['*']['edit'] = true;
	$wgGroupPermissions['*']['writeapi'] = true;
}

Since my issue is, as you mentioned, different than this post, i'm going to post it as a separate issue. Thx!

Well, in that case, I'm at my wit's end... sorry ¯\_(ツ)_/¯.

Turns out this issue was apparently caused by Softaculous. I installed MW manually, and imported my sql dump into it. VisualEditor works with:

wfLoadExtension( 'VisualEditor' );
$wgGroupPermissions['*']['writeapi'] = true;
$wgRevokePermissions['*']['writeapi'] = false;
$wgGroupPermissions['*']['read'] = true;
$wgGroupPermissions['*']['edit'] = true;
# By default, VisualEditor is only enabled for the namespaces "Main", "User", "File" and "Category"
$wgVisualEditorAvailableNamespaces = [
    "Portal" => true,
    "Draft" => true,
    NS_PORTAL_TALK => true,
    NS_DRAFT_TALK => true
    ];