From 4660ce5a6930e07899ed083801845ee4c44c09df Mon Sep 17 00:00:00 2001
From: CHI Cheng <cloudream@gmail.com>
Date: Wed, 2 May 2018 23:20:04 +1000
Subject: [PATCH] Fixed #29375 -- Removed empty action attribute on HTML forms.

---
 .../ref/class-based-views/generic-editing.txt |  8 ++---
 docs/ref/csrf.txt                             |  4 +--
 docs/topics/forms/formsets.txt                |  6 ++--
 docs/topics/forms/modelforms.txt              |  8 ++---
 .../templates/forms_tests/article_form.html   |  2 +-
 tests/forms_tests/tests/test_forms.py         | 34 +++++++++----------
 tests/templates/form_view.html                |  2 +-
 tests/templates/login.html                    |  2 +-
 tests/test_utils/tests.py                     |  6 ++--
 9 files changed, 36 insertions(+), 36 deletions(-)

diff --git a/docs/ref/class-based-views/generic-editing.txt b/docs/ref/class-based-views/generic-editing.txt
index 8c1fe0f758..969a033a31 100644
--- a/docs/ref/class-based-views/generic-editing.txt
+++ b/docs/ref/class-based-views/generic-editing.txt
@@ -74,7 +74,7 @@ editing content:
 
     .. code-block:: html+django
 
-        <form action="" method="post">{% csrf_token %}
+        <form method="post">{% csrf_token %}
             {{ form.as_p }}
             <input type="submit" value="Send message">
         </form>
@@ -130,7 +130,7 @@ editing content:
 
     .. code-block:: html+django
 
-        <form action="" method="post">{% csrf_token %}
+        <form method="post">{% csrf_token %}
             {{ form.as_p }}
             <input type="submit" value="Save">
         </form>
@@ -187,7 +187,7 @@ editing content:
 
     .. code-block:: html+django
 
-        <form action="" method="post">{% csrf_token %}
+        <form method="post">{% csrf_token %}
             {{ form.as_p }}
             <input type="submit" value="Update">
         </form>
@@ -238,7 +238,7 @@ editing content:
 
     .. code-block:: html+django
 
-        <form action="" method="post">{% csrf_token %}
+        <form method="post">{% csrf_token %}
             <p>Are you sure you want to delete "{{ object }}"?</p>
             <input type="submit" value="Confirm">
         </form>
diff --git a/docs/ref/csrf.txt b/docs/ref/csrf.txt
index fdb373b002..2664a6270f 100644
--- a/docs/ref/csrf.txt
+++ b/docs/ref/csrf.txt
@@ -41,7 +41,7 @@ To take advantage of CSRF protection in your views, follow these steps:
 
    .. code-block:: html+django
 
-       <form action="" method="post">{% csrf_token %}
+       <form method="post">{% csrf_token %}
 
    This should not be done for POST forms that target external URLs, since
    that would cause the CSRF token to be leaked, leading to a vulnerability.
@@ -179,7 +179,7 @@ to ``{% csrf_token %}`` in the Django template language. For example:
 
 .. code-block:: html+jinja
 
-    <form action="" method="post">{{ csrf_input }}
+    <form method="post">{{ csrf_input }}
 
 The decorator method
 --------------------
diff --git a/docs/topics/forms/formsets.txt b/docs/topics/forms/formsets.txt
index cb07e7ad59..eb84da40eb 100644
--- a/docs/topics/forms/formsets.txt
+++ b/docs/topics/forms/formsets.txt
@@ -630,7 +630,7 @@ The ``manage_articles.html`` template might look like this:
 
 .. code-block:: html+django
 
-    <form method="post" action="">
+    <form method="post">
         {{ formset.management_form }}
         <table>
             {% for form in formset %}
@@ -644,7 +644,7 @@ deal with the management form:
 
 .. code-block:: html+django
 
-    <form method="post" action="">
+    <form method="post">
         <table>
             {{ formset }}
         </table>
@@ -662,7 +662,7 @@ If you manually render fields in the template, you can render
 
 .. code-block:: html+django
 
-    <form method="post" action="">
+    <form method="post">
         {{ formset.management_form }}
         {% for form in formset %}
             <ul>
