diff --git a/core/core.services.yml b/core/core.services.yml
index 5080841..94c4810 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -942,6 +942,10 @@ services:
     tags:
       - { name: route_processor_outbound }
     arguments: ['@csrf_token']
+  path_processor_accept:
+    class: Drupal\Core\PathProcessor\PathProcessorAccept
+    tags:
+      - { name: path_processor_inbound, priority: 0 }
   transliteration:
     class: Drupal\Core\Transliteration\PhpTransliteration
     arguments: [null, '@module_handler']
diff --git a/core/lib/Drupal/Core/ContentNegotiation.php b/core/lib/Drupal/Core/ContentNegotiation.php
index 857f9d5..45b67e8 100644
--- a/core/lib/Drupal/Core/ContentNegotiation.php
+++ b/core/lib/Drupal/Core/ContentNegotiation.php
@@ -30,6 +30,10 @@ class ContentNegotiation {
    *   The normalized type of a given request.
    */
   public function getContentType(Request $request) {
+    if ($format = $request->getRequestFormat(NULL)) {
+      return $format;
+    }
+
     // AJAX iframe uploads need special handling, because they contain a JSON
     // response wrapped in <textarea>.
     if ($request->get('ajax_iframe_upload', FALSE)) {
diff --git a/core/lib/Drupal/Core/EventSubscriber/ContentControllerSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/ContentControllerSubscriber.php
index 32f9565..86b0eda 100644
--- a/core/lib/Drupal/Core/EventSubscriber/ContentControllerSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/ContentControllerSubscriber.php
@@ -48,7 +48,7 @@ public function __construct(ContentNegotiation $negotiation) {
   public function onRequestDeriveFormat(GetResponseEvent $event) {
     $request = $event->getRequest();
 
-    if (!$request->attributes->get('_format')) {
+    if (!$request->getRequestFormat(NULL)) {
       $request->setRequestFormat($this->negotiation->getContentType($request));
     }
   }
diff --git a/core/lib/Drupal/Core/EventSubscriber/MainContentViewSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/MainContentViewSubscriber.php
index fcc51a3..1ee5808 100644
--- a/core/lib/Drupal/Core/EventSubscriber/MainContentViewSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/MainContentViewSubscriber.php
@@ -76,7 +76,7 @@ public function onViewRenderArray(GetResponseForControllerResultEvent $event) {
     $request = $event->getRequest();
     $result = $event->getControllerResult();
 
-    $format = $request->getRequestFormat();
+    $format = $request->getRequestFormat(NULL);
 
     // Render the controller result into a response if it's a render array.
     if (is_array($result)) {
diff --git a/core/lib/Drupal/Core/PathProcessor/PathProcessorAccept.php b/core/lib/Drupal/Core/PathProcessor/PathProcessorAccept.php
new file mode 100644
index 0000000..9865612
--- /dev/null
+++ b/core/lib/Drupal/Core/PathProcessor/PathProcessorAccept.php
@@ -0,0 +1,42 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\PathProcessor\PathProcessorAccept.
+ */
+
+namespace Drupal\Core\PathProcessor;
+
+use Symfony\Component\HttpFoundation\Request;
+
+class PathProcessorAccept implements InboundPathProcessorInterface {
+
+  protected $mapping = [
+    'json' => 'json',
+    'html' => 'html',
+    'drupal_ajax' => 'drupal_ajax',
+    'drupal_dialog' => 'drupal_dialog',
+    'drupal_modal' => 'drupal_modal',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  public function processInbound($path, Request $request) {
+    // Sets the request format based upon the incoming .extension.
+    $match = [];
+    if (preg_match('/\.([a-z_]+)$/', $path, $match)) {
+      if (isset($this->mapping[$match[1]])) {
+        $request->setRequestFormat($this->mapping[$match[1]]);
+        // -1 for the dot.
+        $path = substr($path, 0, strlen($path) - strlen($match[1]) - 1);
+      }
+    }
+    return $path;
+  }
+
+  public function addMapping($extension, $format) {
+    $this->mapping[$extension] = $format;
+  }
+
+}
diff --git a/core/misc/ajax.js b/core/misc/ajax.js
index ac90282..f01f819 100644
--- a/core/misc/ajax.js
+++ b/core/misc/ajax.js
@@ -52,7 +52,7 @@
           element_settings.url = $(this).attr('href');
           element_settings.event = 'click';
         }
-        element_settings.accepts = $(this).data('accepts');
+        element_settings.format = $(this).data('format');
         element_settings.dialog = $(this).data('dialog-options');
         var baseUseAjax = $(this).attr('id');
         Drupal.ajax[baseUseAjax] = new Drupal.ajax(baseUseAjax, this, element_settings);
@@ -216,6 +216,12 @@
     // 4. /nojs# - Followed by a fragment (e.g.: path/nojs#myfragment).
     this.url = this.url.replace(/\/nojs(\/|$|\?|#)/g, '/ajax$1');
 
+    // Append the extension for the URL.
+    var extension = element_settings.format || 'drupal_ajax';
+    if (extension) {
+      this.url += '.' + extension;
+    }
+
     // Set the options for the ajaxSubmit function.
     // The 'this' variable will not persist inside of the options object.
     var ajax = this;
@@ -248,9 +254,6 @@
         }
       },
       dataType: 'json',
-      accepts: {
-        json: element_settings.accepts || 'application/vnd.drupal-ajax'
-      },
       type: 'POST'
     };
 
diff --git a/core/modules/aggregator/src/Tests/AggregatorRenderingTest.php b/core/modules/aggregator/src/Tests/AggregatorRenderingTest.php
index efb3d2f..6b84a67 100644
--- a/core/modules/aggregator/src/Tests/AggregatorRenderingTest.php
+++ b/core/modules/aggregator/src/Tests/AggregatorRenderingTest.php
@@ -83,7 +83,7 @@ public function testBlockLinks() {
    * Creates a feed and checks that feed's page.
    */
   public function testFeedPage() {
-    // Increase the number of items published in the rss.xml feed so we have
+    // Increase the number of items published in the rss feed so we have
     // enough articles to test paging.
     $view = entity_load('view', 'frontpage');
     $display = &$view->getDisplay('feed_1');
diff --git a/core/modules/aggregator/src/Tests/AggregatorTestBase.php b/core/modules/aggregator/src/Tests/AggregatorTestBase.php
index cf845db..8935620 100644
--- a/core/modules/aggregator/src/Tests/AggregatorTestBase.php
+++ b/core/modules/aggregator/src/Tests/AggregatorTestBase.php
@@ -36,13 +36,24 @@ protected function setUp() {
   }
 
   /**
+   * Deletes an aggregator feed.
+   *
+   * @param \Drupal\aggregator\FeedInterface $feed
+   *   Feed object representing the feed.
+   */
+  function deleteFeed(FeedInterface $feed) {
+    $this->drupalPostForm('aggregator/sources/' . $feed->id() . '/delete', array(), t('Delete'));
+    $this->assertRaw(t('The feed %title has been deleted.', array('%title' => $feed->label())), 'Feed deleted successfully.');
+  }
+
+  /**
    * Creates an aggregator feed.
    *
    * This method simulates the form submission on path aggregator/sources/add.
    *
    * @param $feed_url
    *   (optional) If given, feed will be created with this URL, otherwise
-   *   /rss.xml will be used. Defaults to NULL.
+   *   /rss will be used. Defaults to NULL.
    * @param array $edit
    *   Array with additional form fields.
    *
@@ -62,22 +73,11 @@ function createFeed($feed_url = NULL, array $edit = array()) {
   }
 
   /**
-   * Deletes an aggregator feed.
-   *
-   * @param \Drupal\aggregator\FeedInterface $feed
-   *   Feed object representing the feed.
-   */
-  function deleteFeed(FeedInterface $feed) {
-    $this->drupalPostForm('aggregator/sources/' . $feed->id() . '/delete', array(), t('Delete'));
-    $this->assertRaw(t('The feed %title has been deleted.', array('%title' => $feed->label())), 'Feed deleted successfully.');
-  }
-
-  /**
    * Returns a randomly generated feed edit array.
    *
    * @param $feed_url
    *   (optional) If given, feed will be created with this URL, otherwise
-   *   /rss.xml will be used. Defaults to NULL.
+   *   /rss will be used. Defaults to NULL.
    * @param array $edit
    *   Array with additional form fields.
    *
@@ -105,7 +105,7 @@ function getFeedEditArray($feed_url = NULL, array $edit = array()) {
    *
    * @param string $feed_url
    *   (optional) If given, feed will be created with this URL, otherwise
-   *   /rss.xml will be used. Defaults to NULL.
+   *   /rss will be used. Defaults to NULL.
    * @param array $values
    *   (optional) Default values to initialize object properties with.
    *
@@ -135,7 +135,7 @@ function getFeedEditObject($feed_url = NULL, array $values = array()) {
    *   Number of feed items on default feed created by createFeed().
    */
   function getDefaultFeedItemCount() {
-    // Our tests are based off of rss.xml, so let's find out how many elements should be related.
+    // Our tests are based off of rss, so let's find out how many elements should be related.
     $feed_count = db_query_range('SELECT COUNT(DISTINCT nid) FROM {node_field_data} n WHERE n.promote = 1 AND n.status = 1', 0, $this->config('system.rss')->get('items.limit'))->fetchField();
     return $feed_count > 10 ? 10 : $feed_count;
   }
diff --git a/core/modules/block/src/BlockListBuilder.php b/core/modules/block/src/BlockListBuilder.php
index 293f088..c06dd67 100644
--- a/core/modules/block/src/BlockListBuilder.php
+++ b/core/modules/block/src/BlockListBuilder.php
@@ -362,7 +362,7 @@ public function buildForm(array $form, FormStateInterface $form_state) {
         ]),
         'attributes' => array(
           'class' => array('use-ajax', 'block-filter-text-source'),
-          'data-accepts' => 'application/vnd.drupal-modal',
+          'data-format' => 'drupal_modal',
           'data-dialog-options' => Json::encode(array(
             'width' => 700,
           )),
diff --git a/core/modules/ckeditor/js/ckeditor.js b/core/modules/ckeditor/js/ckeditor.js
index 1596808..018fe3a 100644
--- a/core/modules/ckeditor/js/ckeditor.js
+++ b/core/modules/ckeditor/js/ckeditor.js
@@ -161,7 +161,7 @@
       var $content = $('<div class="ckeditor-dialog-loading"><span style="top: -40px;" class="ckeditor-dialog-loading-link"><a>' + Drupal.t('Loading...') + '</a></span></div>');
       $content.appendTo($target);
       new Drupal.ajax('ckeditor-dialog', $content.find('a').get(0), {
-        accepts: 'application/vnd.drupal-modal',
+        format: 'drupal_modal',
         dialog: dialogSettings,
         selector: '.ckeditor-dialog-loading-link',
         url: url,
diff --git a/core/modules/comment/src/Tests/CommentRssTest.php b/core/modules/comment/src/Tests/CommentRssTest.php
index ca3acda..2ec7424 100644
--- a/core/modules/comment/src/Tests/CommentRssTest.php
+++ b/core/modules/comment/src/Tests/CommentRssTest.php
@@ -30,14 +30,14 @@ function testCommentRss() {
     // Find comment in RSS feed.
     $this->drupalLogin($this->webUser);
     $this->postComment($this->node, $this->randomMachineName(), $this->randomMachineName());
-    $this->drupalGet('rss.xml');
+    $this->drupalGet('rss');
     $raw = '<comments>' . $this->node->url('canonical', array('fragment' => 'comments', 'absolute' => TRUE)) . '</comments>';
     $this->assertRaw($raw, 'Comments as part of RSS feed.');
 
     // Hide comments from RSS feed and check presence.
     $this->node->set('comment', CommentItemInterface::HIDDEN);
     $this->node->save();
-    $this->drupalGet('rss.xml');
+    $this->drupalGet('rss');
     $this->assertNoRaw($raw, 'Hidden comments is not a part of RSS feed.');
   }
 }
diff --git a/core/modules/config/src/Form/ConfigSync.php b/core/modules/config/src/Form/ConfigSync.php
index 2742e93..28fa86d 100644
--- a/core/modules/config/src/Form/ConfigSync.php
+++ b/core/modules/config/src/Form/ConfigSync.php
@@ -280,7 +280,7 @@ public function buildForm(array $form, FormStateInterface $form_state) {
             'url' => Url::fromRoute($route_name, $route_options),
             'attributes' => array(
               'class' => array('use-ajax'),
-              'data-accepts' => 'application/vnd.drupal-modal',
+              'data-format' => 'drupal_modal',
               'data-dialog-options' => json_encode(array(
                 'width' => 700
               )),
diff --git a/core/modules/file/src/Tests/FileFieldRSSContentTest.php b/core/modules/file/src/Tests/FileFieldRSSContentTest.php
index 7f04ac2..0234895 100644
--- a/core/modules/file/src/Tests/FileFieldRSSContentTest.php
+++ b/core/modules/file/src/Tests/FileFieldRSSContentTest.php
@@ -66,7 +66,7 @@ function testFileFieldRSSContent() {
     $node_file = file_load($node->{$field_name}->target_id);
 
     // Check that the RSS enclosure appears in the RSS feed.
-    $this->drupalGet('rss.xml');
+    $this->drupalGet('rss');
     $uploaded_filename = str_replace('public://', '', $node_file->getFileUri());
     $test_element = array(
       'key' => 'enclosure',
diff --git a/core/modules/hal/src/HalServiceProvider.php b/core/modules/hal/src/HalServiceProvider.php
new file mode 100644
index 0000000..8e2115d
--- /dev/null
+++ b/core/modules/hal/src/HalServiceProvider.php
@@ -0,0 +1,24 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\hal\HalServiceProvider.
+ */
+
+namespace Drupal\hal;
+
+use Drupal\Core\DependencyInjection\ContainerBuilder;
+use Drupal\Core\DependencyInjection\ServiceModifierInterface;
+
+class HalServiceProvider implements ServiceModifierInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function alter(ContainerBuilder $container) {
+    if ($definition = $container->getDefinition('path_processor_accept')) {
+      $definition->addMethodCall('addMapping', ['hal_json', 'hal_json']);
+    }
+  }
+
+}
diff --git a/core/modules/node/config/install/views.view.frontpage.yml b/core/modules/node/config/install/views.view.frontpage.yml
index d9dc888..2221d45 100644
--- a/core/modules/node/config/install/views.view.frontpage.yml
+++ b/core/modules/node/config/install/views.view.frontpage.yml
@@ -244,7 +244,7 @@ display:
     position: 2
     display_options:
       sitename_title: true
-      path: rss.xml
+      path: rss
       displays:
         page_1: page_1
         default: ''
diff --git a/core/modules/node/src/Plugin/Block/SyndicateBlock.php b/core/modules/node/src/Plugin/Block/SyndicateBlock.php
index f4e7123..7974677 100644
--- a/core/modules/node/src/Plugin/Block/SyndicateBlock.php
+++ b/core/modules/node/src/Plugin/Block/SyndicateBlock.php
@@ -44,7 +44,7 @@ protected function blockAccess(AccountInterface $account) {
   public function build() {
     return array(
       '#theme' => 'feed_icon',
-      '#url' => 'rss.xml',
+      '#url' => 'rss',
     );
   }
 
diff --git a/core/modules/node/src/Tests/NodeRSSContentTest.php b/core/modules/node/src/Tests/NodeRSSContentTest.php
index e4b7cb3..2a0f1bc 100644
--- a/core/modules/node/src/Tests/NodeRSSContentTest.php
+++ b/core/modules/node/src/Tests/NodeRSSContentTest.php
@@ -12,7 +12,7 @@
  *
  * Create a node, enable the node_test module to ensure that extra data is
  * added to the node's renderable array, then verify that the data appears on
- * the site-wide RSS feed at rss.xml.
+ * the site-wide RSS feed at /rss.
  *
  * @group node
  */
@@ -42,7 +42,7 @@ function testNodeRSSContent() {
     // Create a node.
     $node = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1));
 
-    $this->drupalGet('rss.xml');
+    $this->drupalGet('rss');
 
     // Check that content added in 'rss' view mode appear in RSS feed.
     $rss_only_content = t('Extra data that should appear only in the RSS feed for node !nid.', array('!nid' => $node->id()));
diff --git a/core/modules/system/tests/modules/ajax_test/src/Controller/AjaxTestController.php b/core/modules/system/tests/modules/ajax_test/src/Controller/AjaxTestController.php
index b54b823..bee2b58 100644
--- a/core/modules/system/tests/modules/ajax_test/src/Controller/AjaxTestController.php
+++ b/core/modules/system/tests/modules/ajax_test/src/Controller/AjaxTestController.php
@@ -120,7 +120,7 @@ public function dialog() {
       '#url' => Url::fromRoute('ajax_test.dialog_contents'),
       '#attributes' => array(
         'class' => array('use-ajax'),
-        'data-accepts' => 'application/vnd.drupal-modal',
+        'data-format' => 'drupal_modal',
       ),
     );
 
@@ -133,7 +133,7 @@ public function dialog() {
           'url' => Url::fromRoute('ajax_test.dialog_contents'),
           'attributes' => array(
             'class' => array('use-ajax'),
-            'data-accepts' => 'application/vnd.drupal-modal',
+            'data-format' => 'drupal_modal',
             'data-dialog-options' => json_encode(array(
               'width' => 400,
             ))
@@ -144,7 +144,7 @@ public function dialog() {
           'url' => Url::fromRoute('ajax_test.dialog_contents'),
           'attributes' => array(
             'class' => array('use-ajax'),
-            'data-accepts' => 'application/vnd.drupal-dialog',
+            'data-format' => 'drupal-dialog',
             'data-dialog-options' => json_encode(array(
               'target' => 'ajax-test-dialog-wrapper-1',
               'width' => 800,
@@ -163,7 +163,7 @@ public function dialog() {
           'url' => Url::fromRoute('ajax_test.dialog_form'),
           'attributes' => array(
             'class' => array('use-ajax'),
-            'data-accepts' => 'application/vnd.drupal-modal',
+            'data-format' => 'drupal_modal',
           ),
         ),
         'link6' => array(
@@ -171,7 +171,7 @@ public function dialog() {
           'url' => Url::fromRoute('contact.form_add'),
           'attributes' => array(
             'class' => array('use-ajax'),
-            'data-accepts' => 'application/vnd.drupal-modal',
+            'data-format' => 'drupal_modal',
             'data-dialog-options' => json_encode(array(
               'width' => 800,
               'height' => 500,
@@ -183,7 +183,7 @@ public function dialog() {
           'url' => Url::fromRoute('ajax_test.dialog_contents'),
           'attributes' => array(
             'class' => array('use-ajax'),
-            'data-accepts' => 'application/vnd.drupal-dialog',
+            'data-format' => 'drupal-dialog',
             'data-dialog-options' => json_encode(array(
               'width' => 800,
             ))
diff --git a/core/modules/taxonomy/src/Tests/RssTest.php b/core/modules/taxonomy/src/Tests/RssTest.php
index d0b5c3a..9887086 100644
--- a/core/modules/taxonomy/src/Tests/RssTest.php
+++ b/core/modules/taxonomy/src/Tests/RssTest.php
@@ -80,7 +80,7 @@ protected function setUp() {
   /**
    * Tests that terms added to nodes are displayed in core RSS feed.
    *
-   * Create a node and assert that taxonomy terms appear in rss.xml.
+   * Create a node and assert that taxonomy terms appear in /rss.
    */
   function testTaxonomyRss() {
     // Create two taxonomy terms.
@@ -107,7 +107,7 @@ function testTaxonomyRss() {
     $this->drupalPostForm('node/add/article', $edit, t('Save'));
 
     // Check that the term is displayed when the RSS feed is viewed.
-    $this->drupalGet('rss.xml');
+    $this->drupalGet('rss');
     $test_element = array(
       'key' => 'category',
       'value' => $term1->getName(),
diff --git a/core/modules/views/src/Plugin/views/display/Feed.php b/core/modules/views/src/Plugin/views/display/Feed.php
index 24e76ba..7d97484 100644
--- a/core/modules/views/src/Plugin/views/display/Feed.php
+++ b/core/modules/views/src/Plugin/views/display/Feed.php
@@ -234,7 +234,7 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
         );
         break;
       case 'path':
-        $form['path']['#description'] = $this->t('This view will be displayed by visiting this path on your site. It is recommended that the path be something like "path/%/%/feed" or "path/%/%/rss.xml", putting one % in the path for each contextual filter you have defined in the view.');
+        $form['path']['#description'] = $this->t('This view will be displayed by visiting this path on your site. It is recommended that the path be something like "path/%/%/feed" or "path/%/%/rss", putting one % in the path for each contextual filter you have defined in the view.');
     }
   }
 
diff --git a/core/modules/views/src/Tests/Plugin/StyleOpmlTest.php b/core/modules/views/src/Tests/Plugin/StyleOpmlTest.php
index 6580c0c..a9ac57b 100644
--- a/core/modules/views/src/Tests/Plugin/StyleOpmlTest.php
+++ b/core/modules/views/src/Tests/Plugin/StyleOpmlTest.php
@@ -48,7 +48,7 @@ public function testOpmlOutput() {
     // Create a test feed.
     $values = array(
       'title' => $this->randomMachineName(10),
-      'url' => 'http://example.com/rss.xml',
+      'url' => 'http://example.com/rss',
       'refresh' => '900',
     );
     $feed = $this->container->get('entity.manager')
diff --git a/core/profiles/standard/src/Tests/StandardTest.php b/core/profiles/standard/src/Tests/StandardTest.php
index 2171765..bd4b714 100644
--- a/core/profiles/standard/src/Tests/StandardTest.php
+++ b/core/profiles/standard/src/Tests/StandardTest.php
@@ -98,7 +98,7 @@ function testStandard() {
       'comment_body[0][value]' => 'Then she picked out two somebodies, Sally and me',
     ), t('Save'));
     // Fetch the feed.
-    $this->drupalGet('rss.xml');
+    $this->drupalGet('rss');
     $this->assertText('Foobar');
     $this->assertNoText('Then she picked out two somebodies, Sally and me');
 
