Skip to content

Commit

Permalink
Don't copy request data or body on newRequest()
Browse files Browse the repository at this point in the history
Enables multi-step forms, or requests after a form submission, without sending data from earlier submissions.

Fixes #1778
  • Loading branch information
jhy committed Jan 20, 2023
1 parent 9127dba commit a242df8
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 3 deletions.
6 changes: 6 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ Release 1.15.4 [PENDING]
* Bugfix: if a Node or an Element was replaced with itself, that node would incorrectly be orphaned.
<https://github.com/jhy/jsoup/issues/1843>

* Bugfix: form data on a previous request was copied to a new request in newRequest(), resulting in an accumulation of
form data when executing multi-step form submissions, or data sent to later requests incorrectly. Now, newRequest()
only copies session related settings (cookies, proxy settings, user-agent, etc) but not the request data nor the
body.
<https://github.com/jhy/jsoup/issues/1778>

Release 1.15.3 [2022-Aug-24]
* Security: fixed an issue where the jsoup cleaner may incorrectly sanitize crafted XSS attempts if
SafeList.preserveRelativeLinks is enabled.
Expand Down
7 changes: 4 additions & 3 deletions src/main/java/org/jsoup/helper/HttpConnection.java
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ public HttpConnection() {
}

/**
Create a new Request by deep-copying an existing Request
Create a new Request by deep-copying an existing Request. Note that the data and body of the original are not
copied. All other settings (proxy, parser, cookies, etc) are copied.
@param copy the request to copy
*/
HttpConnection(Request copy) {
Expand Down Expand Up @@ -666,8 +667,8 @@ public static class Request extends HttpConnection.Base<Connection.Request> impl
timeoutMilliseconds = copy.timeoutMilliseconds;
maxBodySizeBytes = copy.maxBodySizeBytes;
followRedirects = copy.followRedirects;
data = new ArrayList<>(); data.addAll(copy.data()); // this is shallow, but holds immutable string keyval, and possibly an InputStream which can only be read once anyway, so using as a prototype would be unsupported
body = copy.body;
data = new ArrayList<>(); // data not copied
//body not copied
ignoreHttpErrors = copy.ignoreHttpErrors;
ignoreContentType = copy.ignoreContentType;
parser = copy.parser.newInstance(); // parsers and their tree-builders maintain state, so need a fresh copy
Expand Down
60 changes: 60 additions & 0 deletions src/test/java/org/jsoup/integration/ConnectTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -682,4 +682,64 @@ public void maxBodySizeInReadToByteBuffer() throws IOException {
assertEquals(actualDocText, largeRes.body().length());
assertEquals(actualDocText, unlimitedRes.body().length());
}

@Test void formLoginFlow() throws IOException {
String echoUrl = EchoServlet.Url;
String cookieUrl = CookieServlet.Url;

String startUrl = FileServlet.urlTo("/htmltests/form-tests.html");
Document loginDoc = Jsoup.connect(startUrl).get();
FormElement form = loginDoc.select("#login").forms().get(0);
assertNotNull(form);
form.expectFirst("[name=username]").val("admin");
form.expectFirst("[name=password]").val("Netscape engineers are weenies!");

// post it- should go to Cookie then bounce to Echo
Connection submit = form.submit();
assertEquals(Connection.Method.POST, submit.request().method());
Connection.Response postRes = submit.execute();
assertEquals(echoUrl, postRes.url().toExternalForm());
assertEquals(Connection.Method.GET, postRes.method());
Document resultDoc = postRes.parse();
assertEquals("One=EchoServlet; One=Root", ihVal("Cookie", resultDoc));
// should be no form data sent to the echo redirect
assertEquals("", ihVal("Query String", resultDoc));

// new request to echo, should not have form data, but should have cookies from implicit session
Document newEcho = submit.newRequest().url(echoUrl).get();
assertEquals("One=EchoServlet; One=Root", ihVal("Cookie", newEcho));
assertEquals("", ihVal("Query String", newEcho));

Document cookieDoc = submit.newRequest().url(cookieUrl).get();
assertEquals("CookieServlet", ihVal("One", cookieDoc)); // different cookie path

}

@Test void formLoginFlow2() throws IOException {
String echoUrl = EchoServlet.Url;
String cookieUrl = CookieServlet.Url;
String startUrl = FileServlet.urlTo("/htmltests/form-tests.html");

Connection session = Jsoup.newSession();
Document loginDoc = session.newRequest().url(startUrl).get();
FormElement form = loginDoc.select("#login2").forms().get(0);
assertNotNull(form);
String username = "admin";
form.expectFirst("[name=username]").val(username);
String password = "Netscape engineers are weenies!";
form.expectFirst("[name=password]").val(password);

Connection submit = form.submit();
assertEquals(username, submit.data("username").value());
assertEquals(password, submit.data("password").value());

Connection.Response postRes = submit.execute();
assertEquals(cookieUrl, postRes.url().toExternalForm());
assertEquals(Connection.Method.POST, postRes.method());
Document resultDoc = postRes.parse();

Document echo2 = resultDoc.connection().newRequest().url(echoUrl).get();
assertEquals("", ihVal("Query String", echo2)); // should not re-send the data
assertEquals("One=EchoServlet; One=Root", ihVal("Cookie", echo2));
}
}
16 changes: 16 additions & 0 deletions src/test/resources/htmltests/form-tests.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<title>Form test</title>

<form id="login" action="/CookieServlet" method="post">
<input name="setCookies" value="1" type="hidden">
<input name="loc" value="/EchoServlet" type="hidden">

Username: <input name="username"><br>
Password: <input name="password" type="password">
</form>

<form id="login2" action="/CookieServlet" method="post">
<input name="setCookies" value="1" type="hidden">

Username: <input name="username"><br>
Password: <input name="password" type="password">
</form>

0 comments on commit a242df8

Please sign in to comment.