title: POST request through AJAX results in error 404 in Firefox only
body: <p>In my Flask-app I try to implement POST request through AJAX call when user clicks on the link.
  It works like a charm in Chromium. I have no problems when requesting my view function through <code>httpie</code> either:</p>
  
  <pre><code>$ http --json POST http://127.0.0.1:5000/ctrl/remove-category id=1 csrf=1
  
  (venv) $ : http --json POST http://127.0.0.1:5000/ctrl/remove-category id=5 csrf=1
  HTTP/1.0 200 OK
  Content-Length: 78
  Content-Type: application/json
  Date: Sat, 09 Jul 2016 09:05:20 GMT
  Server: Werkzeug/0.11.8 Python/3.5.1
  
  {
      "message": "Category 'test 5' has been removed",
      "status": "success"
  }
  </code></pre>
  
  <p>But in Firefox something strange happens. I tested it under two FF profiles. Both of them give me 404 error. When clicking the link under my first FF profile I get 404 and nothing happens, i.e. I don't even see POST request to Werkzeug server, only GET request.</p>
  
  <p>Under the second FF profile I still get an error in Firebug console:</p>
  
  <pre><code>POST http://127.0.0.1:5000/ctrl/remove-category 31ms        jquery.min.js (line 6)
  Error code: 404                                             categories (line 455)
  </code></pre>
  
  <p>So POST request is sent and I see it in my Werkzeug logs:</p>
  
  <pre><code>127.0.0.1 - - [09/Jul/2016 11:29:11] "POST /ctrl/remove-category HTTP/1.1" 200 -
  127.0.0.1 - - [09/Jul/2016 11:29:12] "GET /ctrl/categories HTTP/1.1" 200 -
  </code></pre>
  
  <p>Nonetheless, I still don't get other things done in my AJAX `.success' call (like saving things to localStorage, etc.)</p>
  
  <p>Here is my jQuery script:</p>
  
  <pre><code>&lt;script&gt;
   $('.remove').click( function() {
       var data = {};
       data['csrf'] = $('#csrf-removal').val()
       data['id'] = $(this).data('id-removal');
  
       $.ajaxSetup({
       beforeSend: function(xhr, settings) {
               if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type) &amp;&amp; !this.crossDomain) {
           xhr.setRequestHeader("X-CSRFToken", data['csrf'])
               }
       }
       });
  
       var remove = confirm('Are you sure?');
       if (remove == true) {
       $.ajax({
               url: "{{ url_for('ctrl.remove_category', _external=True) }}",
               type: 'post',
               dataType: 'json',
               contentType: 'application/json;charset=UTF-8',
               data: JSON.stringify(data, null, '\t'),
           success: function(response) {
           // message to user
           var flash = "&lt;div class='alert alert-" + response['status'] + "'&gt;" +
                       "&lt;button type='button' class='close' data-dismiss='alert'&gt;&amp;times;&lt;/button&gt;" +
                       response['message'] + "&lt;/div&gt;";
           // save message to localStorage
           window.onbeforeunload = function() {
               localStorage.setItem('message', flash);
           }
           // reload the page
           location.reload();
           // jump to the top of the page
           $('html,body').scrollTop(0);
               },
               error: function(jqXHR, textStatus, errorThrown) {
           console.log('Error code: ' + jqXHR.status);
               }
       });
       }
   });
  &lt;/script&gt;
  </code></pre>
  
  <p>This is my view function:</p>
  
  <pre><code>@csrf.exempt # for httpie testing
  @ctrl.route('/remove-category', methods=['POST'])
  #@permission_required(Permission.ADMINISTER) # httpie testing
  def remove_category():
      try:
          id = request.json['id']
          csrf = request.json['csrf']
      except KeyError:
          return jsonify({
              'status': 'error',
              'message': 'Function takes two parameters: '
                         'id of the entry to be removed; csrf token',
          })
  
      category = Category.query.get_or_404(id)
      if category.posts.count():
          status = 'warning'
          message = "Category '{0}' is not empty and cannot be removed".\
                    format(category.title)
      else:
          status = 'success'
          message = "Category '{0}' has been removed".\
                    format(category.title)
          db.session.delete(category)
      return jsonify({
          'status': status,
          'message': message,
      })
  </code></pre>
  
  <p>I'm using jQuery 2.0.3, Flask 0.10.1, Flask-WTF 0.9.4 and Firefox 47.0.
  I'm very new to javascript and cross-browser things related to js, so any help is appreciated.</p>
  
  <p>P.S. I'm aware of <a href="https://stackoverflow.com/questions/16767741/jquerys-ajax-function-works-in-chrome-but-returns-404-in-firefox">this topic</a>, but using <code>accepts</code> with 'application/json' in ajax call didn't help.</p>
  
  <p><strong>UPDATE:</strong> Using DevTools in Chromium and Firebug in Firefox, I copied POST requests from both browsers as cURL commands and compared their results:</p>
  
  <ol>
  <li><p>Chromium (see <a href="https://gist.githubusercontent.com/anonymous/a6da0898f1ed136fffd8eb81fce70f39/raw/7398520797c6ebca2cb64917e13b479be53b08b5/gistfile1.txt" rel="nofollow">gist</a>) works as expected, server gets a request and sends response.</p></li>
  <li><p>Firefox (see <a href="https://gist.githubusercontent.com/anonymous/4c2911c1471bfa8d693654a3ff1a50bb/raw/0f8bc2b73d920d658c646614c22ee557fcd16511/gistfile1.txt" rel="nofollow">gist</a>) doesn't work. Request sent, but response is never received. <code>cURL' is hanging untill I terminate it with</code>^C'. Upon termination I see logs that <code>Werkzeug</code> webserver returns error 400:</p>
  
  <p>127.0.0.1 - - [09/Jul/2016 14:29:01] "POST /ctrl/remove-category HTTP/1.1" 400</p></li>
  </ol>