Make WordPress Core

Changeset 61839


Ignore:
Timestamp:
03/05/2026 09:23:25 AM (4 weeks ago)
Author:
ellatrix
Message:

Real-time collaboration: prevent fall-through in sync polling server.

When a user sends a stale compaction update to WP_HTTP_Polling_Sync_Server, it falls through the switch statement and results in a rest_invalid_update_type error (bad request).

This generally has no ill effect since the compaction request is rescinded on the next polling cycle, but it could cause confusion for users who are monitoring client-side requests or server logs.

To fix, replace the break after the $has_newer_compaction check with return true so that the stale compaction is silently discarded instead of falling through. Covered by unit test.

Developed in: https://github.com/WordPress/wordpress-develop/pull/11118.
Syncs: https://github.com/WordPress/gutenberg/pull/76060.

Fixes #64781.
Props czarate, mindctrl.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/collaboration/class-wp-http-polling-sync-server.php

    r61838 r61839  
    424424                    return $this->add_update( $room, $client_id, $type, $data );
    425425                }
    426                 break;
     426
     427                // Reaching this point means there's a newer compaction, so we can
     428                // silently ignore this one.
     429                return true;
    427430
    428431            case self::UPDATE_TYPE_SYNC_STEP1:
  • trunk/tests/phpunit/tests/rest-api/rest-sync-server.php

    r61838 r61839  
    624624    }
    625625
     626    public function test_sync_stale_compaction_succeeds_when_newer_compaction_exists() {
     627        wp_set_current_user( self::$editor_id );
     628
     629        $room   = $this->get_post_room();
     630        $update = array(
     631            'type' => 'update',
     632            'data' => 'dGVzdA==',
     633        );
     634
     635        // Client 1 sends an update to seed the room.
     636        $response = $this->dispatch_sync(
     637            array(
     638                $this->build_room( $room, 1, 0, array( 'user' => 'c1' ), array( $update ) ),
     639            )
     640        );
     641
     642        $end_cursor = $response->get_data()['rooms'][0]['end_cursor'];
     643
     644        // Client 2 sends a compaction at the current cursor.
     645        $compaction = array(
     646            'type' => 'compaction',
     647            'data' => 'Y29tcGFjdGVk',
     648        );
     649
     650        $this->dispatch_sync(
     651            array(
     652                $this->build_room( $room, 2, $end_cursor, array( 'user' => 'c2' ), array( $compaction ) ),
     653            )
     654        );
     655
     656        // Client 3 sends a stale compaction at cursor 0. The server should find
     657        // client 2's compaction in the updates after cursor 0 and silently discard
     658        // this one.
     659        $stale_compaction = array(
     660            'type' => 'compaction',
     661            'data' => 'c3RhbGU=',
     662        );
     663        $response         = $this->dispatch_sync(
     664            array(
     665                $this->build_room( $room, 3, 0, array( 'user' => 'c3' ), array( $stale_compaction ) ),
     666            )
     667        );
     668
     669        $this->assertSame( 200, $response->get_status() );
     670
     671        // Verify the newer compaction is preserved and the stale one was not stored.
     672        $response    = $this->dispatch_sync(
     673            array(
     674                $this->build_room( $room, 4, 0, array( 'user' => 'c4' ) ),
     675            )
     676        );
     677        $update_data = wp_list_pluck( $response->get_data()['rooms'][0]['updates'], 'data' );
     678
     679        $this->assertContains( 'Y29tcGFjdGVk', $update_data, 'The newer compaction should be preserved.' );
     680        $this->assertNotContains( 'c3RhbGU=', $update_data, 'The stale compaction should not be stored.' );
     681    }
     682
    626683    /*
    627684     * Awareness tests.
Note: See TracChangeset for help on using the changeset viewer.