diff --git a/docs/topics/forms/modelforms.txt b/docs/topics/forms/modelforms.txt
index ec7c7a0587..aa3c6855e2 100644
--- a/docs/topics/forms/modelforms.txt
+++ b/docs/topics/forms/modelforms.txt
@@ -1071,14 +1071,14 @@ There are three ways to render a formset in a Django template.
 
 First, you can let the formset do most of the work::
 
-    <form method="post" action="">
+    <form method="post">
         {{ formset }}
     </form>
 
 Second, you can manually render the formset, but let the form deal with
 itself::
 
-    <form method="post" action="">
+    <form method="post">
         {{ formset.management_form }}
         {% for form in formset %}
             {{ form }}
@@ -1091,7 +1091,7 @@ form as shown above. See the :ref:`management form documentation
 
 Third, you can manually render each field::
 
-    <form method="post" action="">
+    <form method="post">
         {{ formset.management_form }}
         {% for form in formset %}
             {% for field in form %}
@@ -1104,7 +1104,7 @@ If you opt to use this third method and you don't iterate over the fields with
 a ``{% for %}`` loop, you'll need to render the primary key field. For example,
 if you were rendering the ``name`` and ``age`` fields of a model::
 
-    <form method="post" action="">
+    <form method="post">
         {{ formset.management_form }}
         {% for form in formset %}
             {{ form.id }}
diff --git a/tests/forms_tests/templates/forms_tests/article_form.html b/tests/forms_tests/templates/forms_tests/article_form.html
index 8ab7a85bb9..3edd8713de 100644
--- a/tests/forms_tests/templates/forms_tests/article_form.html
+++ b/tests/forms_tests/templates/forms_tests/article_form.html
@@ -1,6 +1,6 @@
 <html>
 <body>
-  <form method="post" action="">{% csrf_token %}
+  <form method="post">{% csrf_token %}
     {{ form.as_p }}<br>
     <input id="submit" type="submit">
   </form>
diff --git a/tests/forms_tests/tests/test_forms.py b/tests/forms_tests/tests/test_forms.py
index f603a95a17..914f2b5345 100644
--- a/tests/forms_tests/tests/test_forms.py
+++ b/tests/forms_tests/tests/test_forms.py
@@ -2482,13 +2482,13 @@ Password: <input type="password" name="password" required>
                 return 'VALID: %r' % sorted(form.cleaned_data.items())
 
             t = Template(
-                '<form action="" method="post">\n'
+                '<form method="post">\n'
                 '<table>\n{{ form }}\n</table>\n<input type="submit" required>\n</form>'
             )
             return t.render(Context({'form': form}))
 
         # Case 1: GET (an empty form, with no errors).)
-        self.assertHTMLEqual(my_function('GET', {}), """<form action="" method="post">
+        self.assertHTMLEqual(my_function('GET', {}), """<form method="post">
 <table>
 <tr><th>Username:</th><td><input type="text" name="username" maxlength="10" required></td></tr>
 <tr><th>Password1:</th><td><input type="password" name="password1" required></td></tr>
@@ -2499,7 +2499,7 @@ Password: <input type="password" name="password" required>
         # Case 2: POST with erroneous data (a redisplayed form, with errors).)
         self.assertHTMLEqual(
             my_function('POST', {'username': 'this-is-a-long-username', 'password1': 'foo', 'password2': 'bar'}),
-            """<form action="" method="post">
+            """<form method="post">
 <table>
 <tr><td colspan="2"><ul class="errorlist nonfield"><li>Please make sure your passwords match.</li></ul></td></tr>
 <tr><th>Username:</th><td><ul class="errorlist">
@@ -2535,13 +2535,13 @@ Password: <input type="password" name="password" required>
         # fields. Note, however, that this flexibility comes with the responsibility of
         # displaying all the errors, including any that might not be associated with a
         # particular field.
-        t = Template('''<form action="">
+        t = Template('''<form>
 {{ form.username.errors.as_ul }}<p><label>Your username: {{ form.username }}</label></p>
 {{ form.password1.errors.as_ul }}<p><label>Password: {{ form.password1 }}</label></p>
 {{ form.password2.errors.as_ul }}<p><label>Password (again): {{ form.password2 }}</label></p>
 <input type="submit" required>
 </form>''')
-        self.assertHTMLEqual(t.render(Context({'form': UserRegistration(auto_id=False)})), """<form action="">
+        self.assertHTMLEqual(t.render(Context({'form': UserRegistration(auto_id=False)})), """<form>
 <p><label>Your username: <input type="text" name="username" maxlength="10" required></label></p>
 <p><label>Password: <input type="password" name="password1" required></label></p>
 <p><label>Password (again): <input type="password" name="password2" required></label></p>
@@ -2549,7 +2549,7 @@ Password: <input type="password" name="password" required>
 </form>""")
         self.assertHTMLEqual(
             t.render(Context({'form': UserRegistration({'username': 'django'}, auto_id=False)})),
-            """<form action="">
+            """<form>
 <p><label>Your username: <input type="text" name="username" value="django" maxlength="10" required></label></p>
 <ul class="errorlist"><li>This field is required.</li></ul><p>
 <label>Password: <input type="password" name="password1" required></label></p>
@@ -2563,13 +2563,13 @@ Password: <input type="password" name="password" required>
         # a field by using the 'label' argument to a Field class. If you don't specify
         # 'label', Django will use the field name with underscores converted to spaces,
         # and the initial letter capitalized.
-        t = Template('''<form action="">
+        t = Template('''<form>
 <p><label>{{ form.username.label }}: {{ form.username }}</label></p>
 <p><label>{{ form.password1.label }}: {{ form.password1 }}</label></p>
 <p><label>{{ form.password2.label }}: {{ form.password2 }}</label></p>
 <input type="submit" required>
 </form>''')
-        self.assertHTMLEqual(t.render(Context({'form': UserRegistration(auto_id=False)})), """<form action="">
+        self.assertHTMLEqual(t.render(Context({'form': UserRegistration(auto_id=False)})), """<form>
 <p><label>Username: <input type="text" name="username" maxlength="10" required></label></p>
 <p><label>Password1: <input type="password" name="password1" required></label></p>
 <p><label>Password2: <input type="password" name="password2" required></label></p>
@@ -2580,19 +2580,19 @@ Password: <input type="password" name="password" required>
         # wrapped around it, but *only* if the given field has an "id" attribute.
         # Recall from above that passing the "auto_id" argument to a Form gives each
         # field an "id" attribute.
-        t = Template('''<form action="">
+        t = Template('''<form>
 <p>{{ form.username.label_tag }} {{ form.username }}</p>
 <p>{{ form.password1.label_tag }} {{ form.password1 }}</p>
 <p>{{ form.password2.label_tag }} {{ form.password2 }}</p>
 <input type="submit" required>
 </form>''')
-        self.assertHTMLEqual(t.render(Context({'form': UserRegistration(auto_id=False)})), """<form action="">
+        self.assertHTMLEqual(t.render(Context({'form': UserRegistration(auto_id=False)})), """<form>
 <p>Username: <input type="text" name="username" maxlength="10" required></p>
 <p>Password1: <input type="password" name="password1" required></p>
 <p>Password2: <input type="password" name="password2" required></p>
 <input type="submit" required>
 </form>""")
-        self.assertHTMLEqual(t.render(Context({'form': UserRegistration(auto_id='id_%s')})), """<form action="">
+        self.assertHTMLEqual(t.render(Context({'form': UserRegistration(auto_id='id_%s')})), """<form>
 <p><label for="id_username">Username:</label>
 <input id="id_username" type="text" name="username" maxlength="10" required></p>
 <p><label for="id_password1">Password1:</label>
@@ -2604,7 +2604,7 @@ Password: <input type="password" name="password" required>
 
         # User form.[field].help_text to output a field's help text. If the given field
         # does not have help text, nothing will be output.
-        t = Template('''<form action="">
+        t = Template('''<form>
 <p>{{ form.username.label_tag }} {{ form.username }}<br>{{ form.username.help_text }}</p>
 <p>{{ form.password1.label_tag }} {{ form.password1 }}</p>
 <p>{{ form.password2.label_tag }} {{ form.password2 }}</p>
@@ -2612,7 +2612,7 @@ Password: <input type="password" name="password" required>
 </form>''')
         self.assertHTMLEqual(
             t.render(Context({'form': UserRegistration(auto_id=False)})),
-            """<form action="">
+            """<form>
 <p>Username: <input type="text" name="username" maxlength="10" required><br>
 Good luck picking a username that doesn&#39;t already exist.</p>
 <p>Password1: <input type="password" name="password1" required></p>
@@ -2629,7 +2629,7 @@ Good luck picking a username that doesn&#39;t already exist.</p>
         # the errors caused by Form.clean() -- use {{ form.non_field_errors }} in the
         # template. If used on its own, it is displayed as a <ul> (or an empty string, if
         # the list of errors is empty). You can also use it in {% if %} statements.
-        t = Template('''<form action="">
+        t = Template('''<form>
 {{ form.username.errors.as_ul }}<p><label>Your username: {{ form.username }}</label></p>
 {{ form.password1.errors.as_ul }}<p><label>Password: {{ form.password1 }}</label></p>
 {{ form.password2.errors.as_ul }}<p><label>Password (again): {{ form.password2 }}</label></p>
@@ -2639,14 +2639,14 @@ Good luck picking a username that doesn&#39;t already exist.</p>
             t.render(Context({
                 'form': UserRegistration({'username': 'django', 'password1': 'foo', 'password2': 'bar'}, auto_id=False)
             })),
-            """<form action="">
+            """<form>
 <p><label>Your username: <input type="text" name="username" value="django" maxlength="10" required></label></p>
 <p><label>Password: <input type="password" name="password1" required></label></p>
 <p><label>Password (again): <input type="password" name="password2" required></label></p>
 <input type="submit" required>
 </form>"""
         )
-        t = Template('''<form action="">
+        t = Template('''<form>
 {{ form.non_field_errors }}
 {{ form.username.errors.as_ul }}<p><label>Your username: {{ form.username }}</label></p>
 {{ form.password1.errors.as_ul }}<p><label>Password: {{ form.password1 }}</label></p>
@@ -2657,7 +2657,7 @@ Good luck picking a username that doesn&#39;t already exist.</p>
             t.render(Context({
                 'form': UserRegistration({'username': 'django', 'password1': 'foo', 'password2': 'bar'}, auto_id=False)
             })),
-            """<form action="">
+            """<form>
 <ul class="errorlist nonfield"><li>Please make sure your passwords match.</li></ul>
 <p><label>Your username: <input type="text" name="username" value="django" maxlength="10" required></label></p>
 <p><label>Password: <input type="password" name="password1" required></label></p>
diff --git a/tests/templates/form_view.html b/tests/templates/form_view.html
index 1ef410fb71..16945a018c 100644
--- a/tests/templates/form_view.html
+++ b/tests/templates/form_view.html
@@ -2,7 +2,7 @@
 {% block title %}Submit data{% endblock %}
 {% block content %}
 <h1>{{ message }}</h1>
-<form method="post" action="">
+<form method="post">
 {% if form.errors %}
 <p class='warning'>Please correct the errors below:</p>
 {% endif %}
diff --git a/tests/templates/login.html b/tests/templates/login.html
index d9909aea60..ddc3224009 100644
--- a/tests/templates/login.html
+++ b/tests/templates/login.html
@@ -5,7 +5,7 @@
 <p>Your username and password didn't match. Please try again.</p>
 {% endif %}
 
-<form method="post" action="">
+<form method="post">
 <table>
 <tr><td><label for="id_username">Username:</label></td><td>{{ form.username }}</td></tr>
 <tr><td><label for="id_password">Password:</label></td><td>{{ form.password }}</td></tr>
diff --git a/tests/test_utils/tests.py b/tests/test_utils/tests.py
index ff0bda6b8d..dbb6cd573f 100644
--- a/tests/test_utils/tests.py
+++ b/tests/test_utils/tests.py
@@ -691,15 +691,15 @@ class HTMLEqualTests(SimpleTestCase):
 
     def test_contains_html(self):
         response = HttpResponse('''<body>
-        This is a form: <form action="" method="get">
+        This is a form: <form method="get">
             <input type="text" name="Hello" />
         </form></body>''')
 
         self.assertNotContains(response, "<input name='Hello' type='text'>")
-        self.assertContains(response, '<form action="" method="get">')
+        self.assertContains(response, '<form method="get">')
 
         self.assertContains(response, "<input name='Hello' type='text'>", html=True)
-        self.assertNotContains(response, '<form action="" method="get">', html=True)
+        self.assertNotContains(response, '<form method="get">', html=True)
 
         invalid_response = HttpResponse('''<body <bad>>''')