diff -Nru jetty9-9.4.51/aggregates/jetty-all/pom.xml jetty9-9.4.53/aggregates/jetty-all/pom.xml --- jetty9-9.4.51/aggregates/jetty-all/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/aggregates/jetty-all/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 ../../pom.xml 4.0.0 diff -Nru jetty9-9.4.51/aggregates/jetty-all-compact3/pom.xml jetty9-9.4.53/aggregates/jetty-all-compact3/pom.xml --- jetty9-9.4.51/aggregates/jetty-all-compact3/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/aggregates/jetty-all-compact3/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 ../../pom.xml 4.0.0 diff -Nru jetty9-9.4.51/apache-jsp/pom.xml jetty9-9.4.53/apache-jsp/pom.xml --- jetty9-9.4.51/apache-jsp/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/apache-jsp/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 apache-jsp diff -Nru jetty9-9.4.51/apache-jstl/pom.xml jetty9-9.4.53/apache-jstl/pom.xml --- jetty9-9.4.51/apache-jstl/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/apache-jstl/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 apache-jstl diff -Nru jetty9-9.4.51/build-resources/pom.xml jetty9-9.4.53/build-resources/pom.xml --- jetty9-9.4.51/build-resources/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/build-resources/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ 4.0.0 org.eclipse.jetty build-resources - 9.4.51.v20230217 + 9.4.53.v20231009 jar Jetty :: Build Resources diff -Nru jetty9-9.4.51/CODE_OF_CONDUCT.md jetty9-9.4.53/CODE_OF_CONDUCT.md --- jetty9-9.4.51/CODE_OF_CONDUCT.md 1970-01-01 00:00:00.000000000 +0000 +++ jetty9-9.4.53/CODE_OF_CONDUCT.md 2023-10-09 12:27:40.000000000 +0000 @@ -0,0 +1,93 @@ +# Community Code of Conduct + +**Version 2.0 +January 1, 2023** + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as community members, contributors, Committers[^1], and Project Leads (collectively "Contributors") pledge to make participation in our projects and our community a harassment-free and inclusive experience for everyone. + +This Community Code of Conduct ("Code") outlines our behavior expectations as members of our community in all Eclipse Foundation activities, both offline and online. It is not intended to govern scenarios or behaviors outside of the scope of Eclipse Foundation activities. Nor is it intended to replace or supersede the protections offered to all our community members under the law. Please follow both the spirit and letter of this Code and encourage other Contributors to follow these principles into our work. Failure to read or acknowledge this Code does not excuse a Contributor from compliance with the Code. + +## Our Standards + +Examples of behavior that contribute to creating a positive and professional environment include: + +- Using welcoming and inclusive language; +- Actively encouraging all voices; +- Helping others bring their perspectives and listening actively. If you find yourself dominating a discussion, it is especially important to encourage other voices to join in; +- Being respectful of differing viewpoints and experiences; +- Gracefully accepting constructive criticism; +- Focusing on what is best for the community; +- Showing empathy towards other community members; +- Being direct but professional; and +- Leading by example by holding yourself and others accountable + +Examples of unacceptable behavior by Contributors include: + +- The use of sexualized language or imagery; +- Unwelcome sexual attention or advances; +- Trolling, insulting/derogatory comments, and personal or political attacks; +- Public or private harassment, repeated harassment; +- Publishing others' private information, such as a physical or electronic address, without explicit permission; +- Violent threats or language directed against another person; +- Sexist, racist, or otherwise discriminatory jokes and language; +- Posting sexually explicit or violent material; +- Sharing private content, such as emails sent privately or non-publicly, or unlogged forums such as IRC channel history; +- Personal insults, especially those using racist or sexist terms; +- Excessive or unnecessary profanity; +- Advocating for, or encouraging, any of the above behavior; and +- Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +With the support of the Eclipse Foundation employees, consultants, officers, and directors (collectively, the "Staff"), Committers, and Project Leads, the Eclipse Foundation Conduct Committee (the "Conduct Committee") is responsible for clarifying the standards of acceptable behavior. The Conduct Committee takes appropriate and fair corrective action in response to any instances of unacceptable behavior. + +## Scope + +This Code applies within all Project, Working Group, and Interest Group spaces and communication channels of the Eclipse Foundation (collectively, "Eclipse spaces"), within any Eclipse-organized event or meeting, and in public spaces when an individual is representing an Eclipse Foundation Project, Working Group, Interest Group, or their communities. Examples of representing a Project or community include posting via an official social media account, personal accounts, or acting as an appointed representative at an online or offline event. Representation of Projects, Working Groups, and Interest Groups may be further defined and clarified by Committers, Project Leads, or the Staff. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the Conduct Committee via conduct@eclipse-foundation.org. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. Without the explicit consent of the reporter, the Conduct Committee is obligated to maintain confidentiality with regard to the reporter of an incident. The Conduct Committee is further obligated to ensure that the respondent is provided with sufficient information about the complaint to reply. If such details cannot be provided while maintaining confidentiality, the Conduct Committee will take the respondent‘s inability to provide a defense into account in its deliberations and decisions. Further details of enforcement guidelines may be posted separately. + +Staff, Committers and Project Leads have the right to report, remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code, or to block temporarily or permanently any Contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. Any such actions will be reported to the Conduct Committee for transparency and record keeping. + +Any Staff (including officers and directors of the Eclipse Foundation), Committers, Project Leads, or Conduct Committee members who are the subject of a complaint to the Conduct Committee will be recused from the process of resolving any such complaint. + +## Responsibility + +The responsibility for administering this Code rests with the Conduct Committee, with oversight by the Executive Director and the Board of Directors. For additional information on the Conduct Committee and its process, please write to . + +## Investigation of Potential Code Violations + +All conflict is not bad as a healthy debate may sometimes be necessary to push us to do our best. It is, however, unacceptable to be disrespectful or offensive, or violate this Code. If you see someone engaging in objectionable behavior violating this Code, we encourage you to address the behavior directly with those involved. If for some reason, you are unable to resolve the matter or feel uncomfortable doing so, or if the behavior is threatening or harassing, please report it following the procedure laid out below. + +Reports should be directed to . It is the Conduct Committee’s role to receive and address reported violations of this Code and to ensure a fair and speedy resolution. + +The Eclipse Foundation takes all reports of potential Code violations seriously and is committed to confidentiality and a full investigation of all allegations. The identity of the reporter will be omitted from the details of the report supplied to the accused. Contributors who are being investigated for a potential Code violation will have an opportunity to be heard prior to any final determination. Those found to have violated the Code can seek reconsideration of the violation and disciplinary action decisions. Every effort will be made to have all matters disposed of within 60 days of the receipt of the complaint. + +## Actions +Contributors who do not follow this Code in good faith may face temporary or permanent repercussions as determined by the Conduct Committee. + +This Code does not address all conduct. It works in conjunction with our [Communication Channel Guidelines](https://www.eclipse.org/org/documents/communication-channel-guidelines/), [Social Media Guidelines](https://www.eclipse.org/org/documents/social_media_guidelines.php), [Bylaws](https://www.eclipse.org/org/documents/eclipse-foundation-be-bylaws-en.pdf), and [Internal Rules](https://www.eclipse.org/org/documents/ef-be-internal-rules.pdf) which set out additional protections for, and obligations of, all contributors. The Foundation has additional policies that provide further guidance on other matters. + +It’s impossible to spell out every possible scenario that might be deemed a violation of this Code. Instead, we rely on one another’s good judgment to uphold a high standard of integrity within all Eclipse Spaces. Sometimes, identifying the right thing to do isn’t an easy call. In such a scenario, raise the issue as early as possible. + +## No Retaliation + +The Eclipse community relies upon and values the help of Contributors who identify potential problems that may need to be addressed within an Eclipse Space. Any retaliation against a Contributor who raises an issue honestly is a violation of this Code. That a Contributor has raised a concern honestly or participated in an investigation, cannot be the basis for any adverse action, including threats, harassment, or discrimination. If you work with someone who has raised a concern or provided information in an investigation, you should continue to treat the person with courtesy and respect. If you believe someone has retaliated against you, report the matter as described by this Code. Honest reporting does not mean that you have to be right when you raise a concern; you just have to believe that the information you are providing is accurate. + +False reporting, especially when intended to retaliate or exclude, is itself a violation of this Code and will not be accepted or tolerated. + +Everyone is encouraged to ask questions about this Code. Your feedback is welcome, and you will get a response within three business days. Write to . + +## Amendments + +The Eclipse Foundation Board of Directors may amend this Code from time to time and may vary the procedures it sets out where appropriate in a particular case. + +### Attribution + +This Code was inspired by the [Contributor Covenant](https://www.contributor-covenant.org/), version 1.4, available [here](https://www.contributor-covenant.org/version/1/4/code-of-conduct/). + +[^1]: Capitalized terms used herein without definition shall have the meanings assigned to them in the Bylaws. \ No newline at end of file diff -Nru jetty9-9.4.51/debian/changelog jetty9-9.4.53/debian/changelog --- jetty9-9.4.51/debian/changelog 2023-05-27 14:47:13.000000000 +0000 +++ jetty9-9.4.53/debian/changelog 2023-10-09 21:07:28.000000000 +0000 @@ -1,3 +1,17 @@ +jetty9 (9.4.53-1) unstable; urgency=medium + + * New upstream release + + -- Emmanuel Bourg Mon, 09 Oct 2023 23:07:28 +0200 + +jetty9 (9.4.52-1) unstable; urgency=medium + + * Team upload. + * New upstream version 9.4.52. + * Refresh the patches. + + -- Markus Koschany Sun, 24 Sep 2023 01:40:05 +0200 + jetty9 (9.4.51-2) experimental; urgency=medium * Team upload. @@ -5,12 +19,20 @@ -- Markus Koschany Sat, 27 May 2023 16:47:13 +0200 +jetty9 (9.4.50-4) unstable; urgency=medium + + * Team upload. + * Revert the switch to libtomcat10-java. For now Jetty 9 only works correctly + with libtomcat9-java. (Closes: #1036798) + + -- Markus Koschany Sat, 27 May 2023 16:28:19 +0200 + jetty9 (9.4.51-1) experimental; urgency=medium * Team upload. * New upstream release. * Replace dependency on lsb-base with sysvinit-utils. - - Fix: litian error depends-on-obsolete-package. + - Fix: lintian error depends-on-obsolete-package. * Add a systemd timer for debian/jetty9.service. - Fix: lintian warning missing-systemd-timer-for-cron-script. * Fix lintian warning skip-systemd-native-flag-missing-pre-depends. diff -Nru jetty9-9.4.51/debian/copyright jetty9-9.4.53/debian/copyright --- jetty9-9.4.51/debian/copyright 2023-05-27 14:47:13.000000000 +0000 +++ jetty9-9.4.53/debian/copyright 2023-10-09 20:50:53.000000000 +0000 @@ -6,7 +6,7 @@ jetty-unixsocket/src/test/resources/haproxy Files: * -Copyright: 2006-2022, Mort Bay Consulting Pty. Ltd. +Copyright: 2006-2023, Mort Bay Consulting Pty. Ltd. License: Apache-2.0 or EPL-1.0 Files: jetty-ant/src/main/java/org/eclipse/jetty/ant/utils/TaskLog.java diff -Nru jetty9-9.4.51/debian/patches/01-maven-bundle-plugin-version.patch jetty9-9.4.53/debian/patches/01-maven-bundle-plugin-version.patch --- jetty9-9.4.51/debian/patches/01-maven-bundle-plugin-version.patch 2023-05-27 14:47:13.000000000 +0000 +++ jetty9-9.4.53/debian/patches/01-maven-bundle-plugin-version.patch 2023-10-09 20:50:53.000000000 +0000 @@ -8,7 +8,7 @@ --- a/pom.xml +++ b/pom.xml -@@ -436,6 +436,7 @@ +@@ -437,6 +437,7 @@ org.apache.felix maven-bundle-plugin diff -Nru jetty9-9.4.51/debian/patches/02-import-alpn-api.patch jetty9-9.4.53/debian/patches/02-import-alpn-api.patch --- jetty9-9.4.51/debian/patches/02-import-alpn-api.patch 2023-05-27 14:47:13.000000000 +0000 +++ jetty9-9.4.53/debian/patches/02-import-alpn-api.patch 2023-10-09 20:50:53.000000000 +0000 @@ -11,9 +11,6 @@ create mode 100644 jetty-alpn/jetty-alpn-api/pom.xml create mode 100644 jetty-alpn/jetty-alpn-api/src/main/java/org/eclipse/jetty/alpn/ALPN.java -diff --git a/jetty-alpn/jetty-alpn-api/pom.xml b/jetty-alpn/jetty-alpn-api/pom.xml -new file mode 100644 -index 0000000..4b3b511 --- /dev/null +++ b/jetty-alpn/jetty-alpn-api/pom.xml @@ -0,0 +1,117 @@ @@ -134,9 +131,6 @@ + + + -diff --git a/jetty-alpn/jetty-alpn-api/src/main/java/org/eclipse/jetty/alpn/ALPN.java b/jetty-alpn/jetty-alpn-api/src/main/java/org/eclipse/jetty/alpn/ALPN.java -new file mode 100644 -index 0000000..8a40558 --- /dev/null +++ b/jetty-alpn/jetty-alpn-api/src/main/java/org/eclipse/jetty/alpn/ALPN.java @@ -0,0 +1,249 @@ @@ -389,8 +383,6 @@ + } +} + -diff --git a/jetty-alpn/pom.xml b/jetty-alpn/pom.xml -index 73b2b73..ebf2eaa 100644 --- a/jetty-alpn/pom.xml +++ b/jetty-alpn/pom.xml @@ -10,6 +10,7 @@ diff -Nru jetty9-9.4.51/debian/patches/04-weksocket-1.1-compatibility.patch jetty9-9.4.53/debian/patches/04-weksocket-1.1-compatibility.patch --- jetty9-9.4.51/debian/patches/04-weksocket-1.1-compatibility.patch 2023-05-27 14:47:13.000000000 +0000 +++ jetty9-9.4.53/debian/patches/04-weksocket-1.1-compatibility.patch 2023-10-09 20:50:53.000000000 +0000 @@ -7,15 +7,12 @@ .../java/org/eclipse/jetty/websocket/jsr356/JsrSession.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) -diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrSession.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrSession.java -index c567a1f..3c1ca80 100644 --- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrSession.java +++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/JsrSession.java -@@ -144,6 +144,18 @@ public class JsrSession extends WebSocketSession implements javax.websocket.Sess - } +@@ -145,6 +145,18 @@ public class JsrSession extends WebSocke } -+ @Override + @Override + public void addMessageHandler(Class clazz, MessageHandler.Partial handler) throws IllegalStateException + { + throw new UnsupportedOperationException(); @@ -27,6 +24,7 @@ + throw new UnsupportedOperationException(); + } + - @Override ++ @Override public void close(CloseReason closeReason) throws IOException { + close(closeReason.getCloseCode().getCode(), closeReason.getReasonPhrase()); diff -Nru jetty9-9.4.51/debian/patches/06-ignore-jetty-documentation.patch jetty9-9.4.53/debian/patches/06-ignore-jetty-documentation.patch --- jetty9-9.4.51/debian/patches/06-ignore-jetty-documentation.patch 2023-05-27 14:47:13.000000000 +0000 +++ jetty9-9.4.53/debian/patches/06-ignore-jetty-documentation.patch 2023-10-09 20:50:53.000000000 +0000 @@ -10,7 +10,7 @@ --- a/pom.xml +++ b/pom.xml -@@ -221,7 +221,6 @@ +@@ -222,7 +222,6 @@ jetty-alpn jetty-home jetty-bom diff -Nru jetty9-9.4.51/debian/patches/07-assembly-plugin-configuration.patch jetty9-9.4.53/debian/patches/07-assembly-plugin-configuration.patch --- jetty9-9.4.51/debian/patches/07-assembly-plugin-configuration.patch 2023-05-27 14:47:13.000000000 +0000 +++ jetty9-9.4.53/debian/patches/07-assembly-plugin-configuration.patch 2023-10-09 20:50:53.000000000 +0000 @@ -14,7 +14,7 @@ --- a/jetty-cdi/pom.xml +++ b/jetty-cdi/pom.xml -@@ -60,9 +60,9 @@ +@@ -70,9 +70,9 @@ single @@ -44,7 +44,7 @@ --- a/pom.xml +++ b/pom.xml -@@ -1364,9 +1364,9 @@ +@@ -1370,9 +1370,9 @@ single diff -Nru jetty9-9.4.51/debian/patches/08-ignore-jetty-test-policy.patch jetty9-9.4.53/debian/patches/08-ignore-jetty-test-policy.patch --- jetty9-9.4.51/debian/patches/08-ignore-jetty-test-policy.patch 2023-05-27 14:47:13.000000000 +0000 +++ jetty9-9.4.53/debian/patches/08-ignore-jetty-test-policy.patch 2023-10-09 20:50:53.000000000 +0000 @@ -8,8 +8,6 @@ jetty-client/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) -diff --git a/jetty-client/pom.xml b/jetty-client/pom.xml -index ac6bfd0..3ae9d0e 100644 --- a/jetty-client/pom.xml +++ b/jetty-client/pom.xml @@ -21,7 +21,7 @@ diff -Nru jetty9-9.4.51/debian/patches/09-tweak-distribution.patch jetty9-9.4.53/debian/patches/09-tweak-distribution.patch --- jetty9-9.4.51/debian/patches/09-tweak-distribution.patch 2023-05-27 14:47:13.000000000 +0000 +++ jetty9-9.4.53/debian/patches/09-tweak-distribution.patch 2023-10-09 20:50:53.000000000 +0000 @@ -9,8 +9,6 @@ jetty-home/pom.xml | 20 ++++++-------------- 2 files changed, 12 insertions(+), 20 deletions(-) -diff --git a/jetty-distribution/pom.xml b/jetty-distribution/pom.xml -index 6de9e06..9f1c398 100644 --- a/jetty-distribution/pom.xml +++ b/jetty-distribution/pom.xml @@ -75,7 +75,7 @@ @@ -67,16 +65,12 @@ unpack -diff --git a/jetty-home/pom.xml b/jetty-home/pom.xml -index 6b3f176..90471d7 100644 --- a/jetty-home/pom.xml +++ b/jetty-home/pom.xml -@@ -78,16 +78,6 @@ - - +@@ -80,16 +80,6 @@ -- -- org.eclipse.jetty + + org.eclipse.jetty - jetty-project - ${project.version} - version @@ -85,9 +79,11 @@ - ${assembly-directory}/ - VERSION.txt - - - org.eclipse.jetty +- +- org.eclipse.jetty jetty-start + ${project.version} + shaded @@ -104,7 +94,7 @@ diff -Nru jetty9-9.4.51/debian/patches/servlet-api.patch jetty9-9.4.53/debian/patches/servlet-api.patch --- jetty9-9.4.51/debian/patches/servlet-api.patch 2023-05-27 14:47:13.000000000 +0000 +++ jetty9-9.4.53/debian/patches/servlet-api.patch 2023-10-09 20:50:53.000000000 +0000 @@ -7,8 +7,6 @@ jetty-home/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) -diff --git a/jetty-home/pom.xml b/jetty-home/pom.xml -index 90471d7..fee2898 100644 --- a/jetty-home/pom.xml +++ b/jetty-home/pom.xml @@ -284,10 +284,10 @@ diff -Nru jetty9-9.4.51/examples/async-rest/async-rest-jar/pom.xml jetty9-9.4.53/examples/async-rest/async-rest-jar/pom.xml --- jetty9-9.4.51/examples/async-rest/async-rest-jar/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/examples/async-rest/async-rest-jar/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty example-async-rest - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 diff -Nru jetty9-9.4.51/examples/async-rest/async-rest-webapp/pom.xml jetty9-9.4.53/examples/async-rest/async-rest-webapp/pom.xml --- jetty9-9.4.51/examples/async-rest/async-rest-webapp/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/examples/async-rest/async-rest-webapp/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty example-async-rest - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 diff -Nru jetty9-9.4.51/examples/async-rest/pom.xml jetty9-9.4.53/examples/async-rest/pom.xml --- jetty9-9.4.51/examples/async-rest/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/examples/async-rest/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty.examples examples-parent - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 diff -Nru jetty9-9.4.51/examples/embedded/pom.xml jetty9-9.4.53/examples/embedded/pom.xml --- jetty9-9.4.51/examples/embedded/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/examples/embedded/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty.examples examples-parent - 9.4.51.v20230217 + 9.4.53.v20231009 ../pom.xml 4.0.0 diff -Nru jetty9-9.4.51/examples/pom.xml jetty9-9.4.53/examples/pom.xml --- jetty9-9.4.51/examples/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/examples/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 diff -Nru jetty9-9.4.51/Jenkinsfile jetty9-9.4.53/Jenkinsfile --- jetty9-9.4.51/Jenkinsfile 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/Jenkinsfile 2023-10-09 12:27:40.000000000 +0000 @@ -110,7 +110,7 @@ "MAVEN_OPTS=-Xms2g -Xmx4g -Djava.awt.headless=true"]) { configFileProvider( [configFile(fileId: 'oss-settings.xml', variable: 'GLOBAL_MVN_SETTINGS')]) { - sh "mvn --no-transfer-progress -s $GLOBAL_MVN_SETTINGS -Dmaven.repo.local=.repository -Pci -DexcludedGroups=\"external, large-disk-resource, stress, slow\" -V -B -e -Djetty.testtracker.log=true $cmdline -Dunix.socket.tmp=/tmp/unixsocket" + sh "mvn --no-transfer-progress -s $GLOBAL_MVN_SETTINGS -Dmaven.repo.local=.repository -Pci -V -B -e $cmdline -Dunix.socket.tmp=/tmp/unixsocket" } } } diff -Nru jetty9-9.4.51/jetty-alpn/jetty-alpn-client/pom.xml jetty9-9.4.53/jetty-alpn/jetty-alpn-client/pom.xml --- jetty9-9.4.51/jetty-alpn/jetty-alpn-client/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-alpn/jetty-alpn-client/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-alpn-parent - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 jetty-alpn-client diff -Nru jetty9-9.4.51/jetty-alpn/jetty-alpn-conscrypt-client/pom.xml jetty9-9.4.53/jetty-alpn/jetty-alpn-conscrypt-client/pom.xml --- jetty9-9.4.51/jetty-alpn/jetty-alpn-conscrypt-client/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-alpn/jetty-alpn-conscrypt-client/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -4,7 +4,7 @@ org.eclipse.jetty jetty-alpn-parent - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 diff -Nru jetty9-9.4.51/jetty-alpn/jetty-alpn-conscrypt-server/pom.xml jetty9-9.4.53/jetty-alpn/jetty-alpn-conscrypt-server/pom.xml --- jetty9-9.4.51/jetty-alpn/jetty-alpn-conscrypt-server/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-alpn/jetty-alpn-conscrypt-server/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ org.eclipse.jetty jetty-alpn-parent - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 diff -Nru jetty9-9.4.51/jetty-alpn/jetty-alpn-java-client/pom.xml jetty9-9.4.53/jetty-alpn/jetty-alpn-java-client/pom.xml --- jetty9-9.4.51/jetty-alpn/jetty-alpn-java-client/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-alpn/jetty-alpn-java-client/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -4,7 +4,7 @@ org.eclipse.jetty jetty-alpn-parent - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 diff -Nru jetty9-9.4.51/jetty-alpn/jetty-alpn-java-server/pom.xml jetty9-9.4.53/jetty-alpn/jetty-alpn-java-server/pom.xml --- jetty9-9.4.51/jetty-alpn/jetty-alpn-java-server/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-alpn/jetty-alpn-java-server/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ org.eclipse.jetty jetty-alpn-parent - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 diff -Nru jetty9-9.4.51/jetty-alpn/jetty-alpn-openjdk8-client/pom.xml jetty9-9.4.53/jetty-alpn/jetty-alpn-openjdk8-client/pom.xml --- jetty9-9.4.51/jetty-alpn/jetty-alpn-openjdk8-client/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-alpn/jetty-alpn-openjdk8-client/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -4,7 +4,7 @@ org.eclipse.jetty jetty-alpn-parent - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 diff -Nru jetty9-9.4.51/jetty-alpn/jetty-alpn-openjdk8-server/pom.xml jetty9-9.4.53/jetty-alpn/jetty-alpn-openjdk8-server/pom.xml --- jetty9-9.4.51/jetty-alpn/jetty-alpn-openjdk8-server/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-alpn/jetty-alpn-openjdk8-server/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ org.eclipse.jetty jetty-alpn-parent - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 diff -Nru jetty9-9.4.51/jetty-alpn/jetty-alpn-server/pom.xml jetty9-9.4.53/jetty-alpn/jetty-alpn-server/pom.xml --- jetty9-9.4.51/jetty-alpn/jetty-alpn-server/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-alpn/jetty-alpn-server/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-alpn-parent - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 jetty-alpn-server diff -Nru jetty9-9.4.51/jetty-alpn/pom.xml jetty9-9.4.53/jetty-alpn/pom.xml --- jetty9-9.4.51/jetty-alpn/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-alpn/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 jetty-alpn-parent diff -Nru jetty9-9.4.51/jetty-annotations/pom.xml jetty9-9.4.53/jetty-annotations/pom.xml --- jetty9-9.4.51/jetty-annotations/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-annotations/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 jetty-annotations diff -Nru jetty9-9.4.51/jetty-ant/pom.xml jetty9-9.4.53/jetty-ant/pom.xml --- jetty9-9.4.51/jetty-ant/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-ant/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 jetty-ant diff -Nru jetty9-9.4.51/jetty-bom/pom.xml jetty9-9.4.53/jetty-bom/pom.xml --- jetty9-9.4.51/jetty-bom/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-bom/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -9,7 +9,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 @@ -53,336 +53,336 @@ org.eclipse.jetty apache-jsp - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty apache-jstl - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty jetty-alpn-client - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty jetty-alpn-java-client - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty jetty-alpn-java-server - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty jetty-alpn-openjdk8-client - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty jetty-alpn-openjdk8-server - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty jetty-alpn-conscrypt-client - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty jetty-alpn-conscrypt-server - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty jetty-alpn-server - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty jetty-annotations - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty jetty-ant - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty jetty-client - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty jetty-continuation - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty jetty-deploy - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty jetty-distribution - 9.4.51.v20230217 + 9.4.53.v20231009 zip org.eclipse.jetty jetty-distribution - 9.4.51.v20230217 + 9.4.53.v20231009 tar.gz org.eclipse.jetty.fcgi fcgi-client - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty.fcgi fcgi-server - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty.gcloud jetty-gcloud-session-manager - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty jetty-home - 9.4.51.v20230217 + 9.4.53.v20231009 zip org.eclipse.jetty jetty-home - 9.4.51.v20230217 + 9.4.53.v20231009 tar.gz org.eclipse.jetty jetty-http - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty.http2 http2-client - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty.http2 http2-common - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty.http2 http2-hpack - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty.http2 http2-http-client-transport - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty.http2 http2-server - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty jetty-http-spi - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty infinispan-common - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty infinispan-remote-query - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty infinispan-embedded-query - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty jetty-hazelcast - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty jetty-io - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty jetty-jaas - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty jetty-jaspi - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty jetty-jmx - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty jetty-jndi - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty.memcached jetty-memcached-sessions - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty jetty-nosql - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty.osgi jetty-osgi-boot - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty.osgi jetty-osgi-boot-jsp - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty.osgi jetty-osgi-boot-warurl - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty.osgi jetty-httpservice - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty jetty-plus - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty jetty-proxy - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty jetty-quickstart - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty jetty-rewrite - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty jetty-security - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty jetty-openid - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty jetty-server - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty jetty-servlet - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty jetty-servlets - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty jetty-spring - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty jetty-unixsocket - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty jetty-util - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty jetty-util-ajax - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty jetty-webapp - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty.websocket javax-websocket-client-impl - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty.websocket javax-websocket-server-impl - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty.websocket websocket-api - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty.websocket websocket-client - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty.websocket websocket-common - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty.websocket websocket-server - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty.websocket websocket-servlet - 9.4.51.v20230217 + 9.4.53.v20231009 org.eclipse.jetty jetty-xml - 9.4.51.v20230217 + 9.4.53.v20231009 diff -Nru jetty9-9.4.51/jetty-cdi/pom.xml jetty9-9.4.53/jetty-cdi/pom.xml --- jetty9-9.4.51/jetty-cdi/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-cdi/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 org.eclipse.jetty @@ -46,6 +46,16 @@ weld-servlet-core ${weld.version} test + + + org.jboss.logging + jboss-logging + + + + + org.jboss.logging + jboss-logging diff -Nru jetty9-9.4.51/jetty-client/pom.xml jetty9-9.4.53/jetty-client/pom.xml --- jetty9-9.4.51/jetty-client/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-client/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 @@ -115,14 +115,14 @@ org.apache.kerby kerb-simplekdc - 2.0.2 + 2.0.3 test net.minidev json-smart - 2.4.8 + 2.5.0 test diff -Nru jetty9-9.4.51/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTLSTest.java jetty9-9.4.53/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTLSTest.java --- jetty9-9.4.51/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTLSTest.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTLSTest.java 2023-10-09 12:27:40.000000000 +0000 @@ -71,6 +71,7 @@ import org.hamcrest.Matchers; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledForJreRange; import org.junit.jupiter.api.condition.JRE; @@ -367,7 +368,7 @@ // Excluded in JDK 11+ because resumed sessions cannot be compared // using their session IDs even though they are resumed correctly. - @EnabledForJreRange(max = JRE.JAVA_10) + @Disabled("No longer supported on newer Java 8 releases") @Test public void testHandshakeSucceededWithSessionResumption() throws Exception { @@ -447,7 +448,7 @@ // Excluded in JDK 11+ because resumed sessions cannot be compared // using their session IDs even though they are resumed correctly. - @EnabledForJreRange(max = JRE.JAVA_10) + @Disabled("Not supported with newer Java 8 releases") @Test public void testClientRawCloseDoesNotInvalidateSession() throws Exception { diff -Nru jetty9-9.4.51/jetty-continuation/pom.xml jetty9-9.4.53/jetty-continuation/pom.xml --- jetty9-9.4.51/jetty-continuation/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-continuation/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 jetty-continuation diff -Nru jetty9-9.4.51/jetty-deploy/pom.xml jetty9-9.4.53/jetty-deploy/pom.xml --- jetty9-9.4.51/jetty-deploy/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-deploy/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 jetty-deploy diff -Nru jetty9-9.4.51/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/DeploymentTempDirTest.java jetty9-9.4.53/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/DeploymentTempDirTest.java --- jetty9-9.4.51/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/DeploymentTempDirTest.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/DeploymentTempDirTest.java 2023-10-09 12:27:40.000000000 +0000 @@ -101,7 +101,10 @@ public void testTmpDirectory() throws Exception { Path warPath = MavenTestingUtils.getTestResourcePath("webapps/foo-webapp-1.war"); - String deploymentXml = "\n" + + String deploymentXml = + "\n" + + "\n" + + "\n" + "" + warPath + "\n" + "" + tmpDir + "\n" + "false\n" + @@ -141,7 +144,10 @@ public void testPersistentTmpDirectory() throws Exception { Path warPath = MavenTestingUtils.getTestResourcePath("webapps/foo-webapp-1.war"); - String deploymentXml = "\n" + + String deploymentXml = + "\n" + + "\n" + + "\n" + "" + warPath + "\n" + "" + tmpDir + "\n" + "true\n" + diff -Nru jetty9-9.4.51/jetty-deploy/src/test/resources/context-binding-test-1.xml jetty9-9.4.53/jetty-deploy/src/test/resources/context-binding-test-1.xml --- jetty9-9.4.51/jetty-deploy/src/test/resources/context-binding-test-1.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-deploy/src/test/resources/context-binding-test-1.xml 2023-10-09 12:27:40.000000000 +0000 @@ -1,3 +1,5 @@ + + diff -Nru jetty9-9.4.51/jetty-deploy/src/test/resources/jetty.xml jetty9-9.4.53/jetty-deploy/src/test/resources/jetty.xml --- jetty9-9.4.51/jetty-deploy/src/test/resources/jetty.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-deploy/src/test/resources/jetty.xml 2023-10-09 12:27:40.000000000 +0000 @@ -1,4 +1,5 @@ - + + diff -Nru jetty9-9.4.51/jetty-distribution/pom.xml jetty9-9.4.53/jetty-distribution/pom.xml --- jetty9-9.4.51/jetty-distribution/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-distribution/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 jetty-distribution diff -Nru jetty9-9.4.51/jetty-fcgi/fcgi-client/pom.xml jetty9-9.4.53/jetty-fcgi/fcgi-client/pom.xml --- jetty9-9.4.51/jetty-fcgi/fcgi-client/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-fcgi/fcgi-client/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ org.eclipse.jetty.fcgi fcgi-parent - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 diff -Nru jetty9-9.4.51/jetty-fcgi/fcgi-server/pom.xml jetty9-9.4.53/jetty-fcgi/fcgi-server/pom.xml --- jetty9-9.4.51/jetty-fcgi/fcgi-server/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-fcgi/fcgi-server/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ org.eclipse.jetty.fcgi fcgi-parent - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 diff -Nru jetty9-9.4.51/jetty-fcgi/pom.xml jetty9-9.4.53/jetty-fcgi/pom.xml --- jetty9-9.4.51/jetty-fcgi/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-fcgi/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 diff -Nru jetty9-9.4.51/jetty-gcloud/jetty-gcloud-session-manager/pom.xml jetty9-9.4.53/jetty-gcloud/jetty-gcloud-session-manager/pom.xml --- jetty9-9.4.51/jetty-gcloud/jetty-gcloud-session-manager/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-gcloud/jetty-gcloud-session-manager/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ org.eclipse.jetty.gcloud gcloud-parent - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 diff -Nru jetty9-9.4.51/jetty-gcloud/pom.xml jetty9-9.4.53/jetty-gcloud/pom.xml --- jetty9-9.4.51/jetty-gcloud/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-gcloud/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ jetty-project org.eclipse.jetty - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 diff -Nru jetty9-9.4.51/jetty-hazelcast/pom.xml jetty9-9.4.53/jetty-hazelcast/pom.xml --- jetty9-9.4.51/jetty-hazelcast/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-hazelcast/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 diff -Nru jetty9-9.4.51/jetty-home/pom.xml jetty9-9.4.53/jetty-home/pom.xml --- jetty9-9.4.51/jetty-home/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-home/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ jetty-project org.eclipse.jetty - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 jetty-home diff -Nru jetty9-9.4.51/jetty-http/pom.xml jetty9-9.4.53/jetty-http/pom.xml --- jetty9-9.4.51/jetty-http/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ jetty-project org.eclipse.jetty - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 jetty-http diff -Nru jetty9-9.4.51/jetty-http/src/main/java/org/eclipse/jetty/http/compression/EncodingException.java jetty9-9.4.53/jetty-http/src/main/java/org/eclipse/jetty/http/compression/EncodingException.java --- jetty9-9.4.51/jetty-http/src/main/java/org/eclipse/jetty/http/compression/EncodingException.java 1970-01-01 00:00:00.000000000 +0000 +++ jetty9-9.4.53/jetty-http/src/main/java/org/eclipse/jetty/http/compression/EncodingException.java 2023-10-09 12:27:40.000000000 +0000 @@ -0,0 +1,27 @@ +// +// ======================================================================== +// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http.compression; + +public class EncodingException extends Exception +{ + public EncodingException(String message) + { + super(message); + } +} diff -Nru jetty9-9.4.51/jetty-http/src/main/java/org/eclipse/jetty/http/compression/HuffmanDecoder.java jetty9-9.4.53/jetty-http/src/main/java/org/eclipse/jetty/http/compression/HuffmanDecoder.java --- jetty9-9.4.51/jetty-http/src/main/java/org/eclipse/jetty/http/compression/HuffmanDecoder.java 1970-01-01 00:00:00.000000000 +0000 +++ jetty9-9.4.53/jetty-http/src/main/java/org/eclipse/jetty/http/compression/HuffmanDecoder.java 2023-10-09 12:27:40.000000000 +0000 @@ -0,0 +1,143 @@ +// +// ======================================================================== +// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http.compression; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.http.HttpTokens; +import org.eclipse.jetty.util.CharsetStringBuilder; + +import static org.eclipse.jetty.http.compression.Huffman.rowbits; +import static org.eclipse.jetty.http.compression.Huffman.rowsym; + +/** + *

Used to decoded Huffman encoded strings.

+ * + *

Characters which are illegal field-vchar values are replaced with + * either ' ' or '?' as described in RFC9110

+ */ +public class HuffmanDecoder +{ + private final CharsetStringBuilder.Iso88591StringBuilder _builder = new CharsetStringBuilder.Iso88591StringBuilder(); + private int _length = 0; + private int _count = 0; + private int _node = 0; + private int _current = 0; + private int _bits = 0; + + /** + * @param length in bytes of the huffman data. + */ + public void setLength(int length) + { + if (_count != 0) + throw new IllegalStateException(); + _length = length; + } + + /** + * @param buffer the buffer containing the Huffman encoded bytes. + * @return the decoded String. + * @throws EncodingException if the huffman encoding is invalid. + */ + public String decode(ByteBuffer buffer) throws EncodingException + { + for (; _count < _length; _count++) + { + if (!buffer.hasRemaining()) + return null; + + int b = buffer.get() & 0xFF; + _current = (_current << 8) | b; + _bits += 8; + while (_bits >= 8) + { + int i = (_current >>> (_bits - 8)) & 0xFF; + _node = Huffman.tree[_node * 256 + i]; + if (rowbits[_node] != 0) + { + if (rowsym[_node] == Huffman.EOS) + { + reset(); + throw new EncodingException("eos_in_content"); + } + + // terminal node + char c = rowsym[_node]; + c = HttpTokens.sanitizeFieldVchar(c); + _builder.append((byte)c); + _bits -= rowbits[_node]; + _node = 0; + } + else + { + // non-terminal node + _bits -= 8; + } + } + } + + while (_bits > 0) + { + int i = (_current << (8 - _bits)) & 0xFF; + int lastNode = _node; + _node = Huffman.tree[_node * 256 + i]; + + if (rowbits[_node] == 0 || rowbits[_node] > _bits) + { + int requiredPadding = 0; + for (int j = 0; j < _bits; j++) + { + requiredPadding = (requiredPadding << 1) | 1; + } + + if ((i >> (8 - _bits)) != requiredPadding) + throw new EncodingException("incorrect_padding"); + + _node = lastNode; + break; + } + + char c = rowsym[_node]; + c = HttpTokens.sanitizeFieldVchar(c); + _builder.append((byte)c); + _bits -= rowbits[_node]; + _node = 0; + } + + if (_node != 0) + { + reset(); + throw new EncodingException("bad_termination"); + } + + String value = _builder.build(); + reset(); + return value; + } + + public void reset() + { + _builder.reset(); + _count = 0; + _current = 0; + _node = 0; + _bits = 0; + } +} diff -Nru jetty9-9.4.51/jetty-http/src/main/java/org/eclipse/jetty/http/compression/HuffmanEncoder.java jetty9-9.4.53/jetty-http/src/main/java/org/eclipse/jetty/http/compression/HuffmanEncoder.java --- jetty9-9.4.51/jetty-http/src/main/java/org/eclipse/jetty/http/compression/HuffmanEncoder.java 1970-01-01 00:00:00.000000000 +0000 +++ jetty9-9.4.53/jetty-http/src/main/java/org/eclipse/jetty/http/compression/HuffmanEncoder.java 2023-10-09 12:27:40.000000000 +0000 @@ -0,0 +1,142 @@ +// +// ======================================================================== +// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http.compression; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.http.HttpTokens; + +import static org.eclipse.jetty.http.compression.Huffman.CODES; +import static org.eclipse.jetty.http.compression.Huffman.LCCODES; + +/** + *

Used to encode strings Huffman encoding.

+ * + *

Characters are encoded with ISO-8859-1, if any multi-byte characters or + * control characters are present the encoder will throw {@link EncodingException}.

+ */ +public class HuffmanEncoder +{ + private HuffmanEncoder() + { + } + + /** + * @param s the string to encode. + * @return the number of octets needed to encode the string, or -1 if it cannot be encoded. + */ + public static int octetsNeeded(String s) + { + return octetsNeeded(CODES, s); + } + + /** + * @param b the byte array to encode. + * @return the number of octets needed to encode the bytes, or -1 if it cannot be encoded. + */ + public static int octetsNeeded(byte[] b) + { + int needed = 0; + for (byte value : b) + { + int c = 0xFF & value; + needed += CODES[c][1]; + } + return (needed + 7) / 8; + } + + /** + * @param buffer the buffer to encode into. + * @param s the string to encode. + */ + public static void encode(ByteBuffer buffer, String s) + { + encode(CODES, buffer, s); + } + + /** + * @param s the string to encode in lowercase. + * @return the number of octets needed to encode the string, or -1 if it cannot be encoded. + */ + public static int octetsNeededLowerCase(String s) + { + return octetsNeeded(LCCODES, s); + } + + /** + * @param buffer the buffer to encode into in lowercase. + * @param s the string to encode. + */ + public static void encodeLowerCase(ByteBuffer buffer, String s) + { + encode(LCCODES, buffer, s); + } + + private static int octetsNeeded(final int[][] table, String s) + { + int needed = 0; + int len = s.length(); + for (int i = 0; i < len; i++) + { + char c = s.charAt(i); + if (HttpTokens.isIllegalFieldVchar(c)) + return -1; + needed += table[c][1]; + } + + return (needed + 7) / 8; + } + + /** + * @param table The table to encode by + * @param buffer The buffer to encode to + * @param s The string to encode + */ + private static void encode(final int[][] table, ByteBuffer buffer, String s) + { + long current = 0; + int n = 0; + int len = s.length(); + for (int i = 0; i < len; i++) + { + char c = s.charAt(i); + if (HttpTokens.isIllegalFieldVchar(c)) + throw new IllegalArgumentException(); + int code = table[c][0]; + int bits = table[c][1]; + + current <<= bits; + current |= code; + n += bits; + + while (n >= 8) + { + n -= 8; + buffer.put((byte)(current >> n)); + } + } + + if (n > 0) + { + current <<= (8 - n); + current |= (0xFF >>> n); + buffer.put((byte)(current)); + } + } +} diff -Nru jetty9-9.4.51/jetty-http/src/main/java/org/eclipse/jetty/http/compression/Huffman.java jetty9-9.4.53/jetty-http/src/main/java/org/eclipse/jetty/http/compression/Huffman.java --- jetty9-9.4.51/jetty-http/src/main/java/org/eclipse/jetty/http/compression/Huffman.java 1970-01-01 00:00:00.000000000 +0000 +++ jetty9-9.4.53/jetty-http/src/main/java/org/eclipse/jetty/http/compression/Huffman.java 2023-10-09 12:27:40.000000000 +0000 @@ -0,0 +1,357 @@ +// +// ======================================================================== +// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http.compression; + +/** + * This class contains the Huffman Codes defined in RFC7541. + */ +public class Huffman +{ + private Huffman() + { + } + + // Appendix C: Huffman Codes + // http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-12#appendix-C + static final int[][] CODES = + { + /* ( 0) |11111111|11000 */ {0x1ff8, 13}, + /* ( 1) |11111111|11111111|1011000 */ {0x7fffd8, 23}, + /* ( 2) |11111111|11111111|11111110|0010 */ {0xfffffe2, 28}, + /* ( 3) |11111111|11111111|11111110|0011 */ {0xfffffe3, 28}, + /* ( 4) |11111111|11111111|11111110|0100 */ {0xfffffe4, 28}, + /* ( 5) |11111111|11111111|11111110|0101 */ {0xfffffe5, 28}, + /* ( 6) |11111111|11111111|11111110|0110 */ {0xfffffe6, 28}, + /* ( 7) |11111111|11111111|11111110|0111 */ {0xfffffe7, 28}, + /* ( 8) |11111111|11111111|11111110|1000 */ {0xfffffe8, 28}, + /* ( 9) |11111111|11111111|11101010 */ {0xffffea, 24}, + /* ( 10) |11111111|11111111|11111111|111100 */ {0x3ffffffc, 30}, + /* ( 11) |11111111|11111111|11111110|1001 */ {0xfffffe9, 28}, + /* ( 12) |11111111|11111111|11111110|1010 */ {0xfffffea, 28}, + /* ( 13) |11111111|11111111|11111111|111101 */ {0x3ffffffd, 30}, + /* ( 14) |11111111|11111111|11111110|1011 */ {0xfffffeb, 28}, + /* ( 15) |11111111|11111111|11111110|1100 */ {0xfffffec, 28}, + /* ( 16) |11111111|11111111|11111110|1101 */ {0xfffffed, 28}, + /* ( 17) |11111111|11111111|11111110|1110 */ {0xfffffee, 28}, + /* ( 18) |11111111|11111111|11111110|1111 */ {0xfffffef, 28}, + /* ( 19) |11111111|11111111|11111111|0000 */ {0xffffff0, 28}, + /* ( 20) |11111111|11111111|11111111|0001 */ {0xffffff1, 28}, + /* ( 21) |11111111|11111111|11111111|0010 */ {0xffffff2, 28}, + /* ( 22) |11111111|11111111|11111111|111110 */ {0x3ffffffe, 30}, + /* ( 23) |11111111|11111111|11111111|0011 */ {0xffffff3, 28}, + /* ( 24) |11111111|11111111|11111111|0100 */ {0xffffff4, 28}, + /* ( 25) |11111111|11111111|11111111|0101 */ {0xffffff5, 28}, + /* ( 26) |11111111|11111111|11111111|0110 */ {0xffffff6, 28}, + /* ( 27) |11111111|11111111|11111111|0111 */ {0xffffff7, 28}, + /* ( 28) |11111111|11111111|11111111|1000 */ {0xffffff8, 28}, + /* ( 29) |11111111|11111111|11111111|1001 */ {0xffffff9, 28}, + /* ( 30) |11111111|11111111|11111111|1010 */ {0xffffffa, 28}, + /* ( 31) |11111111|11111111|11111111|1011 */ {0xffffffb, 28}, + /*' ' ( 32) |010100 */ {0x14, 6}, + /*'!' ( 33) |11111110|00 */ {0x3f8, 10}, + /*'"' ( 34) |11111110|01 */ {0x3f9, 10}, + /*'#' ( 35) |11111111|1010 */ {0xffa, 12}, + /*'$' ( 36) |11111111|11001 */ {0x1ff9, 13}, + /*'%' ( 37) |010101 */ {0x15, 6}, + /*'&' ( 38) |11111000 */ {0xf8, 8}, + /*''' ( 39) |11111111|010 */ {0x7fa, 11}, + /*'(' ( 40) |11111110|10 */ {0x3fa, 10}, + /*')' ( 41) |11111110|11 */ {0x3fb, 10}, + /*'*' ( 42) |11111001 */ {0xf9, 8}, + /*'+' ( 43) |11111111|011 */ {0x7fb, 11}, + /*',' ( 44) |11111010 */ {0xfa, 8}, + /*'-' ( 45) |010110 */ {0x16, 6}, + /*'.' ( 46) |010111 */ {0x17, 6}, + /*'/' ( 47) |011000 */ {0x18, 6}, + /*'0' ( 48) |00000 */ {0x0, 5}, + /*'1' ( 49) |00001 */ {0x1, 5}, + /*'2' ( 50) |00010 */ {0x2, 5}, + /*'3' ( 51) |011001 */ {0x19, 6}, + /*'4' ( 52) |011010 */ {0x1a, 6}, + /*'5' ( 53) |011011 */ {0x1b, 6}, + /*'6' ( 54) |011100 */ {0x1c, 6}, + /*'7' ( 55) |011101 */ {0x1d, 6}, + /*'8' ( 56) |011110 */ {0x1e, 6}, + /*'9' ( 57) |011111 */ {0x1f, 6}, + /*':' ( 58) |1011100 */ {0x5c, 7}, + /*';' ( 59) |11111011 */ {0xfb, 8}, + /*'<' ( 60) |11111111|1111100 */ {0x7ffc, 15}, + /*'=' ( 61) |100000 */ {0x20, 6}, + /*'>' ( 62) |11111111|1011 */ {0xffb, 12}, + /*'?' ( 63) |11111111|00 */ {0x3fc, 10}, + /*'@' ( 64) |11111111|11010 */ {0x1ffa, 13}, + /*'A' ( 65) |100001 */ {0x21, 6}, + /*'B' ( 66) |1011101 */ {0x5d, 7}, + /*'C' ( 67) |1011110 */ {0x5e, 7}, + /*'D' ( 68) |1011111 */ {0x5f, 7}, + /*'E' ( 69) |1100000 */ {0x60, 7}, + /*'F' ( 70) |1100001 */ {0x61, 7}, + /*'G' ( 71) |1100010 */ {0x62, 7}, + /*'H' ( 72) |1100011 */ {0x63, 7}, + /*'I' ( 73) |1100100 */ {0x64, 7}, + /*'J' ( 74) |1100101 */ {0x65, 7}, + /*'K' ( 75) |1100110 */ {0x66, 7}, + /*'L' ( 76) |1100111 */ {0x67, 7}, + /*'M' ( 77) |1101000 */ {0x68, 7}, + /*'N' ( 78) |1101001 */ {0x69, 7}, + /*'O' ( 79) |1101010 */ {0x6a, 7}, + /*'P' ( 80) |1101011 */ {0x6b, 7}, + /*'Q' ( 81) |1101100 */ {0x6c, 7}, + /*'R' ( 82) |1101101 */ {0x6d, 7}, + /*'S' ( 83) |1101110 */ {0x6e, 7}, + /*'T' ( 84) |1101111 */ {0x6f, 7}, + /*'U' ( 85) |1110000 */ {0x70, 7}, + /*'V' ( 86) |1110001 */ {0x71, 7}, + /*'W' ( 87) |1110010 */ {0x72, 7}, + /*'X' ( 88) |11111100 */ {0xfc, 8}, + /*'Y' ( 89) |1110011 */ {0x73, 7}, + /*'Z' ( 90) |11111101 */ {0xfd, 8}, + /*'[' ( 91) |11111111|11011 */ {0x1ffb, 13}, + /*'\' ( 92) |11111111|11111110|000 */ {0x7fff0, 19}, + /*']' ( 93) |11111111|11100 */ {0x1ffc, 13}, + /*'^' ( 94) |11111111|111100 */ {0x3ffc, 14}, + /*'_' ( 95) |100010 */ {0x22, 6}, + /*'`' ( 96) |11111111|1111101 */ {0x7ffd, 15}, + /*'a' ( 97) |00011 */ {0x3, 5}, + /*'b' ( 98) |100011 */ {0x23, 6}, + /*'c' ( 99) |00100 */ {0x4, 5}, + /*'d' (100) |100100 */ {0x24, 6}, + /*'e' (101) |00101 */ {0x5, 5}, + /*'f' (102) |100101 */ {0x25, 6}, + /*'g' (103) |100110 */ {0x26, 6}, + /*'h' (104) |100111 */ {0x27, 6}, + /*'i' (105) |00110 */ {0x6, 5}, + /*'j' (106) |1110100 */ {0x74, 7}, + /*'k' (107) |1110101 */ {0x75, 7}, + /*'l' (108) |101000 */ {0x28, 6}, + /*'m' (109) |101001 */ {0x29, 6}, + /*'n' (110) |101010 */ {0x2a, 6}, + /*'o' (111) |00111 */ {0x7, 5}, + /*'p' (112) |101011 */ {0x2b, 6}, + /*'q' (113) |1110110 */ {0x76, 7}, + /*'r' (114) |101100 */ {0x2c, 6}, + /*'s' (115) |01000 */ {0x8, 5}, + /*'t' (116) |01001 */ {0x9, 5}, + /*'u' (117) |101101 */ {0x2d, 6}, + /*'v' (118) |1110111 */ {0x77, 7}, + /*'w' (119) |1111000 */ {0x78, 7}, + /*'x' (120) |1111001 */ {0x79, 7}, + /*'y' (121) |1111010 */ {0x7a, 7}, + /*'z' (122) |1111011 */ {0x7b, 7}, + /*'{' (123) |11111111|1111110 */ {0x7ffe, 15}, + /*'|' (124) |11111111|100 */ {0x7fc, 11}, + /*'}' (125) |11111111|111101 */ {0x3ffd, 14}, + /*'~' (126) |11111111|11101 */ {0x1ffd, 13}, + /* (127) |11111111|11111111|11111111|1100 */ {0xffffffc, 28}, + /* (128) |11111111|11111110|0110 */ {0xfffe6, 20}, + /* (129) |11111111|11111111|010010 */ {0x3fffd2, 22}, + /* (130) |11111111|11111110|0111 */ {0xfffe7, 20}, + /* (131) |11111111|11111110|1000 */ {0xfffe8, 20}, + /* (132) |11111111|11111111|010011 */ {0x3fffd3, 22}, + /* (133) |11111111|11111111|010100 */ {0x3fffd4, 22}, + /* (134) |11111111|11111111|010101 */ {0x3fffd5, 22}, + /* (135) |11111111|11111111|1011001 */ {0x7fffd9, 23}, + /* (136) |11111111|11111111|010110 */ {0x3fffd6, 22}, + /* (137) |11111111|11111111|1011010 */ {0x7fffda, 23}, + /* (138) |11111111|11111111|1011011 */ {0x7fffdb, 23}, + /* (139) |11111111|11111111|1011100 */ {0x7fffdc, 23}, + /* (140) |11111111|11111111|1011101 */ {0x7fffdd, 23}, + /* (141) |11111111|11111111|1011110 */ {0x7fffde, 23}, + /* (142) |11111111|11111111|11101011 */ {0xffffeb, 24}, + /* (143) |11111111|11111111|1011111 */ {0x7fffdf, 23}, + /* (144) |11111111|11111111|11101100 */ {0xffffec, 24}, + /* (145) |11111111|11111111|11101101 */ {0xffffed, 24}, + /* (146) |11111111|11111111|010111 */ {0x3fffd7, 22}, + /* (147) |11111111|11111111|1100000 */ {0x7fffe0, 23}, + /* (148) |11111111|11111111|11101110 */ {0xffffee, 24}, + /* (149) |11111111|11111111|1100001 */ {0x7fffe1, 23}, + /* (150) |11111111|11111111|1100010 */ {0x7fffe2, 23}, + /* (151) |11111111|11111111|1100011 */ {0x7fffe3, 23}, + /* (152) |11111111|11111111|1100100 */ {0x7fffe4, 23}, + /* (153) |11111111|11111110|11100 */ {0x1fffdc, 21}, + /* (154) |11111111|11111111|011000 */ {0x3fffd8, 22}, + /* (155) |11111111|11111111|1100101 */ {0x7fffe5, 23}, + /* (156) |11111111|11111111|011001 */ {0x3fffd9, 22}, + /* (157) |11111111|11111111|1100110 */ {0x7fffe6, 23}, + /* (158) |11111111|11111111|1100111 */ {0x7fffe7, 23}, + /* (159) |11111111|11111111|11101111 */ {0xffffef, 24}, + /* (160) |11111111|11111111|011010 */ {0x3fffda, 22}, + /* (161) |11111111|11111110|11101 */ {0x1fffdd, 21}, + /* (162) |11111111|11111110|1001 */ {0xfffe9, 20}, + /* (163) |11111111|11111111|011011 */ {0x3fffdb, 22}, + /* (164) |11111111|11111111|011100 */ {0x3fffdc, 22}, + /* (165) |11111111|11111111|1101000 */ {0x7fffe8, 23}, + /* (166) |11111111|11111111|1101001 */ {0x7fffe9, 23}, + /* (167) |11111111|11111110|11110 */ {0x1fffde, 21}, + /* (168) |11111111|11111111|1101010 */ {0x7fffea, 23}, + /* (169) |11111111|11111111|011101 */ {0x3fffdd, 22}, + /* (170) |11111111|11111111|011110 */ {0x3fffde, 22}, + /* (171) |11111111|11111111|11110000 */ {0xfffff0, 24}, + /* (172) |11111111|11111110|11111 */ {0x1fffdf, 21}, + /* (173) |11111111|11111111|011111 */ {0x3fffdf, 22}, + /* (174) |11111111|11111111|1101011 */ {0x7fffeb, 23}, + /* (175) |11111111|11111111|1101100 */ {0x7fffec, 23}, + /* (176) |11111111|11111111|00000 */ {0x1fffe0, 21}, + /* (177) |11111111|11111111|00001 */ {0x1fffe1, 21}, + /* (178) |11111111|11111111|100000 */ {0x3fffe0, 22}, + /* (179) |11111111|11111111|00010 */ {0x1fffe2, 21}, + /* (180) |11111111|11111111|1101101 */ {0x7fffed, 23}, + /* (181) |11111111|11111111|100001 */ {0x3fffe1, 22}, + /* (182) |11111111|11111111|1101110 */ {0x7fffee, 23}, + /* (183) |11111111|11111111|1101111 */ {0x7fffef, 23}, + /* (184) |11111111|11111110|1010 */ {0xfffea, 20}, + /* (185) |11111111|11111111|100010 */ {0x3fffe2, 22}, + /* (186) |11111111|11111111|100011 */ {0x3fffe3, 22}, + /* (187) |11111111|11111111|100100 */ {0x3fffe4, 22}, + /* (188) |11111111|11111111|1110000 */ {0x7ffff0, 23}, + /* (189) |11111111|11111111|100101 */ {0x3fffe5, 22}, + /* (190) |11111111|11111111|100110 */ {0x3fffe6, 22}, + /* (191) |11111111|11111111|1110001 */ {0x7ffff1, 23}, + /* (192) |11111111|11111111|11111000|00 */ {0x3ffffe0, 26}, + /* (193) |11111111|11111111|11111000|01 */ {0x3ffffe1, 26}, + /* (194) |11111111|11111110|1011 */ {0xfffeb, 20}, + /* (195) |11111111|11111110|001 */ {0x7fff1, 19}, + /* (196) |11111111|11111111|100111 */ {0x3fffe7, 22}, + /* (197) |11111111|11111111|1110010 */ {0x7ffff2, 23}, + /* (198) |11111111|11111111|101000 */ {0x3fffe8, 22}, + /* (199) |11111111|11111111|11110110|0 */ {0x1ffffec, 25}, + /* (200) |11111111|11111111|11111000|10 */ {0x3ffffe2, 26}, + /* (201) |11111111|11111111|11111000|11 */ {0x3ffffe3, 26}, + /* (202) |11111111|11111111|11111001|00 */ {0x3ffffe4, 26}, + /* (203) |11111111|11111111|11111011|110 */ {0x7ffffde, 27}, + /* (204) |11111111|11111111|11111011|111 */ {0x7ffffdf, 27}, + /* (205) |11111111|11111111|11111001|01 */ {0x3ffffe5, 26}, + /* (206) |11111111|11111111|11110001 */ {0xfffff1, 24}, + /* (207) |11111111|11111111|11110110|1 */ {0x1ffffed, 25}, + /* (208) |11111111|11111110|010 */ {0x7fff2, 19}, + /* (209) |11111111|11111111|00011 */ {0x1fffe3, 21}, + /* (210) |11111111|11111111|11111001|10 */ {0x3ffffe6, 26}, + /* (211) |11111111|11111111|11111100|000 */ {0x7ffffe0, 27}, + /* (212) |11111111|11111111|11111100|001 */ {0x7ffffe1, 27}, + /* (213) |11111111|11111111|11111001|11 */ {0x3ffffe7, 26}, + /* (214) |11111111|11111111|11111100|010 */ {0x7ffffe2, 27}, + /* (215) |11111111|11111111|11110010 */ {0xfffff2, 24}, + /* (216) |11111111|11111111|00100 */ {0x1fffe4, 21}, + /* (217) |11111111|11111111|00101 */ {0x1fffe5, 21}, + /* (218) |11111111|11111111|11111010|00 */ {0x3ffffe8, 26}, + /* (219) |11111111|11111111|11111010|01 */ {0x3ffffe9, 26}, + /* (220) |11111111|11111111|11111111|1101 */ {0xffffffd, 28}, + /* (221) |11111111|11111111|11111100|011 */ {0x7ffffe3, 27}, + /* (222) |11111111|11111111|11111100|100 */ {0x7ffffe4, 27}, + /* (223) |11111111|11111111|11111100|101 */ {0x7ffffe5, 27}, + /* (224) |11111111|11111110|1100 */ {0xfffec, 20}, + /* (225) |11111111|11111111|11110011 */ {0xfffff3, 24}, + /* (226) |11111111|11111110|1101 */ {0xfffed, 20}, + /* (227) |11111111|11111111|00110 */ {0x1fffe6, 21}, + /* (228) |11111111|11111111|101001 */ {0x3fffe9, 22}, + /* (229) |11111111|11111111|00111 */ {0x1fffe7, 21}, + /* (230) |11111111|11111111|01000 */ {0x1fffe8, 21}, + /* (231) |11111111|11111111|1110011 */ {0x7ffff3, 23}, + /* (232) |11111111|11111111|101010 */ {0x3fffea, 22}, + /* (233) |11111111|11111111|101011 */ {0x3fffeb, 22}, + /* (234) |11111111|11111111|11110111|0 */ {0x1ffffee, 25}, + /* (235) |11111111|11111111|11110111|1 */ {0x1ffffef, 25}, + /* (236) |11111111|11111111|11110100 */ {0xfffff4, 24}, + /* (237) |11111111|11111111|11110101 */ {0xfffff5, 24}, + /* (238) |11111111|11111111|11111010|10 */ {0x3ffffea, 26}, + /* (239) |11111111|11111111|1110100 */ {0x7ffff4, 23}, + /* (240) |11111111|11111111|11111010|11 */ {0x3ffffeb, 26}, + /* (241) |11111111|11111111|11111100|110 */ {0x7ffffe6, 27}, + /* (242) |11111111|11111111|11111011|00 */ {0x3ffffec, 26}, + /* (243) |11111111|11111111|11111011|01 */ {0x3ffffed, 26}, + /* (244) |11111111|11111111|11111100|111 */ {0x7ffffe7, 27}, + /* (245) |11111111|11111111|11111101|000 */ {0x7ffffe8, 27}, + /* (246) |11111111|11111111|11111101|001 */ {0x7ffffe9, 27}, + /* (247) |11111111|11111111|11111101|010 */ {0x7ffffea, 27}, + /* (248) |11111111|11111111|11111101|011 */ {0x7ffffeb, 27}, + /* (249) |11111111|11111111|11111111|1110 */ {0xffffffe, 28}, + /* (250) |11111111|11111111|11111101|100 */ {0x7ffffec, 27}, + /* (251) |11111111|11111111|11111101|101 */ {0x7ffffed, 27}, + /* (252) |11111111|11111111|11111101|110 */ {0x7ffffee, 27}, + /* (253) |11111111|11111111|11111101|111 */ {0x7ffffef, 27}, + /* (254) |11111111|11111111|11111110|000 */ {0x7fffff0, 27}, + /* (255) |11111111|11111111|11111011|10 */ {0x3ffffee, 26}, + /*EOS (256) |11111111|11111111|11111111|111111 */ {0x3fffffff, 30} + }; + + static final int[][] LCCODES = new int[CODES.length][]; + static final char EOS = 256; + + // Huffman decode tree stored in a flattened char array for good + // locality of reference. + static final char[] tree; + static final char[] rowsym; + static final byte[] rowbits; + + // Build the Huffman lookup tree and LC TABLE + static + { + System.arraycopy(CODES, 0, LCCODES, 0, CODES.length); + for (int i = 'A'; i <= 'Z'; i++) + { + LCCODES[i] = LCCODES['a' + i - 'A']; + } + + int r = 0; + for (int[] ints : CODES) + { + r += (ints[1] + 7) / 8; + } + tree = new char[r * 256]; + rowsym = new char[r]; + rowbits = new byte[r]; + + r = 0; + for (int sym = 0; sym < CODES.length; sym++) + { + int code = CODES[sym][0]; + int len = CODES[sym][1]; + + int current = 0; + + while (len > 8) + { + len -= 8; + int i = ((code >>> len) & 0xFF); + + int t = current * 256 + i; + current = tree[t]; + if (current == 0) + { + tree[t] = (char)++r; + current = r; + } + } + + int terminal = ++r; + rowsym[r] = (char)sym; + int b = len & 0x07; + int terminalBits = b == 0 ? 8 : b; + + rowbits[r] = (byte)terminalBits; + int shift = 8 - len; + int start = current * 256 + ((code << shift) & 0xFF); + int end = start + (1 << shift); + for (int i = start; i < end; i++) + { + tree[i] = (char)terminal; + } + } + } +} diff -Nru jetty9-9.4.51/jetty-http/src/main/java/org/eclipse/jetty/http/compression/NBitIntegerDecoder.java jetty9-9.4.53/jetty-http/src/main/java/org/eclipse/jetty/http/compression/NBitIntegerDecoder.java --- jetty9-9.4.51/jetty-http/src/main/java/org/eclipse/jetty/http/compression/NBitIntegerDecoder.java 1970-01-01 00:00:00.000000000 +0000 +++ jetty9-9.4.53/jetty-http/src/main/java/org/eclipse/jetty/http/compression/NBitIntegerDecoder.java 2023-10-09 12:27:40.000000000 +0000 @@ -0,0 +1,113 @@ +// +// ======================================================================== +// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http.compression; + +import java.nio.ByteBuffer; + +/** + * Used to decode integers as described in RFC7541. + */ +public class NBitIntegerDecoder +{ + private int _prefix; + private long _total; + private long _multiplier; + private boolean _started; + + /** + * Set the prefix length in of the integer representation in bits. + * A prefix of 6 means the integer representation starts after the first 2 bits. + * @param prefix the number of bits in the integer prefix. + */ + public void setPrefix(int prefix) + { + if (_started) + throw new IllegalStateException(); + _prefix = prefix; + } + + /** + * Decode an integer from the buffer. If the buffer does not contain the complete integer representation + * a value of -1 is returned to indicate that more data is needed to complete parsing. + * This should be only after the prefix has been set with {@link #setPrefix(int)}. + * @param buffer the buffer containing the encoded integer. + * @return the decoded integer or -1 to indicate that more data is needed. + * @throws ArithmeticException if the value overflows a int. + */ + public int decodeInt(ByteBuffer buffer) + { + return Math.toIntExact(decodeLong(buffer)); + } + + /** + * Decode a long from the buffer. If the buffer does not contain the complete integer representation + * a value of -1 is returned to indicate that more data is needed to complete parsing. + * This should be only after the prefix has been set with {@link #setPrefix(int)}. + * @param buffer the buffer containing the encoded integer. + * @return the decoded long or -1 to indicate that more data is needed. + * @throws ArithmeticException if the value overflows a long. + */ + public long decodeLong(ByteBuffer buffer) + { + if (!_started) + { + if (!buffer.hasRemaining()) + return -1; + + _started = true; + _multiplier = 1; + int nbits = 0xFF >>> (8 - _prefix); + _total = buffer.get() & nbits; + if (_total < nbits) + { + long total = _total; + reset(); + return total; + } + } + + while (true) + { + // If we have no more remaining we return -1 to indicate that more data is needed to continue parsing. + if (!buffer.hasRemaining()) + return -1; + + int b = buffer.get() & 0xFF; + _total = Math.addExact(_total, (b & 127) * _multiplier); + _multiplier = Math.multiplyExact(_multiplier, 128); + if ((b & 128) == 0) + { + long total = _total; + reset(); + return total; + } + } + } + + /** + * Reset the internal state of the parser. + */ + public void reset() + { + _prefix = 0; + _total = 0; + _multiplier = 1; + _started = false; + } +} diff -Nru jetty9-9.4.51/jetty-http/src/main/java/org/eclipse/jetty/http/compression/NBitIntegerEncoder.java jetty9-9.4.53/jetty-http/src/main/java/org/eclipse/jetty/http/compression/NBitIntegerEncoder.java --- jetty9-9.4.51/jetty-http/src/main/java/org/eclipse/jetty/http/compression/NBitIntegerEncoder.java 1970-01-01 00:00:00.000000000 +0000 +++ jetty9-9.4.53/jetty-http/src/main/java/org/eclipse/jetty/http/compression/NBitIntegerEncoder.java 2023-10-09 12:27:40.000000000 +0000 @@ -0,0 +1,96 @@ +// +// ======================================================================== +// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http.compression; + +import java.nio.ByteBuffer; + +/** + * Used to encode integers as described in RFC7541. + */ +public class NBitIntegerEncoder +{ + private NBitIntegerEncoder() + { + } + + /** + * @param prefix the prefix used to encode this long. + * @param value the integer to encode. + * @return the number of octets it would take to encode the long. + */ + public static int octetsNeeded(int prefix, long value) + { + if (prefix <= 0 || prefix > 8) + throw new IllegalArgumentException(); + + int nbits = 0xFF >>> (8 - prefix); + value = value - nbits; + if (value < 0) + return 1; + if (value == 0) + return 2; + int lz = Long.numberOfLeadingZeros(value); + int log = 64 - lz; + + // The return value is 1 for the prefix + the number of 7-bit groups necessary to encode the value. + return 1 + (log + 6) / 7; + } + + /** + * + * @param buffer the buffer to encode into. + * @param prefix the prefix used to encode this long. + * @param value the long to encode into the buffer. + */ + public static void encode(ByteBuffer buffer, int prefix, long value) + { + if (prefix <= 0 || prefix > 8) + throw new IllegalArgumentException(); + + // If prefix is 8 we add an empty byte as we initially modify last byte from the buffer. + if (prefix == 8) + buffer.put((byte)0x00); + + int bits = 0xFF >>> (8 - prefix); + int p = buffer.position() - 1; + if (value < bits) + { + buffer.put(p, (byte)((buffer.get(p) & ~bits) | value)); + } + else + { + buffer.put(p, (byte)(buffer.get(p) | bits)); + long length = value - bits; + while (true) + { + // The value of ~0x7F is different to 0x80 because of all the 1s from the MSB. + if ((length & ~0x7FL) == 0) + { + buffer.put((byte)length); + return; + } + else + { + buffer.put((byte)((length & 0x7F) | 0x80)); + length >>>= 7; + } + } + } + } +} diff -Nru jetty9-9.4.51/jetty-http/src/main/java/org/eclipse/jetty/http/compression/NBitStringDecoder.java jetty9-9.4.53/jetty-http/src/main/java/org/eclipse/jetty/http/compression/NBitStringDecoder.java --- jetty9-9.4.51/jetty-http/src/main/java/org/eclipse/jetty/http/compression/NBitStringDecoder.java 1970-01-01 00:00:00.000000000 +0000 +++ jetty9-9.4.53/jetty-http/src/main/java/org/eclipse/jetty/http/compression/NBitStringDecoder.java 2023-10-09 12:27:40.000000000 +0000 @@ -0,0 +1,138 @@ +// +// ======================================================================== +// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http.compression; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.util.CharsetStringBuilder; + +/** + *

Used to decode string literals as described in RFC7541.

+ * + *

The string literal representation consists of a single bit to indicate whether huffman encoding is used, + * followed by the string byte length encoded with the n-bit integer representation also from RFC7541, and + * the bytes of the string are directly after this.

+ * + *

Characters which are illegal field-vchar values are replaced with + * either ' ' or '?' as described in RFC9110

+ */ +public class NBitStringDecoder +{ + private final NBitIntegerDecoder _integerDecoder; + private final HuffmanDecoder _huffmanBuilder; + private final CharsetStringBuilder.Iso88591StringBuilder _builder; + private boolean _huffman; + private int _count; + private int _length; + private int _prefix; + + private State _state = State.PARSING; + + private enum State + { + PARSING, + LENGTH, + VALUE + } + + public NBitStringDecoder() + { + _integerDecoder = new NBitIntegerDecoder(); + _huffmanBuilder = new HuffmanDecoder(); + _builder = new CharsetStringBuilder.Iso88591StringBuilder(); + } + + /** + * Set the prefix length in of the string representation in bits. + * A prefix of 6 means the string representation starts after the first 2 bits. + * @param prefix the number of bits in the string prefix. + */ + public void setPrefix(int prefix) + { + if (_state != State.PARSING) + throw new IllegalStateException(); + _prefix = prefix; + } + + /** + * Decode a string from the buffer. If the buffer does not contain the complete string representation + * then a value of null is returned to indicate that more data is needed to complete parsing. + * This should be only after the prefix has been set with {@link #setPrefix(int)}. + * @param buffer the buffer containing the encoded string. + * @return the decoded string or null to indicate that more data is needed. + * @throws ArithmeticException if the string length value overflows a int. + * @throws EncodingException if the string encoding is invalid. + */ + public String decode(ByteBuffer buffer) throws EncodingException + { + while (true) + { + switch (_state) + { + case PARSING: + byte firstByte = buffer.get(buffer.position()); + _huffman = ((0x80 >>> (8 - _prefix)) & firstByte) != 0; + _state = State.LENGTH; + _integerDecoder.setPrefix(_prefix - 1); + continue; + + case LENGTH: + _length = _integerDecoder.decodeInt(buffer); + if (_length < 0) + return null; + _state = State.VALUE; + _huffmanBuilder.setLength(_length); + continue; + + case VALUE: + String value = _huffman ? _huffmanBuilder.decode(buffer) : stringDecode(buffer); + if (value != null) + reset(); + return value; + + default: + throw new IllegalStateException(_state.name()); + } + } + } + + private String stringDecode(ByteBuffer buffer) + { + for (; _count < _length; _count++) + { + if (!buffer.hasRemaining()) + return null; + _builder.append(buffer.get()); + } + + return _builder.build(); + } + + public void reset() + { + _state = State.PARSING; + _integerDecoder.reset(); + _huffmanBuilder.reset(); + _builder.reset(); + _prefix = 0; + _count = 0; + _length = 0; + _huffman = false; + } +} diff -Nru jetty9-9.4.51/jetty-http/src/main/java/org/eclipse/jetty/http/compression/NBitStringEncoder.java jetty9-9.4.53/jetty-http/src/main/java/org/eclipse/jetty/http/compression/NBitStringEncoder.java --- jetty9-9.4.51/jetty-http/src/main/java/org/eclipse/jetty/http/compression/NBitStringEncoder.java 1970-01-01 00:00:00.000000000 +0000 +++ jetty9-9.4.53/jetty-http/src/main/java/org/eclipse/jetty/http/compression/NBitStringEncoder.java 2023-10-09 12:27:40.000000000 +0000 @@ -0,0 +1,82 @@ +// +// ======================================================================== +// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http.compression; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.http.HttpTokens; + +public class NBitStringEncoder +{ + private NBitStringEncoder() + { + } + + public static int octetsNeeded(int prefix, String value, boolean huffman) + { + if (prefix <= 0 || prefix > 8) + throw new IllegalArgumentException(); + + int contentPrefix = (prefix == 1) ? 8 : prefix - 1; + int encodedValueSize = huffman ? HuffmanEncoder.octetsNeeded(value) : value.length(); + int encodedLengthSize = NBitIntegerEncoder.octetsNeeded(contentPrefix, encodedValueSize); + + // If prefix was 1, then we count an extra byte needed for the prefix. + return encodedLengthSize + encodedValueSize + (prefix == 1 ? 1 : 0); + } + + public static void encode(ByteBuffer buffer, int prefix, String value, boolean huffman) + { + if (prefix <= 0 || prefix > 8) + throw new IllegalArgumentException(); + + byte huffmanFlag = huffman ? (byte)(0x01 << (prefix - 1)) : (byte)0x00; + if (prefix == 8) + { + buffer.put(huffmanFlag); + } + else + { + int p = buffer.position() - 1; + buffer.put(p, (byte)(buffer.get(p) | huffmanFlag)); + } + + // Start encoding size & content in rest of prefix. + // If prefix was 1 we set it back to 8 to indicate to start on a new byte. + prefix = (prefix == 1) ? 8 : prefix - 1; + + if (huffman) + { + int encodedValueSize = HuffmanEncoder.octetsNeeded(value); + NBitIntegerEncoder.encode(buffer, prefix, encodedValueSize); + HuffmanEncoder.encode(buffer, value); + } + else + { + int encodedValueSize = value.length(); + NBitIntegerEncoder.encode(buffer, prefix, encodedValueSize); + for (int i = 0; i < encodedValueSize; i++) + { + char c = value.charAt(i); + c = HttpTokens.sanitizeFieldVchar(c); + buffer.put((byte)c); + } + } + } +} diff -Nru jetty9-9.4.51/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java jetty9-9.4.53/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java --- jetty9-9.4.51/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java 2023-10-09 12:27:40.000000000 +0000 @@ -499,7 +499,7 @@ /* Quick lookahead for the start state looking for a request method or an HTTP version, * otherwise skip white space until something else to parse. */ - private boolean quickStart(ByteBuffer buffer) + private void quickStart(ByteBuffer buffer) { if (_requestHandler != null) { @@ -510,7 +510,7 @@ buffer.position(buffer.position() + _methodString.length() + 1); setState(State.SPACE1); - return false; + return; } } else if (_responseHandler != null) @@ -520,7 +520,7 @@ { buffer.position(buffer.position() + _version.asString().length() + 1); setState(State.SPACE1); - return false; + return; } } @@ -541,7 +541,7 @@ _string.setLength(0); _string.append(t.getChar()); setState(_requestHandler != null ? State.METHOD : State.RESPONSE_VERSION); - return false; + return; } case OTEXT: case SPACE: @@ -559,7 +559,6 @@ throw new BadMessageException(HttpStatus.BAD_REQUEST_400); } } - return false; } private void setString(String s) @@ -974,23 +973,20 @@ case CONTENT_LENGTH: if (_hasTransferEncoding && complianceViolation(TRANSFER_ENCODING_WITH_CONTENT_LENGTH)) throw new BadMessageException(HttpStatus.BAD_REQUEST_400, "Transfer-Encoding and Content-Length"); - + long contentLength = convertContentLength(_valueString); if (_hasContentLength) { if (complianceViolation(MULTIPLE_CONTENT_LENGTHS)) throw new BadMessageException(HttpStatus.BAD_REQUEST_400, MULTIPLE_CONTENT_LENGTHS.description); - if (convertContentLength(_valueString) != _contentLength) - throw new BadMessageException(HttpStatus.BAD_REQUEST_400, MULTIPLE_CONTENT_LENGTHS.description); + if (contentLength != _contentLength) + throw new BadMessageException(HttpStatus.BAD_REQUEST_400, MULTIPLE_CONTENT_LENGTHS.getDescription()); } _hasContentLength = true; if (_endOfContent != EndOfContent.CHUNKED_CONTENT) { - _contentLength = convertContentLength(_valueString); - if (_contentLength <= 0) - _endOfContent = EndOfContent.NO_CONTENT; - else - _endOfContent = EndOfContent.CONTENT_LENGTH; + _contentLength = contentLength; + _endOfContent = EndOfContent.CONTENT_LENGTH; } break; @@ -1107,15 +1103,21 @@ private long convertContentLength(String valueString) { - try - { - return Long.parseLong(valueString); - } - catch (NumberFormatException e) + if (valueString == null || valueString.length() == 0) + throw new BadMessageException("Invalid Content-Length Value", new NumberFormatException()); + + long value = 0; + int length = valueString.length(); + + for (int i = 0; i < length; i++) { - LOG.ignore(e); - throw new BadMessageException(HttpStatus.BAD_REQUEST_400, "Invalid Content-Length Value", e); + char c = valueString.charAt(i); + if (c < '0' || c > '9') + throw new BadMessageException("Invalid Content-Length Value", new NumberFormatException()); + + value = Math.addExact(Math.multiplyExact(value, 10L), c - '0'); } + return value; } /* @@ -1511,12 +1513,11 @@ _methodString = null; _endOfContent = EndOfContent.UNKNOWN_CONTENT; _header = null; - if (quickStart(buffer)) - return true; + quickStart(buffer); } // Request/response line - if (_state.ordinal() >= State.START.ordinal() && _state.ordinal() < State.HEADER.ordinal()) + if (_state.ordinal() < State.HEADER.ordinal()) { if (parseLine(buffer)) return true; @@ -2036,7 +2037,6 @@ } } - @SuppressWarnings("serial") private static class IllegalCharacterException extends BadMessageException { private IllegalCharacterException(State state, HttpTokens.Token token, ByteBuffer buffer) diff -Nru jetty9-9.4.51/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTokens.java jetty9-9.4.53/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTokens.java --- jetty9-9.4.51/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTokens.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTokens.java 2023-10-09 12:27:40.000000000 +0000 @@ -188,5 +188,49 @@ } } } + + /** + * This is used when decoding to not decode illegal characters based on RFC9110. + * CR, LF, or NUL are replaced with ' ', all other control and multibyte characters + * are replaced with '?'. If this is given a legal character the same value will be returned. + *
+     * field-vchar = VCHAR / obs-text
+     * obs-text    = %x80-FF
+     * VCHAR       = %x21-7E
+     * 
+ * @param c the character to test. + * @return the original character or the replacement character ' ' or '?', + * the return value is guaranteed to be a valid ISO-8859-1 character. + */ + public static char sanitizeFieldVchar(char c) + { + switch (c) + { + // A recipient of CR, LF, or NUL within a field value MUST either reject the message + // or replace each of those characters with SP before further processing + case '\r': + case '\n': + case 0x00: + return ' '; + + default: + if (isIllegalFieldVchar(c)) + return '?'; + } + return c; + } + + /** + * Checks whether this is an invalid VCHAR based on RFC9110. + * If this not a valid ISO-8859-1 character or a control character + * we say that it is illegal. + * + * @param c the character to test. + * @return true if this is invalid VCHAR. + */ + public static boolean isIllegalFieldVchar(char c) + { + return (c >= 256 || c < ' '); + } } diff -Nru jetty9-9.4.51/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java jetty9-9.4.53/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java --- jetty9-9.4.51/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java 2023-10-09 12:27:40.000000000 +0000 @@ -41,6 +41,7 @@ import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.nullValue; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -1672,7 +1673,7 @@ } @Test - public void testUnknownReponseVersion() + public void testUnknownResponseVersion() { ByteBuffer buffer = BufferUtil.toBuffer( "HPPT/7.7 200 OK\r\n" + @@ -1815,65 +1816,31 @@ assertEquals(HttpParser.State.CLOSED, parser.getState()); } - @Test - public void testBadContentLength0() - { - ByteBuffer buffer = BufferUtil.toBuffer( - "GET / HTTP/1.0\r\n" + - "Content-Length: abc\r\n" + - "Connection: close\r\n" + - "\r\n"); - - HttpParser.RequestHandler handler = new Handler(); - HttpParser parser = new HttpParser(handler); - - parser.parseNext(buffer); - assertEquals("GET", _methodOrVersion); - assertEquals("Invalid Content-Length Value", _bad); - assertFalse(buffer.hasRemaining()); - assertEquals(HttpParser.State.CLOSE, parser.getState()); - parser.atEOF(); - parser.parseNext(BufferUtil.EMPTY_BUFFER); - assertEquals(HttpParser.State.CLOSED, parser.getState()); - } - - @Test - public void testBadContentLength1() - { - ByteBuffer buffer = BufferUtil.toBuffer( - "GET / HTTP/1.0\r\n" + - "Content-Length: 9999999999999999999999999999999999999999999999\r\n" + - "Connection: close\r\n" + - "\r\n"); - - HttpParser.RequestHandler handler = new Handler(); - HttpParser parser = new HttpParser(handler); - - parser.parseNext(buffer); - assertEquals("GET", _methodOrVersion); - assertEquals("Invalid Content-Length Value", _bad); - assertFalse(buffer.hasRemaining()); - assertEquals(HttpParser.State.CLOSE, parser.getState()); - parser.atEOF(); - parser.parseNext(BufferUtil.EMPTY_BUFFER); - assertEquals(HttpParser.State.CLOSED, parser.getState()); - } - - @Test - public void testBadContentLength2() + @ParameterizedTest + @ValueSource(strings = { + "abc", + "1.5", + "9999999999999999999999999999999999999999999999", + "-10", + "+10", + "1.0", + "1,0", + "10," + }) + public void testBadContentLengths(String contentLength) { ByteBuffer buffer = BufferUtil.toBuffer( - "GET / HTTP/1.0\r\n" + - "Content-Length: 1.5\r\n" + - "Connection: close\r\n" + - "\r\n"); + "GET /test HTTP/1.1\r\n" + + "Host: localhost\r\n" + + "Content-Length: " + contentLength + "\r\n" + + "\r\n" + + "1234567890\r\n"); HttpParser.RequestHandler handler = new Handler(); - HttpParser parser = new HttpParser(handler); + HttpParser parser = new HttpParser(handler, HttpCompliance.RFC2616_LEGACY); + parseAll(parser, buffer); - parser.parseNext(buffer); - assertEquals("GET", _methodOrVersion); - assertEquals("Invalid Content-Length Value", _bad); + assertThat(_bad, notNullValue()); assertFalse(buffer.hasRemaining()); assertEquals(HttpParser.State.CLOSE, parser.getState()); parser.atEOF(); @@ -2084,7 +2051,7 @@ @Test public void testBadIPv6Host() { - try (StacklessLogging s = new StacklessLogging(HttpParser.class)) + try (StacklessLogging ignored = new StacklessLogging(HttpParser.class)) { ByteBuffer buffer = BufferUtil.toBuffer( "GET / HTTP/1.1\r\n" + @@ -2930,8 +2897,8 @@ private String _methodOrVersion; private String _uriOrStatus; private String _versionOrReason; - private List _fields = new ArrayList<>(); - private List _trailers = new ArrayList<>(); + private final List _fields = new ArrayList<>(); + private final List _trailers = new ArrayList<>(); private String[] _hdr; private String[] _val; private int _headers; diff -Nru jetty9-9.4.51/jetty-http/src/test/java/org/eclipse/jetty/http/HuffmanTest.java jetty9-9.4.53/jetty-http/src/test/java/org/eclipse/jetty/http/HuffmanTest.java --- jetty9-9.4.51/jetty-http/src/test/java/org/eclipse/jetty/http/HuffmanTest.java 1970-01-01 00:00:00.000000000 +0000 +++ jetty9-9.4.53/jetty-http/src/test/java/org/eclipse/jetty/http/HuffmanTest.java 2023-10-09 12:27:40.000000000 +0000 @@ -0,0 +1,168 @@ +// +// ======================================================================== +// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http; + +import java.nio.ByteBuffer; +import java.util.Locale; +import java.util.stream.Stream; + +import org.eclipse.jetty.http.compression.EncodingException; +import org.eclipse.jetty.http.compression.HuffmanDecoder; +import org.eclipse.jetty.http.compression.HuffmanEncoder; +import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.TypeUtil; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.greaterThan; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class HuffmanTest +{ + public static String decode(ByteBuffer buffer, int length) throws EncodingException + { + HuffmanDecoder huffmanDecoder = new HuffmanDecoder(); + huffmanDecoder.setLength(length); + String decoded = huffmanDecoder.decode(buffer); + if (decoded == null) + throw new EncodingException("invalid string encoding"); + + huffmanDecoder.reset(); + return decoded; + } + + public static Stream data() + { + return Stream.of( + new String[][]{ + {"D.4.1", "f1e3c2e5f23a6ba0ab90f4ff", "www.example.com"}, + {"D.4.2", "a8eb10649cbf", "no-cache"}, + {"D.6.1k", "6402", "302"}, + {"D.6.1v", "aec3771a4b", "private"}, + {"D.6.1d", "d07abe941054d444a8200595040b8166e082a62d1bff", "Mon, 21 Oct 2013 20:13:21 GMT"}, + {"D.6.1l", "9d29ad171863c78f0b97c8e9ae82ae43d3", "https://www.example.com"}, + {"D.6.2te", "640cff", "303"}, + }).map(Arguments::of); + } + + @ParameterizedTest(name = "[{index}] spec={0}") + @MethodSource("data") + public void testDecode(String specSection, String hex, String expected) throws Exception + { + byte[] encoded = TypeUtil.fromHexString(hex); + HuffmanDecoder huffmanDecoder = new HuffmanDecoder(); + huffmanDecoder.setLength(encoded.length); + String decoded = huffmanDecoder.decode(ByteBuffer.wrap(encoded)); + assertEquals(expected, decoded, specSection); + } + + @ParameterizedTest(name = "[{index}] spec={0}") + @MethodSource("data") + public void testEncode(String specSection, String hex, String expected) + { + ByteBuffer buf = BufferUtil.allocate(1024); + int pos = BufferUtil.flipToFill(buf); + HuffmanEncoder.encode(buf, expected); + BufferUtil.flipToFlush(buf, pos); + String encoded = TypeUtil.toHexString(BufferUtil.toArray(buf)).toLowerCase(Locale.ENGLISH); + assertEquals(hex, encoded, specSection); + assertEquals(hex.length() / 2, HuffmanEncoder.octetsNeeded(expected)); + } + + public static Stream testDecode8859OnlyArguments() + { + return Stream.of( + // These are valid characters for ISO-8859-1. + Arguments.of("FfFe6f", (char)128), + Arguments.of("FfFfFbBf", (char)255), + + // RFC9110 specifies these to be replaced as ' ' during decoding. + Arguments.of("FfC7", ' '), // (char)0 + Arguments.of("FfFfFfF7", ' '), // '\r' + Arguments.of("FfFfFfF3", ' '), // '\n' + + // We replace control chars with the default replacement character of '?'. + Arguments.of("FfFfFfBf", '?') // (char)(' ' - 1) + ); + } + + @ParameterizedTest(name = "[{index}]") // don't include unprintable character in test display-name + @MethodSource("testDecode8859OnlyArguments") + public void testDecode8859Only(String hexString, char expected) throws Exception + { + ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(hexString)); + String decoded = decode(buffer, buffer.remaining()); + assertThat(decoded, equalTo("" + expected)); + } + + public static Stream testEncode8859OnlyArguments() + { + return Stream.of( + Arguments.of((char)128, (char)128), + Arguments.of((char)255, (char)255), + Arguments.of((char)0, null), + Arguments.of('\r', null), + Arguments.of('\n', null), + Arguments.of((char)456, null), + Arguments.of((char)256, null), + Arguments.of((char)-1, null), + Arguments.of((char)(' ' - 1), null) + ); + } + + @ParameterizedTest(name = "[{index}]") // don't include unprintable character in test display-name + @MethodSource("testEncode8859OnlyArguments") + public void testEncode8859Only(char value, Character expectedValue) throws Exception + { + String s = "value = '" + value + "'"; + + // If expected is null we should not be able to encode. + if (expectedValue == null) + { + assertThat(HuffmanEncoder.octetsNeeded(s), equalTo(-1)); + assertThrows(Throwable.class, () -> encode(s)); + return; + } + + String expected = "value = '" + expectedValue + "'"; + assertThat(HuffmanEncoder.octetsNeeded(s), greaterThan(0)); + ByteBuffer buffer = encode(s); + String decode = decode(buffer); + System.err.println("decoded: " + decode); + assertThat(decode, equalTo(expected)); + } + + private ByteBuffer encode(String s) + { + ByteBuffer buffer = BufferUtil.allocate(32); + BufferUtil.clearToFill(buffer); + HuffmanEncoder.encode(buffer, s); + BufferUtil.flipToFlush(buffer, 0); + return buffer; + } + + private String decode(ByteBuffer buffer) throws Exception + { + return decode(buffer, buffer.remaining()); + } +} diff -Nru jetty9-9.4.51/jetty-http/src/test/java/org/eclipse/jetty/http/NBitIntegerTest.java jetty9-9.4.53/jetty-http/src/test/java/org/eclipse/jetty/http/NBitIntegerTest.java --- jetty9-9.4.51/jetty-http/src/test/java/org/eclipse/jetty/http/NBitIntegerTest.java 1970-01-01 00:00:00.000000000 +0000 +++ jetty9-9.4.53/jetty-http/src/test/java/org/eclipse/jetty/http/NBitIntegerTest.java 2023-10-09 12:27:40.000000000 +0000 @@ -0,0 +1,207 @@ +// +// ======================================================================== +// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http; + +import java.nio.ByteBuffer; + +import org.eclipse.jetty.http.compression.NBitIntegerDecoder; +import org.eclipse.jetty.http.compression.NBitIntegerEncoder; +import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.TypeUtil; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +@SuppressWarnings("PointlessArithmeticExpression") +public class NBitIntegerTest +{ + private final NBitIntegerDecoder _decoder = new NBitIntegerDecoder(); + + @Test + public void testOctetsNeeded() + { + assertEquals(1, NBitIntegerEncoder.octetsNeeded(5, 10)); + assertEquals(3, NBitIntegerEncoder.octetsNeeded(5, 1337)); + assertEquals(1, NBitIntegerEncoder.octetsNeeded(8, 42)); + assertEquals(3, NBitIntegerEncoder.octetsNeeded(8, 1337)); + + assertEquals(1, NBitIntegerEncoder.octetsNeeded(6, 62)); + assertEquals(2, NBitIntegerEncoder.octetsNeeded(6, 63)); + assertEquals(2, NBitIntegerEncoder.octetsNeeded(6, 64)); + assertEquals(3, NBitIntegerEncoder.octetsNeeded(6, 63 + 0x00 + 0x80 * 0x01)); + assertEquals(4, NBitIntegerEncoder.octetsNeeded(6, 63 + 0x00 + 0x80 * 0x80)); + assertEquals(5, NBitIntegerEncoder.octetsNeeded(6, 63 + 0x00 + 0x80 * 0x80 * 0x80)); + } + + @Test + public void testEncode() + { + testEncode(6, 0, "00"); + testEncode(6, 1, "01"); + testEncode(6, 62, "3e"); + testEncode(6, 63, "3f00"); + testEncode(6, 63 + 1, "3f01"); + testEncode(6, 63 + 0x7e, "3f7e"); + testEncode(6, 63 + 0x7f, "3f7f"); + testEncode(6, 63 + 0x00 + 0x80 * 0x01, "3f8001"); + testEncode(6, 63 + 0x01 + 0x80 * 0x01, "3f8101"); + testEncode(6, 63 + 0x7f + 0x80 * 0x01, "3fFf01"); + testEncode(6, 63 + 0x00 + 0x80 * 0x02, "3f8002"); + testEncode(6, 63 + 0x01 + 0x80 * 0x02, "3f8102"); + testEncode(6, 63 + 0x7f + 0x80 * 0x7f, "3fFf7f"); + testEncode(6, 63 + 0x00 + 0x80 * 0x80, "3f808001"); + testEncode(6, 63 + 0x7f + 0x80 * 0x80 * 0x7f, "3fFf807f"); + testEncode(6, 63 + 0x00 + 0x80 * 0x80 * 0x80, "3f80808001"); + + testEncode(8, 0, "00"); + testEncode(8, 1, "01"); + testEncode(8, 128, "80"); + testEncode(8, 254, "Fe"); + testEncode(8, 255, "Ff00"); + testEncode(8, 255 + 1, "Ff01"); + testEncode(8, 255 + 0x7e, "Ff7e"); + testEncode(8, 255 + 0x7f, "Ff7f"); + testEncode(8, 255 + 0x80, "Ff8001"); + testEncode(8, 255 + 0x00 + 0x80 * 0x80, "Ff808001"); + } + + public void testEncode(int n, int i, String expected) + { + ByteBuffer buf = BufferUtil.allocate(16); + int p = BufferUtil.flipToFill(buf); + if (n < 8) + buf.put((byte)0x00); + NBitIntegerEncoder.encode(buf, n, i); + BufferUtil.flipToFlush(buf, p); + String r = TypeUtil.toHexString(BufferUtil.toArray(buf)); + assertEquals(expected, r); + + assertEquals(expected.length() / 2, NBitIntegerEncoder.octetsNeeded(n, i)); + } + + @Test + public void testDecode() + { + testDecode(6, 0, "00"); + testDecode(6, 1, "01"); + testDecode(6, 62, "3e"); + testDecode(6, 63, "3f00"); + testDecode(6, 63 + 1, "3f01"); + testDecode(6, 63 + 0x7e, "3f7e"); + testDecode(6, 63 + 0x7f, "3f7f"); + testDecode(6, 63 + 0x80, "3f8001"); + testDecode(6, 63 + 0x81, "3f8101"); + testDecode(6, 63 + 0x7f + 0x80 * 0x01, "3fFf01"); + testDecode(6, 63 + 0x00 + 0x80 * 0x02, "3f8002"); + testDecode(6, 63 + 0x01 + 0x80 * 0x02, "3f8102"); + testDecode(6, 63 + 0x7f + 0x80 * 0x7f, "3fFf7f"); + testDecode(6, 63 + 0x00 + 0x80 * 0x80, "3f808001"); + testDecode(6, 63 + 0x7f + 0x80 * 0x80 * 0x7f, "3fFf807f"); + testDecode(6, 63 + 0x00 + 0x80 * 0x80 * 0x80, "3f80808001"); + + testDecode(8, 0, "00"); + testDecode(8, 1, "01"); + testDecode(8, 128, "80"); + testDecode(8, 254, "Fe"); + testDecode(8, 255, "Ff00"); + testDecode(8, 255 + 1, "Ff01"); + testDecode(8, 255 + 0x7e, "Ff7e"); + testDecode(8, 255 + 0x7f, "Ff7f"); + testDecode(8, 255 + 0x80, "Ff8001"); + testDecode(8, 255 + 0x00 + 0x80 * 0x80, "Ff808001"); + } + + public void testDecode(int n, int expected, String encoded) + { + ByteBuffer buf = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); + _decoder.setPrefix(n); + assertEquals(expected, _decoder.decodeInt(buf)); + } + + @Test + public void testEncodeExampleD11() + { + ByteBuffer buf = BufferUtil.allocate(16); + int p = BufferUtil.flipToFill(buf); + buf.put((byte)0x77); + buf.put((byte)0xFF); + NBitIntegerEncoder.encode(buf, 5, 10); + BufferUtil.flipToFlush(buf, p); + + String r = TypeUtil.toHexString(BufferUtil.toArray(buf)); + + assertEquals("77Ea", r); + } + + @Test + public void testDecodeExampleD11() + { + ByteBuffer buf = ByteBuffer.wrap(TypeUtil.fromHexString("77EaFF")); + buf.position(1); + _decoder.setPrefix(5); + assertEquals(10, _decoder.decodeInt(buf)); + } + + @Test + public void testEncodeExampleD12() + { + ByteBuffer buf = BufferUtil.allocate(16); + int p = BufferUtil.flipToFill(buf); + buf.put((byte)0x88); + buf.put((byte)0x00); + NBitIntegerEncoder.encode(buf, 5, 1337); + BufferUtil.flipToFlush(buf, p); + + String r = TypeUtil.toHexString(BufferUtil.toArray(buf)); + assertEquals("881f9a0a", r); + } + + @Test + public void testDecodeExampleD12() + { + ByteBuffer buf = ByteBuffer.wrap(TypeUtil.fromHexString("881f9a0aff")); + buf.position(1); + _decoder.setPrefix(5); + assertEquals(1337, _decoder.decodeInt(buf)); + } + + @Test + public void testEncodeExampleD13() + { + ByteBuffer buf = BufferUtil.allocate(16); + int p = BufferUtil.flipToFill(buf); + buf.put((byte)0x88); + buf.put((byte)0xFF); + NBitIntegerEncoder.encode(buf, 8, 42); + BufferUtil.flipToFlush(buf, p); + + String r = TypeUtil.toHexString(BufferUtil.toArray(buf)); + + assertEquals("88Ff2a", r); + } + + @Test + public void testDecodeExampleD13() + { + ByteBuffer buf = ByteBuffer.wrap(TypeUtil.fromHexString("882aFf")); + buf.position(1); + _decoder.setPrefix(8); + assertEquals(42, _decoder.decodeInt(buf)); + } +} diff -Nru jetty9-9.4.51/jetty-http2/http2-alpn-tests/pom.xml jetty9-9.4.53/jetty-http2/http2-alpn-tests/pom.xml --- jetty9-9.4.51/jetty-http2/http2-alpn-tests/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-alpn-tests/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ org.eclipse.jetty.http2 http2-parent - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 diff -Nru jetty9-9.4.51/jetty-http2/http2-client/pom.xml jetty9-9.4.53/jetty-http2/http2-client/pom.xml --- jetty9-9.4.51/jetty-http2/http2-client/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-client/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ org.eclipse.jetty.http2 http2-parent - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 diff -Nru jetty9-9.4.51/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java jetty9-9.4.53/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java --- jetty9-9.4.51/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientConnectionFactory.java 2023-10-09 12:27:40.000000000 +0000 @@ -27,10 +27,12 @@ import org.eclipse.jetty.http2.HTTP2Connection; import org.eclipse.jetty.http2.ISession; import org.eclipse.jetty.http2.api.Session; +import org.eclipse.jetty.http2.frames.Frame; import org.eclipse.jetty.http2.frames.PrefaceFrame; import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.http2.frames.WindowUpdateFrame; import org.eclipse.jetty.http2.generator.Generator; +import org.eclipse.jetty.http2.hpack.HpackContext; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.ClientConnectionFactory; @@ -56,25 +58,32 @@ public Connection newConnection(EndPoint endPoint, Map context) { HTTP2Client client = (HTTP2Client)context.get(CLIENT_CONTEXT_KEY); - ByteBufferPool byteBufferPool = (ByteBufferPool)context.get(BYTE_BUFFER_POOL_CONTEXT_KEY); - Executor executor = (Executor)context.get(EXECUTOR_CONTEXT_KEY); - Scheduler scheduler = (Scheduler)context.get(SCHEDULER_CONTEXT_KEY); + ByteBufferPool byteBufferPool = client.getByteBufferPool(); + Executor executor = client.getExecutor(); + Scheduler scheduler = client.getScheduler(); Session.Listener listener = (Session.Listener)context.get(SESSION_LISTENER_CONTEXT_KEY); @SuppressWarnings("unchecked") - Promise promise = (Promise)context.get(SESSION_PROMISE_CONTEXT_KEY); + Promise sessionPromise = (Promise)context.get(SESSION_PROMISE_CONTEXT_KEY); - Generator generator = new Generator(byteBufferPool, client.getMaxDynamicTableSize(), client.getMaxHeaderBlockFragment()); + Generator generator = new Generator(byteBufferPool, client.getMaxHeaderBlockFragment()); FlowControlStrategy flowControl = client.getFlowControlStrategyFactory().newFlowControlStrategy(); - HTTP2ClientSession session = new HTTP2ClientSession(scheduler, endPoint, generator, listener, flowControl); - session.setMaxRemoteStreams(client.getMaxConcurrentPushedStreams()); - Parser parser = new Parser(byteBufferPool, session, 4096, 8192); - parser.setMaxFrameLength(client.getMaxFrameLength()); + Parser parser = new Parser(byteBufferPool, client.getMaxResponseHeadersSize()); + parser.setMaxFrameSize(client.getMaxFrameSize()); parser.setMaxSettingsKeys(client.getMaxSettingsKeys()); + HTTP2ClientSession session = new HTTP2ClientSession(scheduler, endPoint, parser, generator, listener, flowControl); + session.setMaxRemoteStreams(client.getMaxConcurrentPushedStreams()); + session.setMaxEncoderTableCapacity(client.getMaxEncoderTableCapacity()); + long streamIdleTimeout = client.getStreamIdleTimeout(); + if (streamIdleTimeout > 0) + session.setStreamIdleTimeout(streamIdleTimeout); + HTTP2ClientConnection connection = new HTTP2ClientConnection(client, byteBufferPool, executor, endPoint, - parser, session, client.getInputBufferSize(), promise, listener); + session, client.getInputBufferSize(), sessionPromise, listener); connection.addListener(connectionListener); + parser.init(connection.wrapParserListener(session)); + return customize(connection, context); } @@ -84,9 +93,9 @@ private final Promise promise; private final Session.Listener listener; - private HTTP2ClientConnection(HTTP2Client client, ByteBufferPool byteBufferPool, Executor executor, EndPoint endpoint, Parser parser, ISession session, int bufferSize, Promise promise, Session.Listener listener) + private HTTP2ClientConnection(HTTP2Client client, ByteBufferPool byteBufferPool, Executor executor, EndPoint endpoint, ISession session, int bufferSize, Promise promise, Session.Listener listener) { - super(byteBufferPool, executor, endpoint, parser, session, bufferSize); + super(byteBufferPool, executor, endpoint, session, bufferSize); this.client = client; this.promise = promise; this.listener = listener; @@ -98,12 +107,52 @@ Map settings = listener.onPreface(getSession()); if (settings == null) settings = new HashMap<>(); - settings.computeIfAbsent(SettingsFrame.INITIAL_WINDOW_SIZE, k -> client.getInitialStreamRecvWindow()); - settings.computeIfAbsent(SettingsFrame.MAX_CONCURRENT_STREAMS, k -> client.getMaxConcurrentPushedStreams()); - Integer maxFrameLength = settings.get(SettingsFrame.MAX_FRAME_SIZE); - if (maxFrameLength != null) - getParser().setMaxFrameLength(maxFrameLength); + // Below we want to populate any settings to send to the server + // that have a different default than what prescribed by the RFC. + // Changing the configuration is done when the SETTINGS is sent. + + settings.compute(SettingsFrame.HEADER_TABLE_SIZE, (k, v) -> + { + if (v == null) + { + v = client.getMaxDecoderTableCapacity(); + if (v == HpackContext.DEFAULT_MAX_TABLE_CAPACITY) + v = null; + } + return v; + }); + settings.computeIfAbsent(SettingsFrame.MAX_CONCURRENT_STREAMS, k -> client.getMaxConcurrentPushedStreams()); + settings.compute(SettingsFrame.INITIAL_WINDOW_SIZE, (k, v) -> + { + if (v == null) + { + v = client.getInitialStreamRecvWindow(); + if (v == FlowControlStrategy.DEFAULT_WINDOW_SIZE) + v = null; + } + return v; + }); + settings.compute(SettingsFrame.MAX_FRAME_SIZE, (k, v) -> + { + if (v == null) + { + v = client.getMaxFrameSize(); + if (v == Frame.DEFAULT_MAX_LENGTH) + v = null; + } + return v; + }); + settings.compute(SettingsFrame.MAX_HEADER_LIST_SIZE, (k, v) -> + { + if (v == null) + { + v = client.getMaxResponseHeadersSize(); + if (v <= 0) + v = null; + } + return v; + }); PrefaceFrame prefaceFrame = new PrefaceFrame(); SettingsFrame settingsFrame = new SettingsFrame(settings, false); diff -Nru jetty9-9.4.51/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java jetty9-9.4.53/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java --- jetty9-9.4.51/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java 2023-10-09 12:27:40.000000000 +0000 @@ -36,6 +36,7 @@ import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.http2.frames.Frame; import org.eclipse.jetty.http2.frames.SettingsFrame; +import org.eclipse.jetty.http2.hpack.HpackContext; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.ClientConnectionFactory; import org.eclipse.jetty.io.Connection; @@ -125,6 +126,7 @@ private int selectors = 1; private long idleTimeout = 30000; private long connectTimeout = 10000; + private long streamIdleTimeout; private boolean connectBlocking; private SocketAddress bindAddress; private boolean tcpNoDelay = true; @@ -132,11 +134,13 @@ private List protocols = Arrays.asList("h2", "h2-17", "h2-16", "h2-15", "h2-14"); private int initialSessionRecvWindow = 16 * 1024 * 1024; private int initialStreamRecvWindow = 8 * 1024 * 1024; - private int maxFrameLength = Frame.DEFAULT_MAX_LENGTH; + private int maxFrameSize = Frame.DEFAULT_MAX_LENGTH; private int maxConcurrentPushedStreams = 32; private int maxSettingsKeys = SettingsFrame.DEFAULT_MAX_KEYS; - private int maxDynamicTableSize = 4096; + private int maxDecoderTableCapacity = HpackContext.DEFAULT_MAX_TABLE_CAPACITY; + private int maxEncoderTableCapacity = HpackContext.DEFAULT_MAX_TABLE_CAPACITY; private int maxHeaderBlockFragment = 0; + private int maxResponseHeadersSize = 8 * 1024; private FlowControlStrategy.Factory flowControlStrategyFactory = () -> new BufferingFlowControlStrategy(0.5F); @Override @@ -263,6 +267,17 @@ this.idleTimeout = idleTimeout; } + @ManagedAttribute("The stream idle timeout in milliseconds") + public long getStreamIdleTimeout() + { + return streamIdleTimeout; + } + + public void setStreamIdleTimeout(long streamIdleTimeout) + { + this.streamIdleTimeout = streamIdleTimeout; + } + @ManagedAttribute("The connect timeout in milliseconds") public long getConnectTimeout() { @@ -352,15 +367,28 @@ this.initialStreamRecvWindow = initialStreamRecvWindow; } + @Deprecated @ManagedAttribute("The max frame length in bytes") public int getMaxFrameLength() { - return maxFrameLength; + return getMaxFrameSize(); } + @Deprecated public void setMaxFrameLength(int maxFrameLength) { - this.maxFrameLength = maxFrameLength; + setMaxFrameSize(maxFrameLength); + } + + @ManagedAttribute("The max frame size in bytes") + public int getMaxFrameSize() + { + return maxFrameSize; + } + + public void setMaxFrameSize(int maxFrameSize) + { + this.maxFrameSize = maxFrameSize; } @ManagedAttribute("The max number of concurrent pushed streams") @@ -385,15 +413,45 @@ this.maxSettingsKeys = maxSettingsKeys; } + @ManagedAttribute("The HPACK encoder dynamic table maximum capacity") + public int getMaxEncoderTableCapacity() + { + return maxEncoderTableCapacity; + } + + /** + *

Sets the limit for the encoder HPACK dynamic table capacity.

+ *

Setting this value to {@code 0} disables the use of the dynamic table.

+ * + * @param maxEncoderTableCapacity The HPACK encoder dynamic table maximum capacity + */ + public void setMaxEncoderTableCapacity(int maxEncoderTableCapacity) + { + this.maxEncoderTableCapacity = maxEncoderTableCapacity; + } + + @ManagedAttribute("The HPACK decoder dynamic table maximum capacity") + public int getMaxDecoderTableCapacity() + { + return maxDecoderTableCapacity; + } + + public void setMaxDecoderTableCapacity(int maxDecoderTableCapacity) + { + this.maxDecoderTableCapacity = maxDecoderTableCapacity; + } + + @Deprecated @ManagedAttribute("The HPACK dynamic table maximum size") public int getMaxDynamicTableSize() { - return maxDynamicTableSize; + return getMaxDecoderTableCapacity(); } + @Deprecated public void setMaxDynamicTableSize(int maxDynamicTableSize) { - this.maxDynamicTableSize = maxDynamicTableSize; + setMaxDecoderTableCapacity(maxDynamicTableSize); } @ManagedAttribute("The max size of header block fragments") @@ -407,6 +465,17 @@ this.maxHeaderBlockFragment = maxHeaderBlockFragment; } + @ManagedAttribute("The max size of response headers") + public int getMaxResponseHeadersSize() + { + return maxResponseHeadersSize; + } + + public void setMaxResponseHeadersSize(int maxResponseHeadersSize) + { + this.maxResponseHeadersSize = maxResponseHeadersSize; + } + public void connect(InetSocketAddress address, Session.Listener listener, Promise promise) { connect(null, address, listener, promise); diff -Nru jetty9-9.4.51/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java jetty9-9.4.53/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java --- jetty9-9.4.51/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2ClientSession.java 2023-10-09 12:27:40.000000000 +0000 @@ -29,6 +29,7 @@ import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.PushPromiseFrame; import org.eclipse.jetty.http2.generator.Generator; +import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.log.Log; @@ -39,9 +40,16 @@ { private static final Logger LOG = Log.getLogger(HTTP2ClientSession.class); + @Deprecated public HTTP2ClientSession(Scheduler scheduler, EndPoint endPoint, Generator generator, Session.Listener listener, FlowControlStrategy flowControl) { - super(scheduler, endPoint, generator, listener, flowControl, 1); + this(scheduler, endPoint, null, generator, listener, flowControl); + throw new UnsupportedOperationException(); + } + + public HTTP2ClientSession(Scheduler scheduler, EndPoint endPoint, Parser parser, Generator generator, Session.Listener listener, FlowControlStrategy flowControl) + { + super(scheduler, endPoint, parser, generator, listener, flowControl, 1); } @Override diff -Nru jetty9-9.4.51/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java jetty9-9.4.53/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java --- jetty9-9.4.51/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java 2023-10-09 12:27:40.000000000 +0000 @@ -26,6 +26,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Random; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; @@ -40,6 +41,7 @@ import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.ErrorCode; +import org.eclipse.jetty.http2.HTTP2Session; import org.eclipse.jetty.http2.api.Session; import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.api.server.ServerSessionListener; @@ -49,10 +51,7 @@ import org.eclipse.jetty.http2.frames.ResetFrame; import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.http2.hpack.HpackException; -import org.eclipse.jetty.http2.parser.RateControl; -import org.eclipse.jetty.http2.parser.ServerParser; import org.eclipse.jetty.http2.server.RawHTTP2ServerConnectionFactory; -import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; @@ -60,15 +59,19 @@ import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.Jetty; import org.eclipse.jetty.util.Promise; +import org.eclipse.jetty.util.StringUtil; import org.junit.jupiter.api.Test; import static org.awaitility.Awaitility.await; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -742,6 +745,7 @@ @Test public void testGoAwayRespondedWithGoAway() throws Exception { + CountDownLatch goAwayLatch = new CountDownLatch(1); ServerSessionListener.Adapter serverListener = new ServerSessionListener.Adapter() { @Override @@ -753,24 +757,15 @@ stream.getSession().close(ErrorCode.NO_ERROR.code, null, Callback.NOOP); return null; } - }; - CountDownLatch goAwayLatch = new CountDownLatch(1); - RawHTTP2ServerConnectionFactory connectionFactory = new RawHTTP2ServerConnectionFactory(new HttpConfiguration(), serverListener) - { + @Override - protected ServerParser newServerParser(Connector connector, ServerParser.Listener listener, RateControl rateControl) + public void onGoAway(Session session, GoAwayFrame frame) { - return super.newServerParser(connector, new ServerParser.Listener.Wrapper(listener) - { - @Override - public void onGoAway(GoAwayFrame frame) - { - super.onGoAway(frame); - goAwayLatch.countDown(); - } - }, rateControl); + goAwayLatch.countDown(); } }; + + RawHTTP2ServerConnectionFactory connectionFactory = new RawHTTP2ServerConnectionFactory(new HttpConfiguration(), serverListener); prepareServer(connectionFactory); server.start(); @@ -897,6 +892,150 @@ assertTrue(resetLatch.await(5, TimeUnit.SECONDS)); } + @Test + public void testClientSendsLargeHeader() throws Exception + { + CountDownLatch settingsLatch = new CountDownLatch(2); + + CompletableFuture serverFailureFuture = new CompletableFuture<>(); + CompletableFuture serverCloseReasonFuture = new CompletableFuture<>(); + start(new ServerSessionListener.Adapter() + { + @Override + public void onSettings(Session session, SettingsFrame frame) + { + settingsLatch.countDown(); + } + + @Override + public void onFailure(Session session, Throwable failure) + { + serverFailureFuture.complete(failure); + } + + @Override + public void onClose(Session session, GoAwayFrame frame) + { + serverCloseReasonFuture.complete(frame.tryConvertPayload()); + } + }); + + CompletableFuture clientFailureFuture = new CompletableFuture<>(); + CompletableFuture clientCloseReasonFuture = new CompletableFuture<>(); + Session.Listener.Adapter listener = new Session.Listener.Adapter() + { + @Override + public void onSettings(Session session, SettingsFrame frame) + { + settingsLatch.countDown(); + } + + @Override + public void onFailure(Session session, Throwable failure) + { + clientFailureFuture.complete(failure); + } + + @Override + public void onClose(Session session, GoAwayFrame frame) + { + clientCloseReasonFuture.complete(frame.tryConvertPayload()); + } + }; + + HTTP2Session session = (HTTP2Session)newClient(listener); + assertTrue(settingsLatch.await(5, TimeUnit.SECONDS)); + session.getGenerator().getHpackEncoder().setMaxHeaderListSize(1024 * 1024); + + String value = StringUtil.stringFrom("x", 8 * 1024); + HttpFields requestFields = new HttpFields(); + requestFields.put("custom", value); + MetaData.Request metaData = newRequest("GET", requestFields); + HeadersFrame request = new HeadersFrame(metaData, null, true); + session.newStream(request, new FuturePromise<>(), new Stream.Listener.Adapter()); + + // Test failure and close reason on client. + String closeReason = clientCloseReasonFuture.get(5, TimeUnit.SECONDS); + assertThat(closeReason, equalTo("invalid_hpack_block")); + assertNull(clientFailureFuture.getNow(null)); + + // Test failure and close reason on server. + closeReason = serverCloseReasonFuture.get(5, TimeUnit.SECONDS); + assertThat(closeReason, equalTo("invalid_hpack_block")); + Throwable failure = serverFailureFuture.get(5, TimeUnit.SECONDS); + assertThat(failure, instanceOf(IOException.class)); + assertThat(failure.getMessage(), containsString("invalid_hpack_block")); + } + + @Test + public void testServerSendsLargeHeader() throws Exception + { + CompletableFuture serverFailureFuture = new CompletableFuture<>(); + CompletableFuture serverCloseReasonFuture = new CompletableFuture<>(); + start(new ServerSessionListener.Adapter() + { + @Override + public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) + { + HTTP2Session session = (HTTP2Session)stream.getSession(); + session.getGenerator().getHpackEncoder().setMaxHeaderListSize(1024 * 1024); + + String value = StringUtil.stringFrom("x", 8 * 1024); + HttpFields fields = new HttpFields(); + fields.put("custom", value); + MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, fields); + stream.headers(new HeadersFrame(stream.getId(), response, null, true), Callback.NOOP); + return null; + } + + @Override + public void onFailure(Session session, Throwable failure) + { + serverFailureFuture.complete(failure); + } + + @Override + public void onClose(Session session, GoAwayFrame frame) + { + serverCloseReasonFuture.complete(frame.tryConvertPayload()); + } + }); + + CompletableFuture clientFailureFuture = new CompletableFuture<>(); + CompletableFuture clientCloseReasonFuture = new CompletableFuture<>(); + Session.Listener.Adapter listener = new Session.Listener.Adapter() + { + @Override + public void onFailure(Session session, Throwable failure) + { + clientFailureFuture.complete(failure); + } + + @Override + public void onClose(Session session, GoAwayFrame frame) + { + clientCloseReasonFuture.complete(frame.tryConvertPayload()); + } + }; + + Session session = newClient(listener); + MetaData.Request metaData = newRequest("GET", new HttpFields()); + HeadersFrame request = new HeadersFrame(metaData, null, true); + session.newStream(request, new FuturePromise<>(), new Stream.Listener.Adapter()); + + // Test failure and close reason on server. + String closeReason = serverCloseReasonFuture.get(5, TimeUnit.SECONDS); + assertThat(closeReason, equalTo("invalid_hpack_block")); + assertNull(serverFailureFuture.getNow(null)); + + // Test failure and close reason on client. + closeReason = clientCloseReasonFuture.get(5, TimeUnit.SECONDS); + assertThat(closeReason, equalTo("invalid_hpack_block")); + Throwable failure = clientFailureFuture.get(5, TimeUnit.SECONDS); + assertThat(failure, instanceOf(IOException.class)); + assertThat(failure.getMessage(), containsString("invalid_hpack_block")); + } + private static void sleep(long time) { try diff -Nru jetty9-9.4.51/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PrefaceTest.java jetty9-9.4.53/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PrefaceTest.java --- jetty9-9.4.51/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PrefaceTest.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PrefaceTest.java 2023-10-09 12:27:40.000000000 +0000 @@ -35,7 +35,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; -import java.util.function.UnaryOperator; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpStatus; @@ -169,15 +168,15 @@ socket.write(buffers.toArray(new ByteBuffer[buffers.size()])); Queue settings = new ArrayDeque<>(); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 4096); + parser.init(new Parser.Listener.Adapter() { @Override public void onSettings(SettingsFrame frame) { settings.offer(frame); } - }, 4096, 8192); - parser.init(UnaryOperator.identity()); + }); ByteBuffer buffer = byteBufferPool.acquire(1024, true); while (true) @@ -302,7 +301,8 @@ CountDownLatch clientSettingsLatch = new CountDownLatch(1); AtomicBoolean responded = new AtomicBoolean(); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 4096); + parser.init(new Parser.Listener.Adapter() { @Override public void onSettings(SettingsFrame frame) @@ -319,8 +319,7 @@ if (frame.isEndStream()) responded.set(true); } - }, 4096, 8192); - parser.init(UnaryOperator.identity()); + }); // HTTP/2 parsing. while (true) diff -Nru jetty9-9.4.51/jetty-http2/http2-common/pom.xml jetty9-9.4.53/jetty-http2/http2-common/pom.xml --- jetty9-9.4.51/jetty-http2/http2-common/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-common/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ org.eclipse.jetty.http2 http2-parent - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 diff -Nru jetty9-9.4.51/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java jetty9-9.4.53/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java --- jetty9-9.4.51/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/generator/Generator.java 2023-10-09 12:27:40.000000000 +0000 @@ -35,15 +35,21 @@ public Generator(ByteBufferPool byteBufferPool) { - this(byteBufferPool, 4096, 0); + this(byteBufferPool, 0); } + @Deprecated public Generator(ByteBufferPool byteBufferPool, int maxDynamicTableSize, int maxHeaderBlockFragment) { + this(byteBufferPool, maxHeaderBlockFragment); + } + + public Generator(ByteBufferPool byteBufferPool, int maxHeaderBlockFragment) + { this.byteBufferPool = byteBufferPool; headerGenerator = new HeaderGenerator(); - hpackEncoder = new HpackEncoder(maxDynamicTableSize); + hpackEncoder = new HpackEncoder(); this.generators = new FrameGenerator[FrameType.values().length]; this.generators[FrameType.HEADERS.getType()] = new HeadersGenerator(headerGenerator, hpackEncoder, maxHeaderBlockFragment); @@ -66,14 +72,21 @@ return byteBufferPool; } + public HpackEncoder getHpackEncoder() + { + return hpackEncoder; + } + + @Deprecated public void setValidateHpackEncoding(boolean validateEncoding) { - hpackEncoder.setValidateEncoding(validateEncoding); + getHpackEncoder().setValidateEncoding(validateEncoding); } - public void setHeaderTableSize(int headerTableSize) + @Deprecated + public void setHeaderTableSize(int maxTableSize) { - hpackEncoder.setRemoteMaxDynamicTableSize(headerTableSize); + getHpackEncoder().setTableCapacity(maxTableSize); } public void setMaxFrameSize(int maxFrameSize) @@ -91,8 +104,9 @@ return dataGenerator.generate(lease, frame, maxLength); } + @Deprecated public void setMaxHeaderListSize(int value) { - hpackEncoder.setMaxHeaderListSize(value); + getHpackEncoder().setMaxHeaderListSize(value); } } diff -Nru jetty9-9.4.51/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java jetty9-9.4.53/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java --- jetty9-9.4.51/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java 2023-10-09 12:27:40.000000000 +0000 @@ -27,6 +27,7 @@ import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.parser.Parser; +import org.eclipse.jetty.http2.parser.ServerParser; import org.eclipse.jetty.io.AbstractConnection; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.EndPoint; @@ -52,23 +53,26 @@ private final HTTP2Producer producer = new HTTP2Producer(); private final AtomicLong bytesIn = new AtomicLong(); private final ByteBufferPool byteBufferPool; - private final Parser parser; private final ISession session; private final int bufferSize; private final ExecutionStrategy strategy; + @Deprecated public HTTP2Connection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endPoint, Parser parser, ISession session, int bufferSize) { + this(byteBufferPool, executor, endPoint, session, bufferSize); + } + + public HTTP2Connection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endPoint, ISession session, int bufferSize) + { super(endPoint, executor); this.byteBufferPool = byteBufferPool; - this.parser = parser; this.session = session; this.bufferSize = bufferSize; if (PEC_MODE) executor = new TryExecutor.NoTryExecutor(executor); this.strategy = new EatWhatYouKill(producer, executor); LifeCycle.start(strategy); - parser.init(ParserListener::new); } @Override @@ -104,7 +108,8 @@ protected Parser getParser() { - return parser; + // TODO: can we downcast. + return ((HTTP2Session)session).getParser(); } protected void setInputBuffer(ByteBuffer buffer) @@ -112,6 +117,11 @@ producer.setInputBuffer(buffer); } + public Parser.Listener wrapParserListener(Parser.Listener listener) + { + return new ParserListener(listener); + } + @Override public void onOpen() { @@ -258,7 +268,7 @@ { while (networkBuffer.hasRemaining()) { - parser.parse(networkBuffer.getBuffer()); + getParser().parse(networkBuffer.getBuffer()); if (failed) return null; } @@ -378,7 +388,7 @@ { private ParserListener(Parser.Listener listener) { - super(listener); + super(listener == null ? new ServerParser.Listener.Adapter() : listener); } @Override diff -Nru jetty9-9.4.51/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java jetty9-9.4.53/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java --- jetty9-9.4.51/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java 2023-10-09 12:27:40.000000000 +0000 @@ -55,6 +55,7 @@ import org.eclipse.jetty.http2.frames.StreamFrame; import org.eclipse.jetty.http2.frames.WindowUpdateFrame; import org.eclipse.jetty.http2.generator.Generator; +import org.eclipse.jetty.http2.hpack.HpackEncoder; import org.eclipse.jetty.http2.hpack.HpackException; import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.ByteBufferPool; @@ -94,6 +95,7 @@ private final AtomicLong bytesWritten = new AtomicLong(); private final Scheduler scheduler; private final EndPoint endPoint; + private final Parser parser; private final Generator generator; private final Session.Listener listener; private final FlowControlStrategy flowControl; @@ -103,12 +105,21 @@ private long streamIdleTimeout; private int initialSessionRecvWindow; private int writeThreshold; + private int maxEncoderTableCapacity; private boolean pushEnabled; + @Deprecated public HTTP2Session(Scheduler scheduler, EndPoint endPoint, Generator generator, Session.Listener listener, FlowControlStrategy flowControl, int initialStreamId) { + this(scheduler, endPoint, null, generator, listener, flowControl, initialStreamId); + throw new UnsupportedOperationException(); + } + + public HTTP2Session(Scheduler scheduler, EndPoint endPoint, Parser parser, Generator generator, Session.Listener listener, FlowControlStrategy flowControl, int initialStreamId) + { this.scheduler = scheduler; this.endPoint = endPoint; + this.parser = parser; this.generator = generator; this.listener = listener; this.flowControl = flowControl; @@ -205,11 +216,27 @@ this.writeThreshold = writeThreshold; } + @ManagedAttribute("The HPACK encoder dynamic table maximum capacity") + public int getMaxEncoderTableCapacity() + { + return maxEncoderTableCapacity; + } + + public void setMaxEncoderTableCapacity(int maxEncoderTableCapacity) + { + this.maxEncoderTableCapacity = maxEncoderTableCapacity; + } + public EndPoint getEndPoint() { return endPoint; } + public Parser getParser() + { + return parser; + } + public Generator getGenerator() { return generator; @@ -346,8 +373,20 @@ if (frame.isReply()) return; - // Iterate over all settings - for (Map.Entry entry : frame.getSettings().entrySet()) + Map settings = frame.getSettings(); + configure(settings, false); + notifySettings(this, frame); + + if (reply) + { + SettingsFrame replyFrame = new SettingsFrame(Collections.emptyMap(), true); + settings(replyFrame, Callback.NOOP); + } + } + + private void configure(Map settings, boolean local) + { + for (Map.Entry entry : settings.entrySet()) { int key = entry.getKey(); int value = entry.getValue(); @@ -356,8 +395,17 @@ case SettingsFrame.HEADER_TABLE_SIZE: { if (LOG.isDebugEnabled()) - LOG.debug("Updating HPACK header table size to {} for {}", value, this); - generator.setHeaderTableSize(value); + LOG.debug("Updating HPACK {} max table capacity to {} for {}", local ? "decoder" : "encoder", value, this); + if (local) + { + parser.getHpackDecoder().setMaxTableCapacity(value); + } + else + { + HpackEncoder hpackEncoder = generator.getHpackEncoder(); + hpackEncoder.setMaxTableCapacity(value); + hpackEncoder.setTableCapacity(Math.min(value, getMaxEncoderTableCapacity())); + } break; } case SettingsFrame.ENABLE_PUSH: @@ -371,29 +419,38 @@ case SettingsFrame.MAX_CONCURRENT_STREAMS: { if (LOG.isDebugEnabled()) - LOG.debug("Updating max local concurrent streams to {} for {}", value, this); - maxLocalStreams = value; + LOG.debug("Updating max {} concurrent streams to {} for {}", local ? "remote" : "local", value, this); + if (local) + maxRemoteStreams = value; + else + maxLocalStreams = value; break; } case SettingsFrame.INITIAL_WINDOW_SIZE: { if (LOG.isDebugEnabled()) LOG.debug("Updating initial stream window size to {} for {}", value, this); - flowControl.updateInitialStreamWindow(this, value, false); + flowControl.updateInitialStreamWindow(this, value, local); break; } case SettingsFrame.MAX_FRAME_SIZE: { if (LOG.isDebugEnabled()) - LOG.debug("Updating max frame size to {} for {}", value, this); - generator.setMaxFrameSize(value); + LOG.debug("Updating {} max frame size to {} for {}", local ? "parser" : "generator", value, this); + if (local) + parser.setMaxFrameSize(value); + else + generator.setMaxFrameSize(value); break; } case SettingsFrame.MAX_HEADER_LIST_SIZE: { if (LOG.isDebugEnabled()) - LOG.debug("Updating max header list size to {} for {}", value, this); - generator.setMaxHeaderListSize(value); + LOG.debug("Updating {} max header list size to {} for {}", local ? "decoder" : "encoder", value, this); + if (local) + parser.getHpackDecoder().setMaxHeaderListSize(value); + else + generator.getHpackEncoder().setMaxHeaderListSize(value); break; } default: @@ -404,13 +461,6 @@ } } } - notifySettings(this, frame); - - if (reply) - { - SettingsFrame replyFrame = new SettingsFrame(Collections.emptyMap(), true); - settings(replyFrame, Callback.NOOP); - } } @Override @@ -487,6 +537,21 @@ } @Override + public void onWindowUpdate(IStream stream, WindowUpdateFrame frame) + { + // WindowUpdateFrames arrive concurrently with writes. + // Increasing (or reducing) the window size concurrently + // with writes requires coordination with the flusher, that + // decides how many frames to write depending on the available + // window sizes. If the window sizes vary concurrently, the + // flusher may take non-optimal or wrong decisions. + // Here, we "queue" window updates to the flusher, so it will + // be the only component responsible for window updates, for + // both increments and reductions. + flusher.window(stream, frame); + } + + @Override public void onStreamFailure(int streamId, int error, String reason) { Callback callback = Callback.from(() -> reset(getStream(streamId), new ResetFrame(streamId, error), Callback.NOOP)); @@ -889,21 +954,6 @@ } @Override - public void onWindowUpdate(IStream stream, WindowUpdateFrame frame) - { - // WindowUpdateFrames arrive concurrently with writes. - // Increasing (or reducing) the window size concurrently - // with writes requires coordination with the flusher, that - // decides how many frames to write depending on the available - // window sizes. If the window sizes vary concurrently, the - // flusher may take non-optimal or wrong decisions. - // Here, we "queue" window updates to the flusher, so it will - // be the only component responsible for window updates, for - // both increments and reductions. - flusher.window(stream, frame); - } - - @Override @ManagedAttribute(value = "Whether HTTP/2 push is enabled", readonly = true) public boolean isPushEnabled() { @@ -1005,7 +1055,7 @@ return lastRemoteStreamId.get(); } - private void updateLastRemoteStreamId(int streamId) + protected void updateLastRemoteStreamId(int streamId) { Atomics.updateMax(lastRemoteStreamId, streamId); } @@ -1208,9 +1258,8 @@ case SETTINGS: { SettingsFrame settingsFrame = (SettingsFrame)frame; - Integer initialWindow = settingsFrame.getSettings().get(SettingsFrame.INITIAL_WINDOW_SIZE); - if (initialWindow != null) - flowControl.updateInitialStreamWindow(HTTP2Session.this, initialWindow, true); + if (!settingsFrame.isReply()) + configure(settingsFrame.getSettings(), true); break; } default: @@ -1407,6 +1456,8 @@ @Override public void failed(Throwable x) { + if (LOG.isDebugEnabled()) + LOG.debug("OnReset failed", x); complete(); } @@ -1424,14 +1475,15 @@ /** *

The HTTP/2 specification requires that stream ids are monotonically increasing, - * see https://tools.ietf.org/html/rfc7540#section-5.1.1.

+ * see RFC 7540, 5.1.1.

*

This implementation uses a queue to atomically reserve a stream id and claim * a slot in the queue; the slot is then assigned the entries to write.

*

Concurrent threads push slots in the queue but only one thread flushes * the slots, up to the slot that has a non-null entries to write, therefore * guaranteeing that frames are sent strictly in their stream id order.

*

This class also coordinates the creation of streams with the close of - * the session, see https://tools.ietf.org/html/rfc7540#section-6.8.

+ * the session, see + * RFC 7540, 6.8.

*/ private class StreamsState { @@ -2180,7 +2232,7 @@ if (flushing == null) flushing = thread; else if (flushing != thread) - return; // another thread is flushing + return; // Another thread is flushing. Slot slot = slots.peek(); entries = slot == null ? null : slot.entries; @@ -2188,7 +2240,8 @@ if (entries == null) { flushing = null; - break; // No more slots or null entries, so we may iterate on the flusher + // No more slots or null entries, so we may iterate on the flusher. + break; } slots.poll(); diff -Nru jetty9-9.4.51/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ContinuationBodyParser.java jetty9-9.4.53/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ContinuationBodyParser.java --- jetty9-9.4.51/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ContinuationBodyParser.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ContinuationBodyParser.java 2023-10-09 12:27:40.000000000 +0000 @@ -80,16 +80,28 @@ int remaining = buffer.remaining(); if (remaining < length) { - headerBlockFragments.storeFragment(buffer, remaining, false); + ContinuationFrame frame = new ContinuationFrame(getStreamId(), false); + if (!rateControlOnEvent(frame)) + return connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_continuation_frame_rate"); + + if (!headerBlockFragments.storeFragment(buffer, remaining, false)) + return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_continuation_stream"); + length -= remaining; break; } else { - boolean last = hasFlag(Flags.END_HEADERS); - headerBlockFragments.storeFragment(buffer, length, last); + boolean endHeaders = hasFlag(Flags.END_HEADERS); + ContinuationFrame frame = new ContinuationFrame(getStreamId(), endHeaders); + if (!rateControlOnEvent(frame)) + return connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_continuation_frame_rate"); + + if (!headerBlockFragments.storeFragment(buffer, length, endHeaders)) + return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_continuation_stream"); + reset(); - if (last) + if (endHeaders) return onHeaders(buffer); return true; } @@ -107,17 +119,21 @@ { ByteBuffer headerBlock = headerBlockFragments.complete(); MetaData metaData = headerBlockParser.parse(headerBlock, headerBlock.remaining()); - if (metaData == null) - return true; + HeadersFrame frame = new HeadersFrame(getStreamId(), metaData, headerBlockFragments.getPriorityFrame(), headerBlockFragments.isEndStream()); + headerBlockFragments.reset(); + if (metaData == HeaderBlockParser.SESSION_FAILURE) return false; - HeadersFrame frame = new HeadersFrame(getStreamId(), metaData, headerBlockFragments.getPriorityFrame(), headerBlockFragments.isEndStream()); - if (metaData == HeaderBlockParser.STREAM_FAILURE) + + if (metaData != HeaderBlockParser.STREAM_FAILURE) + { + notifyHeaders(frame); + } + else { if (!rateControlOnEvent(frame)) - return connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_continuation_frame_rate"); + return connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_headers_frame_rate"); } - notifyHeaders(frame); return true; } diff -Nru jetty9-9.4.51/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderBlockFragments.java jetty9-9.4.53/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderBlockFragments.java --- jetty9-9.4.51/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderBlockFragments.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderBlockFragments.java 2023-10-09 12:27:40.000000000 +0000 @@ -24,22 +24,40 @@ public class HeaderBlockFragments { + private final int maxCapacity; private PriorityFrame priorityFrame; - private boolean endStream; private int streamId; + private boolean endStream; private ByteBuffer storage; - public void storeFragment(ByteBuffer fragment, int length, boolean last) + public HeaderBlockFragments(int maxCapacity) + { + this.maxCapacity = maxCapacity; + } + + void reset() + { + priorityFrame = null; + streamId = 0; + endStream = false; + storage = null; + } + + public boolean storeFragment(ByteBuffer fragment, int length, boolean last) { if (storage == null) { - int space = last ? length : length * 2; - storage = ByteBuffer.allocate(space); + if (length > maxCapacity) + return false; + int capacity = last ? length : length * 2; + storage = ByteBuffer.allocate(capacity); } // Grow the storage if necessary. if (storage.remaining() < length) { + if (storage.position() + length > maxCapacity) + return false; int space = last ? length : length * 2; int capacity = storage.position() + space; ByteBuffer newStorage = ByteBuffer.allocate(capacity); @@ -53,6 +71,7 @@ fragment.limit(fragment.position() + length); storage.put(fragment); fragment.limit(limit); + return true; } public PriorityFrame getPriorityFrame() @@ -77,10 +96,8 @@ public ByteBuffer complete() { - ByteBuffer result = storage; - storage = null; - result.flip(); - return result; + storage.flip(); + return storage; } public int getStreamId() diff -Nru jetty9-9.4.51/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderBlockParser.java jetty9-9.4.53/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderBlockParser.java --- jetty9-9.4.51/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderBlockParser.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeaderBlockParser.java 2023-10-09 12:27:40.000000000 +0000 @@ -50,6 +50,11 @@ this.notifier = notifier; } + public int getMaxHeaderListSize() + { + return hpackDecoder.getMaxHeaderListSize(); + } + /** * Parses @{code blockLength} HPACK bytes from the given {@code buffer}. * diff -Nru jetty9-9.4.51/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java jetty9-9.4.53/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java --- jetty9-9.4.51/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/HeadersBodyParser.java 2023-10-09 12:27:40.000000000 +0000 @@ -76,8 +76,15 @@ } else { - headerBlockFragments.setStreamId(getStreamId()); - headerBlockFragments.setEndStream(isEndStream()); + if (headerBlockFragments.getStreamId() != 0) + { + connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_headers_frame"); + } + else + { + headerBlockFragments.setStreamId(getStreamId()); + headerBlockFragments.setEndStream(isEndStream()); + } } } @@ -173,8 +180,24 @@ } case HEADERS: { + if (!hasFlag(Flags.END_HEADERS)) + { + headerBlockFragments.setStreamId(getStreamId()); + headerBlockFragments.setEndStream(isEndStream()); + if (hasFlag(Flags.PRIORITY)) + headerBlockFragments.setPriorityFrame(new PriorityFrame(getStreamId(), parentStreamId, weight, exclusive)); + } + state = State.HEADER_BLOCK; + break; + } + case HEADER_BLOCK: + { if (hasFlag(Flags.END_HEADERS)) { + int maxLength = headerBlockParser.getMaxHeaderListSize(); + if (maxLength > 0 && length > maxLength) + return connectionFailure(buffer, ErrorCode.REFUSED_STREAM_ERROR.code, "invalid_headers_frame"); + MetaData metaData = headerBlockParser.parse(buffer, length); if (metaData == HeaderBlockParser.SESSION_FAILURE) return false; @@ -192,7 +215,7 @@ { HeadersFrame frame = new HeadersFrame(getStreamId(), metaData, null, isEndStream()); if (!rateControlOnEvent(frame)) - connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_headers_frame_rate"); + return connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_headers_frame_rate"); } } } @@ -201,16 +224,14 @@ int remaining = buffer.remaining(); if (remaining < length) { - headerBlockFragments.storeFragment(buffer, remaining, false); + if (!headerBlockFragments.storeFragment(buffer, remaining, false)) + return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_headers_frame"); length -= remaining; } else { - headerBlockFragments.setStreamId(getStreamId()); - headerBlockFragments.setEndStream(isEndStream()); - if (hasFlag(Flags.PRIORITY)) - headerBlockFragments.setPriorityFrame(new PriorityFrame(getStreamId(), parentStreamId, weight, exclusive)); - headerBlockFragments.storeFragment(buffer, length, false); + if (!headerBlockFragments.storeFragment(buffer, length, false)) + return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_headers_frame"); state = State.PADDING; loop = paddingLength == 0; } @@ -254,6 +275,6 @@ private enum State { - PREPARE, PADDING_LENGTH, EXCLUSIVE, PARENT_STREAM_ID, PARENT_STREAM_ID_BYTES, WEIGHT, HEADERS, PADDING + PREPARE, PADDING_LENGTH, EXCLUSIVE, PARENT_STREAM_ID, PARENT_STREAM_ID_BYTES, WEIGHT, HEADERS, HEADER_BLOCK, PADDING } } diff -Nru jetty9-9.4.51/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java jetty9-9.4.53/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java --- jetty9-9.4.51/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java 2023-10-09 12:27:40.000000000 +0000 @@ -49,36 +49,50 @@ private static final Logger LOG = Log.getLogger(Parser.class); private final ByteBufferPool byteBufferPool; - private final Listener listener; private final HeaderParser headerParser; private final HpackDecoder hpackDecoder; private final BodyParser[] bodyParsers; + private Listener listener; private UnknownBodyParser unknownBodyParser; - private int maxFrameLength = Frame.DEFAULT_MAX_LENGTH; + private int maxFrameSize = Frame.DEFAULT_MAX_LENGTH; private int maxSettingsKeys = SettingsFrame.DEFAULT_MAX_KEYS; private boolean continuation; private State state = State.HEADER; + @Deprecated public Parser(ByteBufferPool byteBufferPool, Listener listener, int maxDynamicTableSize, int maxHeaderSize) { - this(byteBufferPool, listener, maxDynamicTableSize, maxHeaderSize, RateControl.NO_RATE_CONTROL); + this(byteBufferPool, maxHeaderSize, RateControl.NO_RATE_CONTROL); } - public Parser(ByteBufferPool byteBufferPool, Listener listener, int maxDynamicTableSize, int maxHeaderSize, RateControl rateControl) + public Parser(ByteBufferPool byteBufferPool, int maxHeaderSize) + { + this(byteBufferPool, maxHeaderSize, RateControl.NO_RATE_CONTROL); + } + + public Parser(ByteBufferPool byteBufferPool, int maxHeaderSize, RateControl rateControl) { this.byteBufferPool = byteBufferPool; - this.listener = listener; this.headerParser = new HeaderParser(rateControl == null ? RateControl.NO_RATE_CONTROL : rateControl); - this.hpackDecoder = new HpackDecoder(maxDynamicTableSize, maxHeaderSize); + this.hpackDecoder = new HpackDecoder(maxHeaderSize); this.bodyParsers = new BodyParser[FrameType.values().length]; } + @Deprecated public void init(UnaryOperator wrapper) { - Listener listener = wrapper.apply(this.listener); + Listener listener = wrapper.apply(new Listener.Adapter()); + init(listener); + } + + public void init(Listener listener) + { + if (this.listener != null) + throw new IllegalStateException("Invalid parser initialization"); + this.listener = listener; unknownBodyParser = new UnknownBodyParser(headerParser, listener); HeaderBlockParser headerBlockParser = new HeaderBlockParser(headerParser, byteBufferPool, hpackDecoder, unknownBodyParser); - HeaderBlockFragments headerBlockFragments = new HeaderBlockFragments(); + HeaderBlockFragments headerBlockFragments = new HeaderBlockFragments(hpackDecoder.getMaxHeaderListSize()); bodyParsers[FrameType.DATA.getType()] = new DataBodyParser(headerParser, listener); bodyParsers[FrameType.HEADERS.getType()] = new HeadersBodyParser(headerParser, listener, headerBlockParser, headerBlockFragments); bodyParsers[FrameType.PRIORITY.getType()] = new PriorityBodyParser(headerParser, listener); @@ -91,6 +105,16 @@ bodyParsers[FrameType.CONTINUATION.getType()] = new ContinuationBodyParser(headerParser, listener, headerBlockParser, headerBlockFragments); } + protected Listener getListener() + { + return listener; + } + + public HpackDecoder getHpackDecoder() + { + return hpackDecoder; + } + private void reset() { headerParser.reset(); @@ -151,7 +175,7 @@ if (LOG.isDebugEnabled()) LOG.debug("Parsed {} frame header from {}@{}", headerParser, buffer, Integer.toHexString(buffer.hashCode())); - if (headerParser.getLength() > getMaxFrameLength()) + if (headerParser.getLength() > getMaxFrameSize()) return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR, "invalid_frame_length"); FrameType frameType = FrameType.from(getFrameType()); @@ -219,14 +243,26 @@ return headerParser.hasFlag(bit); } + @Deprecated public int getMaxFrameLength() { - return maxFrameLength; + return getMaxFrameSize(); + } + + @Deprecated + public void setMaxFrameLength(int maxFrameSize) + { + setMaxFrameSize(maxFrameSize); + } + + public int getMaxFrameSize() + { + return maxFrameSize; } - public void setMaxFrameLength(int maxFrameLength) + public void setMaxFrameSize(int maxFrameSize) { - this.maxFrameLength = maxFrameLength; + this.maxFrameSize = maxFrameSize; } public int getMaxSettingsKeys() diff -Nru jetty9-9.4.51/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java jetty9-9.4.53/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java --- jetty9-9.4.51/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/PushPromiseBodyParser.java 2023-10-09 12:27:40.000000000 +0000 @@ -23,6 +23,7 @@ import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http2.ErrorCode; import org.eclipse.jetty.http2.Flags; +import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.PushPromiseFrame; public class PushPromiseBodyParser extends BodyParser @@ -70,13 +71,9 @@ length = getBodyLength(); if (isPadding()) - { state = State.PADDING_LENGTH; - } else - { state = State.STREAM_ID; - } break; } case PADDING_LENGTH: @@ -124,6 +121,10 @@ } case HEADERS: { + int maxLength = headerBlockParser.getMaxHeaderListSize(); + if (maxLength > 0 && length > maxLength) + return connectionFailure(buffer, ErrorCode.REFUSED_STREAM_ERROR.code, "invalid_headers_frame"); + MetaData metaData = headerBlockParser.parse(buffer, length); if (metaData == HeaderBlockParser.SESSION_FAILURE) return false; @@ -132,7 +133,15 @@ state = State.PADDING; loop = paddingLength == 0; if (metaData != HeaderBlockParser.STREAM_FAILURE) + { onPushPromise(streamId, metaData); + } + else + { + HeadersFrame frame = new HeadersFrame(getStreamId(), metaData, null, isEndStream()); + if (!rateControlOnEvent(frame)) + return connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_headers_frame_rate"); + } } break; } diff -Nru jetty9-9.4.51/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java jetty9-9.4.53/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java --- jetty9-9.4.51/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ResetBodyParser.java 2023-10-09 12:27:40.000000000 +0000 @@ -63,7 +63,7 @@ { if (buffer.remaining() >= 4) { - return onReset(buffer.getInt()); + return onReset(buffer, buffer.getInt()); } else { @@ -78,7 +78,7 @@ --cursor; error += currByte << (8 * cursor); if (cursor == 0) - return onReset(error); + return onReset(buffer, error); break; } default: @@ -90,9 +90,11 @@ return false; } - private boolean onReset(int error) + private boolean onReset(ByteBuffer buffer, int error) { ResetFrame frame = new ResetFrame(getStreamId(), error); + if (!rateControlOnEvent(frame)) + return connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_rst_stream_frame_rate"); reset(); notifyReset(frame); return true; diff -Nru jetty9-9.4.51/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ServerParser.java jetty9-9.4.53/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ServerParser.java --- jetty9-9.4.51/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ServerParser.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/ServerParser.java 2023-10-09 12:27:40.000000000 +0000 @@ -32,15 +32,30 @@ { private static final Logger LOG = Log.getLogger(ServerParser.class); - private final Listener listener; - private final PrefaceParser prefaceParser; + private PrefaceParser prefaceParser; private State state = State.PREFACE; private boolean notifyPreface = true; + @Deprecated public ServerParser(ByteBufferPool byteBufferPool, Listener listener, int maxDynamicTableSize, int maxHeaderSize, RateControl rateControl) { - super(byteBufferPool, listener, maxDynamicTableSize, maxHeaderSize, rateControl); - this.listener = listener; + this(byteBufferPool, maxHeaderSize, rateControl); + } + + public ServerParser(ByteBufferPool byteBufferPool, int maxHeaderSize) + { + super(byteBufferPool, maxHeaderSize); + } + + public ServerParser(ByteBufferPool byteBufferPool, int maxHeaderSize, RateControl rateControl) + { + super(byteBufferPool, maxHeaderSize, rateControl); + } + + @Override + public void init(Parser.Listener listener) + { + super.init(listener); this.prefaceParser = new PrefaceParser(listener); } @@ -137,9 +152,23 @@ private void notifyPreface() { + Parser.Listener listener = getListener(); try { - listener.onPreface(); + while (true) + { + if (listener instanceof ServerParser.Listener) + { + ((ServerParser.Listener)listener).onPreface(); + break; + } + + // Unwrap to try and find a ServerParser.Listener. + if (listener instanceof Parser.Listener.Wrapper) + listener = ((Parser.Listener.Wrapper)listener).getParserListener(); + else + break; + } } catch (Throwable x) { diff -Nru jetty9-9.4.51/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java jetty9-9.4.53/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java --- jetty9-9.4.51/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/SettingsBodyParser.java 2023-10-09 12:27:40.000000000 +0000 @@ -73,12 +73,22 @@ @Override protected void emptyBody(ByteBuffer buffer) { + if (!validateFrame(buffer, getStreamId(), 0)) + return; boolean isReply = hasFlag(Flags.ACK); SettingsFrame frame = new SettingsFrame(Collections.emptyMap(), isReply); - if (!isReply && !rateControlOnEvent(frame)) - connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_settings_frame_rate"); - else - onSettings(frame); + onSettings(buffer, frame); + } + + private boolean validateFrame(ByteBuffer buffer, int streamId, int bodyLength) + { + // SPEC: wrong streamId is treated as connection error. + if (streamId != 0) + return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_settings_frame"); + // SPEC: reply with body is treated as connection error. + if (hasFlag(Flags.ACK) && bodyLength > 0) + return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_settings_frame"); + return true; } @Override @@ -95,9 +105,8 @@ { case PREPARE: { - // SPEC: wrong streamId is treated as connection error. - if (streamId != 0) - return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_settings_frame"); + if (!validateFrame(buffer, streamId, bodyLength)) + return false; length = bodyLength; settings = new HashMap<>(); state = State.SETTING_ID; @@ -211,11 +220,13 @@ return connectionFailure(buffer, ErrorCode.PROTOCOL_ERROR.code, "invalid_settings_max_frame_size"); SettingsFrame frame = new SettingsFrame(settings, hasFlag(Flags.ACK)); - return onSettings(frame); + return onSettings(buffer, frame); } - private boolean onSettings(SettingsFrame frame) + private boolean onSettings(ByteBuffer buffer, SettingsFrame frame) { + if (!rateControlOnEvent(frame)) + return connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_settings_frame_rate"); reset(); notifySettings(frame); return true; diff -Nru jetty9-9.4.51/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/UnknownBodyParser.java jetty9-9.4.53/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/UnknownBodyParser.java --- jetty9-9.4.51/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/UnknownBodyParser.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/UnknownBodyParser.java 2023-10-09 12:27:40.000000000 +0000 @@ -40,7 +40,6 @@ boolean parsed = cursor == 0; if (parsed && !rateControlOnEvent(new UnknownFrame(getFrameType()))) return connectionFailure(buffer, ErrorCode.ENHANCE_YOUR_CALM_ERROR.code, "invalid_unknown_frame_rate"); - return parsed; } diff -Nru jetty9-9.4.51/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ContinuationParseTest.java jetty9-9.4.53/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ContinuationParseTest.java --- jetty9-9.4.51/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ContinuationParseTest.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ContinuationParseTest.java 2023-10-09 12:27:40.000000000 +0000 @@ -21,7 +21,8 @@ import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; -import java.util.function.UnaryOperator; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.IntStream; import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpField; @@ -38,6 +39,8 @@ import org.eclipse.jetty.io.MappedByteBufferPool; import org.junit.jupiter.api.Test; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.greaterThan; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -51,7 +54,8 @@ HeadersGenerator generator = new HeadersGenerator(new HeaderGenerator(), new HpackEncoder()); final List frames = new ArrayList<>(); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 4096); + parser.init(new Parser.Listener.Adapter() { @Override public void onHeaders(HeadersFrame frame) @@ -64,8 +68,7 @@ { frames.add(new HeadersFrame(null, null, false)); } - }, 4096, 8192); - parser.init(UnaryOperator.identity()); + }); // Iterate a few times to be sure the parser is properly reset. for (int i = 0; i < 2; ++i) @@ -160,4 +163,54 @@ assertNull(priority); } } + + @Test + public void testLargeHeadersBlock() throws Exception + { + // Use a ByteBufferPool with a small factor, so that the accumulation buffer is not too large. + ByteBufferPool byteBufferPool = new MappedByteBufferPool(128); + // A small max headers size, used for both accumulation and decoding. + int maxHeadersSize = 512; + Parser parser = new Parser(byteBufferPool, maxHeadersSize); + // Specify headers block size to generate CONTINUATION frames. + int maxHeadersBlockFragment = 128; + HeadersGenerator generator = new HeadersGenerator(new HeaderGenerator(), new HpackEncoder(), maxHeadersBlockFragment); + + int streamId = 13; + HttpFields fields = new HttpFields(); + fields.put("Accept", "text/html"); + // Large header that generates a large headers block. + StringBuilder large = new StringBuilder(); + IntStream.range(0, 256).forEach(i -> large.append("Jetty")); + fields.put("User-Agent", large.toString()); + + MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP.asString(), new HostPortHttpField("localhost:8080"), "/path", HttpVersion.HTTP_2, fields, -1); + + ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); + generator.generateHeaders(lease, streamId, metaData, null, true); + List byteBuffers = lease.getByteBuffers(); + assertThat(byteBuffers.stream().mapToInt(ByteBuffer::remaining).sum(), greaterThan(maxHeadersSize)); + + AtomicBoolean failed = new AtomicBoolean(); + parser.init(new Parser.Listener.Adapter() + { + @Override + public void onConnectionFailure(int error, String reason) + { + failed.set(true); + } + }); + // Set a large max headers size for decoding, to ensure + // the failure is due to accumulation, not decoding. + parser.getHpackDecoder().setMaxHeaderListSize(10 * maxHeadersSize); + + for (ByteBuffer byteBuffer : byteBuffers) + { + parser.parse(byteBuffer); + if (failed.get()) + break; + } + + assertTrue(failed.get()); + } } diff -Nru jetty9-9.4.51/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java jetty9-9.4.53/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java --- jetty9-9.4.51/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java 2023-10-09 12:27:40.000000000 +0000 @@ -22,7 +22,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Random; -import java.util.function.UnaryOperator; import org.eclipse.jetty.http2.generator.DataGenerator; import org.eclipse.jetty.http2.generator.HeaderGenerator; @@ -93,15 +92,15 @@ DataGenerator generator = new DataGenerator(new HeaderGenerator()); final List frames = new ArrayList<>(); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 4096); + parser.init(new Parser.Listener.Adapter() { @Override public void onData(DataFrame frame) { frames.add(frame); } - }, 4096, 8192); - parser.init(UnaryOperator.identity()); + }); // Iterate a few times to be sure generator and parser are properly reset. for (int i = 0; i < 2; ++i) @@ -133,15 +132,15 @@ DataGenerator generator = new DataGenerator(new HeaderGenerator()); final List frames = new ArrayList<>(); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 4096); + parser.init(new Parser.Listener.Adapter() { @Override public void onData(DataFrame frame) { frames.add(frame); } - }, 4096, 8192); - parser.init(UnaryOperator.identity()); + }); // Iterate a few times to be sure generator and parser are properly reset. for (int i = 0; i < 2; ++i) diff -Nru jetty9-9.4.51/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/FrameFloodTest.java jetty9-9.4.53/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/FrameFloodTest.java --- jetty9-9.4.51/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/FrameFloodTest.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/FrameFloodTest.java 2023-10-09 12:27:40.000000000 +0000 @@ -21,7 +21,6 @@ import java.nio.ByteBuffer; import java.time.Duration; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.UnaryOperator; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; @@ -95,21 +94,29 @@ } @Test - public void testSettingsFrameFlood() + public void testEmptySettingsFrameFlood() { byte[] payload = new byte[0]; testFrameFlood(null, frameFrom(payload.length, FrameType.SETTINGS.getType(), 0, 0, payload)); } @Test + public void testSettingsFrameFlood() + { + // | Key0 | Key1 | Value0 | Value1 | Value2 | Value3 | + byte[] payload = new byte[]{0, 8, 0, 0, 0, 1}; + testFrameFlood(null, frameFrom(payload.length, FrameType.SETTINGS.getType(), 0, 0, payload)); + } + + @Test public void testPingFrameFlood() { byte[] payload = {0, 0, 0, 0, 0, 0, 0, 0}; testFrameFlood(null, frameFrom(payload.length, FrameType.PING.getType(), 0, 0, payload)); } - + @Test - public void testContinuationFrameFlood() + public void testEmptyContinuationFrameFlood() { int streamId = 13; byte[] headersPayload = new byte[0]; @@ -119,6 +126,23 @@ } @Test + public void testContinuationFrameFlood() + { + int streamId = 13; + byte[] headersPayload = new byte[0]; + byte[] headersBytes = frameFrom(headersPayload.length, FrameType.HEADERS.getType(), 0, streamId, headersPayload); + byte[] continuationPayload = new byte[1]; + testFrameFlood(headersBytes, frameFrom(continuationPayload.length, FrameType.CONTINUATION.getType(), 0, streamId, continuationPayload)); + } + + @Test + public void testResetStreamFrameFlood() + { + byte[] payload = {0, 0, 0, 0}; + testFrameFlood(null, frameFrom(payload.length, FrameType.RST_STREAM.getType(), 0, 13, payload)); + } + + @Test public void testUnknownFrameFlood() { byte[] payload = {0, 0, 0, 0}; @@ -128,15 +152,15 @@ private void testFrameFlood(byte[] preamble, byte[] bytes) { AtomicBoolean failed = new AtomicBoolean(); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 8192, new WindowRateControl(8, Duration.ofSeconds(1))); + parser.init(new Parser.Listener.Adapter() { @Override public void onConnectionFailure(int error, String reason) { failed.set(true); } - }, 4096, 8192, new WindowRateControl(8, Duration.ofSeconds(1))); - parser.init(UnaryOperator.identity()); + }); if (preamble != null) { diff -Nru jetty9-9.4.51/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java jetty9-9.4.53/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java --- jetty9-9.4.51/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java 2023-10-09 12:27:40.000000000 +0000 @@ -22,7 +22,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Random; -import java.util.function.UnaryOperator; import org.eclipse.jetty.http2.generator.GoAwayGenerator; import org.eclipse.jetty.http2.generator.HeaderGenerator; @@ -45,15 +44,15 @@ GoAwayGenerator generator = new GoAwayGenerator(new HeaderGenerator()); final List frames = new ArrayList<>(); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 4096); + parser.init(new Parser.Listener.Adapter() { @Override public void onGoAway(GoAwayFrame frame) { frames.add(frame); } - }, 4096, 8192); - parser.init(UnaryOperator.identity()); + }); int lastStreamId = 13; int error = 17; @@ -87,15 +86,15 @@ GoAwayGenerator generator = new GoAwayGenerator(new HeaderGenerator()); final List frames = new ArrayList<>(); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 4096); + parser.init(new Parser.Listener.Adapter() { @Override public void onGoAway(GoAwayFrame frame) { frames.add(frame); } - }, 4096, 8192); - parser.init(UnaryOperator.identity()); + }); int lastStreamId = 13; int error = 17; diff -Nru jetty9-9.4.51/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java jetty9-9.4.53/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java --- jetty9-9.4.51/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java 2023-10-09 12:27:40.000000000 +0000 @@ -21,7 +21,6 @@ import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; -import java.util.function.UnaryOperator; import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpField; @@ -57,15 +56,15 @@ MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP, new HostPortHttpField("localhost:8080"), "/path", HttpVersion.HTTP_2, fields); final List frames = new ArrayList<>(); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 4096); + parser.init(new Parser.Listener.Adapter() { @Override public void onHeaders(HeadersFrame frame) { frames.add(frame); } - }, 4096, 8192); - parser.init(UnaryOperator.identity()); + }); // Iterate a few times to be sure generator and parser are properly reset. for (int i = 0; i < 2; ++i) @@ -110,15 +109,15 @@ HeadersGenerator generator = new HeadersGenerator(new HeaderGenerator(), new HpackEncoder()); final List frames = new ArrayList<>(); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 4096); + parser.init(new Parser.Listener.Adapter() { @Override public void onHeaders(HeadersFrame frame) { frames.add(frame); } - }, 4096, 8192); - parser.init(UnaryOperator.identity()); + }); // Iterate a few times to be sure generator and parser are properly reset. for (int i = 0; i < 2; ++i) diff -Nru jetty9-9.4.51/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/MaxFrameSizeParseTest.java jetty9-9.4.53/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/MaxFrameSizeParseTest.java --- jetty9-9.4.51/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/MaxFrameSizeParseTest.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/MaxFrameSizeParseTest.java 2023-10-09 12:27:40.000000000 +0000 @@ -20,7 +20,6 @@ import java.nio.ByteBuffer; import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.UnaryOperator; import org.eclipse.jetty.http2.ErrorCode; import org.eclipse.jetty.http2.parser.Parser; @@ -40,16 +39,16 @@ int maxFrameLength = Frame.DEFAULT_MAX_LENGTH + 16; AtomicInteger failure = new AtomicInteger(); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 4096); + parser.setMaxFrameSize(maxFrameLength); + parser.init(new Parser.Listener.Adapter() { @Override public void onConnectionFailure(int error, String reason) { failure.set(error); } - }, 4096, 8192); - parser.setMaxFrameLength(maxFrameLength); - parser.init(UnaryOperator.identity()); + }); // Iterate a few times to be sure the parser is properly reset. for (int i = 0; i < 2; ++i) diff -Nru jetty9-9.4.51/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java jetty9-9.4.53/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java --- jetty9-9.4.51/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java 2023-10-09 12:27:40.000000000 +0000 @@ -22,7 +22,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Random; -import java.util.function.UnaryOperator; import org.eclipse.jetty.http2.generator.HeaderGenerator; import org.eclipse.jetty.http2.generator.PingGenerator; @@ -45,15 +44,15 @@ PingGenerator generator = new PingGenerator(new HeaderGenerator()); final List frames = new ArrayList<>(); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 4096); + parser.init(new Parser.Listener.Adapter() { @Override public void onPing(PingFrame frame) { frames.add(frame); } - }, 4096, 8192); - parser.init(UnaryOperator.identity()); + }); byte[] payload = new byte[8]; new Random().nextBytes(payload); @@ -86,15 +85,15 @@ PingGenerator generator = new PingGenerator(new HeaderGenerator()); final List frames = new ArrayList<>(); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 4096); + parser.init(new Parser.Listener.Adapter() { @Override public void onPing(PingFrame frame) { frames.add(frame); } - }, 4096, 8192); - parser.init(UnaryOperator.identity()); + }); byte[] payload = new byte[8]; new Random().nextBytes(payload); @@ -127,15 +126,15 @@ PingGenerator generator = new PingGenerator(new HeaderGenerator()); final List frames = new ArrayList<>(); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 4096); + parser.init(new Parser.Listener.Adapter() { @Override public void onPing(PingFrame frame) { frames.add(frame); } - }, 4096, 8192); - parser.init(UnaryOperator.identity()); + }); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); PingFrame ping = new PingFrame(System.nanoTime(), true); diff -Nru jetty9-9.4.51/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java jetty9-9.4.53/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java --- jetty9-9.4.51/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java 2023-10-09 12:27:40.000000000 +0000 @@ -21,7 +21,6 @@ import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; -import java.util.function.UnaryOperator; import org.eclipse.jetty.http2.generator.HeaderGenerator; import org.eclipse.jetty.http2.generator.PriorityGenerator; @@ -42,15 +41,15 @@ PriorityGenerator generator = new PriorityGenerator(new HeaderGenerator()); final List frames = new ArrayList<>(); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 4096); + parser.init(new Parser.Listener.Adapter() { @Override public void onPriority(PriorityFrame frame) { frames.add(frame); } - }, 4096, 8192); - parser.init(UnaryOperator.identity()); + }); int streamId = 13; int parentStreamId = 17; @@ -87,15 +86,15 @@ PriorityGenerator generator = new PriorityGenerator(new HeaderGenerator()); final List frames = new ArrayList<>(); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 4096); + parser.init(new Parser.Listener.Adapter() { @Override public void onPriority(PriorityFrame frame) { frames.add(frame); } - }, 4096, 8192); - parser.init(UnaryOperator.identity()); + }); int streamId = 13; int parentStreamId = 17; diff -Nru jetty9-9.4.51/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java jetty9-9.4.53/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java --- jetty9-9.4.51/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java 2023-10-09 12:27:40.000000000 +0000 @@ -21,7 +21,6 @@ import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; -import java.util.function.UnaryOperator; import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpField; @@ -50,15 +49,15 @@ PushPromiseGenerator generator = new PushPromiseGenerator(new HeaderGenerator(), new HpackEncoder()); final List frames = new ArrayList<>(); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 4096); + parser.init(new Parser.Listener.Adapter() { @Override public void onPushPromise(PushPromiseFrame frame) { frames.add(frame); } - }, 4096, 8192); - parser.init(UnaryOperator.identity()); + }); int streamId = 13; int promisedStreamId = 17; @@ -103,15 +102,15 @@ PushPromiseGenerator generator = new PushPromiseGenerator(new HeaderGenerator(), new HpackEncoder()); final List frames = new ArrayList<>(); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 4096); + parser.init(new Parser.Listener.Adapter() { @Override public void onPushPromise(PushPromiseFrame frame) { frames.add(frame); } - }, 4096, 8192); - parser.init(UnaryOperator.identity()); + }); int streamId = 13; int promisedStreamId = 17; diff -Nru jetty9-9.4.51/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java jetty9-9.4.53/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java --- jetty9-9.4.51/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java 2023-10-09 12:27:40.000000000 +0000 @@ -21,7 +21,6 @@ import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; -import java.util.function.UnaryOperator; import org.eclipse.jetty.http2.generator.HeaderGenerator; import org.eclipse.jetty.http2.generator.ResetGenerator; @@ -42,15 +41,15 @@ ResetGenerator generator = new ResetGenerator(new HeaderGenerator()); final List frames = new ArrayList<>(); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 4096); + parser.init(new Parser.Listener.Adapter() { @Override public void onReset(ResetFrame frame) { frames.add(frame); } - }, 4096, 8192); - parser.init(UnaryOperator.identity()); + }); int streamId = 13; int error = 17; @@ -83,15 +82,15 @@ ResetGenerator generator = new ResetGenerator(new HeaderGenerator()); final List frames = new ArrayList<>(); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 4096); + parser.init(new Parser.Listener.Adapter() { @Override public void onReset(ResetFrame frame) { frames.add(frame); } - }, 4096, 8192); - parser.init(UnaryOperator.identity()); + }); int streamId = 13; int error = 17; diff -Nru jetty9-9.4.51/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java jetty9-9.4.53/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java --- jetty9-9.4.51/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java 2023-10-09 12:27:40.000000000 +0000 @@ -25,7 +25,6 @@ import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.UnaryOperator; import org.eclipse.jetty.http2.ErrorCode; import org.eclipse.jetty.http2.generator.HeaderGenerator; @@ -36,6 +35,7 @@ import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; public class SettingsGenerateParseTest @@ -45,8 +45,7 @@ @Test public void testGenerateParseNoSettings() { - - List frames = testGenerateParse(Collections.emptyMap()); + List frames = testGenerateParse(Collections.emptyMap(), true); assertEquals(1, frames.size()); SettingsFrame frame = frames.get(0); assertEquals(0, frame.getSettings().size()); @@ -63,7 +62,7 @@ int key2 = 19; Integer value2 = 23; settings1.put(key2, value2); - List frames = testGenerateParse(settings1); + List frames = testGenerateParse(settings1, false); assertEquals(1, frames.size()); SettingsFrame frame = frames.get(0); Map settings2 = frame.getSettings(); @@ -72,26 +71,26 @@ assertEquals(value2, settings2.get(key2)); } - private List testGenerateParse(Map settings) + private List testGenerateParse(Map settings, boolean reply) { SettingsGenerator generator = new SettingsGenerator(new HeaderGenerator()); List frames = new ArrayList<>(); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 8192); + parser.init(new Parser.Listener.Adapter() { @Override public void onSettings(SettingsFrame frame) { frames.add(frame); } - }, 4096, 8192); - parser.init(UnaryOperator.identity()); + }); // Iterate a few times to be sure generator and parser are properly reset. for (int i = 0; i < 2; ++i) { ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - generator.generateSettings(lease, settings, true); + generator.generateSettings(lease, settings, reply); frames.clear(); for (ByteBuffer buffer : lease.getByteBuffers()) @@ -112,20 +111,20 @@ SettingsGenerator generator = new SettingsGenerator(new HeaderGenerator()); AtomicInteger errorRef = new AtomicInteger(); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 8192); + parser.init(new Parser.Listener.Adapter() { @Override public void onConnectionFailure(int error, String reason) { errorRef.set(error); } - }, 4096, 8192); - parser.init(UnaryOperator.identity()); + }); Map settings1 = new HashMap<>(); settings1.put(13, 17); ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - generator.generateSettings(lease, settings1, true); + generator.generateSettings(lease, settings1, false); // Modify the length of the frame to make it invalid ByteBuffer bytes = lease.getByteBuffers().get(0); bytes.putShort(1, (short)(bytes.getShort(1) - 1)); @@ -147,15 +146,15 @@ SettingsGenerator generator = new SettingsGenerator(new HeaderGenerator()); List frames = new ArrayList<>(); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 8192); + parser.init(new Parser.Listener.Adapter() { @Override public void onSettings(SettingsFrame frame) { frames.add(frame); } - }, 4096, 8192); - parser.init(UnaryOperator.identity()); + }); Map settings1 = new HashMap<>(); int key = 13; @@ -166,7 +165,7 @@ for (int i = 0; i < 2; ++i) { ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool); - generator.generateSettings(lease, settings1, true); + generator.generateSettings(lease, settings1, false); frames.clear(); for (ByteBuffer buffer : lease.getByteBuffers()) @@ -182,7 +181,7 @@ Map settings2 = frame.getSettings(); assertEquals(1, settings2.size()); assertEquals(value, settings2.get(key)); - assertTrue(frame.isReply()); + assertFalse(frame.isReply()); } } @@ -192,17 +191,17 @@ SettingsGenerator generator = new SettingsGenerator(new HeaderGenerator()); AtomicInteger errorRef = new AtomicInteger(); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 8192); + int maxSettingsKeys = 32; + parser.setMaxSettingsKeys(maxSettingsKeys); + parser.init(new Parser.Listener.Adapter() { @Override public void onConnectionFailure(int error, String reason) { errorRef.set(error); } - }, 4096, 8192); - int maxSettingsKeys = 32; - parser.setMaxSettingsKeys(maxSettingsKeys); - parser.init(UnaryOperator.identity()); + }); Map settings = new HashMap<>(); for (int i = 0; i < maxSettingsKeys + 1; ++i) @@ -232,10 +231,10 @@ int maxSettingsKeys = pairs / 2; AtomicInteger errorRef = new AtomicInteger(); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter(), 4096, 8192); + Parser parser = new Parser(byteBufferPool, 8192); parser.setMaxSettingsKeys(maxSettingsKeys); - parser.setMaxFrameLength(Frame.DEFAULT_MAX_LENGTH); - parser.init(listener -> new Parser.Listener.Wrapper(listener) + parser.setMaxFrameSize(Frame.DEFAULT_MAX_LENGTH); + parser.init(new Parser.Listener.Adapter() { @Override public void onConnectionFailure(int error, String reason) @@ -273,17 +272,17 @@ SettingsGenerator generator = new SettingsGenerator(new HeaderGenerator()); AtomicInteger errorRef = new AtomicInteger(); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 8192); + int maxSettingsKeys = 32; + parser.setMaxSettingsKeys(maxSettingsKeys); + parser.init(new Parser.Listener.Adapter() { @Override public void onConnectionFailure(int error, String reason) { errorRef.set(error); } - }, 4096, 8192); - int maxSettingsKeys = 32; - parser.setMaxSettingsKeys(maxSettingsKeys); - parser.init(UnaryOperator.identity()); + }); Map settings = new HashMap<>(); settings.put(13, 17); diff -Nru jetty9-9.4.51/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/UnknownParseTest.java jetty9-9.4.53/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/UnknownParseTest.java --- jetty9-9.4.51/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/UnknownParseTest.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/UnknownParseTest.java 2023-10-09 12:27:40.000000000 +0000 @@ -22,7 +22,6 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; -import java.util.function.UnaryOperator; import org.eclipse.jetty.http2.ErrorCode; import org.eclipse.jetty.http2.parser.Parser; @@ -53,8 +52,8 @@ public void testInvalidFrameSize() { AtomicInteger failure = new AtomicInteger(); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter(), 4096, 8192); - parser.init(listener -> new Parser.Listener.Wrapper(listener) + Parser parser = new Parser(byteBufferPool, 4096); + parser.init(new Parser.Listener.Adapter() { @Override public void onConnectionFailure(int error, String reason) @@ -62,7 +61,7 @@ failure.set(error); } }); - parser.setMaxFrameLength(Frame.DEFAULT_MAX_LENGTH); + parser.setMaxFrameSize(Frame.DEFAULT_MAX_LENGTH); // 0x4001 == 16385 which is > Frame.DEFAULT_MAX_LENGTH. byte[] bytes = new byte[]{0, 0x40, 0x01, 64, 0, 0, 0, 0, 0}; @@ -78,15 +77,15 @@ private void testParse(Function fn) { AtomicBoolean failure = new AtomicBoolean(); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 4096); + parser.init(new Parser.Listener.Adapter() { @Override public void onConnectionFailure(int error, String reason) { failure.set(true); } - }, 4096, 8192); - parser.init(UnaryOperator.identity()); + }); // Iterate a few times to be sure the parser is properly reset. for (int i = 0; i < 2; ++i) diff -Nru jetty9-9.4.51/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java jetty9-9.4.53/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java --- jetty9-9.4.51/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java 2023-10-09 12:27:40.000000000 +0000 @@ -21,7 +21,6 @@ import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; -import java.util.function.UnaryOperator; import org.eclipse.jetty.http2.generator.HeaderGenerator; import org.eclipse.jetty.http2.generator.WindowUpdateGenerator; @@ -42,15 +41,15 @@ WindowUpdateGenerator generator = new WindowUpdateGenerator(new HeaderGenerator()); final List frames = new ArrayList<>(); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 4096); + parser.init(new Parser.Listener.Adapter() { @Override public void onWindowUpdate(WindowUpdateFrame frame) { frames.add(frame); } - }, 4096, 8192); - parser.init(UnaryOperator.identity()); + }); int streamId = 13; int windowUpdate = 17; @@ -83,15 +82,15 @@ WindowUpdateGenerator generator = new WindowUpdateGenerator(new HeaderGenerator()); final List frames = new ArrayList<>(); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 4096); + parser.init(new Parser.Listener.Adapter() { @Override public void onWindowUpdate(WindowUpdateFrame frame) { frames.add(frame); } - }, 4096, 8192); - parser.init(UnaryOperator.identity()); + }); int streamId = 13; int windowUpdate = 17; diff -Nru jetty9-9.4.51/jetty-http2/http2-hpack/pom.xml jetty9-9.4.53/jetty-http2/http2-hpack/pom.xml --- jetty9-9.4.51/jetty-http2/http2-hpack/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-hpack/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ org.eclipse.jetty.http2 http2-parent - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 diff -Nru jetty9-9.4.51/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java jetty9-9.4.53/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java --- jetty9-9.4.51/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java 2023-10-09 12:27:40.000000000 +0000 @@ -29,6 +29,8 @@ import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpScheme; +import org.eclipse.jetty.http.compression.HuffmanEncoder; +import org.eclipse.jetty.http.compression.NBitIntegerEncoder; import org.eclipse.jetty.util.ArrayTernaryTrie; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.Trie; @@ -118,6 +120,7 @@ private static final StaticEntry[] __staticTableByHeader = new StaticEntry[HttpHeader.UNKNOWN.ordinal()]; private static final StaticEntry[] __staticTable = new StaticEntry[STATIC_TABLE.length]; public static final int STATIC_SIZE = STATIC_TABLE.length - 1; + public static final int DEFAULT_MAX_TABLE_CAPACITY = 4096; static { @@ -153,7 +156,7 @@ case C_STATUS: { - entry = new StaticEntry(i, new StaticTableHttpField(header, name, value, Integer.valueOf(value))); + entry = new StaticEntry(i, new StaticTableHttpField(header, name, value, value)); break; } @@ -187,26 +190,26 @@ } } - private int _maxDynamicTableSizeInBytes; - private int _dynamicTableSizeInBytes; private final DynamicTable _dynamicTable; private final Map _fieldMap = new HashMap<>(); private final Map _nameMap = new HashMap<>(); + private int _maxTableSize; + private int _tableSize; - HpackContext(int maxDynamicTableSize) + HpackContext(int maxTableSize) { - _maxDynamicTableSizeInBytes = maxDynamicTableSize; - int guesstimateEntries = 10 + maxDynamicTableSize / (32 + 10 + 10); + _maxTableSize = maxTableSize; + int guesstimateEntries = 10 + maxTableSize / (32 + 10 + 10); _dynamicTable = new DynamicTable(guesstimateEntries); if (LOG.isDebugEnabled()) - LOG.debug(String.format("HdrTbl[%x] created max=%d", hashCode(), maxDynamicTableSize)); + LOG.debug(String.format("HdrTbl[%x] created max=%d", hashCode(), maxTableSize)); } public void resize(int newMaxDynamicTableSize) { if (LOG.isDebugEnabled()) - LOG.debug(String.format("HdrTbl[%x] resized max=%d->%d", hashCode(), _maxDynamicTableSizeInBytes, newMaxDynamicTableSize)); - _maxDynamicTableSizeInBytes = newMaxDynamicTableSize; + LOG.debug(String.format("HdrTbl[%x] resized max=%d->%d", hashCode(), _maxTableSize, newMaxDynamicTableSize)); + _maxTableSize = newMaxDynamicTableSize; _dynamicTable.evict(); } @@ -251,14 +254,14 @@ { Entry entry = new Entry(field); int size = entry.getSize(); - if (size > _maxDynamicTableSizeInBytes) + if (size > _maxTableSize) { if (LOG.isDebugEnabled()) - LOG.debug(String.format("HdrTbl[%x] !added size %d>%d", hashCode(), size, _maxDynamicTableSizeInBytes)); + LOG.debug(String.format("HdrTbl[%x] !added size %d>%d", hashCode(), size, _maxTableSize)); _dynamicTable.evictAll(); return null; } - _dynamicTableSizeInBytes += size; + _tableSize += size; _dynamicTable.add(entry); _fieldMap.put(field, entry); _nameMap.put(field.getLowerCaseName(), entry); @@ -282,7 +285,7 @@ */ public int getDynamicTableSize() { - return _dynamicTableSizeInBytes; + return _tableSize; } /** @@ -290,7 +293,7 @@ */ public int getMaxDynamicTableSize() { - return _maxDynamicTableSizeInBytes; + return _maxTableSize; } public int index(Entry entry) @@ -316,15 +319,15 @@ @Override public String toString() { - return String.format("HpackContext@%x{entries=%d,size=%d,max=%d}", hashCode(), _dynamicTable.size(), _dynamicTableSizeInBytes, _maxDynamicTableSizeInBytes); + return String.format("HpackContext@%x{entries=%d,size=%d,max=%d}", hashCode(), _dynamicTable.size(), _tableSize, _maxTableSize); } private class DynamicTable { - Entry[] _entries; - int _size; - int _offset; - int _growby; + private Entry[] _entries; + private final int _growby; + private int _size; + private int _offset; private DynamicTable(int initCapacity) { @@ -372,7 +375,7 @@ private void evict() { - while (_dynamicTableSizeInBytes > _maxDynamicTableSizeInBytes) + while (_tableSize > _maxTableSize) { Entry entry = _entries[_offset]; _entries[_offset] = null; @@ -380,7 +383,7 @@ _size--; if (LOG.isDebugEnabled()) LOG.debug(String.format("HdrTbl[%x] evict %s", HpackContext.this.hashCode(), entry)); - _dynamicTableSizeInBytes -= entry.getSize(); + _tableSize -= entry.getSize(); entry._slot = -1; _fieldMap.remove(entry.getHttpField()); String lc = entry.getHttpField().getLowerCaseName(); @@ -388,7 +391,7 @@ _nameMap.remove(lc); } if (LOG.isDebugEnabled()) - LOG.debug(String.format("HdrTbl[%x] entries=%d, size=%d, max=%d", HpackContext.this.hashCode(), _dynamicTable.size(), _dynamicTableSizeInBytes, _maxDynamicTableSizeInBytes)); + LOG.debug(String.format("HdrTbl[%x] entries=%d, size=%d, max=%d", HpackContext.this.hashCode(), _dynamicTable.size(), _tableSize, _maxTableSize)); } private void evictAll() @@ -401,7 +404,7 @@ _nameMap.clear(); _offset = 0; _size = 0; - _dynamicTableSizeInBytes = 0; + _tableSize = 0; Arrays.fill(_entries, null); } } @@ -461,21 +464,21 @@ super(field); _slot = index; String value = field.getValue(); - if (value != null && value.length() > 0) + if (value != null && !value.isEmpty()) { - int huffmanLen = Huffman.octetsNeeded(value); + int huffmanLen = HuffmanEncoder.octetsNeeded(value); if (huffmanLen < 0) throw new IllegalStateException("bad value"); - int lenLen = NBitInteger.octectsNeeded(7, huffmanLen); - _huffmanValue = new byte[1 + lenLen + huffmanLen]; + int lenLen = NBitIntegerEncoder.octetsNeeded(7, huffmanLen); + _huffmanValue = new byte[lenLen + huffmanLen]; ByteBuffer buffer = ByteBuffer.wrap(_huffmanValue); // Indicate Huffman buffer.put((byte)0x80); // Add huffman length - NBitInteger.encode(buffer, 7, huffmanLen); + NBitIntegerEncoder.encode(buffer, 7, huffmanLen); // Encode value - Huffman.encode(buffer, value); + HuffmanEncoder.encode(buffer, value); } else _huffmanValue = null; diff -Nru jetty9-9.4.51/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java jetty9-9.4.53/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java --- jetty9-9.4.51/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackDecoder.java 2023-10-09 12:27:40.000000000 +0000 @@ -24,8 +24,12 @@ import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpTokens; import org.eclipse.jetty.http.MetaData; +import org.eclipse.jetty.http.compression.EncodingException; +import org.eclipse.jetty.http.compression.HuffmanDecoder; +import org.eclipse.jetty.http.compression.NBitIntegerDecoder; import org.eclipse.jetty.http2.hpack.HpackContext.Entry; -import org.eclipse.jetty.util.TypeUtil; +import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.CharsetStringBuilder; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -41,17 +45,27 @@ private final HpackContext _context; private final MetaDataBuilder _builder; - private int _localMaxDynamicTableSize; + private final HuffmanDecoder _huffmanDecoder; + private final NBitIntegerDecoder _integerDecoder; + private int _maxTableCapacity; + + @Deprecated + public HpackDecoder(int localMaxDynamicTableSize, int maxHeaderSize) + { + this(maxHeaderSize); + } /** - * @param localMaxDynamicTableSize The maximum allowed size of the local dynamic header field table. - * @param maxHeaderSize The maximum allowed size of a headers block, expressed as total of all name and value characters, plus 32 per field + * @param maxHeaderSize The maximum allowed size of a decoded headers block, + * expressed as total of all name and value bytes, plus 32 bytes per field */ - public HpackDecoder(int localMaxDynamicTableSize, int maxHeaderSize) + public HpackDecoder(int maxHeaderSize) { - _context = new HpackContext(localMaxDynamicTableSize); - _localMaxDynamicTableSize = localMaxDynamicTableSize; + _context = new HpackContext(HpackContext.DEFAULT_MAX_TABLE_CAPACITY); _builder = new MetaDataBuilder(maxHeaderSize); + _huffmanDecoder = new HuffmanDecoder(); + _integerDecoder = new NBitIntegerDecoder(); + setMaxTableCapacity(HpackContext.DEFAULT_MAX_TABLE_CAPACITY); } public HpackContext getHpackContext() @@ -59,9 +73,44 @@ return _context; } - public void setLocalMaxDynamicTableSize(int localMaxdynamciTableSize) + public int getMaxTableCapacity() + { + return _maxTableCapacity; + } + + /** + *

Sets the limit for the capacity of the dynamic header table.

+ *

This value acts as a limit for the values received from the + * remote peer via the HPACK dynamic table size update instruction.

+ *

After calling this method, a SETTINGS frame must be sent to the other + * peer, containing the {@code SETTINGS_HEADER_TABLE_SIZE} setting with + * the value passed as argument to this method.

+ * + * @param maxTableCapacity the limit for capacity of the dynamic header table + */ + public void setMaxTableCapacity(int maxTableCapacity) + { + _maxTableCapacity = maxTableCapacity; + } + + /** + * @param maxTableSizeLimit the local dynamic table max size + * @deprecated use {@link #setMaxTableCapacity(int)} instead + */ + @Deprecated + public void setLocalMaxDynamicTableSize(int maxTableSizeLimit) { - _localMaxDynamicTableSize = localMaxdynamciTableSize; + setMaxTableCapacity(maxTableSizeLimit); + } + + public int getMaxHeaderListSize() + { + return _builder.getMaxSize(); + } + + public void setMaxHeaderListSize(int maxHeaderListSize) + { + _builder.setMaxSize(maxHeaderListSize); } public MetaData decode(ByteBuffer buffer) throws HpackException.SessionException, HpackException.StreamException @@ -69,27 +118,22 @@ if (LOG.isDebugEnabled()) LOG.debug(String.format("CtxTbl[%x] decoding %d octets", _context.hashCode(), buffer.remaining())); - // If the buffer is big, don't even think about decoding it - if (buffer.remaining() > _builder.getMaxSize()) - throw new HpackException.SessionException("431 Request Header Fields too large"); + // If the buffer is larger than the max headers size, don't even start decoding it. + int maxSize = _builder.getMaxSize(); + if (maxSize > 0 && buffer.remaining() > maxSize) + throw new HpackException.SessionException("Header fields size too large"); boolean emitted = false; - while (buffer.hasRemaining()) { - if (LOG.isDebugEnabled() && buffer.hasArray()) - { - int l = Math.min(buffer.remaining(), 32); - LOG.debug("decode {}{}", - TypeUtil.toHexString(buffer.array(), buffer.arrayOffset() + buffer.position(), l), - l < buffer.remaining() ? "..." : ""); - } + if (LOG.isDebugEnabled()) + LOG.debug("decode {}", BufferUtil.toHexString(buffer)); byte b = buffer.get(); if (b < 0) { // 7.1 indexed if the high bit is set - int index = NBitInteger.decode(buffer, 7); + int index = integerDecode(buffer, 7); Entry entry = _context.get(index); if (entry == null) throw new HpackException.SessionException("Unknown index %d", index); @@ -130,11 +174,11 @@ case 2: // 7.3 case 3: // 7.3 // change table size - int size = NBitInteger.decode(buffer, 5); + int size = integerDecode(buffer, 5); if (LOG.isDebugEnabled()) - LOG.debug("decode resize=" + size); - if (size > _localMaxDynamicTableSize) - throw new IllegalArgumentException(); + LOG.debug("decode resize={}", size); + if (size > getMaxTableCapacity()) + throw new HpackException.CompressionException("Dynamic table resize exceeded max limit"); if (emitted) throw new HpackException.CompressionException("Dynamic table resize after fields"); _context.resize(size); @@ -143,7 +187,7 @@ case 0: // 7.2.2 case 1: // 7.2.3 indexed = false; - nameIndex = NBitInteger.decode(buffer, 4); + nameIndex = integerDecode(buffer, 4); break; case 4: // 7.2.1 @@ -151,7 +195,7 @@ case 6: // 7.2.1 case 7: // 7.2.1 indexed = true; - nameIndex = NBitInteger.decode(buffer, 6); + nameIndex = integerDecode(buffer, 6); break; default: @@ -170,12 +214,11 @@ else { huffmanName = (buffer.get() & 0x80) == 0x80; - int length = NBitInteger.decode(buffer, 7); - _builder.checkSize(length, huffmanName); + int length = integerDecode(buffer, 7); if (huffmanName) - name = Huffman.decode(buffer, length); + name = huffmanDecode(buffer, length); else - name = toASCIIString(buffer, length); + name = toISO88591String(buffer, length); check: for (int i = name.length(); i-- > 0; ) { @@ -211,12 +254,11 @@ // decode the value boolean huffmanValue = (buffer.get() & 0x80) == 0x80; - int length = NBitInteger.decode(buffer, 7); - _builder.checkSize(length, huffmanValue); + int length = integerDecode(buffer, 7); if (huffmanValue) - value = Huffman.decode(buffer, length); + value = huffmanDecode(buffer, length); else - value = toASCIIString(buffer, length); + value = toISO88591String(buffer, length); // Make the new field HttpField field; @@ -277,19 +319,61 @@ return _builder.build(); } - public static String toASCIIString(ByteBuffer buffer, int length) + private int integerDecode(ByteBuffer buffer, int prefix) throws HpackException.CompressionException + { + try + { + if (prefix != 8) + buffer.position(buffer.position() - 1); + + _integerDecoder.setPrefix(prefix); + int decodedInt = _integerDecoder.decodeInt(buffer); + if (decodedInt < 0) + throw new EncodingException("invalid integer encoding"); + return decodedInt; + } + catch (EncodingException e) + { + HpackException.CompressionException compressionException = new HpackException.CompressionException(e.getMessage()); + compressionException.initCause(e); + throw compressionException; + } + finally + { + _integerDecoder.reset(); + } + } + + private String huffmanDecode(ByteBuffer buffer, int length) throws HpackException.CompressionException + { + try + { + _huffmanDecoder.setLength(length); + String decoded = _huffmanDecoder.decode(buffer); + if (decoded == null) + throw new HpackException.CompressionException("invalid string encoding"); + return decoded; + } + catch (EncodingException e) + { + HpackException.CompressionException compressionException = new HpackException.CompressionException(e.getMessage()); + compressionException.initCause(e); + throw compressionException; + } + finally + { + _huffmanDecoder.reset(); + } + } + + public static String toISO88591String(ByteBuffer buffer, int length) { - StringBuilder builder = new StringBuilder(length); - int position = buffer.position(); - int start = buffer.arrayOffset() + position; - int end = start + length; - buffer.position(position + length); - byte[] array = buffer.array(); - for (int i = start; i < end; i++) + CharsetStringBuilder.Iso88591StringBuilder builder = new CharsetStringBuilder.Iso88591StringBuilder(); + for (int i = 0; i < length; ++i) { - builder.append((char)(0x7f & array[i])); + builder.append(HttpTokens.sanitizeFieldVchar((char)buffer.get())); } - return builder.toString(); + return builder.build(); } @Override diff -Nru jetty9-9.4.51/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java jetty9-9.4.53/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java --- jetty9-9.4.51/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackEncoder.java 2023-10-09 12:27:40.000000000 +0000 @@ -19,7 +19,6 @@ package org.eclipse.jetty.http2.hpack; import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; import java.util.EnumMap; import java.util.EnumSet; import java.util.HashSet; @@ -34,10 +33,13 @@ import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http.PreEncodedHttpField; +import org.eclipse.jetty.http.compression.HuffmanEncoder; +import org.eclipse.jetty.http.compression.NBitIntegerEncoder; +import org.eclipse.jetty.http.compression.NBitStringEncoder; import org.eclipse.jetty.http2.hpack.HpackContext.Entry; import org.eclipse.jetty.http2.hpack.HpackContext.StaticEntry; +import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.StringUtil; -import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -97,34 +99,78 @@ private final HpackContext _context; private final boolean _debug; - private int _remoteMaxDynamicTableSize; - private int _localMaxDynamicTableSize; + private int _maxTableCapacity; + private int _tableCapacity; private int _maxHeaderListSize; private int _headerListSize; private boolean _validateEncoding = true; - public HpackEncoder() - { - this(4096, 4096, -1); - } - + @Deprecated public HpackEncoder(int localMaxDynamicTableSize) { this(localMaxDynamicTableSize, 4096, -1); } + @Deprecated public HpackEncoder(int localMaxDynamicTableSize, int remoteMaxDynamicTableSize) { this(localMaxDynamicTableSize, remoteMaxDynamicTableSize, -1); } + @Deprecated public HpackEncoder(int localMaxDynamicTableSize, int remoteMaxDynamicTableSize, int maxHeaderListSize) { - _context = new HpackContext(remoteMaxDynamicTableSize); - _remoteMaxDynamicTableSize = remoteMaxDynamicTableSize; - _localMaxDynamicTableSize = localMaxDynamicTableSize; - _maxHeaderListSize = maxHeaderListSize; + this(); + setLocalMaxDynamicTableSize(localMaxDynamicTableSize); + setRemoteMaxDynamicTableSize(remoteMaxDynamicTableSize); + setMaxHeaderListSize(maxHeaderListSize); + } + + public HpackEncoder() + { + _context = new HpackContext(0); _debug = LOG.isDebugEnabled(); + setMaxTableCapacity(HpackContext.DEFAULT_MAX_TABLE_CAPACITY); + setTableCapacity(HpackContext.DEFAULT_MAX_TABLE_CAPACITY); + } + + public int getMaxTableCapacity() + { + return _maxTableCapacity; + } + + /** + *

Sets the limit for the capacity of the dynamic header table.

+ *

This value is set by the remote peer via the + * {@code SETTINGS_HEADER_TABLE_SIZE} setting.

+ * + * @param maxTableSizeLimit the limit for capacity of the dynamic header table + */ + public void setMaxTableCapacity(int maxTableSizeLimit) + { + _maxTableCapacity = maxTableSizeLimit; + } + + public int getTableCapacity() + { + return _tableCapacity; + } + + /** + *

Sets the capacity of the dynamic header table.

+ *

The value of the capacity may be changed from {@code 0} + * up to {@link #getMaxTableCapacity()}. + * An HPACK instruction with the new capacity value will + * be sent to the decoder when the next call to + * {@link #encode(ByteBuffer, MetaData)} is made.

+ * + * @param tableCapacity the capacity of the dynamic header table + */ + public void setTableCapacity(int tableCapacity) + { + if (tableCapacity > getMaxTableCapacity()) + throw new IllegalArgumentException("Max table capacity exceeded"); + _tableCapacity = tableCapacity; } public int getMaxHeaderListSize() @@ -142,14 +188,16 @@ return _context; } - public void setRemoteMaxDynamicTableSize(int remoteMaxDynamicTableSize) + @Deprecated + public void setRemoteMaxDynamicTableSize(int maxTableSize) { - _remoteMaxDynamicTableSize = remoteMaxDynamicTableSize; + setTableCapacity(maxTableSize); } - public void setLocalMaxDynamicTableSize(int localMaxDynamicTableSize) + @Deprecated + public void setLocalMaxDynamicTableSize(int maxTableSizeLimit) { - _localMaxDynamicTableSize = localMaxDynamicTableSize; + setMaxTableCapacity(maxTableSizeLimit); } public boolean isValidateEncoding() @@ -185,10 +233,10 @@ _headerListSize = 0; int pos = buffer.position(); - // Check the dynamic table sizes! - int maxDynamicTableSize = Math.min(_remoteMaxDynamicTableSize, _localMaxDynamicTableSize); - if (maxDynamicTableSize != _context.getMaxDynamicTableSize()) - encodeMaxDynamicTableSize(buffer, maxDynamicTableSize); + // If max table size changed, send the correspondent instruction. + int tableCapacity = getTableCapacity(); + if (tableCapacity != _context.getMaxDynamicTableSize()) + encodeMaxDynamicTableSize(buffer, tableCapacity); // Add Request/response meta fields if (metadata.isRequest()) @@ -255,13 +303,9 @@ } } - // Check size - if (_maxHeaderListSize > 0 && _headerListSize > _maxHeaderListSize) - { - LOG.warn("Header list size too large {} > {} for {}", _headerListSize, _maxHeaderListSize); - if (LOG.isDebugEnabled()) - LOG.debug("metadata={}", metadata); - } + int maxHeaderListSize = getMaxHeaderListSize(); + if (maxHeaderListSize > 0 && _headerListSize > maxHeaderListSize) + throw new HpackException.SessionException("Header size %d > %d", _headerListSize, maxHeaderListSize); if (LOG.isDebugEnabled()) LOG.debug(String.format("CtxTbl[%x] encoded %d octets", _context.hashCode(), buffer.position() - pos)); @@ -278,13 +322,11 @@ } } - public void encodeMaxDynamicTableSize(ByteBuffer buffer, int maxDynamicTableSize) + public void encodeMaxDynamicTableSize(ByteBuffer buffer, int maxTableSize) { - if (maxDynamicTableSize > _remoteMaxDynamicTableSize) - throw new IllegalArgumentException(); buffer.put((byte)0x20); - NBitInteger.encode(buffer, 5, maxDynamicTableSize); - _context.resize(maxDynamicTableSize); + NBitIntegerEncoder.encode(buffer, 5, maxTableSize); + _context.resize(maxTableSize); } public void encode(ByteBuffer buffer, HttpField field) @@ -295,8 +337,6 @@ int fieldSize = field.getName().length() + field.getValue().length(); _headerListSize += fieldSize + 32; - final int p = _debug ? buffer.position() : -1; - String encoding = null; // Is there an index entry for the field? @@ -314,9 +354,9 @@ { int index = _context.index(entry); buffer.put((byte)0x80); - NBitInteger.encode(buffer, 7, index); + NBitIntegerEncoder.encode(buffer, 7, index); if (_debug) - encoding = "IdxField" + (entry.isStatic() ? "S" : "") + (1 + NBitInteger.octectsNeeded(7, index)); + encoding = "IdxField" + (entry.isStatic() ? "S" : "") + NBitIntegerEncoder.octetsNeeded(7, index); } } else @@ -390,19 +430,19 @@ if (_debug) encoding = "Lit" + - ((name == null) ? "HuffN" : ("IdxN" + (name.isStatic() ? "S" : "") + (1 + NBitInteger.octectsNeeded(4, _context.index(name))))) + + ((name == null) ? "HuffN" : ("IdxN" + (name.isStatic() ? "S" : "") + (1 + NBitIntegerEncoder.octetsNeeded(4, _context.index(name))))) + (huffman ? "HuffV" : "LitV") + (neverIndex ? "!!Idx" : "!Idx"); } else if (fieldSize >= _context.getMaxDynamicTableSize() || header == HttpHeader.CONTENT_LENGTH && !"0".equals(field.getValue())) { - // The field is too large or a non zero content length, so do not index. + // The field is too large or a non-zero content length, so do not index. indexed = false; encodeName(buffer, (byte)0x00, 4, header.asString(), name); encodeValue(buffer, true, field.getValue()); if (_debug) encoding = "Lit" + - ((name == null) ? "HuffN" : "IdxNS" + (1 + NBitInteger.octectsNeeded(4, _context.index(name)))) + + ((name == null) ? "HuffN" : "IdxNS" + (1 + NBitIntegerEncoder.octetsNeeded(4, _context.index(name)))) + "HuffV!Idx"; } else @@ -413,7 +453,7 @@ encodeName(buffer, (byte)0x40, 6, header.asString(), name); encodeValue(buffer, huffman, field.getValue()); if (_debug) - encoding = ((name == null) ? "LitHuffN" : ("LitIdxN" + (name.isStatic() ? "S" : "") + (1 + NBitInteger.octectsNeeded(6, _context.index(name))))) + + encoding = ((name == null) ? "LitHuffN" : ("LitIdxN" + (name.isStatic() ? "S" : "") + (1 + NBitIntegerEncoder.octetsNeeded(6, _context.index(name))))) + (huffman ? "HuffVIdx" : "LitVIdx"); } } @@ -425,10 +465,8 @@ if (_debug) { - byte[] bytes = new byte[buffer.position() - p]; - buffer.position(p); - buffer.get(bytes); - LOG.debug("encode {}:'{}' to '{}'", encoding, field, TypeUtil.toHexString(bytes)); + if (LOG.isDebugEnabled()) + LOG.debug("encode {}:'{}' to '{}'", encoding, field, BufferUtil.toHexString((ByteBuffer)buffer.duplicate().flip())); } } @@ -440,55 +478,17 @@ // leave name index bits as 0 // Encode the name always with lowercase huffman buffer.put((byte)0x80); - NBitInteger.encode(buffer, 7, Huffman.octetsNeededLC(name)); - Huffman.encodeLC(buffer, name); + NBitIntegerEncoder.encode(buffer, 7, HuffmanEncoder.octetsNeededLowerCase(name)); + HuffmanEncoder.encodeLowerCase(buffer, name); } else { - NBitInteger.encode(buffer, bits, _context.index(entry)); + NBitIntegerEncoder.encode(buffer, bits, _context.index(entry)); } } static void encodeValue(ByteBuffer buffer, boolean huffman, String value) { - if (huffman) - { - // huffman literal value - buffer.put((byte)0x80); - - int needed = Huffman.octetsNeeded(value); - if (needed >= 0) - { - NBitInteger.encode(buffer, 7, needed); - Huffman.encode(buffer, value); - } - else - { - // Not iso_8859_1 - byte[] bytes = value.getBytes(StandardCharsets.UTF_8); - NBitInteger.encode(buffer, 7, Huffman.octetsNeeded(bytes)); - Huffman.encode(buffer, bytes); - } - } - else - { - // add literal assuming iso_8859_1 - buffer.put((byte)0x00).mark(); - NBitInteger.encode(buffer, 7, value.length()); - for (int i = 0; i < value.length(); i++) - { - char c = value.charAt(i); - if (c < ' ' || c > 127) - { - // Not iso_8859_1, so re-encode as UTF-8 - buffer.reset(); - byte[] bytes = value.getBytes(StandardCharsets.UTF_8); - NBitInteger.encode(buffer, 7, bytes.length); - buffer.put(bytes, 0, bytes.length); - return; - } - buffer.put((byte)c); - } - } + NBitStringEncoder.encode(buffer, 8, value, huffman); } } diff -Nru jetty9-9.4.51/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackException.java jetty9-9.4.53/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackException.java --- jetty9-9.4.51/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackException.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackException.java 2023-10-09 12:27:40.000000000 +0000 @@ -18,7 +18,6 @@ package org.eclipse.jetty.http2.hpack; -@SuppressWarnings("serial") public abstract class HpackException extends Exception { HpackException(String messageFormat, Object... args) @@ -35,7 +34,7 @@ */ public static class StreamException extends HpackException { - StreamException(String messageFormat, Object... args) + public StreamException(String messageFormat, Object... args) { super(messageFormat, args); } @@ -48,7 +47,7 @@ */ public static class SessionException extends HpackException { - SessionException(String messageFormat, Object... args) + public SessionException(String messageFormat, Object... args) { super(messageFormat, args); } diff -Nru jetty9-9.4.51/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackFieldPreEncoder.java jetty9-9.4.53/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackFieldPreEncoder.java --- jetty9-9.4.51/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackFieldPreEncoder.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackFieldPreEncoder.java 2023-10-09 12:27:40.000000000 +0000 @@ -23,6 +23,8 @@ import org.eclipse.jetty.http.HttpFieldPreEncoder; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http.compression.HuffmanEncoder; +import org.eclipse.jetty.http.compression.NBitIntegerEncoder; import org.eclipse.jetty.util.BufferUtil; /** @@ -31,18 +33,12 @@ public class HpackFieldPreEncoder implements HttpFieldPreEncoder { - /** - * @see org.eclipse.jetty.http.HttpFieldPreEncoder#getHttpVersion() - */ @Override public HttpVersion getHttpVersion() { return HttpVersion.HTTP_2; } - /** - * @see org.eclipse.jetty.http.HttpFieldPreEncoder#getEncodedField(org.eclipse.jetty.http.HttpHeader, java.lang.String, java.lang.String) - */ @Override public byte[] getEncodedField(HttpHeader header, String name, String value) { @@ -78,12 +74,12 @@ int nameIdx = HpackContext.staticIndex(header); if (nameIdx > 0) - NBitInteger.encode(buffer, bits, nameIdx); + NBitIntegerEncoder.encode(buffer, bits, nameIdx); else { buffer.put((byte)0x80); - NBitInteger.encode(buffer, 7, Huffman.octetsNeededLC(name)); - Huffman.encodeLC(buffer, name); + NBitIntegerEncoder.encode(buffer, 7, HuffmanEncoder.octetsNeededLowerCase(name)); + HuffmanEncoder.encodeLowerCase(buffer, name); } HpackEncoder.encodeValue(buffer, huffman, value); diff -Nru jetty9-9.4.51/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/Huffman.java jetty9-9.4.53/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/Huffman.java --- jetty9-9.4.51/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/Huffman.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/Huffman.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,551 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http2.hpack; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.util.Utf8StringBuilder; - -public class Huffman -{ - - // Appendix C: Huffman Codes - // http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-12#appendix-C - static final int[][] CODES = - { - /* ( 0) |11111111|11000 */ {0x1ff8, 13}, - /* ( 1) |11111111|11111111|1011000 */ {0x7fffd8, 23}, - /* ( 2) |11111111|11111111|11111110|0010 */ {0xfffffe2, 28}, - /* ( 3) |11111111|11111111|11111110|0011 */ {0xfffffe3, 28}, - /* ( 4) |11111111|11111111|11111110|0100 */ {0xfffffe4, 28}, - /* ( 5) |11111111|11111111|11111110|0101 */ {0xfffffe5, 28}, - /* ( 6) |11111111|11111111|11111110|0110 */ {0xfffffe6, 28}, - /* ( 7) |11111111|11111111|11111110|0111 */ {0xfffffe7, 28}, - /* ( 8) |11111111|11111111|11111110|1000 */ {0xfffffe8, 28}, - /* ( 9) |11111111|11111111|11101010 */ {0xffffea, 24}, - /* ( 10) |11111111|11111111|11111111|111100 */ {0x3ffffffc, 30}, - /* ( 11) |11111111|11111111|11111110|1001 */ {0xfffffe9, 28}, - /* ( 12) |11111111|11111111|11111110|1010 */ {0xfffffea, 28}, - /* ( 13) |11111111|11111111|11111111|111101 */ {0x3ffffffd, 30}, - /* ( 14) |11111111|11111111|11111110|1011 */ {0xfffffeb, 28}, - /* ( 15) |11111111|11111111|11111110|1100 */ {0xfffffec, 28}, - /* ( 16) |11111111|11111111|11111110|1101 */ {0xfffffed, 28}, - /* ( 17) |11111111|11111111|11111110|1110 */ {0xfffffee, 28}, - /* ( 18) |11111111|11111111|11111110|1111 */ {0xfffffef, 28}, - /* ( 19) |11111111|11111111|11111111|0000 */ {0xffffff0, 28}, - /* ( 20) |11111111|11111111|11111111|0001 */ {0xffffff1, 28}, - /* ( 21) |11111111|11111111|11111111|0010 */ {0xffffff2, 28}, - /* ( 22) |11111111|11111111|11111111|111110 */ {0x3ffffffe, 30}, - /* ( 23) |11111111|11111111|11111111|0011 */ {0xffffff3, 28}, - /* ( 24) |11111111|11111111|11111111|0100 */ {0xffffff4, 28}, - /* ( 25) |11111111|11111111|11111111|0101 */ {0xffffff5, 28}, - /* ( 26) |11111111|11111111|11111111|0110 */ {0xffffff6, 28}, - /* ( 27) |11111111|11111111|11111111|0111 */ {0xffffff7, 28}, - /* ( 28) |11111111|11111111|11111111|1000 */ {0xffffff8, 28}, - /* ( 29) |11111111|11111111|11111111|1001 */ {0xffffff9, 28}, - /* ( 30) |11111111|11111111|11111111|1010 */ {0xffffffa, 28}, - /* ( 31) |11111111|11111111|11111111|1011 */ {0xffffffb, 28}, - /*' ' ( 32) |010100 */ {0x14, 6}, - /*'!' ( 33) |11111110|00 */ {0x3f8, 10}, - /*'"' ( 34) |11111110|01 */ {0x3f9, 10}, - /*'#' ( 35) |11111111|1010 */ {0xffa, 12}, - /*'$' ( 36) |11111111|11001 */ {0x1ff9, 13}, - /*'%' ( 37) |010101 */ {0x15, 6}, - /*'&' ( 38) |11111000 */ {0xf8, 8}, - /*''' ( 39) |11111111|010 */ {0x7fa, 11}, - /*'(' ( 40) |11111110|10 */ {0x3fa, 10}, - /*')' ( 41) |11111110|11 */ {0x3fb, 10}, - /*'*' ( 42) |11111001 */ {0xf9, 8}, - /*'+' ( 43) |11111111|011 */ {0x7fb, 11}, - /*',' ( 44) |11111010 */ {0xfa, 8}, - /*'-' ( 45) |010110 */ {0x16, 6}, - /*'.' ( 46) |010111 */ {0x17, 6}, - /*'/' ( 47) |011000 */ {0x18, 6}, - /*'0' ( 48) |00000 */ {0x0, 5}, - /*'1' ( 49) |00001 */ {0x1, 5}, - /*'2' ( 50) |00010 */ {0x2, 5}, - /*'3' ( 51) |011001 */ {0x19, 6}, - /*'4' ( 52) |011010 */ {0x1a, 6}, - /*'5' ( 53) |011011 */ {0x1b, 6}, - /*'6' ( 54) |011100 */ {0x1c, 6}, - /*'7' ( 55) |011101 */ {0x1d, 6}, - /*'8' ( 56) |011110 */ {0x1e, 6}, - /*'9' ( 57) |011111 */ {0x1f, 6}, - /*':' ( 58) |1011100 */ {0x5c, 7}, - /*';' ( 59) |11111011 */ {0xfb, 8}, - /*'<' ( 60) |11111111|1111100 */ {0x7ffc, 15}, - /*'=' ( 61) |100000 */ {0x20, 6}, - /*'>' ( 62) |11111111|1011 */ {0xffb, 12}, - /*'?' ( 63) |11111111|00 */ {0x3fc, 10}, - /*'@' ( 64) |11111111|11010 */ {0x1ffa, 13}, - /*'A' ( 65) |100001 */ {0x21, 6}, - /*'B' ( 66) |1011101 */ {0x5d, 7}, - /*'C' ( 67) |1011110 */ {0x5e, 7}, - /*'D' ( 68) |1011111 */ {0x5f, 7}, - /*'E' ( 69) |1100000 */ {0x60, 7}, - /*'F' ( 70) |1100001 */ {0x61, 7}, - /*'G' ( 71) |1100010 */ {0x62, 7}, - /*'H' ( 72) |1100011 */ {0x63, 7}, - /*'I' ( 73) |1100100 */ {0x64, 7}, - /*'J' ( 74) |1100101 */ {0x65, 7}, - /*'K' ( 75) |1100110 */ {0x66, 7}, - /*'L' ( 76) |1100111 */ {0x67, 7}, - /*'M' ( 77) |1101000 */ {0x68, 7}, - /*'N' ( 78) |1101001 */ {0x69, 7}, - /*'O' ( 79) |1101010 */ {0x6a, 7}, - /*'P' ( 80) |1101011 */ {0x6b, 7}, - /*'Q' ( 81) |1101100 */ {0x6c, 7}, - /*'R' ( 82) |1101101 */ {0x6d, 7}, - /*'S' ( 83) |1101110 */ {0x6e, 7}, - /*'T' ( 84) |1101111 */ {0x6f, 7}, - /*'U' ( 85) |1110000 */ {0x70, 7}, - /*'V' ( 86) |1110001 */ {0x71, 7}, - /*'W' ( 87) |1110010 */ {0x72, 7}, - /*'X' ( 88) |11111100 */ {0xfc, 8}, - /*'Y' ( 89) |1110011 */ {0x73, 7}, - /*'Z' ( 90) |11111101 */ {0xfd, 8}, - /*'[' ( 91) |11111111|11011 */ {0x1ffb, 13}, - /*'\' ( 92) |11111111|11111110|000 */ {0x7fff0, 19}, - /*']' ( 93) |11111111|11100 */ {0x1ffc, 13}, - /*'^' ( 94) |11111111|111100 */ {0x3ffc, 14}, - /*'_' ( 95) |100010 */ {0x22, 6}, - /*'`' ( 96) |11111111|1111101 */ {0x7ffd, 15}, - /*'a' ( 97) |00011 */ {0x3, 5}, - /*'b' ( 98) |100011 */ {0x23, 6}, - /*'c' ( 99) |00100 */ {0x4, 5}, - /*'d' (100) |100100 */ {0x24, 6}, - /*'e' (101) |00101 */ {0x5, 5}, - /*'f' (102) |100101 */ {0x25, 6}, - /*'g' (103) |100110 */ {0x26, 6}, - /*'h' (104) |100111 */ {0x27, 6}, - /*'i' (105) |00110 */ {0x6, 5}, - /*'j' (106) |1110100 */ {0x74, 7}, - /*'k' (107) |1110101 */ {0x75, 7}, - /*'l' (108) |101000 */ {0x28, 6}, - /*'m' (109) |101001 */ {0x29, 6}, - /*'n' (110) |101010 */ {0x2a, 6}, - /*'o' (111) |00111 */ {0x7, 5}, - /*'p' (112) |101011 */ {0x2b, 6}, - /*'q' (113) |1110110 */ {0x76, 7}, - /*'r' (114) |101100 */ {0x2c, 6}, - /*'s' (115) |01000 */ {0x8, 5}, - /*'t' (116) |01001 */ {0x9, 5}, - /*'u' (117) |101101 */ {0x2d, 6}, - /*'v' (118) |1110111 */ {0x77, 7}, - /*'w' (119) |1111000 */ {0x78, 7}, - /*'x' (120) |1111001 */ {0x79, 7}, - /*'y' (121) |1111010 */ {0x7a, 7}, - /*'z' (122) |1111011 */ {0x7b, 7}, - /*'{' (123) |11111111|1111110 */ {0x7ffe, 15}, - /*'|' (124) |11111111|100 */ {0x7fc, 11}, - /*'}' (125) |11111111|111101 */ {0x3ffd, 14}, - /*'~' (126) |11111111|11101 */ {0x1ffd, 13}, - /* (127) |11111111|11111111|11111111|1100 */ {0xffffffc, 28}, - /* (128) |11111111|11111110|0110 */ {0xfffe6, 20}, - /* (129) |11111111|11111111|010010 */ {0x3fffd2, 22}, - /* (130) |11111111|11111110|0111 */ {0xfffe7, 20}, - /* (131) |11111111|11111110|1000 */ {0xfffe8, 20}, - /* (132) |11111111|11111111|010011 */ {0x3fffd3, 22}, - /* (133) |11111111|11111111|010100 */ {0x3fffd4, 22}, - /* (134) |11111111|11111111|010101 */ {0x3fffd5, 22}, - /* (135) |11111111|11111111|1011001 */ {0x7fffd9, 23}, - /* (136) |11111111|11111111|010110 */ {0x3fffd6, 22}, - /* (137) |11111111|11111111|1011010 */ {0x7fffda, 23}, - /* (138) |11111111|11111111|1011011 */ {0x7fffdb, 23}, - /* (139) |11111111|11111111|1011100 */ {0x7fffdc, 23}, - /* (140) |11111111|11111111|1011101 */ {0x7fffdd, 23}, - /* (141) |11111111|11111111|1011110 */ {0x7fffde, 23}, - /* (142) |11111111|11111111|11101011 */ {0xffffeb, 24}, - /* (143) |11111111|11111111|1011111 */ {0x7fffdf, 23}, - /* (144) |11111111|11111111|11101100 */ {0xffffec, 24}, - /* (145) |11111111|11111111|11101101 */ {0xffffed, 24}, - /* (146) |11111111|11111111|010111 */ {0x3fffd7, 22}, - /* (147) |11111111|11111111|1100000 */ {0x7fffe0, 23}, - /* (148) |11111111|11111111|11101110 */ {0xffffee, 24}, - /* (149) |11111111|11111111|1100001 */ {0x7fffe1, 23}, - /* (150) |11111111|11111111|1100010 */ {0x7fffe2, 23}, - /* (151) |11111111|11111111|1100011 */ {0x7fffe3, 23}, - /* (152) |11111111|11111111|1100100 */ {0x7fffe4, 23}, - /* (153) |11111111|11111110|11100 */ {0x1fffdc, 21}, - /* (154) |11111111|11111111|011000 */ {0x3fffd8, 22}, - /* (155) |11111111|11111111|1100101 */ {0x7fffe5, 23}, - /* (156) |11111111|11111111|011001 */ {0x3fffd9, 22}, - /* (157) |11111111|11111111|1100110 */ {0x7fffe6, 23}, - /* (158) |11111111|11111111|1100111 */ {0x7fffe7, 23}, - /* (159) |11111111|11111111|11101111 */ {0xffffef, 24}, - /* (160) |11111111|11111111|011010 */ {0x3fffda, 22}, - /* (161) |11111111|11111110|11101 */ {0x1fffdd, 21}, - /* (162) |11111111|11111110|1001 */ {0xfffe9, 20}, - /* (163) |11111111|11111111|011011 */ {0x3fffdb, 22}, - /* (164) |11111111|11111111|011100 */ {0x3fffdc, 22}, - /* (165) |11111111|11111111|1101000 */ {0x7fffe8, 23}, - /* (166) |11111111|11111111|1101001 */ {0x7fffe9, 23}, - /* (167) |11111111|11111110|11110 */ {0x1fffde, 21}, - /* (168) |11111111|11111111|1101010 */ {0x7fffea, 23}, - /* (169) |11111111|11111111|011101 */ {0x3fffdd, 22}, - /* (170) |11111111|11111111|011110 */ {0x3fffde, 22}, - /* (171) |11111111|11111111|11110000 */ {0xfffff0, 24}, - /* (172) |11111111|11111110|11111 */ {0x1fffdf, 21}, - /* (173) |11111111|11111111|011111 */ {0x3fffdf, 22}, - /* (174) |11111111|11111111|1101011 */ {0x7fffeb, 23}, - /* (175) |11111111|11111111|1101100 */ {0x7fffec, 23}, - /* (176) |11111111|11111111|00000 */ {0x1fffe0, 21}, - /* (177) |11111111|11111111|00001 */ {0x1fffe1, 21}, - /* (178) |11111111|11111111|100000 */ {0x3fffe0, 22}, - /* (179) |11111111|11111111|00010 */ {0x1fffe2, 21}, - /* (180) |11111111|11111111|1101101 */ {0x7fffed, 23}, - /* (181) |11111111|11111111|100001 */ {0x3fffe1, 22}, - /* (182) |11111111|11111111|1101110 */ {0x7fffee, 23}, - /* (183) |11111111|11111111|1101111 */ {0x7fffef, 23}, - /* (184) |11111111|11111110|1010 */ {0xfffea, 20}, - /* (185) |11111111|11111111|100010 */ {0x3fffe2, 22}, - /* (186) |11111111|11111111|100011 */ {0x3fffe3, 22}, - /* (187) |11111111|11111111|100100 */ {0x3fffe4, 22}, - /* (188) |11111111|11111111|1110000 */ {0x7ffff0, 23}, - /* (189) |11111111|11111111|100101 */ {0x3fffe5, 22}, - /* (190) |11111111|11111111|100110 */ {0x3fffe6, 22}, - /* (191) |11111111|11111111|1110001 */ {0x7ffff1, 23}, - /* (192) |11111111|11111111|11111000|00 */ {0x3ffffe0, 26}, - /* (193) |11111111|11111111|11111000|01 */ {0x3ffffe1, 26}, - /* (194) |11111111|11111110|1011 */ {0xfffeb, 20}, - /* (195) |11111111|11111110|001 */ {0x7fff1, 19}, - /* (196) |11111111|11111111|100111 */ {0x3fffe7, 22}, - /* (197) |11111111|11111111|1110010 */ {0x7ffff2, 23}, - /* (198) |11111111|11111111|101000 */ {0x3fffe8, 22}, - /* (199) |11111111|11111111|11110110|0 */ {0x1ffffec, 25}, - /* (200) |11111111|11111111|11111000|10 */ {0x3ffffe2, 26}, - /* (201) |11111111|11111111|11111000|11 */ {0x3ffffe3, 26}, - /* (202) |11111111|11111111|11111001|00 */ {0x3ffffe4, 26}, - /* (203) |11111111|11111111|11111011|110 */ {0x7ffffde, 27}, - /* (204) |11111111|11111111|11111011|111 */ {0x7ffffdf, 27}, - /* (205) |11111111|11111111|11111001|01 */ {0x3ffffe5, 26}, - /* (206) |11111111|11111111|11110001 */ {0xfffff1, 24}, - /* (207) |11111111|11111111|11110110|1 */ {0x1ffffed, 25}, - /* (208) |11111111|11111110|010 */ {0x7fff2, 19}, - /* (209) |11111111|11111111|00011 */ {0x1fffe3, 21}, - /* (210) |11111111|11111111|11111001|10 */ {0x3ffffe6, 26}, - /* (211) |11111111|11111111|11111100|000 */ {0x7ffffe0, 27}, - /* (212) |11111111|11111111|11111100|001 */ {0x7ffffe1, 27}, - /* (213) |11111111|11111111|11111001|11 */ {0x3ffffe7, 26}, - /* (214) |11111111|11111111|11111100|010 */ {0x7ffffe2, 27}, - /* (215) |11111111|11111111|11110010 */ {0xfffff2, 24}, - /* (216) |11111111|11111111|00100 */ {0x1fffe4, 21}, - /* (217) |11111111|11111111|00101 */ {0x1fffe5, 21}, - /* (218) |11111111|11111111|11111010|00 */ {0x3ffffe8, 26}, - /* (219) |11111111|11111111|11111010|01 */ {0x3ffffe9, 26}, - /* (220) |11111111|11111111|11111111|1101 */ {0xffffffd, 28}, - /* (221) |11111111|11111111|11111100|011 */ {0x7ffffe3, 27}, - /* (222) |11111111|11111111|11111100|100 */ {0x7ffffe4, 27}, - /* (223) |11111111|11111111|11111100|101 */ {0x7ffffe5, 27}, - /* (224) |11111111|11111110|1100 */ {0xfffec, 20}, - /* (225) |11111111|11111111|11110011 */ {0xfffff3, 24}, - /* (226) |11111111|11111110|1101 */ {0xfffed, 20}, - /* (227) |11111111|11111111|00110 */ {0x1fffe6, 21}, - /* (228) |11111111|11111111|101001 */ {0x3fffe9, 22}, - /* (229) |11111111|11111111|00111 */ {0x1fffe7, 21}, - /* (230) |11111111|11111111|01000 */ {0x1fffe8, 21}, - /* (231) |11111111|11111111|1110011 */ {0x7ffff3, 23}, - /* (232) |11111111|11111111|101010 */ {0x3fffea, 22}, - /* (233) |11111111|11111111|101011 */ {0x3fffeb, 22}, - /* (234) |11111111|11111111|11110111|0 */ {0x1ffffee, 25}, - /* (235) |11111111|11111111|11110111|1 */ {0x1ffffef, 25}, - /* (236) |11111111|11111111|11110100 */ {0xfffff4, 24}, - /* (237) |11111111|11111111|11110101 */ {0xfffff5, 24}, - /* (238) |11111111|11111111|11111010|10 */ {0x3ffffea, 26}, - /* (239) |11111111|11111111|1110100 */ {0x7ffff4, 23}, - /* (240) |11111111|11111111|11111010|11 */ {0x3ffffeb, 26}, - /* (241) |11111111|11111111|11111100|110 */ {0x7ffffe6, 27}, - /* (242) |11111111|11111111|11111011|00 */ {0x3ffffec, 26}, - /* (243) |11111111|11111111|11111011|01 */ {0x3ffffed, 26}, - /* (244) |11111111|11111111|11111100|111 */ {0x7ffffe7, 27}, - /* (245) |11111111|11111111|11111101|000 */ {0x7ffffe8, 27}, - /* (246) |11111111|11111111|11111101|001 */ {0x7ffffe9, 27}, - /* (247) |11111111|11111111|11111101|010 */ {0x7ffffea, 27}, - /* (248) |11111111|11111111|11111101|011 */ {0x7ffffeb, 27}, - /* (249) |11111111|11111111|11111111|1110 */ {0xffffffe, 28}, - /* (250) |11111111|11111111|11111101|100 */ {0x7ffffec, 27}, - /* (251) |11111111|11111111|11111101|101 */ {0x7ffffed, 27}, - /* (252) |11111111|11111111|11111101|110 */ {0x7ffffee, 27}, - /* (253) |11111111|11111111|11111101|111 */ {0x7ffffef, 27}, - /* (254) |11111111|11111111|11111110|000 */ {0x7fffff0, 27}, - /* (255) |11111111|11111111|11111011|10 */ {0x3ffffee, 26}, - /*EOS (256) |11111111|11111111|11111111|111111 */ {0x3fffffff, 30} - }; - - static final int[][] LCCODES = new int[CODES.length][]; - static final char EOS = 256; - - // Huffman decode tree stored in a flattened char array for good - // locality of reference. - static final char[] tree; - static final char[] rowsym; - static final byte[] rowbits; - - // Build the Huffman lookup tree and LC TABLE - static - { - System.arraycopy(CODES, 0, LCCODES, 0, CODES.length); - for (int i = 'A'; i <= 'Z'; i++) - { - LCCODES[i] = LCCODES['a' + i - 'A']; - } - - int r = 0; - for (int i = 0; i < CODES.length; i++) - { - r += (CODES[i][1] + 7) / 8; - } - tree = new char[r * 256]; - rowsym = new char[r]; - rowbits = new byte[r]; - - r = 0; - for (int sym = 0; sym < CODES.length; sym++) - { - int code = CODES[sym][0]; - int len = CODES[sym][1]; - - int current = 0; - - while (len > 8) - { - len -= 8; - int i = ((code >>> len) & 0xFF); - - int t = current * 256 + i; - current = tree[t]; - if (current == 0) - { - tree[t] = (char)++r; - current = r; - } - } - - int terminal = ++r; - rowsym[r] = (char)sym; - int b = len & 0x07; - int terminalBits = b == 0 ? 8 : b; - - rowbits[r] = (byte)terminalBits; - int shift = 8 - len; - int start = current * 256 + ((code << shift) & 0xFF); - int end = start + (1 << shift); - for (int i = start; i < end; i++) - { - tree[i] = (char)terminal; - } - } - } - - public static String decode(ByteBuffer buffer) throws HpackException.CompressionException - { - return decode(buffer, buffer.remaining()); - } - - public static String decode(ByteBuffer buffer, int length) throws HpackException.CompressionException - { - Utf8StringBuilder utf8 = new Utf8StringBuilder(length * 2); - int node = 0; - int current = 0; - int bits = 0; - - for (int i = 0; i < length; i++) - { - int b = buffer.get() & 0xFF; - current = (current << 8) | b; - bits += 8; - while (bits >= 8) - { - int c = (current >>> (bits - 8)) & 0xFF; - node = tree[node * 256 + c]; - if (rowbits[node] != 0) - { - if (rowsym[node] == EOS) - throw new HpackException.CompressionException("EOS in content"); - - // terminal node - utf8.append((byte)(0xFF & rowsym[node])); - bits -= rowbits[node]; - node = 0; - } - else - { - // non-terminal node - bits -= 8; - } - } - } - - while (bits > 0) - { - int c = (current << (8 - bits)) & 0xFF; - int lastNode = node; - node = tree[node * 256 + c]; - - if (rowbits[node] == 0 || rowbits[node] > bits) - { - int requiredPadding = 0; - for (int i = 0; i < bits; i++) - { - requiredPadding = (requiredPadding << 1) | 1; - } - - if ((c >> (8 - bits)) != requiredPadding) - throw new HpackException.CompressionException("Incorrect padding"); - - node = lastNode; - break; - } - - utf8.append((byte)(0xFF & rowsym[node])); - bits -= rowbits[node]; - node = 0; - } - - if (node != 0) - throw new HpackException.CompressionException("Bad termination"); - - return utf8.toString(); - } - - public static int octetsNeeded(String s) - { - return octetsNeeded(CODES, s); - } - - public static int octetsNeeded(byte[] b) - { - return octetsNeeded(CODES, b); - } - - public static void encode(ByteBuffer buffer, String s) - { - encode(CODES, buffer, s); - } - - public static void encode(ByteBuffer buffer, byte[] b) - { - encode(CODES, buffer, b); - } - - public static int octetsNeededLC(String s) - { - return octetsNeeded(LCCODES, s); - } - - public static void encodeLC(ByteBuffer buffer, String s) - { - encode(LCCODES, buffer, s); - } - - private static int octetsNeeded(final int[][] table, String s) - { - int needed = 0; - int len = s.length(); - for (int i = 0; i < len; i++) - { - char c = s.charAt(i); - if (c >= 128 || c < ' ') - return -1; - needed += table[c][1]; - } - - return (needed + 7) / 8; - } - - private static int octetsNeeded(final int[][] table, byte[] b) - { - int needed = 0; - int len = b.length; - for (int i = 0; i < len; i++) - { - int c = 0xFF & b[i]; - needed += table[c][1]; - } - return (needed + 7) / 8; - } - - /** - * @param table The table to encode by - * @param buffer The buffer to encode to - * @param s The string to encode - */ - private static void encode(final int[][] table, ByteBuffer buffer, String s) - { - long current = 0; - int n = 0; - int len = s.length(); - for (int i = 0; i < len; i++) - { - char c = s.charAt(i); - if (c >= 128 || c < ' ') - throw new IllegalArgumentException(); - int code = table[c][0]; - int bits = table[c][1]; - - current <<= bits; - current |= code; - n += bits; - - while (n >= 8) - { - n -= 8; - buffer.put((byte)(current >> n)); - } - } - - if (n > 0) - { - current <<= (8 - n); - current |= (0xFF >>> n); - buffer.put((byte)(current)); - } - } - - private static void encode(final int[][] table, ByteBuffer buffer, byte[] b) - { - long current = 0; - int n = 0; - - int len = b.length; - for (int i = 0; i < len; i++) - { - int c = 0xFF & b[i]; - int code = table[c][0]; - int bits = table[c][1]; - - current <<= bits; - current |= code; - n += bits; - - while (n >= 8) - { - n -= 8; - buffer.put((byte)(current >> n)); - } - } - - if (n > 0) - { - current <<= (8 - n); - current |= (0xFF >>> n); - buffer.put((byte)(current)); - } - } -} diff -Nru jetty9-9.4.51/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java jetty9-9.4.53/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java --- jetty9-9.4.51/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/MetaDataBuilder.java 2023-10-09 12:27:40.000000000 +0000 @@ -29,7 +29,7 @@ public class MetaDataBuilder { - private final int _maxSize; + private int _maxSize; private int _size; private Integer _status; private String _method; @@ -60,6 +60,11 @@ return _maxSize; } + public void setMaxSize(int maxSize) + { + _maxSize = maxSize; + } + /** * Get the size. * @@ -70,17 +75,18 @@ return _size; } - public void emit(HttpField field) throws HpackException.SessionException + public void emit(HttpField field) throws SessionException { HttpHeader header = field.getHeader(); String name = field.getName(); - if (name == null || name.length() == 0) - throw new HpackException.SessionException("Header size 0"); + if (name == null || name.isEmpty()) + throw new SessionException("Header size 0"); String value = field.getValue(); int fieldSize = name.length() + (value == null ? 0 : value.length()); _size += fieldSize + 32; - if (_size > _maxSize) - throw new HpackException.SessionException("Header size %d > %d", _size, _maxSize); + int maxSize = getMaxSize(); + if (maxSize > 0 && _size > maxSize) + throw new SessionException("Header size %d > %d", _size, maxSize); if (field instanceof StaticTableHttpField) { @@ -89,7 +95,7 @@ { case C_STATUS: if (checkPseudoHeader(header, _status)) - _status = (Integer)staticField.getStaticValue(); + _status = staticField.getIntValue(); _response = true; break; @@ -157,7 +163,7 @@ case C_PATH: if (checkPseudoHeader(header, _path)) { - if (value != null && value.length() > 0) + if (value != null && !value.isEmpty()) _path = value; else streamException("No Path"); @@ -201,7 +207,7 @@ } } - protected void streamException(String messageFormat, Object... args) + public void streamException(String messageFormat, Object... args) { HpackException.StreamException stream = new HpackException.StreamException(messageFormat, args); if (_streamException == null) @@ -267,23 +273,7 @@ _authority = null; _path = null; _size = 0; - _contentLength = Long.MIN_VALUE; + _contentLength = -1; } } - - /** - * Check that the max size will not be exceeded. - * - * @param length the length - * @param huffman the huffman name - * @throws SessionException in case of size errors - */ - public void checkSize(int length, boolean huffman) throws SessionException - { - // Apply a huffman fudge factor - if (huffman) - length = (length * 4) / 3; - if ((_size + length) > _maxSize) - throw new HpackException.SessionException("Header too large %d > %d", _size + length, _maxSize); - } } diff -Nru jetty9-9.4.51/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/NBitInteger.java jetty9-9.4.53/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/NBitInteger.java --- jetty9-9.4.51/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/NBitInteger.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/NBitInteger.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,151 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http2.hpack; - -import java.nio.ByteBuffer; - -public class NBitInteger -{ - public static int octectsNeeded(int n, int i) - { - if (n == 8) - { - int nbits = 0xFF; - i = i - nbits; - if (i < 0) - return 1; - if (i == 0) - return 2; - int lz = Integer.numberOfLeadingZeros(i); - int log = 32 - lz; - return 1 + (log + 6) / 7; - } - - int nbits = 0xFF >>> (8 - n); - i = i - nbits; - if (i < 0) - return 0; - if (i == 0) - return 1; - int lz = Integer.numberOfLeadingZeros(i); - int log = 32 - lz; - return (log + 6) / 7; - } - - public static void encode(ByteBuffer buf, int n, int i) - { - if (n == 8) - { - if (i < 0xFF) - { - buf.put((byte)i); - } - else - { - buf.put((byte)0xFF); - - int length = i - 0xFF; - while (true) - { - if ((length & ~0x7F) == 0) - { - buf.put((byte)length); - return; - } - else - { - buf.put((byte)((length & 0x7F) | 0x80)); - length >>>= 7; - } - } - } - } - else - { - int p = buf.position() - 1; - int bits = 0xFF >>> (8 - n); - - if (i < bits) - { - buf.put(p, (byte)((buf.get(p) & ~bits) | i)); - } - else - { - buf.put(p, (byte)(buf.get(p) | bits)); - - int length = i - bits; - while (true) - { - if ((length & ~0x7F) == 0) - { - buf.put((byte)length); - return; - } - else - { - buf.put((byte)((length & 0x7F) | 0x80)); - length >>>= 7; - } - } - } - } - } - - public static int decode(ByteBuffer buffer, int n) - { - if (n == 8) - { - int nbits = 0xFF; - - int i = buffer.get() & 0xff; - - if (i == nbits) - { - int m = 1; - int b; - do - { - b = 0xff & buffer.get(); - i = i + (b & 127) * m; - m = m * 128; - } - while ((b & 128) == 128); - } - return i; - } - - int nbits = 0xFF >>> (8 - n); - - int i = buffer.get(buffer.position() - 1) & nbits; - - if (i == nbits) - { - int m = 1; - int b; - do - { - b = 0xff & buffer.get(); - i = i + (b & 127) * m; - m = m * 128; - } - while ((b & 128) == 128); - } - return i; - } -} diff -Nru jetty9-9.4.51/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackContextTest.java jetty9-9.4.53/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackContextTest.java --- jetty9-9.4.51/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackContextTest.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackContextTest.java 2023-10-09 12:27:40.000000000 +0000 @@ -21,6 +21,9 @@ import java.nio.ByteBuffer; import org.eclipse.jetty.http.HttpField; +import org.eclipse.jetty.http.compression.EncodingException; +import org.eclipse.jetty.http.compression.HuffmanDecoder; +import org.eclipse.jetty.http.compression.NBitIntegerDecoder; import org.eclipse.jetty.http2.hpack.HpackContext.Entry; import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; @@ -37,6 +40,32 @@ */ public class HpackContextTest { + public static String decode(ByteBuffer buffer, int length) throws EncodingException + { + HuffmanDecoder huffmanDecoder = new HuffmanDecoder(); + huffmanDecoder.setLength(length); + String decoded = huffmanDecoder.decode(buffer); + if (decoded == null) + throw new EncodingException("invalid string encoding"); + + huffmanDecoder.reset(); + return decoded; + } + + public static int decodeInt(ByteBuffer buffer, int prefix) throws EncodingException + { + // This is a fix for HPACK as it already takes the first byte of the encoded integer. + if (prefix != 8) + buffer.position(buffer.position() - 1); + + NBitIntegerDecoder decoder = new NBitIntegerDecoder(); + decoder.setPrefix(prefix); + int decodedInt = decoder.decodeInt(buffer); + if (decodedInt < 0) + throw new EncodingException("invalid integer encoding"); + decoder.reset(); + return decodedInt; + } @Test public void testStaticName() @@ -428,10 +457,10 @@ int huff = 0xff & buffer.get(); assertTrue((0x80 & huff) == 0x80); - int len = NBitInteger.decode(buffer, 7); + int len = decodeInt(buffer, 7); assertEquals(len, buffer.remaining()); - String value = Huffman.decode(buffer); + String value = decode(buffer, buffer.remaining()); assertEquals(entry.getHttpField().getValue(), value); } diff -Nru jetty9-9.4.51/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java jetty9-9.4.53/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java --- jetty9-9.4.51/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackDecoderTest.java 2023-10-09 12:27:40.000000000 +0000 @@ -62,7 +62,7 @@ @Test public void testDecodeD3() throws Exception { - HpackDecoder decoder = new HpackDecoder(4096, 8192); + HpackDecoder decoder = new HpackDecoder(8192); // First request String encoded = "828684410f7777772e6578616d706c652e636f6d"; @@ -110,7 +110,7 @@ @Test public void testDecodeD4() throws Exception { - HpackDecoder decoder = new HpackDecoder(4096, 8192); + HpackDecoder decoder = new HpackDecoder(8192); // First request String encoded = "828684418cf1e3c2e5f23a6ba0ab90f4ff"; @@ -145,7 +145,7 @@ { String value = "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="; - HpackDecoder decoder = new HpackDecoder(4096, 8192); + HpackDecoder decoder = new HpackDecoder(8192); String encoded = "8682418cF1E3C2E5F23a6bA0Ab90F4Ff841f0822426173696320515778685a475270626a70766347567549484e6c633246745a513d3d"; byte[] bytes = TypeUtil.fromHexString(encoded); byte[] array = new byte[bytes.length + 1]; @@ -167,7 +167,7 @@ @Test public void testDecodeHuffmanWithArrayOffset() throws Exception { - HpackDecoder decoder = new HpackDecoder(4096, 8192); + HpackDecoder decoder = new HpackDecoder(8192); String encoded = "8286418cf1e3c2e5f23a6ba0ab90f4ff84"; byte[] bytes = TypeUtil.fromHexString(encoded); @@ -191,7 +191,7 @@ String encoded = "886196C361Be940b6a65B6850400B8A00571972e080a62D1Bf5f87497cA589D34d1f9a0f0d0234327690Aa69D29aFcA954D3A5358980Ae112e0f7c880aE152A9A74a6bF3"; ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); - HpackDecoder decoder = new HpackDecoder(4096, 8192); + HpackDecoder decoder = new HpackDecoder(8192); MetaData.Response response = (MetaData.Response)decoder.decode(buffer); assertThat(response.getStatus(), is(200)); @@ -209,7 +209,7 @@ { String encoded = "203f136687A0E41d139d090760881c6490B2Cd39Ba7f"; ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); - HpackDecoder decoder = new HpackDecoder(4096, 8192); + HpackDecoder decoder = new HpackDecoder(8192); MetaData metaData = decoder.decode(buffer); assertThat(metaData.getFields().get(HttpHeader.HOST), is("localhost0")); assertThat(metaData.getFields().get(HttpHeader.COOKIE), is("abcdefghij")); @@ -231,7 +231,7 @@ String encoded = "203f136687A0E41d139d090760881c6490B2Cd39Ba7f20"; ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); - HpackDecoder decoder = new HpackDecoder(4096, 8192); + HpackDecoder decoder = new HpackDecoder(8192); try { decoder.decode(buffer); @@ -249,7 +249,8 @@ String encoded = "3f610f17FfEc02Df3990A190A0D4Ee5b3d2940Ec98Aa4a62D127D29e273a0aA20dEcAa190a503b262d8a2671D4A2672a927aA874988a2471D05510750c951139EdA2452a3a548cAa1aA90bE4B228342864A9E0D450A5474a92992a1aA513395448E3A0Aa17B96cFe3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f14E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F353F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F54f"; ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); - HpackDecoder decoder = new HpackDecoder(128, 8192); + HpackDecoder decoder = new HpackDecoder(8192); + decoder.setMaxTableCapacity(128); MetaData metaData = decoder.decode(buffer); assertThat(decoder.getHpackContext().getDynamicTableSize(), is(0)); @@ -262,7 +263,8 @@ String encoded = "BE"; ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); - HpackDecoder decoder = new HpackDecoder(128, 8192); + HpackDecoder decoder = new HpackDecoder(8192); + decoder.setMaxTableCapacity(128); try { @@ -447,7 +449,7 @@ @Test public void testHuffmanEncodedStandard() throws Exception { - HpackDecoder decoder = new HpackDecoder(4096, 8192); + HpackDecoder decoder = new HpackDecoder(8192); String encoded = "82868441" + "83" + "49509F"; ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); @@ -465,68 +467,68 @@ @Test public void testHuffmanEncodedExtraPadding() { - HpackDecoder decoder = new HpackDecoder(4096, 8192); + HpackDecoder decoder = new HpackDecoder(8192); String encoded = "82868441" + "84" + "49509FFF"; ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); CompressionException ex = assertThrows(CompressionException.class, () -> decoder.decode(buffer)); - assertThat(ex.getMessage(), Matchers.containsString("Bad termination")); + assertThat(ex.getMessage(), Matchers.containsString("bad_termination")); } /* 5.2.2: Sends a Huffman-encoded string literal representation padded by zero */ @Test public void testHuffmanEncodedZeroPadding() { - HpackDecoder decoder = new HpackDecoder(4096, 8192); + HpackDecoder decoder = new HpackDecoder(8192); String encoded = "82868441" + "83" + "495090"; ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); CompressionException ex = assertThrows(CompressionException.class, () -> decoder.decode(buffer)); - assertThat(ex.getMessage(), Matchers.containsString("Incorrect padding")); + assertThat(ex.getMessage(), Matchers.containsString("incorrect_padding")); } /* 5.2.3: Sends a Huffman-encoded string literal representation containing the EOS symbol */ @Test public void testHuffmanEncodedWithEOS() { - HpackDecoder decoder = new HpackDecoder(4096, 8192); + HpackDecoder decoder = new HpackDecoder(8192); String encoded = "82868441" + "87" + "497FFFFFFF427F"; ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); CompressionException ex = assertThrows(CompressionException.class, () -> decoder.decode(buffer)); - assertThat(ex.getMessage(), Matchers.containsString("EOS in content")); + assertThat(ex.getMessage(), Matchers.containsString("eos_in_content")); } @Test public void testHuffmanEncodedOneIncompleteOctet() { - HpackDecoder decoder = new HpackDecoder(4096, 8192); + HpackDecoder decoder = new HpackDecoder(8192); String encoded = "82868441" + "81" + "FE"; ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); CompressionException ex = assertThrows(CompressionException.class, () -> decoder.decode(buffer)); - assertThat(ex.getMessage(), Matchers.containsString("Bad termination")); + assertThat(ex.getMessage(), Matchers.containsString("bad_termination")); } @Test public void testHuffmanEncodedTwoIncompleteOctet() { - HpackDecoder decoder = new HpackDecoder(4096, 8192); + HpackDecoder decoder = new HpackDecoder(8192); String encoded = "82868441" + "82" + "FFFE"; ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); CompressionException ex = assertThrows(CompressionException.class, () -> decoder.decode(buffer)); - assertThat(ex.getMessage(), Matchers.containsString("Bad termination")); + assertThat(ex.getMessage(), Matchers.containsString("bad_termination")); } @Test public void testZeroLengthName() { - HpackDecoder decoder = new HpackDecoder(4096, 8192); + HpackDecoder decoder = new HpackDecoder(8192); String encoded = "00000130"; ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); @@ -537,7 +539,7 @@ @Test public void testZeroLengthValue() throws Exception { - HpackDecoder decoder = new HpackDecoder(4096, 8192); + HpackDecoder decoder = new HpackDecoder(8192); String encoded = "00016800"; ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); @@ -549,7 +551,7 @@ @Test public void testUpperCaseName() { - HpackDecoder decoder = new HpackDecoder(4096, 8192); + HpackDecoder decoder = new HpackDecoder(8192); String encoded = "0001480130"; ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); @@ -560,7 +562,7 @@ @Test public void testWhiteSpaceName() { - HpackDecoder decoder = new HpackDecoder(4096, 8192); + HpackDecoder decoder = new HpackDecoder(8192); String encoded = "0001200130"; ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); diff -Nru jetty9-9.4.51/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java jetty9-9.4.53/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java --- jetty9-9.4.51/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackEncoderTest.java 2023-10-09 12:27:40.000000000 +0000 @@ -38,7 +38,7 @@ @Test public void testUnknownFieldsContextManagement() throws Exception { - HpackEncoder encoder = new HpackEncoder(38 * 5); + HpackEncoder encoder = newHpackEncoder(38 * 5); HttpFields fields = new HttpFields(); HttpField[] field = @@ -149,8 +149,9 @@ @Test public void testLargeFieldsNotIndexed() { - HpackEncoder encoder = new HpackEncoder(38 * 5); + HpackEncoder encoder = newHpackEncoder(38 * 5); HpackContext ctx = encoder.getHpackContext(); + ctx.resize(encoder.getMaxTableCapacity()); ByteBuffer buffer = BufferUtil.allocate(4096); @@ -175,8 +176,9 @@ @Test public void testIndexContentLength() { - HpackEncoder encoder = new HpackEncoder(38 * 5); + HpackEncoder encoder = newHpackEncoder(38 * 5); HpackContext ctx = encoder.getHpackContext(); + ctx.resize(encoder.getMaxTableCapacity()); ByteBuffer buffer = BufferUtil.allocate(4096); @@ -197,7 +199,7 @@ @Test public void testNeverIndexSetCookie() throws Exception { - HpackEncoder encoder = new HpackEncoder(38 * 5); + HpackEncoder encoder = newHpackEncoder(38 * 5); ByteBuffer buffer = BufferUtil.allocate(4096); HttpFields fields = new HttpFields(); @@ -231,20 +233,20 @@ { HttpFields fields = new HttpFields(); - HpackEncoder encoder = new HpackEncoder(128); + HpackEncoder encoder = newHpackEncoder(128); ByteBuffer buffer0 = BufferUtil.allocate(4096); int pos = BufferUtil.flipToFill(buffer0); encoder.encode(buffer0, new MetaData(HttpVersion.HTTP_2, fields)); BufferUtil.flipToFlush(buffer0, pos); - encoder = new HpackEncoder(128); + encoder = newHpackEncoder(128); fields.add(new HttpField("user-agent", "jetty/test")); ByteBuffer buffer1 = BufferUtil.allocate(4096); pos = BufferUtil.flipToFill(buffer1); encoder.encode(buffer1, new MetaData(HttpVersion.HTTP_2, fields)); BufferUtil.flipToFlush(buffer1, pos); - encoder = new HpackEncoder(128); + encoder = newHpackEncoder(128); encoder.setValidateEncoding(false); fields.add(new HttpField(":path", "This is a very large field, whose size is larger than the dynamic table so it should not be indexed as it will not fit in the table ever!" + @@ -256,7 +258,7 @@ encoder.encode(buffer2, new MetaData(HttpVersion.HTTP_2, fields)); BufferUtil.flipToFlush(buffer2, pos); - encoder = new HpackEncoder(128); + encoder = newHpackEncoder(128); encoder.setValidateEncoding(false); fields.add(new HttpField("host", "somehost")); ByteBuffer buffer = BufferUtil.allocate(4096); @@ -297,12 +299,12 @@ fields.add("host", "localhost0"); fields.add("cookie", "abcdefghij"); - HpackEncoder encoder = new HpackEncoder(4096); + HpackEncoder encoder = newHpackEncoder(4096); ByteBuffer buffer = BufferUtil.allocate(4096); int pos = BufferUtil.flipToFill(buffer); encoder.encodeMaxDynamicTableSize(buffer, 0); - encoder.setRemoteMaxDynamicTableSize(50); + encoder.setTableCapacity(50); encoder.encode(buffer, new MetaData(HttpVersion.HTTP_2, fields)); BufferUtil.flipToFlush(buffer, pos); @@ -311,4 +313,12 @@ assertThat(context.getMaxDynamicTableSize(), Matchers.is(50)); assertThat(context.size(), Matchers.is(1)); } + + private static HpackEncoder newHpackEncoder(int tableCapacity) + { + HpackEncoder encoder = new HpackEncoder(); + encoder.setMaxTableCapacity(tableCapacity); + encoder.setTableCapacity(tableCapacity); + return encoder; + } } diff -Nru jetty9-9.4.51/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackPerfTest.java jetty9-9.4.53/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackPerfTest.java --- jetty9-9.4.51/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackPerfTest.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackPerfTest.java 2023-10-09 12:27:40.000000000 +0000 @@ -37,7 +37,7 @@ public class HpackPerfTest { - int _maxDynamicTableSize = 4 * 1024; + int _tableCapacity = 4 * 1024; int _unencodedSize; int _encodedSize; @@ -51,7 +51,7 @@ @AfterEach public void after() { - System.err.printf("dynamictable=%d unencoded=%d encoded=%d p=%3.1f%%%n", _maxDynamicTableSize, _unencodedSize, _encodedSize, 100.0 * _encodedSize / _unencodedSize); + System.err.printf("dynamictable=%d unencoded=%d encoded=%d p=%3.1f%%%n", _tableCapacity, _unencodedSize, _encodedSize, 100.0 * _encodedSize / _unencodedSize); } @Test @@ -68,11 +68,14 @@ assertNotNull(files); // Parse JSON - Map[] stories = new Map[files.length]; + @SuppressWarnings("unchecked") + Map[] stories = new Map[files.length]; int i = 0; - for (String story : files) + for (String file : files) { - stories[i++] = (Map)JSON.parse(new FileReader(new File(data, story))); + @SuppressWarnings("unchecked") + Map story = (Map)JSON.parse(new FileReader(new File(data, file))); + stories[i++] = story; } ByteBuffer buffer = BufferUtil.allocate(256 * 1024); @@ -88,27 +91,29 @@ encodeStories(buffer, stories, "response"); } - private void encodeStories(ByteBuffer buffer, Map[] stories, String type) throws Exception + private void encodeStories(ByteBuffer buffer, Map[] stories, String type) throws Exception { - for (Map story : stories) + for (Map story : stories) { if (type.equals(story.get("context"))) { - HpackEncoder encoder = new HpackEncoder(_maxDynamicTableSize, _maxDynamicTableSize); + HpackEncoder encoder = new HpackEncoder(); + encoder.setMaxTableCapacity(_tableCapacity); + encoder.setTableCapacity(_tableCapacity); encoder.setValidateEncoding(false); - // System.err.println(story); Object[] cases = (Object[])story.get("cases"); for (Object c : cases) { - // System.err.println(" "+c); - Object[] headers = (Object[])((Map)c).get("headers"); + @SuppressWarnings("unchecked") + Map kase = (Map)c; + Object[] headers = (Object[])kase.get("headers"); // System.err.println(" "+headers); HttpFields fields = new HttpFields(); for (Object header : headers) { @SuppressWarnings("unchecked") - Map h = (Map)header; + Map h = (Map)header; Map.Entry e = h.entrySet().iterator().next(); fields.add(e.getKey(), e.getValue()); _unencodedSize += e.getKey().length() + e.getValue().length(); diff -Nru jetty9-9.4.51/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java jetty9-9.4.53/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java --- jetty9-9.4.51/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HpackTest.java 2023-10-09 12:27:40.000000000 +0000 @@ -19,7 +19,6 @@ package org.eclipse.jetty.http2.hpack; import java.nio.ByteBuffer; -import java.util.concurrent.TimeUnit; import org.eclipse.jetty.http.DateGenerator; import org.eclipse.jetty.http.HttpField; @@ -43,13 +42,13 @@ { static final HttpField ServerJetty = new PreEncodedHttpField(HttpHeader.SERVER, "jetty"); static final HttpField XPowerJetty = new PreEncodedHttpField(HttpHeader.X_POWERED_BY, "jetty"); - static final HttpField Date = new PreEncodedHttpField(HttpHeader.DATE, DateGenerator.formatDate(TimeUnit.NANOSECONDS.toMillis(System.nanoTime()))); + static final HttpField Date = new PreEncodedHttpField(HttpHeader.DATE, DateGenerator.formatDate(System.currentTimeMillis())); @Test public void encodeDecodeResponseTest() throws Exception { HpackEncoder encoder = new HpackEncoder(); - HpackDecoder decoder = new HpackDecoder(4096, 8192); + HpackDecoder decoder = new HpackDecoder(8192); ByteBuffer buffer = BufferUtil.allocateDirect(16 * 1024); HttpFields fields0 = new HttpFields(); @@ -102,7 +101,7 @@ public void encodeDecodeTooLargeTest() throws Exception { HpackEncoder encoder = new HpackEncoder(); - HpackDecoder decoder = new HpackDecoder(4096, 164); + HpackDecoder decoder = new HpackDecoder(164); ByteBuffer buffer = BufferUtil.allocateDirect(16 * 1024); HttpFields fields0 = new HttpFields(); @@ -133,36 +132,40 @@ } catch (HpackException.SessionException e) { - assertThat(e.getMessage(), containsString("Header too large")); + assertThat(e.getMessage(), containsString("Header size 198 > 164")); } } @Test - public void encodeDecodeNonAscii() throws Exception + public void encodeNonAscii() throws Exception { HpackEncoder encoder = new HpackEncoder(); - HpackDecoder decoder = new HpackDecoder(4096, 8192); ByteBuffer buffer = BufferUtil.allocate(16 * 1024); HttpFields fields0 = new HttpFields(); - // @checkstyle-disable-check : AvoidEscapedUnicodeCharactersCheck + // @checkstyle-disable-check : AvoidEscapedUnicodeCharactersCheck fields0.add("Cookie", "[\uD842\uDF9F]"); fields0.add("custom-key", "[\uD842\uDF9F]"); Response original0 = new MetaData.Response(HttpVersion.HTTP_2, 200, fields0); - BufferUtil.clearToFill(buffer); - encoder.encode(buffer, original0); - BufferUtil.flipToFlush(buffer, 0); - Response decoded0 = (Response)decoder.decode(buffer); + HpackException.SessionException throwable = assertThrows(HpackException.SessionException.class, () -> + { + BufferUtil.clearToFill(buffer); + encoder.encode(buffer, original0); + BufferUtil.flipToFlush(buffer, 0); + }); - assertMetaDataSame(original0, decoded0); + assertThat(throwable.getMessage(), containsString("Could not hpack encode")); } - + @Test public void evictReferencedFieldTest() throws Exception { - HpackEncoder encoder = new HpackEncoder(200, 200); - HpackDecoder decoder = new HpackDecoder(200, 1024); + HpackDecoder decoder = new HpackDecoder(1024); + decoder.setMaxTableCapacity(200); + HpackEncoder encoder = new HpackEncoder(); + encoder.setMaxTableCapacity(decoder.getMaxTableCapacity()); + encoder.setTableCapacity(decoder.getMaxTableCapacity()); ByteBuffer buffer = BufferUtil.allocateDirect(16 * 1024); String longEnoughToBeEvicted = "012345678901234567890123456789012345678901234567890"; @@ -205,7 +208,7 @@ public void testHopHeadersAreRemoved() throws Exception { HpackEncoder encoder = new HpackEncoder(); - HpackDecoder decoder = new HpackDecoder(4096, 16384); + HpackDecoder decoder = new HpackDecoder(16384); HttpFields input = new HttpFields(); input.put(HttpHeader.ACCEPT, "*"); @@ -232,14 +235,14 @@ public void testTETrailers() throws Exception { HpackEncoder encoder = new HpackEncoder(); - HpackDecoder decoder = new HpackDecoder(4096, 16384); + HpackDecoder decoder = new HpackDecoder(16384); - HttpFields input = new HttpFields(); - input.put(HttpHeader.CONNECTION, "TE"); String teValue = "trailers"; - input.put(HttpHeader.TE, teValue); String trailerValue = "Custom"; - input.put(HttpHeader.TRAILER, trailerValue); + HttpFields input = new HttpFields(); + input.add(HttpHeader.CONNECTION, "TE"); + input.add(HttpHeader.TE, teValue); + input.add(HttpHeader.TRAILER, trailerValue); ByteBuffer buffer = BufferUtil.allocate(2048); BufferUtil.clearToFill(buffer); @@ -257,7 +260,7 @@ public void testColonHeaders() throws Exception { HpackEncoder encoder = new HpackEncoder(); - HpackDecoder decoder = new HpackDecoder(4096, 16384); + HpackDecoder decoder = new HpackDecoder(16384); HttpFields input = new HttpFields(); input.put(":status", "200"); diff -Nru jetty9-9.4.51/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HuffmanTest.java jetty9-9.4.53/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HuffmanTest.java --- jetty9-9.4.51/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HuffmanTest.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/HuffmanTest.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,87 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http2.hpack; - -import java.nio.BufferOverflowException; -import java.nio.ByteBuffer; -import java.util.Locale; -import java.util.stream.Stream; - -import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.TypeUtil; -import org.hamcrest.Matchers; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; -import org.junit.jupiter.params.provider.ValueSource; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; - -public class HuffmanTest -{ - public static Stream data() - { - return Stream.of( - new String[][]{ - {"D.4.1", "f1e3c2e5f23a6ba0ab90f4ff", "www.example.com"}, - {"D.4.2", "a8eb10649cbf", "no-cache"}, - {"D.6.1k", "6402", "302"}, - {"D.6.1v", "aec3771a4b", "private"}, - {"D.6.1d", "d07abe941054d444a8200595040b8166e082a62d1bff", "Mon, 21 Oct 2013 20:13:21 GMT"}, - {"D.6.1l", "9d29ad171863c78f0b97c8e9ae82ae43d3", "https://www.example.com"}, - {"D.6.2te", "640cff", "303"}, - }).map(Arguments::of); - } - - @ParameterizedTest(name = "[{index}] spec={0}") - @MethodSource("data") - public void testDecode(String specSection, String hex, String expected) throws Exception - { - byte[] encoded = TypeUtil.fromHexString(hex); - String decoded = Huffman.decode(ByteBuffer.wrap(encoded)); - assertEquals(expected, decoded, specSection); - } - - @ParameterizedTest(name = "[{index}] spec={0}") - @MethodSource("data") - public void testEncode(String specSection, String hex, String expected) - { - ByteBuffer buf = BufferUtil.allocate(1024); - int pos = BufferUtil.flipToFill(buf); - Huffman.encode(buf, expected); - BufferUtil.flipToFlush(buf, pos); - String encoded = TypeUtil.toHexString(BufferUtil.toArray(buf)).toLowerCase(Locale.ENGLISH); - assertEquals(hex, encoded, specSection); - assertEquals(hex.length() / 2, Huffman.octetsNeeded(expected)); - } - - @ParameterizedTest(name = "[{index}]") // don't include unprintable character in test display-name - @ValueSource(chars = {(char)128, (char)0, (char)-1, ' ' - 1}) - public void testEncode8859Only(char bad) - { - String s = "bad '" + bad + "'"; - - assertThat(Huffman.octetsNeeded(s), Matchers.is(-1)); - - assertThrows(BufferOverflowException.class, - () -> Huffman.encode(BufferUtil.allocate(32), s)); - } -} diff -Nru jetty9-9.4.51/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/NBitIntegerTest.java jetty9-9.4.53/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/NBitIntegerTest.java --- jetty9-9.4.51/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/NBitIntegerTest.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-hpack/src/test/java/org/eclipse/jetty/http2/hpack/NBitIntegerTest.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,204 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.http2.hpack; - -import java.nio.ByteBuffer; - -import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.TypeUtil; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -public class NBitIntegerTest -{ - - @Test - public void testOctetsNeeded() - { - assertEquals(0, NBitInteger.octectsNeeded(5, 10)); - assertEquals(2, NBitInteger.octectsNeeded(5, 1337)); - assertEquals(1, NBitInteger.octectsNeeded(8, 42)); - assertEquals(3, NBitInteger.octectsNeeded(8, 1337)); - - assertEquals(0, NBitInteger.octectsNeeded(6, 62)); - assertEquals(1, NBitInteger.octectsNeeded(6, 63)); - assertEquals(1, NBitInteger.octectsNeeded(6, 64)); - assertEquals(2, NBitInteger.octectsNeeded(6, 63 + 0x00 + 0x80 * 0x01)); - assertEquals(3, NBitInteger.octectsNeeded(6, 63 + 0x00 + 0x80 * 0x80)); - assertEquals(4, NBitInteger.octectsNeeded(6, 63 + 0x00 + 0x80 * 0x80 * 0x80)); - } - - @Test - public void testEncode() - { - testEncode(6, 0, "00"); - testEncode(6, 1, "01"); - testEncode(6, 62, "3e"); - testEncode(6, 63, "3f00"); - testEncode(6, 63 + 1, "3f01"); - testEncode(6, 63 + 0x7e, "3f7e"); - testEncode(6, 63 + 0x7f, "3f7f"); - testEncode(6, 63 + 0x00 + 0x80 * 0x01, "3f8001"); - testEncode(6, 63 + 0x01 + 0x80 * 0x01, "3f8101"); - testEncode(6, 63 + 0x7f + 0x80 * 0x01, "3fFf01"); - testEncode(6, 63 + 0x00 + 0x80 * 0x02, "3f8002"); - testEncode(6, 63 + 0x01 + 0x80 * 0x02, "3f8102"); - testEncode(6, 63 + 0x7f + 0x80 * 0x7f, "3fFf7f"); - testEncode(6, 63 + 0x00 + 0x80 * 0x80, "3f808001"); - testEncode(6, 63 + 0x7f + 0x80 * 0x80 * 0x7f, "3fFf807f"); - testEncode(6, 63 + 0x00 + 0x80 * 0x80 * 0x80, "3f80808001"); - - testEncode(8, 0, "00"); - testEncode(8, 1, "01"); - testEncode(8, 128, "80"); - testEncode(8, 254, "Fe"); - testEncode(8, 255, "Ff00"); - testEncode(8, 255 + 1, "Ff01"); - testEncode(8, 255 + 0x7e, "Ff7e"); - testEncode(8, 255 + 0x7f, "Ff7f"); - testEncode(8, 255 + 0x80, "Ff8001"); - testEncode(8, 255 + 0x00 + 0x80 * 0x80, "Ff808001"); - } - - public void testEncode(int n, int i, String expected) - { - ByteBuffer buf = BufferUtil.allocate(16); - int p = BufferUtil.flipToFill(buf); - if (n < 8) - buf.put((byte)0x00); - NBitInteger.encode(buf, n, i); - BufferUtil.flipToFlush(buf, p); - String r = TypeUtil.toHexString(BufferUtil.toArray(buf)); - assertEquals(expected, r); - - assertEquals(expected.length() / 2, (n < 8 ? 1 : 0) + NBitInteger.octectsNeeded(n, i)); - } - - @Test - public void testDecode() - { - testDecode(6, 0, "00"); - testDecode(6, 1, "01"); - testDecode(6, 62, "3e"); - testDecode(6, 63, "3f00"); - testDecode(6, 63 + 1, "3f01"); - testDecode(6, 63 + 0x7e, "3f7e"); - testDecode(6, 63 + 0x7f, "3f7f"); - testDecode(6, 63 + 0x80, "3f8001"); - testDecode(6, 63 + 0x81, "3f8101"); - testDecode(6, 63 + 0x7f + 0x80 * 0x01, "3fFf01"); - testDecode(6, 63 + 0x00 + 0x80 * 0x02, "3f8002"); - testDecode(6, 63 + 0x01 + 0x80 * 0x02, "3f8102"); - testDecode(6, 63 + 0x7f + 0x80 * 0x7f, "3fFf7f"); - testDecode(6, 63 + 0x00 + 0x80 * 0x80, "3f808001"); - testDecode(6, 63 + 0x7f + 0x80 * 0x80 * 0x7f, "3fFf807f"); - testDecode(6, 63 + 0x00 + 0x80 * 0x80 * 0x80, "3f80808001"); - - testDecode(8, 0, "00"); - testDecode(8, 1, "01"); - testDecode(8, 128, "80"); - testDecode(8, 254, "Fe"); - testDecode(8, 255, "Ff00"); - testDecode(8, 255 + 1, "Ff01"); - testDecode(8, 255 + 0x7e, "Ff7e"); - testDecode(8, 255 + 0x7f, "Ff7f"); - testDecode(8, 255 + 0x80, "Ff8001"); - testDecode(8, 255 + 0x00 + 0x80 * 0x80, "Ff808001"); - } - - public void testDecode(int n, int expected, String encoded) - { - ByteBuffer buf = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); - buf.position(n == 8 ? 0 : 1); - assertEquals(expected, NBitInteger.decode(buf, n)); - } - - @Test - public void testEncodeExampleD11() - { - ByteBuffer buf = BufferUtil.allocate(16); - int p = BufferUtil.flipToFill(buf); - buf.put((byte)0x77); - buf.put((byte)0xFF); - NBitInteger.encode(buf, 5, 10); - BufferUtil.flipToFlush(buf, p); - - String r = TypeUtil.toHexString(BufferUtil.toArray(buf)); - - assertEquals("77Ea", r); - } - - @Test - public void testDecodeExampleD11() - { - ByteBuffer buf = ByteBuffer.wrap(TypeUtil.fromHexString("77EaFF")); - buf.position(2); - - assertEquals(10, NBitInteger.decode(buf, 5)); - } - - @Test - public void testEncodeExampleD12() - { - ByteBuffer buf = BufferUtil.allocate(16); - int p = BufferUtil.flipToFill(buf); - buf.put((byte)0x88); - buf.put((byte)0x00); - NBitInteger.encode(buf, 5, 1337); - BufferUtil.flipToFlush(buf, p); - - String r = TypeUtil.toHexString(BufferUtil.toArray(buf)); - - assertEquals("881f9a0a", r); - } - - @Test - public void testDecodeExampleD12() - { - ByteBuffer buf = ByteBuffer.wrap(TypeUtil.fromHexString("881f9a0aff")); - buf.position(2); - - assertEquals(1337, NBitInteger.decode(buf, 5)); - } - - @Test - public void testEncodeExampleD13() - { - ByteBuffer buf = BufferUtil.allocate(16); - int p = BufferUtil.flipToFill(buf); - buf.put((byte)0x88); - buf.put((byte)0xFF); - NBitInteger.encode(buf, 8, 42); - BufferUtil.flipToFlush(buf, p); - - String r = TypeUtil.toHexString(BufferUtil.toArray(buf)); - - assertEquals("88Ff2a", r); - } - - @Test - public void testDecodeExampleD13() - { - ByteBuffer buf = ByteBuffer.wrap(TypeUtil.fromHexString("882aFf")); - buf.position(1); - - assertEquals(42, NBitInteger.decode(buf, 8)); - } -} diff -Nru jetty9-9.4.51/jetty-http2/http2-http-client-transport/pom.xml jetty9-9.4.53/jetty-http2/http2-http-client-transport/pom.xml --- jetty9-9.4.51/jetty-http2/http2-http-client-transport/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-http-client-transport/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ org.eclipse.jetty.http2 http2-parent - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 diff -Nru jetty9-9.4.51/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2Test.java jetty9-9.4.53/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2Test.java --- jetty9-9.4.51/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2Test.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2Test.java 2023-10-09 12:27:40.000000000 +0000 @@ -36,7 +36,6 @@ import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; -import java.util.function.UnaryOperator; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -62,7 +61,6 @@ import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.http2.generator.Generator; import org.eclipse.jetty.http2.hpack.HpackException; -import org.eclipse.jetty.http2.parser.RateControl; import org.eclipse.jetty.http2.parser.ServerParser; import org.eclipse.jetty.http2.server.RawHTTP2ServerConnectionFactory; import org.eclipse.jetty.io.ByteBufferPool; @@ -456,7 +454,8 @@ OutputStream output = socket.getOutputStream(); InputStream input = socket.getInputStream(); - ServerParser parser = new ServerParser(byteBufferPool, new ServerParser.Listener.Adapter() + ServerParser parser = new ServerParser(byteBufferPool, 4096); + parser.init(new ServerParser.Listener.Adapter() { @Override public void onPreface() @@ -508,8 +507,7 @@ x.printStackTrace(); } } - }, 4096, 8192, RateControl.NO_RATE_CONTROL); - parser.init(UnaryOperator.identity()); + }); byte[] bytes = new byte[1024]; while (true) diff -Nru jetty9-9.4.51/jetty-http2/http2-server/pom.xml jetty9-9.4.53/jetty-http2/http2-server/pom.xml --- jetty9-9.4.51/jetty-http2/http2-server/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-server/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ org.eclipse.jetty.http2 http2-parent - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 diff -Nru jetty9-9.4.51/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java jetty9-9.4.53/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java --- jetty9-9.4.51/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java 2023-10-09 12:27:40.000000000 +0000 @@ -34,6 +34,7 @@ import org.eclipse.jetty.http2.frames.Frame; import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.http2.generator.Generator; +import org.eclipse.jetty.http2.hpack.HpackContext; import org.eclipse.jetty.http2.parser.RateControl; import org.eclipse.jetty.http2.parser.ServerParser; import org.eclipse.jetty.http2.parser.WindowRateControl; @@ -53,14 +54,15 @@ { private final HTTP2SessionContainer sessionContainer = new HTTP2SessionContainer(); private final HttpConfiguration httpConfiguration; - private int maxDynamicTableSize = 4096; + private int maxDecoderTableCapacity = HpackContext.DEFAULT_MAX_TABLE_CAPACITY; + private int maxEncoderTableCapacity = HpackContext.DEFAULT_MAX_TABLE_CAPACITY; private int initialSessionRecvWindow = 1024 * 1024; private int initialStreamRecvWindow = 512 * 1024; private int maxConcurrentStreams = 128; private int maxHeaderBlockFragment = 0; - private int maxFrameLength = Frame.DEFAULT_MAX_LENGTH; + private int maxFrameSize = Frame.DEFAULT_MAX_LENGTH; private int maxSettingsKeys = SettingsFrame.DEFAULT_MAX_KEYS; - private RateControl.Factory rateControlFactory = new WindowRateControl.Factory(50); + private RateControl.Factory rateControlFactory = new WindowRateControl.Factory(128); private FlowControlStrategy.Factory flowControlStrategyFactory = () -> new BufferingFlowControlStrategy(0.5F); private long streamIdleTimeout; @@ -83,15 +85,45 @@ setInputBufferSize(Frame.DEFAULT_MAX_LENGTH + Frame.HEADER_LENGTH); } + @Deprecated @ManagedAttribute("The HPACK dynamic table maximum size") public int getMaxDynamicTableSize() { - return maxDynamicTableSize; + return getMaxDecoderTableCapacity(); } + @Deprecated public void setMaxDynamicTableSize(int maxDynamicTableSize) { - this.maxDynamicTableSize = maxDynamicTableSize; + setMaxDecoderTableCapacity(maxDynamicTableSize); + } + + @ManagedAttribute("The HPACK encoder dynamic table maximum capacity") + public int getMaxEncoderTableCapacity() + { + return maxEncoderTableCapacity; + } + + /** + *

Sets the limit for the encoder HPACK dynamic table capacity.

+ *

Setting this value to {@code 0} disables the use of the dynamic table.

+ * + * @param maxEncoderTableCapacity The HPACK encoder dynamic table maximum capacity + */ + public void setMaxEncoderTableCapacity(int maxEncoderTableCapacity) + { + this.maxEncoderTableCapacity = maxEncoderTableCapacity; + } + + @ManagedAttribute("The HPACK decoder dynamic table maximum capacity") + public int getMaxDecoderTableCapacity() + { + return maxDecoderTableCapacity; + } + + public void setMaxDecoderTableCapacity(int maxDecoderTableCapacity) + { + this.maxDecoderTableCapacity = maxDecoderTableCapacity; } @ManagedAttribute("The initial size of session's flow control receive window") @@ -159,15 +191,28 @@ this.streamIdleTimeout = streamIdleTimeout; } + @Deprecated @ManagedAttribute("The max frame length in bytes") public int getMaxFrameLength() { - return maxFrameLength; + return getMaxFrameSize(); } + @Deprecated public void setMaxFrameLength(int maxFrameLength) { - this.maxFrameLength = maxFrameLength; + setMaxFrameSize(maxFrameLength); + } + + @ManagedAttribute("The max frame size in bytes") + public int getMaxFrameSize() + { + return maxFrameSize; + } + + public void setMaxFrameSize(int maxFrameSize) + { + this.maxFrameSize = maxFrameSize; } @ManagedAttribute("The max number of keys in all SETTINGS frames") @@ -267,37 +312,47 @@ { ServerSessionListener listener = newSessionListener(connector, endPoint); - Generator generator = new Generator(connector.getByteBufferPool(), getMaxDynamicTableSize(), getMaxHeaderBlockFragment()); + Generator generator = new Generator(connector.getByteBufferPool(), getMaxHeaderBlockFragment()); FlowControlStrategy flowControl = getFlowControlStrategyFactory().newFlowControlStrategy(); - HTTP2ServerSession session = new HTTP2ServerSession(connector.getScheduler(), endPoint, generator, listener, flowControl); + + ServerParser parser = newServerParser(connector, getRateControlFactory().newRateControl(endPoint)); + parser.setMaxFrameSize(getMaxFrameSize()); + parser.setMaxSettingsKeys(getMaxSettingsKeys()); + + HTTP2ServerSession session = new HTTP2ServerSession(connector.getScheduler(), endPoint, parser, generator, listener, flowControl); session.setMaxLocalStreams(getMaxConcurrentStreams()); session.setMaxRemoteStreams(getMaxConcurrentStreams()); + session.setMaxEncoderTableCapacity(getMaxEncoderTableCapacity()); // For a single stream in a connection, there will be a race between // the stream idle timeout and the connection idle timeout. However, // the typical case is that the connection will be busier and the // stream idle timeout will expire earlier than the connection's. long streamIdleTimeout = getStreamIdleTimeout(); - if (streamIdleTimeout <= 0) + if (streamIdleTimeout == 0) streamIdleTimeout = endPoint.getIdleTimeout(); session.setStreamIdleTimeout(streamIdleTimeout); session.setInitialSessionRecvWindow(getInitialSessionRecvWindow()); session.setWriteThreshold(getHttpConfiguration().getOutputBufferSize()); - ServerParser parser = newServerParser(connector, session, getRateControlFactory().newRateControl(endPoint)); - parser.setMaxFrameLength(getMaxFrameLength()); - parser.setMaxSettingsKeys(getMaxSettingsKeys()); - HTTP2Connection connection = new HTTP2ServerConnection(connector.getByteBufferPool(), connector.getExecutor(), - endPoint, httpConfiguration, parser, session, getInputBufferSize(), listener); + endPoint, httpConfiguration, session, getInputBufferSize(), listener); connection.addListener(sessionContainer); + parser.init(connection.wrapParserListener(session)); + return configure(connection, connector, endPoint); } protected abstract ServerSessionListener newSessionListener(Connector connector, EndPoint endPoint); + @Deprecated protected ServerParser newServerParser(Connector connector, ServerParser.Listener listener, RateControl rateControl) { - return new ServerParser(connector.getByteBufferPool(), listener, getMaxDynamicTableSize(), getHttpConfiguration().getRequestHeaderSize(), rateControl); + return newServerParser(connector, rateControl); + } + + protected ServerParser newServerParser(Connector connector, RateControl rateControl) + { + return new ServerParser(connector.getByteBufferPool(), getHttpConfiguration().getRequestHeaderSize(), rateControl); } @ManagedObject("The container of HTTP/2 sessions") diff -Nru jetty9-9.4.51/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnection.java jetty9-9.4.53/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnection.java --- jetty9-9.4.51/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnection.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnection.java 2023-10-09 12:27:40.000000000 +0000 @@ -89,9 +89,15 @@ private final HttpConfiguration httpConfig; private boolean recycleHttpChannels = true; + @Deprecated public HTTP2ServerConnection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endPoint, HttpConfiguration httpConfig, ServerParser parser, ISession session, int inputBufferSize, ServerSessionListener listener) { - super(byteBufferPool, executor, endPoint, parser, session, inputBufferSize); + this(byteBufferPool, executor, endPoint, httpConfig, session, inputBufferSize, listener); + } + + public HTTP2ServerConnection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endPoint, HttpConfiguration httpConfig, ISession session, int inputBufferSize, ServerSessionListener listener) + { + super(byteBufferPool, executor, endPoint, session, inputBufferSize); this.listener = listener; this.httpConfig = httpConfig; } diff -Nru jetty9-9.4.51/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java jetty9-9.4.53/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java --- jetty9-9.4.51/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerSession.java 2023-10-09 12:27:40.000000000 +0000 @@ -37,6 +37,7 @@ import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.http2.frames.WindowUpdateFrame; import org.eclipse.jetty.http2.generator.Generator; +import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.http2.parser.ServerParser; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.util.Callback; @@ -50,9 +51,16 @@ private final ServerSessionListener listener; + @Deprecated public HTTP2ServerSession(Scheduler scheduler, EndPoint endPoint, Generator generator, ServerSessionListener listener, FlowControlStrategy flowControl) { - super(scheduler, endPoint, generator, listener, flowControl, 2); + this(scheduler, endPoint, null, generator, listener, flowControl); + throw new UnsupportedOperationException(); + } + + public HTTP2ServerSession(Scheduler scheduler, EndPoint endPoint, Parser parser, Generator generator, ServerSessionListener listener, FlowControlStrategy flowControl) + { + super(scheduler, endPoint, parser, generator, listener, flowControl, 2); this.listener = listener; } diff -Nru jetty9-9.4.51/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/CloseTest.java jetty9-9.4.53/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/CloseTest.java --- jetty9-9.4.51/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/CloseTest.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/CloseTest.java 2023-10-09 12:27:40.000000000 +0000 @@ -26,7 +26,6 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; -import java.util.function.UnaryOperator; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpVersion; @@ -92,7 +91,8 @@ output.write(BufferUtil.toArray(buffer)); } - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 4096); + parser.init(new Parser.Listener.Adapter() { @Override public void onHeaders(HeadersFrame frame) @@ -109,8 +109,7 @@ throw new RuntimeIOException(x); } } - }, 4096, 8192); - parser.init(UnaryOperator.identity()); + }); parseResponse(client, parser); @@ -157,7 +156,8 @@ // Don't close the connection; the server should close. final CountDownLatch responseLatch = new CountDownLatch(1); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 4096); + parser.init(new Parser.Listener.Adapter() { @Override public void onHeaders(HeadersFrame frame) @@ -166,8 +166,7 @@ // HEADERS, the server is able to send us the response. responseLatch.countDown(); } - }, 4096, 8192); - parser.init(UnaryOperator.identity()); + }); parseResponse(client, parser); @@ -222,7 +221,8 @@ final CountDownLatch responseLatch = new CountDownLatch(1); final CountDownLatch closeLatch = new CountDownLatch(1); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 4096); + parser.init(new Parser.Listener.Adapter() { @Override public void onHeaders(HeadersFrame frame) @@ -235,8 +235,7 @@ { closeLatch.countDown(); } - }, 4096, 8192); - parser.init(UnaryOperator.identity()); + }); parseResponse(client, parser); diff -Nru jetty9-9.4.51/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2CServerTest.java jetty9-9.4.53/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2CServerTest.java --- jetty9-9.4.51/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2CServerTest.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2CServerTest.java 2023-10-09 12:27:40.000000000 +0000 @@ -30,7 +30,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; -import java.util.function.UnaryOperator; import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpFields; @@ -152,7 +151,8 @@ final AtomicReference headersRef = new AtomicReference<>(); final AtomicReference dataRef = new AtomicReference<>(); final AtomicReference latchRef = new AtomicReference<>(new CountDownLatch(2)); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 4096); + parser.init(new Parser.Listener.Adapter() { @Override public void onHeaders(HeadersFrame frame) @@ -167,8 +167,7 @@ dataRef.set(frame); latchRef.get().countDown(); } - }, 4096, 8192); - parser.init(UnaryOperator.identity()); + }); parseResponse(client, parser); @@ -246,7 +245,8 @@ final AtomicReference headersRef = new AtomicReference<>(); final AtomicReference dataRef = new AtomicReference<>(); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 4096); + parser.init(new Parser.Listener.Adapter() { @Override public void onSettings(SettingsFrame frame) @@ -267,8 +267,7 @@ dataRef.set(frame); latch.countDown(); } - }, 4096, 8192); - parser.init(UnaryOperator.identity()); + }); parseResponse(client, parser); diff -Nru jetty9-9.4.51/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java jetty9-9.4.53/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java --- jetty9-9.4.51/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java 2023-10-09 12:27:40.000000000 +0000 @@ -33,7 +33,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; -import java.util.function.UnaryOperator; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -95,15 +94,15 @@ } final CountDownLatch latch = new CountDownLatch(1); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 4096); + parser.init(new Parser.Listener.Adapter() { @Override public void onGoAway(GoAwayFrame frame) { latch.countDown(); } - }, 4096, 8192); - parser.init(UnaryOperator.identity()); + }); parseResponse(client, parser); @@ -139,7 +138,8 @@ } final AtomicReference frameRef = new AtomicReference<>(); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 4096); + parser.init(new Parser.Listener.Adapter() { @Override public void onSettings(SettingsFrame frame) @@ -153,8 +153,7 @@ frameRef.set(frame); latch.countDown(); } - }, 4096, 8192); - parser.init(UnaryOperator.identity()); + }); parseResponse(client, parser); @@ -198,7 +197,8 @@ final AtomicReference headersRef = new AtomicReference<>(); final AtomicReference dataRef = new AtomicReference<>(); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 4096); + parser.init(new Parser.Listener.Adapter() { @Override public void onSettings(SettingsFrame frame) @@ -219,8 +219,7 @@ dataRef.set(frame); latch.countDown(); } - }, 4096, 8192); - parser.init(UnaryOperator.identity()); + }); parseResponse(client, parser); @@ -258,7 +257,8 @@ output.write(BufferUtil.toArray(buffer)); } - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 4096); + parser.init(new Parser.Listener.Adapter() { @Override public void onGoAway(GoAwayFrame frame) @@ -266,8 +266,7 @@ assertEquals(ErrorCode.FRAME_SIZE_ERROR.code, frame.getError()); latch.countDown(); } - }, 4096, 8192); - parser.init(UnaryOperator.identity()); + }); parseResponse(client, parser); @@ -296,7 +295,8 @@ output.write(BufferUtil.toArray(buffer)); } - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 4096); + parser.init(new Parser.Listener.Adapter() { @Override public void onGoAway(GoAwayFrame frame) @@ -304,8 +304,7 @@ assertEquals(ErrorCode.PROTOCOL_ERROR.code, frame.getError()); latch.countDown(); } - }, 4096, 8192); - parser.init(UnaryOperator.identity()); + }); parseResponse(client, parser); @@ -373,8 +372,8 @@ // The server will close the connection abruptly since it // cannot write and therefore cannot even send the GO_AWAY. - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter(), 4096, 8192); - parser.init(UnaryOperator.identity()); + Parser parser = new Parser(byteBufferPool, 4096); + parser.init(new Parser.Listener.Adapter()); boolean closed = parseResponse(client, parser, 2 * delay); assertTrue(closed); } @@ -411,8 +410,8 @@ } output.flush(); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter(), 4096, 8192); - parser.init(UnaryOperator.identity()); + Parser parser = new Parser(byteBufferPool, 4096); + parser.init(new Parser.Listener.Adapter()); boolean closed = parseResponse(client, parser); assertTrue(closed); @@ -584,7 +583,8 @@ assertTrue(serverLatch.await(5, TimeUnit.SECONDS)); final CountDownLatch clientLatch = new CountDownLatch(1); - Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() + Parser parser = new Parser(byteBufferPool, 4096); + parser.init(new Parser.Listener.Adapter() { @Override public void onHeaders(HeadersFrame frame) @@ -592,8 +592,7 @@ if (frame.isEndStream()) clientLatch.countDown(); } - }, 4096, 8192); - parser.init(UnaryOperator.identity()); + }); boolean closed = parseResponse(client, parser); assertTrue(clientLatch.await(5, TimeUnit.SECONDS)); diff -Nru jetty9-9.4.51/jetty-http2/pom.xml jetty9-9.4.53/jetty-http2/pom.xml --- jetty9-9.4.51/jetty-http2/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http2/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ jetty-project org.eclipse.jetty - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 diff -Nru jetty9-9.4.51/jetty-http-spi/pom.xml jetty9-9.4.53/jetty-http-spi/pom.xml --- jetty9-9.4.51/jetty-http-spi/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-http-spi/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 jetty-http-spi diff -Nru jetty9-9.4.51/jetty-infinispan/infinispan-common/pom.xml jetty9-9.4.53/jetty-infinispan/infinispan-common/pom.xml --- jetty9-9.4.51/jetty-infinispan/infinispan-common/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-infinispan/infinispan-common/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty infinispan-parent - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 infinispan-common @@ -43,6 +43,10 @@ org.wildfly.common wildfly-common + + org.jboss.logging + jboss-logging +
@@ -51,6 +55,16 @@ ${infinispan.protostream.version} true provided + + + org.jboss.logging + jboss-logging + + + + + org.jboss.logging + jboss-logging org.eclipse.jetty @@ -67,12 +81,22 @@ org.apache.logging.log4j * + + org.jboss.logging + jboss-logging + org.infinispan infinispan-remote-query-client provided + + + org.jboss.logging + jboss-logging + + diff -Nru jetty9-9.4.51/jetty-infinispan/infinispan-embedded/pom.xml jetty9-9.4.53/jetty-infinispan/infinispan-embedded/pom.xml --- jetty9-9.4.51/jetty-infinispan/infinispan-embedded/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-infinispan/infinispan-embedded/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty infinispan-parent - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 infinispan-embedded @@ -78,15 +78,5 @@ infinispan-common ${project.version} - - org.infinispan - infinispan-core - - - org.wildfly.common - wildfly-common - - - diff -Nru jetty9-9.4.51/jetty-infinispan/infinispan-embedded-query/pom.xml jetty9-9.4.53/jetty-infinispan/infinispan-embedded-query/pom.xml --- jetty9-9.4.51/jetty-infinispan/infinispan-embedded-query/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-infinispan/infinispan-embedded-query/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty infinispan-parent - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 infinispan-embedded-query @@ -89,11 +89,16 @@ org.infinispan infinispan-query + + + org.jboss.logging + jboss-logging + + - org.eclipse.jetty.toolchain - jetty-test-helper - test + org.jboss.logging + jboss-logging diff -Nru jetty9-9.4.51/jetty-infinispan/infinispan-remote/pom.xml jetty9-9.4.53/jetty-infinispan/infinispan-remote/pom.xml --- jetty9-9.4.51/jetty-infinispan/infinispan-remote/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-infinispan/infinispan-remote/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty infinispan-parent - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 infinispan-remote @@ -88,6 +88,10 @@ org.apache.logging.log4j * + + org.jboss.logging + jboss-logging + @@ -100,6 +104,12 @@ protostream ${infinispan.protostream.version} provided + + + org.jboss.logging + jboss-logging + + diff -Nru jetty9-9.4.51/jetty-infinispan/infinispan-remote-query/pom.xml jetty9-9.4.53/jetty-infinispan/infinispan-remote-query/pom.xml --- jetty9-9.4.51/jetty-infinispan/infinispan-remote-query/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-infinispan/infinispan-remote-query/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty infinispan-parent - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 infinispan-remote-query @@ -99,6 +99,12 @@ org.infinispan infinispan-query + + + org.jboss.logging + jboss-logging + + org.infinispan @@ -109,11 +115,21 @@ org.apache.logging.log4j * + + org.jboss.logging + jboss-logging + org.infinispan infinispan-remote-query-client + + + org.jboss.logging + jboss-logging + + com.google.code.gson diff -Nru jetty9-9.4.51/jetty-infinispan/pom.xml jetty9-9.4.53/jetty-infinispan/pom.xml --- jetty9-9.4.51/jetty-infinispan/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-infinispan/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 diff -Nru jetty9-9.4.51/jetty-io/pom.xml jetty9-9.4.53/jetty-io/pom.xml --- jetty9-9.4.51/jetty-io/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-io/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ jetty-project org.eclipse.jetty - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 jetty-io diff -Nru jetty9-9.4.51/jetty-jaas/pom.xml jetty9-9.4.53/jetty-jaas/pom.xml --- jetty9-9.4.51/jetty-jaas/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-jaas/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 jetty-jaas @@ -12,7 +12,7 @@ ${project.groupId}.jaas 2.0.0.AM26 - 2.1.2 + 2.1.4 org.eclipse.jetty.jaas.* diff -Nru jetty9-9.4.51/jetty-jaspi/pom.xml jetty9-9.4.53/jetty-jaspi/pom.xml --- jetty9-9.4.51/jetty-jaspi/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-jaspi/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 diff -Nru jetty9-9.4.51/jetty-jmh/pom.xml jetty9-9.4.53/jetty-jmh/pom.xml --- jetty9-9.4.51/jetty-jmh/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-jmh/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 @@ -58,6 +58,24 @@
+ + + + org.apache.maven.plugins + maven-jar-plugin + + + + + + + Jetty Jmh Support Classes + + + + + + diff -Nru jetty9-9.4.51/jetty-jmx/pom.xml jetty9-9.4.53/jetty-jmx/pom.xml --- jetty9-9.4.51/jetty-jmx/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-jmx/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 jetty-jmx diff -Nru jetty9-9.4.51/jetty-jndi/pom.xml jetty9-9.4.53/jetty-jndi/pom.xml --- jetty9-9.4.51/jetty-jndi/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-jndi/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 jetty-jndi diff -Nru jetty9-9.4.51/jetty-jspc-maven-plugin/pom.xml jetty9-9.4.53/jetty-jspc-maven-plugin/pom.xml --- jetty9-9.4.51/jetty-jspc-maven-plugin/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-jspc-maven-plugin/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 jetty-jspc-maven-plugin diff -Nru jetty9-9.4.51/jetty-maven-plugin/pom.xml jetty9-9.4.53/jetty-maven-plugin/pom.xml --- jetty9-9.4.51/jetty-maven-plugin/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-maven-plugin/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 jetty-maven-plugin @@ -54,6 +54,11 @@ integration-test verify + + + org.eclipse.jetty:jetty-home:${project.version}:zip + + @@ -110,6 +115,10 @@ maven-core + org.codehaus.plexus + plexus-xml + + org.apache.maven.plugin-tools maven-plugin-tools-api diff -Nru jetty9-9.4.51/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/config/jetty.xml jetty9-9.4.53/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/config/jetty.xml --- jetty9-9.4.51/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/config/jetty.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/config/jetty.xml 2023-10-09 12:27:40.000000000 +0000 @@ -1,4 +1,5 @@ - + + diff -Nru jetty9-9.4.51/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/main/jettyconf/context.xml jetty9-9.4.53/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/main/jettyconf/context.xml --- jetty9-9.4.51/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/main/jettyconf/context.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/main/jettyconf/context.xml 2023-10-09 12:27:40.000000000 +0000 @@ -1,3 +1,6 @@ + + + org.eclipse.jetty.servlet.Default.useFileMappedBuffer diff -Nru jetty9-9.4.51/jetty-memcached/jetty-memcached-sessions/pom.xml jetty9-9.4.53/jetty-memcached/jetty-memcached-sessions/pom.xml --- jetty9-9.4.51/jetty-memcached/jetty-memcached-sessions/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-memcached/jetty-memcached-sessions/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ org.eclipse.jetty.memcached memcached-parent - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 diff -Nru jetty9-9.4.51/jetty-memcached/pom.xml jetty9-9.4.53/jetty-memcached/pom.xml --- jetty9-9.4.51/jetty-memcached/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-memcached/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ jetty-project org.eclipse.jetty - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 diff -Nru jetty9-9.4.51/jetty-nosql/pom.xml jetty9-9.4.53/jetty-nosql/pom.xml --- jetty9-9.4.51/jetty-nosql/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-nosql/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 jetty-nosql diff -Nru jetty9-9.4.51/jetty-openid/pom.xml jetty9-9.4.53/jetty-openid/pom.xml --- jetty9-9.4.51/jetty-openid/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-openid/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 diff -Nru jetty9-9.4.51/jetty-openid/src/main/java/org/eclipse/jetty/security/openid/OpenIdAuthenticator.java jetty9-9.4.53/jetty-openid/src/main/java/org/eclipse/jetty/security/openid/OpenIdAuthenticator.java --- jetty9-9.4.51/jetty-openid/src/main/java/org/eclipse/jetty/security/openid/OpenIdAuthenticator.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-openid/src/main/java/org/eclipse/jetty/security/openid/OpenIdAuthenticator.java 2023-10-09 12:27:40.000000000 +0000 @@ -345,10 +345,7 @@ { if (LOG.isDebugEnabled()) LOG.debug("auth revoked {}", authentication); - synchronized (session) - { - session.removeAttribute(SessionAuthentication.__J_AUTHENTICATED); - } + logout(request); } else { @@ -380,10 +377,11 @@ } } } + + if (LOG.isDebugEnabled()) + LOG.debug("auth {}", authentication); + return authentication; } - if (LOG.isDebugEnabled()) - LOG.debug("auth {}", authentication); - return authentication; } // If we can't send challenge. diff -Nru jetty9-9.4.51/jetty-openid/src/main/java/org/eclipse/jetty/security/openid/OpenIdCredentials.java jetty9-9.4.53/jetty-openid/src/main/java/org/eclipse/jetty/security/openid/OpenIdCredentials.java --- jetty9-9.4.51/jetty-openid/src/main/java/org/eclipse/jetty/security/openid/OpenIdCredentials.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-openid/src/main/java/org/eclipse/jetty/security/openid/OpenIdCredentials.java 2023-10-09 12:27:40.000000000 +0000 @@ -20,6 +20,7 @@ import java.io.Serializable; import java.net.URI; +import java.time.Instant; import java.util.Arrays; import java.util.List; import java.util.Map; @@ -142,12 +143,24 @@ throw new AuthenticationException("Authorized party claim value should be the client_id"); // Check that the ID token has not expired by checking the exp claim. - long expiry = (Long)claims.get("exp"); - long currentTimeSeconds = (long)(System.currentTimeMillis() / 1000F); - if (currentTimeSeconds > expiry) + if (isExpired()) throw new AuthenticationException("ID Token has expired"); } + public boolean isExpired() + { + return checkExpiry(claims); + } + + public static boolean checkExpiry(Map claims) + { + if (claims == null) + return true; + + // Check that the ID token has not expired by checking the exp claim. + return Instant.ofEpochSecond((Long)claims.get("exp")).isBefore(Instant.now()); + } + private void validateAudience(OpenIdConfiguration configuration) throws AuthenticationException { Object aud = claims.get("aud"); diff -Nru jetty9-9.4.51/jetty-openid/src/test/java/org/eclipse/jetty/security/openid/OpenIdAuthenticationTest.java jetty9-9.4.53/jetty-openid/src/test/java/org/eclipse/jetty/security/openid/OpenIdAuthenticationTest.java --- jetty9-9.4.51/jetty-openid/src/test/java/org/eclipse/jetty/security/openid/OpenIdAuthenticationTest.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-openid/src/test/java/org/eclipse/jetty/security/openid/OpenIdAuthenticationTest.java 2023-10-09 12:27:40.000000000 +0000 @@ -18,28 +18,41 @@ package org.eclipse.jetty.security.openid; +import java.io.File; import java.io.IOException; import java.security.Principal; import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Consumer; +import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.api.ContentResponse; +import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpStatus; -import org.eclipse.jetty.security.Authenticator; +import org.eclipse.jetty.security.AbstractLoginService; import org.eclipse.jetty.security.ConstraintMapping; import org.eclipse.jetty.security.ConstraintSecurityHandler; +import org.eclipse.jetty.security.LoginService; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.UserIdentity; +import org.eclipse.jetty.server.session.FileSessionDataStoreFactory; import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.toolchain.test.MavenTestingUtils; +import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.security.Constraint; +import org.eclipse.jetty.util.security.Password; import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; import static org.hamcrest.Matchers.is; public class OpenIdAuthenticationTest @@ -52,8 +65,12 @@ private ServerConnector connector; private HttpClient client; - @BeforeEach - public void setup() throws Exception + public void setup(LoginService loginService) throws Exception + { + setup(loginService, null); + } + + public void setup(LoginService loginService, Consumer configure) throws Exception { openIdProvider = new OpenIdProvider(CLIENT_ID, CLIENT_SECRET); openIdProvider.start(); @@ -93,22 +110,29 @@ // security handler ConstraintSecurityHandler securityHandler = new ConstraintSecurityHandler(); - securityHandler.setRealmName("OpenID Connect Authentication"); + assertThat(securityHandler.getKnownAuthenticatorFactories().size(), greaterThanOrEqualTo(2)); + + securityHandler.setAuthMethod(Constraint.__OPENID_AUTH); + securityHandler.setRealmName(openIdProvider.getProvider()); securityHandler.addConstraintMapping(profileMapping); securityHandler.addConstraintMapping(loginMapping); securityHandler.addConstraintMapping(adminMapping); // Authentication using local OIDC Provider - OpenIdConfiguration configuration = new OpenIdConfiguration(openIdProvider.getProvider(), CLIENT_ID, CLIENT_SECRET); - - // Configure OpenIdLoginService optionally providing a base LoginService to provide user roles - OpenIdLoginService loginService = new OpenIdLoginService(configuration); - securityHandler.setLoginService(loginService); - - Authenticator authenticator = new OpenIdAuthenticator(configuration, "/error"); - securityHandler.setAuthenticator(authenticator); + OpenIdConfiguration openIdConfiguration = new OpenIdConfiguration(openIdProvider.getProvider(), CLIENT_ID, CLIENT_SECRET); + if (configure != null) + configure.accept(openIdConfiguration); + securityHandler.setLoginService(new OpenIdLoginService(openIdConfiguration, loginService)); + server.addBean(openIdConfiguration); + securityHandler.setInitParameter(OpenIdAuthenticator.ERROR_PAGE, "/error"); context.setSecurityHandler(securityHandler); + File datastoreDir = MavenTestingUtils.getTargetTestingDir("datastore"); + IO.delete(datastoreDir); + FileSessionDataStoreFactory fileSessionDataStoreFactory = new FileSessionDataStoreFactory(); + fileSessionDataStoreFactory.setStoreDir(datastoreDir); + server.addBean(fileSessionDataStoreFactory); + server.start(); String redirectUri = "http://localhost:" + connector.getLocalPort() + "/j_security_check"; openIdProvider.addRedirectUri(redirectUri); @@ -127,41 +151,127 @@ @Test public void testLoginLogout() throws Exception { + setup(null); + openIdProvider.setUser(new OpenIdProvider.User("123456789", "Alice")); + String appUriString = "http://localhost:" + connector.getLocalPort(); // Initially not authenticated ContentResponse response = client.GET(appUriString + "/"); assertThat(response.getStatus(), is(HttpStatus.OK_200)); - String[] content = response.getContentAsString().split("[\r\n]+"); - assertThat(content.length, is(1)); - assertThat(content[0], is("not authenticated")); + String content = response.getContentAsString(); + assertThat(content, containsString("not authenticated")); // Request to login is success response = client.GET(appUriString + "/login"); assertThat(response.getStatus(), is(HttpStatus.OK_200)); - content = response.getContentAsString().split("[\r\n]+"); - assertThat(content.length, is(1)); - assertThat(content[0], is("success")); + content = response.getContentAsString(); + assertThat(content, containsString("success")); // Now authenticated we can get info response = client.GET(appUriString + "/"); assertThat(response.getStatus(), is(HttpStatus.OK_200)); - content = response.getContentAsString().split("[\r\n]+"); - assertThat(content.length, is(3)); - assertThat(content[0], is("userId: 123456789")); - assertThat(content[1], is("name: Alice")); - assertThat(content[2], is("email: Alice@example.com")); + content = response.getContentAsString(); + assertThat(content, containsString("userId: 123456789")); + assertThat(content, containsString("name: Alice")); + assertThat(content, containsString("email: Alice@example.com")); // Request to admin page gives 403 as we do not have admin role response = client.GET(appUriString + "/admin"); assertThat(response.getStatus(), is(HttpStatus.FORBIDDEN_403)); + // We can restart the server and still be logged in as we have persistent session datastore. + server.stop(); + server.start(); + appUriString = "http://localhost:" + connector.getLocalPort(); + + // After restarting server the authentication is saved as a session authentication. + response = client.GET(appUriString + "/"); + assertThat(response.getStatus(), is(HttpStatus.OK_200)); + content = response.getContentAsString(); + assertThat(content, containsString("userId: 123456789")); + assertThat(content, containsString("name: Alice")); + assertThat(content, containsString("email: Alice@example.com")); + // We are no longer authenticated after logging out response = client.GET(appUriString + "/logout"); assertThat(response.getStatus(), is(HttpStatus.OK_200)); - content = response.getContentAsString().split("[\r\n]+"); - assertThat(content.length, is(1)); - assertThat(content[0], is("not authenticated")); + content = response.getContentAsString(); + assertThat(content, containsString("not authenticated")); + + // Test that the user was logged out successfully on the openid provider. + assertThat(openIdProvider.getLoggedInUsers().getMax(), equalTo(1L)); + assertThat(openIdProvider.getLoggedInUsers().getTotal(), equalTo(1L)); + } + + @Test + public void testNestedLoginService() throws Exception + { + AtomicBoolean loggedIn = new AtomicBoolean(true); + setup(new AbstractLoginService() + { + @Override + protected String[] loadRoleInfo(UserPrincipal user) + { + return new String[]{"admin"}; + } + + @Override + protected UserPrincipal loadUserInfo(String username) + { + return new UserPrincipal(username, new Password("")); + } + + @Override + public boolean validate(UserIdentity user) + { + if (!loggedIn.get()) + return false; + return super.validate(user); + } + }); + + openIdProvider.setUser(new OpenIdProvider.User("123456789", "Alice")); + + String appUriString = "http://localhost:" + connector.getLocalPort(); + + // Initially not authenticated + ContentResponse response = client.GET(appUriString + "/"); + assertThat(response.getStatus(), is(HttpStatus.OK_200)); + String content = response.getContentAsString(); + assertThat(content, containsString("not authenticated")); + + // Request to login is success + response = client.GET(appUriString + "/login"); + assertThat(response.getStatus(), is(HttpStatus.OK_200)); + content = response.getContentAsString(); + assertThat(content, containsString("success")); + + // Now authenticated we can get info + response = client.GET(appUriString + "/"); + assertThat(response.getStatus(), is(HttpStatus.OK_200)); + content = response.getContentAsString(); + assertThat(content, containsString("userId: 123456789")); + assertThat(content, containsString("name: Alice")); + assertThat(content, containsString("email: Alice@example.com")); + + // The nested login service has supplied the admin role. + response = client.GET(appUriString + "/admin"); + assertThat(response.getStatus(), is(HttpStatus.OK_200)); + + // This causes any validation of UserIdentity in the LoginService to fail + // causing subsequent requests to be redirected to the auth endpoint for login again. + loggedIn.set(false); + client.setFollowRedirects(false); + response = client.GET(appUriString + "/admin"); + assertThat(response.getStatus(), is(HttpStatus.SEE_OTHER_303)); + String location = response.getHeaders().get(HttpHeader.LOCATION); + assertThat(location, containsString(openIdProvider.getProvider() + "/auth")); + + // Note that we couldn't follow "OpenID Connect RP-Initiated Logout 1.0" because we redirect straight to auth endpoint. + assertThat(openIdProvider.getLoggedInUsers().getCurrent(), equalTo(1L)); + assertThat(openIdProvider.getLoggedInUsers().getMax(), equalTo(1L)); + assertThat(openIdProvider.getLoggedInUsers().getTotal(), equalTo(1L)); } public static class LoginPage extends HttpServlet @@ -169,16 +279,18 @@ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { + response.setContentType("text/html"); response.getWriter().println("success"); + response.getWriter().println("
Home"); } } public static class LogoutPage extends HttpServlet { @Override - protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { - request.getSession().invalidate(); + request.logout(); response.sendRedirect("/"); } } @@ -188,7 +300,7 @@ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { - Map userInfo = (Map)request.getSession().getAttribute(OpenIdAuthenticator.CLAIMS); + Map userInfo = (Map)request.getSession().getAttribute(OpenIdAuthenticator.CLAIMS); response.getWriter().println(userInfo.get("sub") + ": success"); } } @@ -198,18 +310,20 @@ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { - response.setContentType("text/plain"); + response.setContentType("text/html"); Principal userPrincipal = request.getUserPrincipal(); if (userPrincipal != null) { - Map userInfo = (Map)request.getSession().getAttribute(OpenIdAuthenticator.CLAIMS); - response.getWriter().println("userId: " + userInfo.get("sub")); - response.getWriter().println("name: " + userInfo.get("name")); - response.getWriter().println("email: " + userInfo.get("email")); + Map userInfo = (Map)request.getSession().getAttribute(OpenIdAuthenticator.CLAIMS); + response.getWriter().println("userId: " + userInfo.get("sub") + "
"); + response.getWriter().println("name: " + userInfo.get("name") + "
"); + response.getWriter().println("email: " + userInfo.get("email") + "
"); + response.getWriter().println("
Logout"); } else { response.getWriter().println("not authenticated"); + response.getWriter().println("
Login"); } } } @@ -219,8 +333,9 @@ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { - response.setContentType("text/plain"); + response.setContentType("text/html"); response.getWriter().println("not authorized"); + response.getWriter().println("
Home"); } } } diff -Nru jetty9-9.4.51/jetty-openid/src/test/java/org/eclipse/jetty/security/openid/OpenIdProvider.java jetty9-9.4.53/jetty-openid/src/test/java/org/eclipse/jetty/security/openid/OpenIdProvider.java --- jetty9-9.4.51/jetty-openid/src/test/java/org/eclipse/jetty/security/openid/OpenIdProvider.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-openid/src/test/java/org/eclipse/jetty/security/openid/OpenIdProvider.java 2023-10-09 12:27:40.000000000 +0000 @@ -19,14 +19,16 @@ package org.eclipse.jetty.security.openid; import java.io.IOException; +import java.io.PrintWriter; import java.time.Duration; +import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Random; +import java.util.Objects; import java.util.UUID; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -40,23 +42,52 @@ import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; -import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.component.ContainerLifeCycle; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.util.statistic.CounterStatistic; public class OpenIdProvider extends ContainerLifeCycle { + private static final Logger LOG = Log.getLogger(OpenIdProvider.class); + private static final String CONFIG_PATH = "/.well-known/openid-configuration"; private static final String AUTH_PATH = "/auth"; private static final String TOKEN_PATH = "/token"; + private static final String END_SESSION_PATH = "/end_session"; private final Map issuedAuthCodes = new HashMap<>(); protected final String clientId; protected final String clientSecret; protected final List redirectUris = new ArrayList<>(); - + private final ServerConnector connector; + private final Server server; + private int port = 0; private String provider; - private Server server; - private ServerConnector connector; + private User preAuthedUser; + private final CounterStatistic loggedInUsers = new CounterStatistic(); + private long _idTokenDuration = Duration.ofSeconds(10).toMillis(); + + public static void main(String[] args) throws Exception + { + String clientId = "CLIENT_ID123"; + String clientSecret = "PASSWORD123"; + int port = 5771; + String redirectUri = "http://localhost:8080/j_security_check"; + + OpenIdProvider openIdProvider = new OpenIdProvider(clientId, clientSecret); + openIdProvider.addRedirectUri(redirectUri); + openIdProvider.setPort(port); + openIdProvider.start(); + try + { + openIdProvider.join(); + } + finally + { + openIdProvider.stop(); + } + } public OpenIdProvider(String clientId, String clientSecret) { @@ -69,25 +100,67 @@ ServletContextHandler contextHandler = new ServletContextHandler(); contextHandler.setContextPath("/"); - contextHandler.addServlet(new ServletHolder(new OpenIdConfigServlet()), CONFIG_PATH); - contextHandler.addServlet(new ServletHolder(new OpenIdAuthEndpoint()), AUTH_PATH); - contextHandler.addServlet(new ServletHolder(new OpenIdTokenEndpoint()), TOKEN_PATH); + contextHandler.addServlet(new ServletHolder(new ConfigServlet()), CONFIG_PATH); + contextHandler.addServlet(new ServletHolder(new AuthEndpoint()), AUTH_PATH); + contextHandler.addServlet(new ServletHolder(new TokenEndpoint()), TOKEN_PATH); + contextHandler.addServlet(new ServletHolder(new EndSessionEndpoint()), END_SESSION_PATH); server.setHandler(contextHandler); addBean(server); } + public void setIdTokenDuration(long duration) + { + _idTokenDuration = duration; + } + + public long getIdTokenDuration() + { + return _idTokenDuration; + } + + public void join() throws InterruptedException + { + server.join(); + } + + public OpenIdConfiguration getOpenIdConfiguration() + { + String provider = getProvider(); + String authEndpoint = provider + AUTH_PATH; + String tokenEndpoint = provider + TOKEN_PATH; + return new OpenIdConfiguration(provider, authEndpoint, tokenEndpoint, clientId, clientSecret, null); + } + + public CounterStatistic getLoggedInUsers() + { + return loggedInUsers; + } + @Override protected void doStart() throws Exception { + connector.setPort(port); super.doStart(); provider = "http://localhost:" + connector.getLocalPort(); } - public String getProvider() + public void setPort(int port) { - if (!isStarted()) + if (isStarted()) throw new IllegalStateException(); + this.port = port; + } + + public void setUser(User user) + { + this.preAuthedUser = user; + } + + public String getProvider() + { + if (!isStarted() && port == 0) + throw new IllegalStateException("Port of OpenIdProvider not configured"); return provider; } @@ -96,10 +169,10 @@ redirectUris.add(uri); } - public class OpenIdAuthEndpoint extends HttpServlet + public class AuthEndpoint extends HttpServlet { @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { if (!clientId.equals(req.getParameter("client_id"))) { @@ -110,12 +183,13 @@ String redirectUri = req.getParameter("redirect_uri"); if (!redirectUris.contains(redirectUri)) { + LOG.warn("invalid redirectUri {}", redirectUri); resp.sendError(HttpServletResponse.SC_FORBIDDEN, "invalid redirect_uri"); return; } String scopeString = req.getParameter("scope"); - List scopes = (scopeString == null) ? Collections.emptyList() : Arrays.asList(StringUtil.csvSplit(scopeString)); + List scopes = (scopeString == null) ? Collections.emptyList() : Arrays.asList(scopeString.split(" ")); if (!scopes.contains("openid")) { resp.sendError(HttpServletResponse.SC_FORBIDDEN, "no openid scope"); @@ -135,20 +209,75 @@ return; } + if (preAuthedUser == null) + { + PrintWriter writer = resp.getWriter(); + resp.setContentType("text/html"); + writer.println("

Login to OpenID Connect Provider

"); + writer.println("
"); + writer.println(""); + writer.println(""); + writer.println(""); + writer.println(""); + writer.println("
"); + } + else + { + redirectUser(req, preAuthedUser, redirectUri, state); + } + } + + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException + { + String redirectUri = req.getParameter("redirectUri"); + if (!redirectUris.contains(redirectUri)) + { + resp.sendError(HttpServletResponse.SC_FORBIDDEN, "invalid redirect_uri"); + return; + } + + String state = req.getParameter("state"); + if (state == null) + { + resp.sendError(HttpServletResponse.SC_FORBIDDEN, "no state param"); + return; + } + + String username = req.getParameter("username"); + if (username == null) + { + resp.sendError(HttpServletResponse.SC_FORBIDDEN, "no username"); + return; + } + + User user = new User(username); + redirectUser(req, user, redirectUri, state); + } + + public void redirectUser(HttpServletRequest request, User user, String redirectUri, String state) throws IOException + { String authCode = UUID.randomUUID().toString().replace("-", ""); - User user = new User(123456789, "Alice"); issuedAuthCodes.put(authCode, user); - final Request baseRequest = Request.getBaseRequest(req); - final Response baseResponse = baseRequest.getResponse(); - redirectUri += "?code=" + authCode + "&state=" + state; - int redirectCode = (baseRequest.getHttpVersion().getVersion() < HttpVersion.HTTP_1_1.getVersion() - ? HttpServletResponse.SC_MOVED_TEMPORARILY : HttpServletResponse.SC_SEE_OTHER); - baseResponse.sendRedirect(redirectCode, resp.encodeRedirectURL(redirectUri)); + try + { + final Request baseRequest = Objects.requireNonNull(Request.getBaseRequest(request)); + final Response baseResponse = baseRequest.getResponse(); + redirectUri += "?code=" + authCode + "&state=" + state; + int redirectCode = (baseRequest.getHttpVersion().getVersion() < HttpVersion.HTTP_1_1.getVersion() + ? HttpServletResponse.SC_MOVED_TEMPORARILY : HttpServletResponse.SC_SEE_OTHER); + baseResponse.sendRedirect(redirectCode, baseResponse.encodeRedirectURL(redirectUri)); + } + catch (Throwable t) + { + issuedAuthCodes.remove(authCode); + throw t; + } } } - public class OpenIdTokenEndpoint extends HttpServlet + private class TokenEndpoint extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException @@ -173,45 +302,79 @@ } String accessToken = "ABCDEFG"; - long expiry = System.currentTimeMillis() + Duration.ofMinutes(10).toMillis(); + long accessTokenDuration = Duration.ofMinutes(10).getSeconds(); String response = "{" + "\"access_token\": \"" + accessToken + "\"," + - "\"id_token\": \"" + JwtEncoder.encode(user.getIdToken()) + "\"," + - "\"expires_in\": " + expiry + "," + + "\"id_token\": \"" + JwtEncoder.encode(user.getIdToken(provider, clientId, _idTokenDuration)) + "\"," + + "\"expires_in\": " + accessTokenDuration + "," + "\"token_type\": \"Bearer\"" + "}"; + loggedInUsers.increment(); resp.setContentType("text/plain"); resp.getWriter().print(response); } } - public class OpenIdConfigServlet extends HttpServlet + private class EndSessionEndpoint extends HttpServlet { @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException + { + doPost(req, resp); + } + + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException + { + String idToken = req.getParameter("id_token_hint"); + if (idToken == null) + { + resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "no id_token_hint"); + return; + } + + String logoutRedirect = req.getParameter("post_logout_redirect_uri"); + if (logoutRedirect == null) + { + resp.setStatus(HttpServletResponse.SC_OK); + resp.getWriter().println("logout success on end_session_endpoint"); + return; + } + + loggedInUsers.decrement(); + resp.setContentType("text/plain"); + resp.sendRedirect(logoutRedirect); + } + } + + private class ConfigServlet extends HttpServlet + { + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { String discoveryDocument = "{" + "\"issuer\": \"" + provider + "\"," + "\"authorization_endpoint\": \"" + provider + AUTH_PATH + "\"," + "\"token_endpoint\": \"" + provider + TOKEN_PATH + "\"," + + "\"end_session_endpoint\": \"" + provider + END_SESSION_PATH + "\"," + "}"; resp.getWriter().write(discoveryDocument); } } - public class User + public static class User { - private long subject; - private String name; + private final String subject; + private final String name; public User(String name) { - this(new Random().nextLong(), name); + this(UUID.nameUUIDFromBytes(name.getBytes()).toString(), name); } - public User(long subject, String name) + public User(String subject, String name) { this.subject = subject; this.name = name; @@ -222,10 +385,29 @@ return name; } - public String getIdToken() + public String getSubject() + { + return subject; + } + + public String getIdToken(String provider, String clientId, long duration) + { + long expiryTime = Instant.now().plusMillis(duration).getEpochSecond(); + return JwtEncoder.createIdToken(provider, clientId, subject, name, expiryTime); + } + + @Override + public boolean equals(Object obj) + { + if (!(obj instanceof User)) + return false; + return Objects.equals(subject, ((User)obj).subject) && Objects.equals(name, ((User)obj).name); + } + + @Override + public int hashCode() { - long expiry = System.currentTimeMillis() + Duration.ofMinutes(1).toMillis(); - return JwtEncoder.createIdToken(provider, clientId, Long.toString(subject), name, expiry); + return Objects.hash(subject, name); } } } diff -Nru jetty9-9.4.51/jetty-osgi/jetty-osgi-alpn/pom.xml jetty9-9.4.53/jetty-osgi/jetty-osgi-alpn/pom.xml --- jetty9-9.4.51/jetty-osgi/jetty-osgi-alpn/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-osgi/jetty-osgi-alpn/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 jetty-osgi-alpn diff -Nru jetty9-9.4.51/jetty-osgi/jetty-osgi-boot/pom.xml jetty9-9.4.53/jetty-osgi/jetty-osgi-boot/pom.xml --- jetty9-9.4.51/jetty-osgi/jetty-osgi-boot/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-osgi/jetty-osgi-boot/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 jetty-osgi-boot diff -Nru jetty9-9.4.51/jetty-osgi/jetty-osgi-boot-jsp/pom.xml jetty9-9.4.53/jetty-osgi/jetty-osgi-boot-jsp/pom.xml --- jetty9-9.4.51/jetty-osgi/jetty-osgi-boot-jsp/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-osgi/jetty-osgi-boot-jsp/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 jetty-osgi-boot-jsp diff -Nru jetty9-9.4.51/jetty-osgi/jetty-osgi-boot-warurl/pom.xml jetty9-9.4.53/jetty-osgi/jetty-osgi-boot-warurl/pom.xml --- jetty9-9.4.51/jetty-osgi/jetty-osgi-boot-warurl/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-osgi/jetty-osgi-boot-warurl/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 9.4.51.v20230217 + 9.4.53.v20231009 ../pom.xml 4.0.0 diff -Nru jetty9-9.4.51/jetty-osgi/jetty-osgi-httpservice/pom.xml jetty9-9.4.53/jetty-osgi/jetty-osgi-httpservice/pom.xml --- jetty9-9.4.51/jetty-osgi/jetty-osgi-httpservice/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-osgi/jetty-osgi-httpservice/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 jetty-httpservice diff -Nru jetty9-9.4.51/jetty-osgi/pom.xml jetty9-9.4.53/jetty-osgi/pom.xml --- jetty9-9.4.51/jetty-osgi/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-osgi/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 @@ -12,14 +12,14 @@ pom - 3.18.200 + 3.18.500 3.11.100 1.6.1 1.5.0 1.4.1 - 3.7.100 + 3.7.200 1.2.0 - 1.2.0 + 1.3.0 1.0.2 1.0.1 1.5.4 @@ -226,6 +226,11 @@ org.osgi.util.tracker ${osgi-util-tracker-version} + + org.osgi + org.osgi.util.promise + ${osgi-util-promise-version} +
diff -Nru jetty9-9.4.51/jetty-osgi/test-jetty-osgi/pom.xml jetty9-9.4.53/jetty-osgi/test-jetty-osgi/pom.xml --- jetty9-9.4.51/jetty-osgi/test-jetty-osgi/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-osgi/test-jetty-osgi/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 9.4.51.v20230217 + 9.4.53.v20231009 ../pom.xml 4.0.0 @@ -13,8 +13,8 @@ ${project.groupId}.boot.test.osgi https://download.eclipse.org/jetty/orbit/ target/distribution - 4.13.1 - 2.6.2 + 4.13.5 + 2.6.14 5.3.0 1.8.3 3.0.0 @@ -453,7 +453,7 @@ org.slf4j - slf4j-log4j12 + slf4j-reload4j ${slf4j.version} test diff -Nru jetty9-9.4.51/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestOSGiUtil.java jetty9-9.4.53/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestOSGiUtil.java --- jetty9-9.4.51/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestOSGiUtil.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestOSGiUtil.java 2023-10-09 12:27:40.000000000 +0000 @@ -127,14 +127,20 @@ res.add(mavenBundle().groupId("org.osgi").artifactId("org.osgi.service.component").versionAsInProject()); res.add(mavenBundle().groupId("org.osgi").artifactId("org.osgi.service.event").versionAsInProject()); res.add(mavenBundle().groupId("org.osgi").artifactId("org.osgi.util.function").versionAsInProject()); - res.add(mavenBundle().groupId("org.osgi").artifactId("org.osgi.util.function").versionAsInProject()); res.add(mavenBundle().groupId("org.osgi").artifactId("org.osgi.util.promise").versionAsInProject()); res.add(mavenBundle().groupId("org.osgi").artifactId("org.osgi.util.measurement").versionAsInProject()); res.add(mavenBundle().groupId("org.osgi").artifactId("org.osgi.util.position").versionAsInProject()); res.add(mavenBundle().groupId("org.osgi").artifactId("org.osgi.util.tracker").versionAsInProject()); res.add(mavenBundle().groupId("org.osgi").artifactId("org.osgi.util.xml").versionAsInProject()); + res.add(mavenBundle().groupId("org.osgi").artifactId("org.osgi.service.device").versionAsInProject()); + res.add(mavenBundle().groupId("org.osgi").artifactId("org.osgi.service.metatype").versionAsInProject()); + res.add(mavenBundle().groupId("org.osgi").artifactId("org.osgi.service.provisioning").versionAsInProject()); + res.add(mavenBundle().groupId("org.osgi").artifactId("org.osgi.service.upnp").versionAsInProject()); + res.add(mavenBundle().groupId("org.osgi").artifactId("org.osgi.service.useradmin").versionAsInProject()); + res.add(mavenBundle().groupId("org.osgi").artifactId("org.osgi.service.wireadmin").versionAsInProject()); res.add(mavenBundle().groupId("org.eclipse.platform").artifactId("org.eclipse.osgi.util").versionAsInProject()); res.add(mavenBundle().groupId("org.eclipse.platform").artifactId("org.eclipse.osgi.services").versionAsInProject()); + res.add(mavenBundle().groupId("org.ow2.asm").artifactId("asm").versionAsInProject().start()); res.add(mavenBundle().groupId("org.ow2.asm").artifactId("asm-commons").versionAsInProject().start()); res.add(mavenBundle().groupId("org.ow2.asm").artifactId("asm-tree").versionAsInProject().start()); diff -Nru jetty9-9.4.51/jetty-osgi/test-jetty-osgi-context/pom.xml jetty9-9.4.53/jetty-osgi/test-jetty-osgi-context/pom.xml --- jetty9-9.4.51/jetty-osgi/test-jetty-osgi-context/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-osgi/test-jetty-osgi-context/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 test-jetty-osgi-context diff -Nru jetty9-9.4.51/jetty-osgi/test-jetty-osgi-fragment/pom.xml jetty9-9.4.53/jetty-osgi/test-jetty-osgi-fragment/pom.xml --- jetty9-9.4.51/jetty-osgi/test-jetty-osgi-fragment/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-osgi/test-jetty-osgi-fragment/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 9.4.51.v20230217 + 9.4.53.v20231009 ../pom.xml 4.0.0 diff -Nru jetty9-9.4.51/jetty-osgi/test-jetty-osgi-server/pom.xml jetty9-9.4.53/jetty-osgi/test-jetty-osgi-server/pom.xml --- jetty9-9.4.51/jetty-osgi/test-jetty-osgi-server/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-osgi/test-jetty-osgi-server/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 test-jetty-osgi-server diff -Nru jetty9-9.4.51/jetty-osgi/test-jetty-osgi-webapp/pom.xml jetty9-9.4.53/jetty-osgi/test-jetty-osgi-webapp/pom.xml --- jetty9-9.4.51/jetty-osgi/test-jetty-osgi-webapp/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-osgi/test-jetty-osgi-webapp/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 9.4.51.v20230217 + 9.4.53.v20231009 ../pom.xml 4.0.0 diff -Nru jetty9-9.4.51/jetty-osgi/test-jetty-osgi-webapp-resources/pom.xml jetty9-9.4.53/jetty-osgi/test-jetty-osgi-webapp-resources/pom.xml --- jetty9-9.4.51/jetty-osgi/test-jetty-osgi-webapp-resources/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-osgi/test-jetty-osgi-webapp-resources/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 test-jetty-osgi-webapp-resources diff -Nru jetty9-9.4.51/jetty-plus/pom.xml jetty9-9.4.53/jetty-plus/pom.xml --- jetty9-9.4.51/jetty-plus/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-plus/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 jetty-plus diff -Nru jetty9-9.4.51/jetty-proxy/pom.xml jetty9-9.4.53/jetty-proxy/pom.xml --- jetty9-9.4.51/jetty-proxy/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-proxy/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 jetty-proxy diff -Nru jetty9-9.4.51/jetty-quickstart/pom.xml jetty9-9.4.53/jetty-quickstart/pom.xml --- jetty9-9.4.51/jetty-quickstart/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-quickstart/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 org.eclipse.jetty diff -Nru jetty9-9.4.51/jetty-rewrite/pom.xml jetty9-9.4.53/jetty-rewrite/pom.xml --- jetty9-9.4.51/jetty-rewrite/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-rewrite/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 jetty-rewrite diff -Nru jetty9-9.4.51/jetty-runner/pom.xml jetty9-9.4.53/jetty-runner/pom.xml --- jetty9-9.4.51/jetty-runner/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-runner/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 jetty-runner @@ -70,8 +70,6 @@ true - - ${project.build.directory}/NON_USED_MANIFEST diff -Nru jetty9-9.4.51/jetty-security/pom.xml jetty9-9.4.53/jetty-security/pom.xml --- jetty9-9.4.51/jetty-security/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-security/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 jetty-security diff -Nru jetty9-9.4.51/jetty-server/pom.xml jetty9-9.4.53/jetty-server/pom.xml --- jetty9-9.4.51/jetty-server/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-server/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 jetty-server diff -Nru jetty9-9.4.51/jetty-server/src/main/java/org/eclipse/jetty/server/handler/SizeLimitHandler.java jetty9-9.4.53/jetty-server/src/main/java/org/eclipse/jetty/server/handler/SizeLimitHandler.java --- jetty9-9.4.51/jetty-server/src/main/java/org/eclipse/jetty/server/handler/SizeLimitHandler.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-server/src/main/java/org/eclipse/jetty/server/handler/SizeLimitHandler.java 2023-10-09 12:27:40.000000000 +0000 @@ -31,8 +31,6 @@ import org.eclipse.jetty.server.HttpOutput; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; /** *

A handler that can limit the size of message bodies in requests and responses.

@@ -46,8 +44,6 @@ */ public class SizeLimitHandler extends HandlerWrapper { - private static final Logger LOG = Log.getLogger(SizeLimitHandler.class); - private final long _requestLimit; private final long _responseLimit; @@ -90,7 +86,7 @@ baseRequest.getHttpInput().addInterceptor(limit); } - if (_responseLimit > 0) + if (_responseLimit >= 0) { httpOutput.setInterceptor(limit); response = new LimitResponse(response); @@ -132,7 +128,7 @@ if (content.hasContent()) { _read += content.remaining(); - checkResponseLimit(_read); + checkRequestLimit(_read); } return content; } diff -Nru jetty9-9.4.51/jetty-server/src/test/java/org/eclipse/jetty/server/handler/SizeLimitHandlerTest.java jetty9-9.4.53/jetty-server/src/test/java/org/eclipse/jetty/server/handler/SizeLimitHandlerTest.java --- jetty9-9.4.51/jetty-server/src/test/java/org/eclipse/jetty/server/handler/SizeLimitHandlerTest.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-server/src/test/java/org/eclipse/jetty/server/handler/SizeLimitHandlerTest.java 2023-10-09 12:27:40.000000000 +0000 @@ -111,6 +111,7 @@ _local.getResponse("GET /ctx/hello HTTP/1.0\r\n\r\n")); assertThat(response.getStatus(), equalTo(500)); assertThat(response.getContent(), containsString("8193>8192")); + assertThat(response.getContent(), containsString("Response body is too large")); } @Test @@ -130,6 +131,7 @@ _local.getResponse("GET /ctx/hello HTTP/1.0\r\n\r\n")); assertThat(response.getStatus(), equalTo(500)); assertThat(response.getContent(), containsString("8193>8192")); + assertThat(response.getContent(), containsString("Response body is too large")); } @Test @@ -219,6 +221,7 @@ "\r\n" + "123456...")); assertThat(response.getStatus(), equalTo(413)); + assertThat(response.getContent(), containsString("Request body is too large")); assertThat(response.getContent(), containsString("32768>8192")); } @@ -253,7 +256,8 @@ HttpTester.Response response = HttpTester.parseResponse(endp.getResponse()); - assertThat(response.getStatus(), equalTo(500)); + assertThat(response.getStatus(), equalTo(413)); + assertThat(response.getContent(), containsString("Request body is too large")); assertThat(response.getContent(), containsString(">8192")); } } diff -Nru jetty9-9.4.51/jetty-servlet/pom.xml jetty9-9.4.53/jetty-servlet/pom.xml --- jetty9-9.4.51/jetty-servlet/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-servlet/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ jetty-project org.eclipse.jetty - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 jetty-servlet diff -Nru jetty9-9.4.51/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/MultiPartServletTest.java jetty9-9.4.53/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/MultiPartServletTest.java --- jetty9-9.4.51/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/MultiPartServletTest.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/MultiPartServletTest.java 2023-10-09 12:27:40.000000000 +0000 @@ -58,12 +58,9 @@ import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.handler.gzip.GzipHandler; import org.eclipse.jetty.util.IO; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.StacklessLogging; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -79,20 +76,22 @@ public class MultiPartServletTest { - private static final Logger LOG = Log.getLogger(MultiPartServletTest.class); - private Server server; private ServerConnector connector; private HttpClient client; private Path tmpDir; + private ServletContextHandler contextHandler; private static final int MAX_FILE_SIZE = 512 * 1024; private static final int MAX_REQUEST_SIZE = 1024 * 1024 * 8; private static final int LARGE_MESSAGE_SIZE = 1024 * 1024; - public static Stream data() + public static Stream complianceModes() { - return Arrays.asList(MultiPartFormDataCompliance.values()).stream().map(Arguments::of); + return Stream.of( + Arguments.of(MultiPartFormDataCompliance.RFC7578), + Arguments.of(MultiPartFormDataCompliance.LEGACY) + ); } public static class RequestParameterServlet extends HttpServlet @@ -149,7 +148,6 @@ public void start() throws Exception { tmpDir = Files.createTempDirectory(MultiPartServletTest.class.getSimpleName()); - Files.deleteIfExists(tmpDir); assertNotNull(tmpDir); server = new Server(); @@ -163,7 +161,7 @@ MultipartConfigElement defaultConfig = new MultipartConfigElement(tmpDir.toAbsolutePath().toString(), -1, -1, 1); - ServletContextHandler contextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS); + contextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS); contextHandler.setContextPath("/"); ServletHolder servletHolder = contextHandler.addServlet(MultiPartServlet.class, "/"); servletHolder.getRegistration().setMultipartConfig(config); @@ -198,7 +196,7 @@ } @ParameterizedTest - @MethodSource("data") + @MethodSource("complianceModes") public void testLargePart(MultiPartFormDataCompliance compliance) throws Exception { connector.getConnectionFactory(HttpConnectionFactory.class).getHttpConfiguration() @@ -220,7 +218,7 @@ // Write large amount of content to the part. byte[] byteArray = new byte[1024 * 1024]; Arrays.fill(byteArray, (byte)1); - for (int i = 0; i < 128 * 2; i++) + for (int i = 0; i < 1024 * 2; i++) { content.getOutputStream().write(byteArray); } @@ -234,13 +232,49 @@ } @ParameterizedTest - @MethodSource("data") + @MethodSource("complianceModes") public void testManyParts(MultiPartFormDataCompliance compliance) throws Exception { + int maxParts = 1000; + contextHandler.setMaxFormKeys(maxParts); + connector.getConnectionFactory(HttpConnectionFactory.class).getHttpConfiguration() + .setMultiPartFormDataCompliance(compliance); + + byte[] byteArray = new byte[10]; + Arrays.fill(byteArray, (byte)1); + + MultiPartContentProvider multiPart = new MultiPartContentProvider(); + for (int i = 0; i < maxParts; i++) + { + BytesContentProvider content = new BytesContentProvider(byteArray); + multiPart.addFieldPart("part" + i, content, null); + } + multiPart.close(); + + InputStreamResponseListener listener = new InputStreamResponseListener(); + client.newRequest("localhost", connector.getLocalPort()) + .path("/defaultConfig") + .scheme(HttpScheme.HTTP.asString()) + .method(HttpMethod.POST) + .content(multiPart) + .send(listener); + + Response response = listener.get(30, TimeUnit.SECONDS); + assertThat(response.getStatus(), equalTo(HttpStatus.OK_200)); + String responseContent = IO.toString(listener.getInputStream()); + assertThat(responseContent, containsString("success")); + } + + @ParameterizedTest + @MethodSource("complianceModes") + public void testTooManyParts(MultiPartFormDataCompliance compliance) throws Exception + { + int maxParts = 1000; + contextHandler.setMaxFormKeys(maxParts); connector.getConnectionFactory(HttpConnectionFactory.class).getHttpConfiguration() .setMultiPartFormDataCompliance(compliance); - byte[] byteArray = new byte[1024]; + byte[] byteArray = new byte[5]; Arrays.fill(byteArray, (byte)1); MultiPartContentProvider multiPart = new MultiPartContentProvider(); @@ -267,7 +301,7 @@ } @ParameterizedTest - @MethodSource("data") + @MethodSource("complianceModes") public void testMaxRequestSize(MultiPartFormDataCompliance compliance) throws Exception { connector.getConnectionFactory(HttpConnectionFactory.class).getHttpConfiguration() @@ -311,24 +345,21 @@ } @ParameterizedTest - @MethodSource("data") + @MethodSource("complianceModes") public void testTempFilesDeletedOnError(MultiPartFormDataCompliance compliance) throws Exception { connector.getConnectionFactory(HttpConnectionFactory.class).getHttpConfiguration() .setMultiPartFormDataCompliance(compliance); byte[] byteArray = new byte[LARGE_MESSAGE_SIZE]; - for (int i = 0; i < byteArray.length; i++) - { - byteArray[i] = 1; - } + Arrays.fill(byteArray, (byte)1); BytesContentProvider contentProvider = new BytesContentProvider(byteArray); MultiPartContentProvider multiPart = new MultiPartContentProvider(); multiPart.addFieldPart("largePart", contentProvider, null); multiPart.close(); - try (StacklessLogging stacklessLogging = new StacklessLogging(HttpChannel.class, MultiPartFormInputStream.class)) + try (StacklessLogging ignored = new StacklessLogging(HttpChannel.class, MultiPartFormInputStream.class)) { ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) .scheme(HttpScheme.HTTP.asString()) @@ -346,9 +377,13 @@ assertThat(fileList.length, is(0)); } - @Test - public void testMultiPartGzip() throws Exception + @ParameterizedTest + @MethodSource("complianceModes") + public void testMultiPartGzip(MultiPartFormDataCompliance compliance) throws Exception { + connector.getConnectionFactory(HttpConnectionFactory.class).getHttpConfiguration() + .setMultiPartFormDataCompliance(compliance); + String contentString = "the quick brown fox jumps over the lazy dog, " + "the quick brown fox jumps over the lazy dog"; StringContentProvider content = new StringContentProvider(contentString); diff -Nru jetty9-9.4.51/jetty-servlets/pom.xml jetty9-9.4.53/jetty-servlets/pom.xml --- jetty9-9.4.51/jetty-servlets/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-servlets/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ jetty-project org.eclipse.jetty - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 jetty-servlets diff -Nru jetty9-9.4.51/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CGI.java jetty9-9.4.53/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CGI.java --- jetty9-9.4.51/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CGI.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CGI.java 2023-10-09 12:27:40.000000000 +0000 @@ -67,7 +67,10 @@ *
ignoreExitState
*
If true then do not act on a non-zero exec exit status")
* + * + * @deprecated do not use, no replacement, will be removed in a future release. */ +@Deprecated public class CGI extends HttpServlet { private static final long serialVersionUID = -6182088932884791074L; diff -Nru jetty9-9.4.51/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/PushSessionCacheFilter.java jetty9-9.4.53/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/PushSessionCacheFilter.java --- jetty9-9.4.51/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/PushSessionCacheFilter.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/PushSessionCacheFilter.java 2023-10-09 12:27:40.000000000 +0000 @@ -41,6 +41,10 @@ import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; +/** + * @deprecated no replacement for this deprecated http feature + */ +@Deprecated public class PushSessionCacheFilter implements Filter { private static final String TARGET_ATTR = "PushCacheFilter.target"; @@ -49,6 +53,11 @@ private final ConcurrentMap _cache = new ConcurrentHashMap<>(); private long _associateDelay = 5000L; + public PushSessionCacheFilter() + { + LOG.warn(PushSessionCacheFilter.class.getSimpleName() + " is an example class not suitable for production."); + } + @Override public void init(FilterConfig config) throws ServletException { diff -Nru jetty9-9.4.51/jetty-spring/pom.xml jetty9-9.4.53/jetty-spring/pom.xml --- jetty9-9.4.51/jetty-spring/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-spring/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,14 +2,14 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 jetty-spring Example :: Jetty Spring - 5.3.25 + 5.3.30 target/dependencies ${project.groupId}.spring true diff -Nru jetty9-9.4.51/jetty-start/pom.xml jetty9-9.4.53/jetty-start/pom.xml --- jetty9-9.4.51/jetty-start/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-start/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 jetty-start diff -Nru jetty9-9.4.51/jetty-start/src/test/resources/bogus.xml jetty9-9.4.53/jetty-start/src/test/resources/bogus.xml --- jetty9-9.4.51/jetty-start/src/test/resources/bogus.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-start/src/test/resources/bogus.xml 2023-10-09 12:27:40.000000000 +0000 @@ -1,2 +1,3 @@ + \ No newline at end of file diff -Nru jetty9-9.4.51/jetty-unixsocket/pom.xml jetty9-9.4.53/jetty-unixsocket/pom.xml --- jetty9-9.4.51/jetty-unixsocket/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-unixsocket/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 jetty-unixsocket diff -Nru jetty9-9.4.51/jetty-util/pom.xml jetty9-9.4.53/jetty-util/pom.xml --- jetty9-9.4.51/jetty-util/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-util/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 jetty-util diff -Nru jetty9-9.4.51/jetty-util/src/main/java/org/eclipse/jetty/util/CharsetStringBuilder.java jetty9-9.4.53/jetty-util/src/main/java/org/eclipse/jetty/util/CharsetStringBuilder.java --- jetty9-9.4.51/jetty-util/src/main/java/org/eclipse/jetty/util/CharsetStringBuilder.java 1970-01-01 00:00:00.000000000 +0000 +++ jetty9-9.4.53/jetty-util/src/main/java/org/eclipse/jetty/util/CharsetStringBuilder.java 2023-10-09 12:27:40.000000000 +0000 @@ -0,0 +1,312 @@ +// +// ======================================================================== +// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.util; + +import java.nio.ByteBuffer; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CodingErrorAction; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Objects; + +/** + *

Build a string from a sequence of bytes and/or characters.

+ *

Implementations of this interface are optimized for processing a mix of calls to already decoded + * character based appends (e.g. {@link #append(char)} and calls to undecoded byte methods (e.g. {@link #append(byte)}. + * This is particularly useful for decoding % encoded strings that are mostly already decoded but may contain + * escaped byte sequences that are not decoded. The standard {@link CharsetDecoder} API is not well suited for this + * use-case.

+ *

Any coding errors in the string will be reported by a {@link CharacterCodingException} thrown + * from the {@link #build()} method.

+ * @see Utf8StringBuilder for UTF-8 decoding with replacement of coding errors and/or fast fail behaviour. + * @see CharsetDecoder for decoding arbitrary {@link Charset}s with control over {@link CodingErrorAction}. + */ +public interface CharsetStringBuilder +{ + /** + * @param b An encoded byte to append + */ + void append(byte b); + + /** + * @param c A decoded character to append + */ + void append(char c); + + /** + * @param bytes Array of encoded bytes to append + */ + default void append(byte[] bytes) + { + append(bytes, 0, bytes.length); + } + + /** + * @param b Array of encoded bytes + * @param offset offset into the array + * @param length the number of bytes to append from the array. + */ + default void append(byte[] b, int offset, int length) + { + int end = offset + length; + for (int i = offset; i < end; i++) + append(b[i]); + } + + /** + * @param chars sequence of decoded characters + * @param offset offset into the array + * @param length the number of character to append from the sequence. + */ + default void append(CharSequence chars, int offset, int length) + { + int end = offset + length; + for (int i = offset; i < end; i++) + append(chars.charAt(i)); + } + + /** + * @param buf Buffer of encoded bytes to append. The bytes are consumed from the buffer. + */ + default void append(ByteBuffer buf) + { + int end = buf.position() + buf.remaining(); + while (buf.position() < end) + append(buf.get()); + } + + /** + *

Build the completed string and reset the buffer.

+ * @return The decoded built string which must be complete in regard to any multibyte sequences. + * @throws CharacterCodingException If the bytes cannot be correctly decoded or a multibyte sequence is incomplete. + */ + String build() throws CharacterCodingException; + + void reset(); + + /** + * @param charset The charset + * @return A {@link CharsetStringBuilder} suitable for the charset. + */ + static CharsetStringBuilder forCharset(Charset charset) + { + Objects.requireNonNull(charset); + if (charset == StandardCharsets.ISO_8859_1) + return new Iso88591StringBuilder(); + if (charset == StandardCharsets.US_ASCII) + return new UsAsciiStringBuilder(); + + // Use a CharsetDecoder that defaults to CodingErrorAction#REPORT + return new DecoderStringBuilder(charset.newDecoder()); + } + + class Iso88591StringBuilder implements CharsetStringBuilder + { + private final StringBuilder _builder = new StringBuilder(); + + @Override + public void append(byte b) + { + _builder.append((char)(0xff & b)); + } + + @Override + public void append(char c) + { + _builder.append(c); + } + + @Override + public void append(CharSequence chars, int offset, int length) + { + _builder.append(chars, offset, offset + length); + } + + @Override + public String build() + { + String s = _builder.toString(); + _builder.setLength(0); + return s; + } + + @Override + public void reset() + { + _builder.setLength(0); + } + } + + class UsAsciiStringBuilder implements CharsetStringBuilder + { + private final StringBuilder _builder = new StringBuilder(); + + @Override + public void append(byte b) + { + if (b < 0) + throw new IllegalArgumentException(); + _builder.append((char)b); + } + + @Override + public void append(char c) + { + _builder.append(c); + } + + @Override + public void append(CharSequence chars, int offset, int length) + { + _builder.append(chars, offset, offset + length); + } + + @Override + public String build() + { + String s = _builder.toString(); + _builder.setLength(0); + return s; + } + + @Override + public void reset() + { + _builder.setLength(0); + } + } + + class DecoderStringBuilder implements CharsetStringBuilder + { + private final CharsetDecoder _decoder; + private final StringBuilder _stringBuilder = new StringBuilder(32); + private ByteBuffer _buffer = ByteBuffer.allocate(32); + + public DecoderStringBuilder(CharsetDecoder charsetDecoder) + { + _decoder = charsetDecoder; + } + + private void ensureSpace(int needed) + { + int space = _buffer.remaining(); + if (space < needed) + { + int position = _buffer.position(); + _buffer = ByteBuffer.wrap(Arrays.copyOf(_buffer.array(), _buffer.capacity() + needed - space + 32)); + _buffer.position(position); + } + } + + @Override + public void append(byte b) + { + ensureSpace(1); + _buffer.put(b); + } + + @Override + public void append(char c) + { + if (_buffer.position() > 0) + { + try + { + // Append any data already in the decoder + _buffer.flip(); + _stringBuilder.append(_decoder.decode(_buffer)); + _buffer.clear(); + } + catch (CharacterCodingException e) + { + // This will be thrown only if the decoder is configured to REPORT, + // otherwise errors will be ignored or replaced and we will not catch here. + throw new RuntimeException(e); + } + } + _stringBuilder.append(c); + } + + @Override + public void append(CharSequence chars, int offset, int length) + { + if (_buffer.position() > 0) + { + try + { + // Append any data already in the decoder + _buffer.flip(); + _stringBuilder.append(_decoder.decode(_buffer)); + _buffer.clear(); + } + catch (CharacterCodingException e) + { + // This will be thrown only if the decoder is configured to REPORT, + // otherwise errors will be ignored or replaced and we will not catch here. + throw new RuntimeException(e); + } + } + _stringBuilder.append(chars, offset, offset + length); + } + + @Override + public void append(byte[] b, int offset, int length) + { + ensureSpace(length); + _buffer.put(b, offset, length); + } + + @Override + public void append(ByteBuffer buf) + { + ensureSpace(buf.remaining()); + _buffer.put(buf); + } + + @Override + public String build() throws CharacterCodingException + { + try + { + if (_buffer.position() > 0) + { + _buffer.flip(); + CharSequence decoded = _decoder.decode(_buffer); + _buffer.clear(); + if (_stringBuilder.length() == 0) + return decoded.toString(); + _stringBuilder.append(decoded); + } + return _stringBuilder.toString(); + } + finally + { + _stringBuilder.setLength(0); + } + } + + @Override + public void reset() + { + _stringBuilder.setLength(0); + } + } +} diff -Nru jetty9-9.4.51/jetty-util/src/main/java/org/eclipse/jetty/util/IteratingCallback.java jetty9-9.4.53/jetty-util/src/main/java/org/eclipse/jetty/util/IteratingCallback.java --- jetty9-9.4.51/jetty-util/src/main/java/org/eclipse/jetty/util/IteratingCallback.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-util/src/main/java/org/eclipse/jetty/util/IteratingCallback.java 2023-10-09 12:27:40.000000000 +0000 @@ -405,6 +405,7 @@ break; case PENDING: { + _state = State.FAILED; failure = true; break; } diff -Nru jetty9-9.4.51/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java jetty9-9.4.53/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java --- jetty9-9.4.51/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java 2023-10-09 12:27:40.000000000 +0000 @@ -107,6 +107,27 @@ '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177' }; + // @checkstyle-disable-check : IllegalTokenTextCheck + private static final char[] uppercases = + { + '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007', + '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017', + '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027', + '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037', + '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047', + '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057', + '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067', + '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077', + '\100', '\101', '\102', '\103', '\104', '\105', '\106', '\107', + '\110', '\111', '\112', '\113', '\114', '\115', '\116', '\117', + '\120', '\121', '\122', '\123', '\124', '\125', '\126', '\127', + '\130', '\131', '\132', '\133', '\134', '\135', '\136', '\137', + '\140', '\101', '\102', '\103', '\104', '\105', '\106', '\107', + '\110', '\111', '\112', '\113', '\114', '\115', '\116', '\117', + '\120', '\121', '\122', '\123', '\124', '\125', '\126', '\127', + '\130', '\131', '\132', '\173', '\174', '\175', '\176', '\177' + }; + /** * fast lower case conversion. Only works on ascii (not unicode) * @@ -145,6 +166,42 @@ } /** + * fast upper case conversion. Only works on ascii (not unicode) + * + * @param s the string to convert + * @return a lower case version of s + */ + public static String asciiToUpperCase(String s) + { + if (s == null) + return null; + + char[] c = null; + int i = s.length(); + // look for first conversion + while (i-- > 0) + { + char c1 = s.charAt(i); + if (c1 <= 127) + { + char c2 = uppercases[c1]; + if (c1 != c2) + { + c = s.toCharArray(); + c[i] = c2; + break; + } + } + } + while (i-- > 0) + { + if (c[i] <= 127) + c[i] = uppercases[c[i]]; + } + return c == null ? s : new String(c); + } + + /** * Replace all characters from input string that are known to have * special meaning in various filesystems. * @@ -454,6 +511,22 @@ } /** + * Generate a string from another string repeated n times. + * + * @param s the string to use + * @param n the number of times this string should be appended + */ + public static String stringFrom(String s, int n) + { + StringBuilder stringBuilder = new StringBuilder(s.length() * n); + for (int i = 0; i < n; i++) + { + stringBuilder.append(s); + } + return stringBuilder.toString(); + } + + /** * Return a non null string. * * @param s String diff -Nru jetty9-9.4.51/jetty-util/src/test/java/org/eclipse/jetty/util/IteratingCallbackTest.java jetty9-9.4.53/jetty-util/src/test/java/org/eclipse/jetty/util/IteratingCallbackTest.java --- jetty9-9.4.51/jetty-util/src/test/java/org/eclipse/jetty/util/IteratingCallbackTest.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-util/src/test/java/org/eclipse/jetty/util/IteratingCallbackTest.java 2023-10-09 12:27:40.000000000 +0000 @@ -20,6 +20,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler; import org.eclipse.jetty.util.thread.Scheduler; @@ -327,4 +328,44 @@ return isSucceeded(); } } + + @Test + public void testMultipleFailures() throws Exception + { + AtomicInteger process = new AtomicInteger(); + AtomicInteger failure = new AtomicInteger(); + IteratingCallback icb = new IteratingCallback() + { + @Override + protected Action process() throws Throwable + { + process.incrementAndGet(); + return Action.SCHEDULED; + } + + @Override + protected void onCompleteFailure(Throwable cause) + { + super.onCompleteFailure(cause); + failure.incrementAndGet(); + } + }; + + icb.iterate(); + assertEquals(1, process.get()); + assertEquals(0, failure.get()); + + icb.failed(new Throwable("test1")); + + assertEquals(1, process.get()); + assertEquals(1, failure.get()); + + icb.succeeded(); + assertEquals(1, process.get()); + assertEquals(1, failure.get()); + + icb.failed(new Throwable("test2")); + assertEquals(1, process.get()); + assertEquals(1, failure.get()); + } } diff -Nru jetty9-9.4.51/jetty-util-ajax/pom.xml jetty9-9.4.53/jetty-util-ajax/pom.xml --- jetty9-9.4.51/jetty-util-ajax/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-util-ajax/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 jetty-util-ajax diff -Nru jetty9-9.4.51/jetty-webapp/pom.xml jetty9-9.4.53/jetty-webapp/pom.xml --- jetty9-9.4.51/jetty-webapp/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-webapp/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 jetty-webapp diff -Nru jetty9-9.4.51/jetty-websocket/javax-websocket-client-impl/pom.xml jetty9-9.4.53/jetty-websocket/javax-websocket-client-impl/pom.xml --- jetty9-9.4.51/jetty-websocket/javax-websocket-client-impl/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-websocket/javax-websocket-client-impl/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ org.eclipse.jetty.websocket websocket-parent - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 diff -Nru jetty9-9.4.51/jetty-websocket/javax-websocket-server-impl/pom.xml jetty9-9.4.53/jetty-websocket/javax-websocket-server-impl/pom.xml --- jetty9-9.4.51/jetty-websocket/javax-websocket-server-impl/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-websocket/javax-websocket-server-impl/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ org.eclipse.jetty.websocket websocket-parent - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 diff -Nru jetty9-9.4.51/jetty-websocket/jetty-websocket-tests/pom.xml jetty9-9.4.53/jetty-websocket/jetty-websocket-tests/pom.xml --- jetty9-9.4.51/jetty-websocket/jetty-websocket-tests/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-websocket/jetty-websocket-tests/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ org.eclipse.jetty.websocket websocket-parent - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 diff -Nru jetty9-9.4.51/jetty-websocket/pom.xml jetty9-9.4.53/jetty-websocket/pom.xml --- jetty9-9.4.51/jetty-websocket/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-websocket/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ jetty-project org.eclipse.jetty - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 diff -Nru jetty9-9.4.51/jetty-websocket/websocket-api/pom.xml jetty9-9.4.53/jetty-websocket/websocket-api/pom.xml --- jetty9-9.4.51/jetty-websocket/websocket-api/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-websocket/websocket-api/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ org.eclipse.jetty.websocket websocket-parent - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 diff -Nru jetty9-9.4.51/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/ExtensionFactory.java jetty9-9.4.53/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/ExtensionFactory.java --- jetty9-9.4.51/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/ExtensionFactory.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/ExtensionFactory.java 2023-10-09 12:27:40.000000000 +0000 @@ -37,7 +37,12 @@ public ExtensionFactory() { availableExtensions = new HashMap<>(); - Iterator iterator = ServiceLoader.load(Extension.class).iterator(); + final ServiceLoader sl = ServiceLoader.load(Extension.class); + if (sl == null) + { + return; + } + final Iterator iterator = sl.iterator(); while (true) { try diff -Nru jetty9-9.4.51/jetty-websocket/websocket-client/pom.xml jetty9-9.4.53/jetty-websocket/websocket-client/pom.xml --- jetty9-9.4.51/jetty-websocket/websocket-client/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-websocket/websocket-client/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ org.eclipse.jetty.websocket websocket-parent - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 diff -Nru jetty9-9.4.51/jetty-websocket/websocket-common/pom.xml jetty9-9.4.53/jetty-websocket/websocket-common/pom.xml --- jetty9-9.4.51/jetty-websocket/websocket-common/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-websocket/websocket-common/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ org.eclipse.jetty.websocket websocket-parent - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 diff -Nru jetty9-9.4.51/jetty-websocket/websocket-server/pom.xml jetty9-9.4.53/jetty-websocket/websocket-server/pom.xml --- jetty9-9.4.51/jetty-websocket/websocket-server/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-websocket/websocket-server/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ org.eclipse.jetty.websocket websocket-parent - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 diff -Nru jetty9-9.4.51/jetty-websocket/websocket-servlet/pom.xml jetty9-9.4.53/jetty-websocket/websocket-servlet/pom.xml --- jetty9-9.4.51/jetty-websocket/websocket-servlet/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-websocket/websocket-servlet/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ org.eclipse.jetty.websocket websocket-parent - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 diff -Nru jetty9-9.4.51/jetty-xml/pom.xml jetty9-9.4.53/jetty-xml/pom.xml --- jetty9-9.4.51/jetty-xml/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-xml/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 jetty-xml diff -Nru jetty9-9.4.51/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java jetty9-9.4.53/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java --- jetty9-9.4.51/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java 2023-10-09 12:27:40.000000000 +0000 @@ -18,6 +18,7 @@ package org.eclipse.jetty.xml; +import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.io.StringReader; @@ -67,6 +68,7 @@ import org.eclipse.jetty.util.resource.Resource; import org.xml.sax.InputSource; import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; /** *

Configures objects from XML.

@@ -203,7 +205,7 @@ private final String _dtd; private ConfigurationProcessor _processor; - ConfigurationParser getParser() + public XmlParser getXmlParser() { Pool.Entry entry = __parsers.acquire(ConfigurationParser::new); if (entry == null) @@ -220,12 +222,22 @@ */ public XmlConfiguration(Resource resource) throws SAXException, IOException { - try (ConfigurationParser parser = getParser(); InputStream inputStream = resource.getInputStream()) + XmlParser parser = getXmlParser(); + try (InputStream inputStream = resource.getInputStream()) { _location = resource; setConfig(parser.parse(inputStream)); _dtd = parser.getDTD(); } + catch (SAXParseException e) + { + throw new SAXParseException("Unable to parse: " + resource, null, e); + } + finally + { + if (parser instanceof Closeable) + ((Closeable)parser).close(); + } } /** @@ -257,13 +269,19 @@ configuration = "\n" + "" + configuration; - try (ConfigurationParser parser = getParser(); StringReader reader = new StringReader(configuration)) + XmlParser parser = getXmlParser(); + try (StringReader reader = new StringReader(configuration)) { InputSource source = new InputSource(reader); _location = null; setConfig(parser.parse(source)); _dtd = parser.getDTD(); } + finally + { + if (parser instanceof Closeable) + ((Closeable)parser).close(); + } } /** @@ -278,12 +296,18 @@ public XmlConfiguration(InputStream configuration) throws SAXException, IOException { InputSource source = new InputSource(configuration); - try (ConfigurationParser parser = getParser()) + XmlParser parser = getXmlParser(); + try { _location = null; setConfig(parser.parse(source)); _dtd = parser.getDTD(); } + finally + { + if (parser instanceof Closeable) + ((Closeable)parser).close(); + } } @Override @@ -1918,7 +1942,7 @@ } } - private static class ConfigurationParser extends XmlParser implements AutoCloseable + private static class ConfigurationParser extends XmlParser implements Closeable { private final Pool.Entry _entry; @@ -1942,8 +1966,23 @@ redirectEntity("http://jetty.mortbay.org/configure.dtd", config93); redirectEntity("http://jetty.eclipse.org/configure.dtd", config93); redirectEntity("https://jetty.eclipse.org/configure.dtd", config93); - redirectEntity("http://www.eclipse.org/jetty/configure.dtd", config93); - redirectEntity("https://www.eclipse.org/jetty/configure.dtd", config93); + redirectEntity("http://jetty.mortbay.org/configure.dtd", config93); + + // Register all variations of DOCTYPE entity references for Config 9.3 + String[] schemes = {"http", "https"}; + String[] hosts = {"www.eclipse.org", "eclipse.org", "www.eclipse.dev", "eclipse.dev"}; + String[] paths = {"/jetty/configure.dtd", "/jetty/configure_9_3.dtd"}; + + for (String scheme : schemes) + { + for (String host : hosts) + { + for (String path : paths) + { + redirectEntity(String.format("%s://%s%s", scheme, host, path), config93); + } + } + } redirectEntity("-//Mort Bay Consulting//DTD Configure//EN", config93); redirectEntity("-//Jetty//Configure//EN", config93); } diff -Nru jetty9-9.4.51/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlParser.java jetty9-9.4.53/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlParser.java --- jetty9-9.4.51/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlParser.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlParser.java 2023-10-09 12:27:40.000000000 +0000 @@ -69,9 +69,9 @@ */ public XmlParser() { - SAXParserFactory factory = SAXParserFactory.newInstance(); - boolean validatingDft = factory.getClass().toString().startsWith("org.apache.xerces."); - String validatingProp = System.getProperty("org.eclipse.jetty.xml.XmlParser.Validating", validatingDft ? "true" : "false"); + SAXParserFactory factory = newSAXParserFactory(); + boolean validatingDefault = factory.getClass().toString().contains("org.apache.xerces."); + String validatingProp = System.getProperty("org.eclipse.jetty.xml.XmlParser.Validating", validatingDefault ? "true" : "false"); boolean validating = Boolean.valueOf(validatingProp).booleanValue(); setValidating(validating); } @@ -81,11 +81,16 @@ setValidating(validating); } + protected SAXParserFactory newSAXParserFactory() + { + return SAXParserFactory.newInstance(); + } + public void setValidating(boolean validating) { try { - SAXParserFactory factory = SAXParserFactory.newInstance(); + SAXParserFactory factory = newSAXParserFactory(); factory.setValidating(validating); _parser = factory.newSAXParser(); @@ -127,6 +132,11 @@ return _parser.isValidating(); } + public SAXParser getSAXParser() + { + return _parser; + } + public synchronized void redirectEntity(String name, URL entity) { if (entity != null) @@ -261,18 +271,10 @@ if (pid != null) entity = _redirectMap.get(pid); if (entity == null) - entity = _redirectMap.get(sid); - if (entity == null) - { - String dtd = sid; - if (dtd.lastIndexOf('/') >= 0) - dtd = dtd.substring(dtd.lastIndexOf('/') + 1); - - if (LOG.isDebugEnabled()) - LOG.debug("Can't exact match entity in redirect map, trying " + dtd); - entity = _redirectMap.get(dtd); - } + entity = (URL)_redirectMap.get(sid); + // Only serve entity if found. + // We don't want to serve from unknown hosts or random paths. if (entity != null) { try @@ -289,6 +291,9 @@ LOG.ignore(e); } } + + if (LOG.isDebugEnabled()) + LOG.debug("Entity not found for PID:{} / SID:{}", pid, sid); return null; } diff -Nru jetty9-9.4.51/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlConfigurationTest.java jetty9-9.4.53/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlConfigurationTest.java --- jetty9-9.4.51/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlConfigurationTest.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlConfigurationTest.java 2023-10-09 12:27:40.000000000 +0000 @@ -28,6 +28,7 @@ import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.StandardOpenOption; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -47,7 +48,6 @@ import org.eclipse.jetty.util.log.StdErrLog; import org.eclipse.jetty.util.resource.PathResource; import org.hamcrest.Matchers; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.RepeatedTest; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -57,6 +57,7 @@ import org.junit.jupiter.params.provider.ArgumentsProvider; import org.junit.jupiter.params.provider.ArgumentsSource; import org.junit.jupiter.params.provider.MethodSource; +import org.xml.sax.InputSource; import org.xml.sax.SAXException; import static java.nio.charset.StandardCharsets.UTF_8; @@ -105,8 +106,16 @@ configuration.configure(); } + public static Stream xmlConfigs() + { + return Stream.of( + Arguments.of("org/eclipse/jetty/xml/configureWithAttr.xml"), + Arguments.of("org/eclipse/jetty/xml/configureWithElements.xml") + ); + } + @ParameterizedTest - @ArgumentsSource(ScenarioProvider.class) + @MethodSource("xmlConfigs") public void testPassedObject(String configure) throws Exception { Map properties = new HashMap<>(); @@ -274,10 +283,15 @@ public XmlConfiguration asXmlConfiguration(String filename, String rawXml) throws IOException, SAXException { + if (!rawXml.contains("!DOCTYPE")) + rawXml = "\n" + + "\n" + + rawXml; Path testFile = workDir.getEmptyPathDir().resolve(filename); - try (BufferedWriter writer = Files.newBufferedWriter(testFile, UTF_8)) + try (BufferedWriter writer = Files.newBufferedWriter(testFile, UTF_8, StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) { writer.write(rawXml); + writer.flush(); } return new XmlConfiguration(new PathResource(testFile)); } @@ -1723,6 +1737,43 @@ } } + public static Stream xmlSystemIdSource() + { + List ids = new ArrayList<>(); + + String[] schemes = {"http", "https"}; + String[] hosts = {"eclipse.org", "www.eclipse.org", "eclipse.dev", "www.eclipse.dev"}; + String[] paths = {"/jetty/configure.dtd", "/jetty/configure_9_3.dtd"}; + + for (String scheme: schemes) + { + for (String host: hosts) + { + for (String path: paths) + { + ids.add(Arguments.of(String.format("%s://%s%s", scheme, host, path))); + } + } + } + + return ids.stream(); + } + + /** + * Test to ensure that all the XML System ID variants are covered in the + * {@link XmlConfiguration} internals. + */ + @ParameterizedTest + @MethodSource("xmlSystemIdSource") + public void testSystemIdVariants(String xmlSystemId) throws IOException, SAXException + { + // empty raw xml, just to instantiate XmlConfiguration, so we can access the XmlParser / ConfigurationParser. + XmlConfiguration xmlConfiguration = asXmlConfiguration(""); + XmlParser configurationProcessor = xmlConfiguration.getXmlParser(); + InputSource inputSource = configurationProcessor.resolveEntity(null, xmlSystemId); + assertNotNull(inputSource, "SystemID: " + xmlSystemId + " does not exist"); + } + private void assertHasExpectedLines(String type, List actualLines, String[] expectedLines) { assertThat("Count of " + type, actualLines.size(), is(expectedLines.length)); diff -Nru jetty9-9.4.51/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlParserTest.java jetty9-9.4.53/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlParserTest.java --- jetty9-9.4.51/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlParserTest.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlParserTest.java 2023-10-09 12:27:40.000000000 +0000 @@ -19,10 +19,17 @@ package org.eclipse.jetty.xml; import java.net.URL; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assumptions.assumeTrue; public class XmlParserTest { @@ -34,7 +41,7 @@ URL configURL = XmlConfiguration.class.getClassLoader().getResource("org/eclipse/jetty/xml/configure_9_3.dtd"); parser.redirectEntity("configure.dtd", configURL); parser.redirectEntity("configure_9_3.dtd", configURL); - //parser.redirectEntity("http://www.eclipse.org/jetty/configure_9_3.dtd", configURL); + parser.redirectEntity("http://www.eclipse.org/jetty/configure_9_3.dtd", configURL); parser.redirectEntity("http://jetty.eclipse.org/configure.dtd", configURL); parser.redirectEntity("-//Mort Bay Consulting//DTD Configure//EN", configURL); @@ -45,4 +52,32 @@ assertTrue(testDocStr.startsWith("")); } + + /** + * Customize SAXParserFactory behavior. + */ + @Test + public void testNewSAXParserFactory() throws SAXException + { + XmlParser xmlParser = new XmlParser() + { + @Override + protected SAXParserFactory newSAXParserFactory() + { + SAXParserFactory saxParserFactory = super.newSAXParserFactory(); + // Configure at factory level + saxParserFactory.setXIncludeAware(false); + return saxParserFactory; + } + }; + + SAXParser saxParser = xmlParser.getSAXParser(); + assertNotNull(saxParser); + + XMLReader xmlReader = saxParser.getXMLReader(); + // Only run testcase if Xerces is being used. + assumeTrue(xmlReader.getClass().getName().contains("org.apache.xerces.")); + // look to see it was set at XMLReader level + assertFalse(xmlReader.getFeature("http://apache.org/xml/features/xinclude")); + } } diff -Nru jetty9-9.4.51/jetty-xml/src/test/resources/org/eclipse/jetty/xml/mortbay.xml jetty9-9.4.53/jetty-xml/src/test/resources/org/eclipse/jetty/xml/mortbay.xml --- jetty9-9.4.51/jetty-xml/src/test/resources/org/eclipse/jetty/xml/mortbay.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/jetty-xml/src/test/resources/org/eclipse/jetty/xml/mortbay.xml 2023-10-09 12:27:40.000000000 +0000 @@ -1,2 +1,3 @@ - + + diff -Nru jetty9-9.4.51/pom.xml jetty9-9.4.53/pom.xml --- jetty9-9.4.51/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -4,7 +4,7 @@ 4.0.0 org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 Jetty :: Project The Eclipse Jetty Project pom @@ -25,17 +25,17 @@ 2.0.10 1.1.3.v20160715 - 1.10.13 - 1.11.1 - 2.2.1 - 9.4 + 1.10.14 + 1.11.3 + 2.2.3 + 9.6 6.3.1 1.5 9.3 - 1.15 - 1.22 - 2.11.0 - 3.12.0 + 1.16.0 + 1.24.0 + 2.14.0 + 3.13.0 2.5.2 3.4.4 3.0.2 @@ -48,9 +48,9 @@ 3.12.12 4.4.4.Final 11.0.17.Final - 2.13.3 - 2.13.3 - 2.13.3 + 2.14.2 + 2.14.2 + 2.14.2 2.82 1.1.0.v201105071233 1.3.2 @@ -59,13 +59,12 @@ 3.1.0 1.3 1.0 - 2.2.1.Final - 2.2.1.Final 3.4.3.Final + 3.5.1.Final 1.0.7 3.1.2 1.2 - 1.36 + 1.37 5.12.1 0.10.4 0.32.13 @@ -76,9 +75,9 @@ 8.5.70 5.9.1 2.17.1 - 1.2.11 - 3.7.1 - 1.9.4 + 1.2.12 + 3.8.2 + 1.9.16 3.9.0 2.14.3 8.1.0 @@ -86,18 +85,18 @@ 1.2.0 1.2.0 2.1.1 - 3.5.0 + 4.0.0 + 4.0.2 1.7.36 1.2.5 1.2.5 - 1.17.6 + 1.19.0 3.1.9.Final - 1.6.0.Final - 2.0.0.Final + 2.2.2.Final 2.4.7 - 2.2.2 + 2.2.4 2.1.0 3.3.0 3.0.0 @@ -109,29 +108,29 @@ 2.7 4.1 3.1.0 - 3.4.2 - 3.5.0 - 3.0.0-M9 - 3.2.1 - 3.2.0 - 3.10.1 - 3.5.0 + 3.6.0 + 3.6.0 + 3.1.2 + 3.3.0 + 3.3.1 + 3.11.0 + 3.6.0 2.10 - 3.2.1 + 3.4.1 3.3.0 3.3.1 3.3.1 - 3.7.1 - 2.5.3 - 3.0.0 - 3.3.0 - 3.4.1 + 3.9.0 + 3.0.1 + 3.1.0 + 3.3.1 + 3.5.1 3.12.1 - 3.2.1 - 3.3.2 - 3.1.0 - 3.1.0 - 1.4.0 + 3.3.0 + 3.4.0 + 3.1.1 + 3.1.1 + 1.5.0 2.11.0 @@ -477,7 +476,7 @@ org.apache.maven.plugins maven-checkstyle-plugin - 3.2.1 + 3.3.0 jetty-checkstyle.xml true @@ -966,6 +965,11 @@ ${plexus-utils.version} + org.codehaus.plexus + plexus-xml + ${plexus-xml.version} + + org.apache.maven maven-plugin-api ${maven.version} @@ -1041,22 +1045,22 @@ org.jboss.logging jboss-logging-processor - 2.2.1.Final + ${jboss.logging.version} org.jboss.logging jboss-logging-annotations - 2.2.1.Final + ${jboss.logging.version} org.jboss.logmanager jboss-logmanager - 2.1.19.Final + ${jboss.logging.version} org.jboss.threads jboss-threads - 3.5.0.Final + ${jboss.threads.version} @@ -1127,11 +1131,6 @@ ${jackson.annotations.version} - org.wildfly.common - wildfly-common - ${wildfly.common.version} - - org.wildfly.security wildfly-elytron ${wildfly.elytron.version} @@ -1489,7 +1488,7 @@ org.apache.maven.plugins maven-gpg-plugin - 3.0.1 + 3.1.0 sign-artifacts @@ -1532,7 +1531,10 @@ maven-surefire-plugin ${maven.surefire.plugin.version} - external, large-disk-resource + external, large-disk-resource, stress, slow + + true + diff -Nru jetty9-9.4.51/scripts/release-jetty.sh jetty9-9.4.53/scripts/release-jetty.sh --- jetty9-9.4.51/scripts/release-jetty.sh 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/scripts/release-jetty.sh 2023-10-09 12:27:40.000000000 +0000 @@ -166,10 +166,7 @@ # This is equivalent to 'mvn release:perform' if proceedyn "Build/Deploy from tag $TAG_NAME? (Y/n)" y; then - git checkout $TAG_NAME - mvn clean package deploy -Peclipse-release $DEPLOY_OPTS - reportMavenTestFailures - git checkout $GIT_BRANCH_ID + mvn clean deploy -Peclipse-release $DEPLOY_OPTS fi if proceedyn "Update working directory for $VER_NEXT? (Y/n)" y; then echo "Update VERSION.txt for $VER_NEXT" diff -Nru jetty9-9.4.51/tests/pom.xml jetty9-9.4.53/tests/pom.xml --- jetty9-9.4.51/tests/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -4,7 +4,7 @@ org.eclipse.jetty jetty-project - 9.4.51.v20230217 + 9.4.53.v20231009 ../pom.xml org.eclipse.jetty.tests diff -Nru jetty9-9.4.51/tests/test-continuation/pom.xml jetty9-9.4.53/tests/test-continuation/pom.xml --- jetty9-9.4.51/tests/test-continuation/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-continuation/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ org.eclipse.jetty.tests tests-parent - 9.4.51.v20230217 + 9.4.53.v20231009 ../pom.xml 4.0.0 diff -Nru jetty9-9.4.51/tests/test-distribution/pom.xml jetty9-9.4.53/tests/test-distribution/pom.xml --- jetty9-9.4.51/tests/test-distribution/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-distribution/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -2,7 +2,7 @@ tests-parent org.eclipse.jetty.tests - 9.4.51.v20230217 + 9.4.53.v20231009 4.0.0 @@ -20,6 +20,17 @@ slf4j-simple + org.codehaus.plexus + plexus-xml + test + + + javax.annotation + javax.annotation-api + + + + org.eclipse.jetty jetty-util ${project.version} diff -Nru jetty9-9.4.51/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/AbstractDistributionTest.java jetty9-9.4.53/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/AbstractDistributionTest.java --- jetty9-9.4.51/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/AbstractDistributionTest.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/AbstractDistributionTest.java 2023-10-09 12:27:40.000000000 +0000 @@ -22,6 +22,7 @@ import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.junit.jupiter.api.AfterEach; public class AbstractDistributionTest @@ -44,6 +45,10 @@ protected void startHttpClient(Supplier supplier) throws Exception { client = supplier.get(); + client.setName("DistributionTest-Client"); + QueuedThreadPool executor = new QueuedThreadPool(); + executor.setName("dist-test-client"); + client.setExecutor(executor); client.start(); } diff -Nru jetty9-9.4.51/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/DemoBaseTests.java jetty9-9.4.53/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/DemoBaseTests.java --- jetty9-9.4.51/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/DemoBaseTests.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/DemoBaseTests.java 2023-10-09 12:27:40.000000000 +0000 @@ -171,10 +171,12 @@ { assertTrue(run.awaitConsoleLogsFor("Started @", 10, TimeUnit.SECONDS)); - startHttpClient(); + startHttpClient(true); ContentResponse response = client.GET("http://localhost:" + httpPort + "/proxy/current/"); assertEquals(HttpStatus.OK_200, response.getStatus()); - assertThat("Expecting APIdoc contents", response.getContentAsString(), containsString("Jetty Util : Common Resource Utilities")); + String body = response.getContentAsString(); + assertThat("Expecting APIdoc contents", body, containsString("All Classes")); + assertThat("Expecting APIdoc contents", body, containsString("Overview (Jetty :: Project 9.")); } } diff -Nru jetty9-9.4.51/tests/test-http-client-transport/pom.xml jetty9-9.4.53/tests/test-http-client-transport/pom.xml --- jetty9-9.4.51/tests/test-http-client-transport/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-http-client-transport/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ <parent> <groupId>org.eclipse.jetty.tests</groupId> <artifactId>tests-parent</artifactId> - <version>9.4.51.v20230217</version> + <version>9.4.53.v20231009</version> </parent> <modelVersion>4.0.0</modelVersion> diff -Nru jetty9-9.4.51/tests/test-integration/pom.xml jetty9-9.4.53/tests/test-integration/pom.xml --- jetty9-9.4.51/tests/test-integration/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-integration/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ <parent> <groupId>org.eclipse.jetty.tests</groupId> <artifactId>tests-parent</artifactId> - <version>9.4.51.v20230217</version> + <version>9.4.53.v20231009</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>test-integration</artifactId> diff -Nru jetty9-9.4.51/tests/test-integration/src/test/resources/RFC2616Base.xml jetty9-9.4.53/tests/test-integration/src/test/resources/RFC2616Base.xml --- jetty9-9.4.51/tests/test-integration/src/test/resources/RFC2616Base.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-integration/src/test/resources/RFC2616Base.xml 2023-10-09 12:27:40.000000000 +0000 @@ -47,7 +47,7 @@ </Array> </Set> <Set name="ResourceBase"><Property name="test.docroot.base"/>/virtualhost</Set> - <Set name="Handler"><New id="reshandler" class="org.eclipse.jetty.server.handler.ResourceHandler"/></Set> + <Set name="Handler"><New id="reshandlervirt" class="org.eclipse.jetty.server.handler.ResourceHandler"/></Set> <Set name="DisplayName">virtual</Set> </New> </Item> @@ -55,7 +55,7 @@ <New id="defcontext" class="org.eclipse.jetty.server.handler.ContextHandler"> <Set name="contextPath">/tests</Set> <Set name="ResourceBase"><Property name="test.docroot.base"/>/default</Set> - <Set name="Handler"><New id="reshandler" class="org.eclipse.jetty.server.handler.ResourceHandler"/></Set> + <Set name="Handler"><New id="reshandlerdefault" class="org.eclipse.jetty.server.handler.ResourceHandler"/></Set> <Set name="DisplayName">default</Set> </New> </Item> diff -Nru jetty9-9.4.51/tests/test-integration/src/test/resources/ssl.xml jetty9-9.4.53/tests/test-integration/src/test/resources/ssl.xml --- jetty9-9.4.51/tests/test-integration/src/test/resources/ssl.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-integration/src/test/resources/ssl.xml 2023-10-09 12:27:40.000000000 +0000 @@ -1,3 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://eclipse.dev/jetty/configure_9_3.dtd"> <Configure id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory$Server"> <Set name="KeyStorePath"><Property name="jetty.home" default="." />/<Property name="jetty.sslContext.keyStorePath" default="keystore"/></Set> <Set name="KeyStorePassword"><Property name="jetty.sslContext.keyStorePassword" default="OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"/></Set> diff -Nru jetty9-9.4.51/tests/test-jmx/jmx-webapp/pom.xml jetty9-9.4.53/tests/test-jmx/jmx-webapp/pom.xml --- jetty9-9.4.51/tests/test-jmx/jmx-webapp/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-jmx/jmx-webapp/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -4,7 +4,7 @@ <parent> <groupId>org.eclipse.jetty.tests</groupId> <artifactId>test-jmx-parent</artifactId> - <version>9.4.51.v20230217</version> + <version>9.4.53.v20231009</version> </parent> <artifactId>jmx-webapp</artifactId> <packaging>war</packaging> diff -Nru jetty9-9.4.51/tests/test-jmx/jmx-webapp-it/pom.xml jetty9-9.4.53/tests/test-jmx/jmx-webapp-it/pom.xml --- jetty9-9.4.51/tests/test-jmx/jmx-webapp-it/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-jmx/jmx-webapp-it/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ <parent> <groupId>org.eclipse.jetty.tests</groupId> <artifactId>test-jmx-parent</artifactId> - <version>9.4.51.v20230217</version> + <version>9.4.53.v20231009</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>jmx-webapp-it</artifactId> diff -Nru jetty9-9.4.51/tests/test-jmx/pom.xml jetty9-9.4.53/tests/test-jmx/pom.xml --- jetty9-9.4.51/tests/test-jmx/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-jmx/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ <parent> <groupId>org.eclipse.jetty.tests</groupId> <artifactId>tests-parent</artifactId> - <version>9.4.51.v20230217</version> + <version>9.4.53.v20231009</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>test-jmx-parent</artifactId> diff -Nru jetty9-9.4.51/tests/test-loginservice/pom.xml jetty9-9.4.53/tests/test-loginservice/pom.xml --- jetty9-9.4.51/tests/test-loginservice/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-loginservice/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -4,7 +4,7 @@ <parent> <groupId>org.eclipse.jetty.tests</groupId> <artifactId>tests-parent</artifactId> - <version>9.4.51.v20230217</version> + <version>9.4.53.v20231009</version> </parent> <artifactId>test-loginservice</artifactId> <name>Jetty Tests :: Login Service</name> diff -Nru jetty9-9.4.51/tests/test-quickstart/pom.xml jetty9-9.4.53/tests/test-quickstart/pom.xml --- jetty9-9.4.51/tests/test-quickstart/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-quickstart/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ <parent> <groupId>org.eclipse.jetty.tests</groupId> <artifactId>tests-parent</artifactId> - <version>9.4.51.v20230217</version> + <version>9.4.53.v20231009</version> <relativePath>../pom.xml</relativePath> </parent> <modelVersion>4.0.0</modelVersion> diff -Nru jetty9-9.4.51/tests/test-sessions/pom.xml jetty9-9.4.53/tests/test-sessions/pom.xml --- jetty9-9.4.51/tests/test-sessions/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-sessions/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -4,7 +4,7 @@ <parent> <groupId>org.eclipse.jetty.tests</groupId> <artifactId>tests-parent</artifactId> - <version>9.4.51.v20230217</version> + <version>9.4.53.v20231009</version> </parent> <artifactId>test-sessions-parent</artifactId> <name>Jetty Tests :: Sessions :: Parent</name> diff -Nru jetty9-9.4.51/tests/test-sessions/test-file-sessions/pom.xml jetty9-9.4.53/tests/test-sessions/test-file-sessions/pom.xml --- jetty9-9.4.51/tests/test-sessions/test-file-sessions/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-sessions/test-file-sessions/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -4,7 +4,7 @@ <parent> <groupId>org.eclipse.jetty.tests</groupId> <artifactId>test-sessions-parent</artifactId> - <version>9.4.51.v20230217</version> + <version>9.4.53.v20231009</version> </parent> <artifactId>test-file-sessions</artifactId> <name>Jetty Tests :: Sessions :: File</name> diff -Nru jetty9-9.4.51/tests/test-sessions/test-gcloud-sessions/pom.xml jetty9-9.4.53/tests/test-sessions/test-gcloud-sessions/pom.xml --- jetty9-9.4.51/tests/test-sessions/test-gcloud-sessions/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-sessions/test-gcloud-sessions/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -4,7 +4,7 @@ <parent> <groupId>org.eclipse.jetty.tests</groupId> <artifactId>test-sessions-parent</artifactId> - <version>9.4.51.v20230217</version> + <version>9.4.53.v20231009</version> </parent> <artifactId>test-gcloud-sessions</artifactId> <name>Jetty Tests :: Sessions :: GCloud</name> diff -Nru jetty9-9.4.51/tests/test-sessions/test-hazelcast-sessions/pom.xml jetty9-9.4.53/tests/test-sessions/test-hazelcast-sessions/pom.xml --- jetty9-9.4.51/tests/test-sessions/test-hazelcast-sessions/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-sessions/test-hazelcast-sessions/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -4,7 +4,7 @@ <parent> <groupId>org.eclipse.jetty.tests</groupId> <artifactId>test-sessions-parent</artifactId> - <version>9.4.51.v20230217</version> + <version>9.4.53.v20231009</version> </parent> <artifactId>test-hazelcast-sessions</artifactId> <name>Jetty Tests :: Sessions :: Hazelcast</name> diff -Nru jetty9-9.4.51/tests/test-sessions/test-infinispan-sessions/pom.xml jetty9-9.4.53/tests/test-sessions/test-infinispan-sessions/pom.xml --- jetty9-9.4.51/tests/test-sessions/test-infinispan-sessions/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-sessions/test-infinispan-sessions/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -4,7 +4,7 @@ <parent> <groupId>org.eclipse.jetty.tests</groupId> <artifactId>test-sessions-parent</artifactId> - <version>9.4.51.v20230217</version> + <version>9.4.53.v20231009</version> </parent> <artifactId>test-infinispan-sessions</artifactId> <name>Jetty Tests :: Sessions :: Infinispan</name> diff -Nru jetty9-9.4.51/tests/test-sessions/test-jdbc-sessions/pom.xml jetty9-9.4.53/tests/test-sessions/test-jdbc-sessions/pom.xml --- jetty9-9.4.51/tests/test-sessions/test-jdbc-sessions/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-sessions/test-jdbc-sessions/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -4,7 +4,7 @@ <parent> <groupId>org.eclipse.jetty.tests</groupId> <artifactId>test-sessions-parent</artifactId> - <version>9.4.51.v20230217</version> + <version>9.4.53.v20231009</version> </parent> <artifactId>test-jdbc-sessions</artifactId> <name>Jetty Tests :: Sessions :: JDBC</name> diff -Nru jetty9-9.4.51/tests/test-sessions/test-memcached-sessions/pom.xml jetty9-9.4.53/tests/test-sessions/test-memcached-sessions/pom.xml --- jetty9-9.4.51/tests/test-sessions/test-memcached-sessions/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-sessions/test-memcached-sessions/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -4,7 +4,7 @@ <parent> <groupId>org.eclipse.jetty.tests</groupId> <artifactId>test-sessions-parent</artifactId> - <version>9.4.51.v20230217</version> + <version>9.4.53.v20231009</version> </parent> <artifactId>test-memcached-sessions</artifactId> <name>Jetty Tests :: Sessions :: Memcached</name> diff -Nru jetty9-9.4.51/tests/test-sessions/test-mongodb-sessions/pom.xml jetty9-9.4.53/tests/test-sessions/test-mongodb-sessions/pom.xml --- jetty9-9.4.51/tests/test-sessions/test-mongodb-sessions/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-sessions/test-mongodb-sessions/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -4,7 +4,7 @@ <parent> <groupId>org.eclipse.jetty.tests</groupId> <artifactId>test-sessions-parent</artifactId> - <version>9.4.51.v20230217</version> + <version>9.4.53.v20231009</version> </parent> <artifactId>test-mongodb-sessions</artifactId> <name>Jetty Tests :: Sessions :: Mongo</name> diff -Nru jetty9-9.4.51/tests/test-sessions/test-sessions-common/pom.xml jetty9-9.4.53/tests/test-sessions/test-sessions-common/pom.xml --- jetty9-9.4.51/tests/test-sessions/test-sessions-common/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-sessions/test-sessions-common/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -4,7 +4,7 @@ <parent> <groupId>org.eclipse.jetty.tests</groupId> <artifactId>test-sessions-parent</artifactId> - <version>9.4.51.v20230217</version> + <version>9.4.53.v20231009</version> </parent> <artifactId>test-sessions-common</artifactId> <name>Jetty Tests :: Sessions :: Common</name> diff -Nru jetty9-9.4.51/tests/test-webapps/pom.xml jetty9-9.4.53/tests/test-webapps/pom.xml --- jetty9-9.4.51/tests/test-webapps/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-webapps/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -4,7 +4,7 @@ <parent> <groupId>org.eclipse.jetty.tests</groupId> <artifactId>tests-parent</artifactId> - <version>9.4.51.v20230217</version> + <version>9.4.53.v20231009</version> <relativePath>../pom.xml</relativePath> </parent> <artifactId>test-webapps-parent</artifactId> diff -Nru jetty9-9.4.51/tests/test-webapps/test-cdi-common-webapp/pom.xml jetty9-9.4.53/tests/test-webapps/test-cdi-common-webapp/pom.xml --- jetty9-9.4.51/tests/test-webapps/test-cdi-common-webapp/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-webapps/test-cdi-common-webapp/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ <parent> <groupId>org.eclipse.jetty.tests</groupId> <artifactId>test-webapps-parent</artifactId> - <version>9.4.51.v20230217</version> + <version>9.4.53.v20231009</version> </parent> <modelVersion>4.0.0</modelVersion> diff -Nru jetty9-9.4.51/tests/test-webapps/test-felix-webapp/pom.xml jetty9-9.4.53/tests/test-webapps/test-felix-webapp/pom.xml --- jetty9-9.4.51/tests/test-webapps/test-felix-webapp/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-webapps/test-felix-webapp/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ <parent> <groupId>org.eclipse.jetty.tests</groupId> <artifactId>test-webapps-parent</artifactId> - <version>9.4.51.v20230217</version> + <version>9.4.53.v20231009</version> </parent> <modelVersion>4.0.0</modelVersion> diff -Nru jetty9-9.4.51/tests/test-webapps/test-http2-webapp/pom.xml jetty9-9.4.53/tests/test-webapps/test-http2-webapp/pom.xml --- jetty9-9.4.51/tests/test-webapps/test-http2-webapp/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-webapps/test-http2-webapp/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ <parent> <groupId>org.eclipse.jetty.tests</groupId> <artifactId>test-webapps-parent</artifactId> - <version>9.4.51.v20230217</version> + <version>9.4.53.v20231009</version> </parent> <modelVersion>4.0.0</modelVersion> diff -Nru jetty9-9.4.51/tests/test-webapps/test-jaas-webapp/pom.xml jetty9-9.4.53/tests/test-webapps/test-jaas-webapp/pom.xml --- jetty9-9.4.51/tests/test-webapps/test-jaas-webapp/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-webapps/test-jaas-webapp/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -4,7 +4,7 @@ <parent> <groupId>org.eclipse.jetty.tests</groupId> <artifactId>test-webapps-parent</artifactId> - <version>9.4.51.v20230217</version> + <version>9.4.53.v20231009</version> </parent> <artifactId>test-jaas-webapp</artifactId> <name>Jetty Tests :: WebApp :: JAAS</name> diff -Nru jetty9-9.4.51/tests/test-webapps/test-jetty-webapp/pom.xml jetty9-9.4.53/tests/test-webapps/test-jetty-webapp/pom.xml --- jetty9-9.4.51/tests/test-webapps/test-jetty-webapp/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-webapps/test-jetty-webapp/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ <parent> <groupId>org.eclipse.jetty.tests</groupId> <artifactId>test-webapps-parent</artifactId> - <version>9.4.51.v20230217</version> + <version>9.4.53.v20231009</version> <relativePath>../pom.xml</relativePath> </parent> <modelVersion>4.0.0</modelVersion> diff -Nru jetty9-9.4.51/tests/test-webapps/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml jetty9-9.4.53/tests/test-webapps/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml --- jetty9-9.4.51/tests/test-webapps/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-webapps/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml 2023-10-09 12:27:40.000000000 +0000 @@ -122,18 +122,6 @@ </servlet-mapping> <servlet> - <servlet-name>CGI</servlet-name> - <servlet-class>org.eclipse.jetty.servlets.CGI</servlet-class> - <load-on-startup>1</load-on-startup> - <async-supported>true</async-supported> - </servlet> - - <servlet-mapping> - <servlet-name>CGI</servlet-name> - <url-pattern>/cgi-bin/*</url-pattern> - </servlet-mapping> - - <servlet> <servlet-name>Chat</servlet-name> <servlet-class>com.acme.ChatServlet</servlet-class> <load-on-startup>1</load-on-startup> diff -Nru jetty9-9.4.51/tests/test-webapps/test-jndi-webapp/pom.xml jetty9-9.4.53/tests/test-webapps/test-jndi-webapp/pom.xml --- jetty9-9.4.51/tests/test-webapps/test-jndi-webapp/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-webapps/test-jndi-webapp/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -4,7 +4,7 @@ <parent> <groupId>org.eclipse.jetty.tests</groupId> <artifactId>test-webapps-parent</artifactId> - <version>9.4.51.v20230217</version> + <version>9.4.53.v20231009</version> </parent> <artifactId>test-jndi-webapp</artifactId> <name>Jetty Tests :: WebApp :: JNDI</name> diff -Nru jetty9-9.4.51/tests/test-webapps/test-mock-resources/pom.xml jetty9-9.4.53/tests/test-webapps/test-mock-resources/pom.xml --- jetty9-9.4.51/tests/test-webapps/test-mock-resources/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-webapps/test-mock-resources/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ <parent> <groupId>org.eclipse.jetty.tests</groupId> <artifactId>test-webapps-parent</artifactId> - <version>9.4.51.v20230217</version> + <version>9.4.53.v20231009</version> </parent> <name>Jetty Tests :: WebApp :: Mock Resources</name> <artifactId>test-mock-resources</artifactId> diff -Nru jetty9-9.4.51/tests/test-webapps/test-owb-cdi-webapp/pom.xml jetty9-9.4.53/tests/test-webapps/test-owb-cdi-webapp/pom.xml --- jetty9-9.4.51/tests/test-webapps/test-owb-cdi-webapp/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-webapps/test-owb-cdi-webapp/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ <parent> <groupId>org.eclipse.jetty.tests</groupId> <artifactId>test-webapps-parent</artifactId> - <version>9.4.51.v20230217</version> + <version>9.4.53.v20231009</version> </parent> <modelVersion>4.0.0</modelVersion> diff -Nru jetty9-9.4.51/tests/test-webapps/test-owb-cdi-webapp/src/main/webapp/WEB-INF/jetty-web-owb.xml jetty9-9.4.53/tests/test-webapps/test-owb-cdi-webapp/src/main/webapp/WEB-INF/jetty-web-owb.xml --- jetty9-9.4.51/tests/test-webapps/test-owb-cdi-webapp/src/main/webapp/WEB-INF/jetty-web-owb.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-webapps/test-owb-cdi-webapp/src/main/webapp/WEB-INF/jetty-web-owb.xml 2023-10-09 12:27:40.000000000 +0000 @@ -1,4 +1,6 @@ -<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd"> +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://eclipse.dev/jetty/configure_9_3.dtd"> + <Configure id="wac" class="org.eclipse.jetty.webapp.WebAppContext"> <!-- Rename this file to jetty-web.xml if the cdi-spi module is not used--> <Get id="wal" name="classLoader"/> diff -Nru jetty9-9.4.51/tests/test-webapps/test-proxy-webapp/pom.xml jetty9-9.4.53/tests/test-webapps/test-proxy-webapp/pom.xml --- jetty9-9.4.51/tests/test-webapps/test-proxy-webapp/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-webapps/test-proxy-webapp/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ <parent> <groupId>org.eclipse.jetty.tests</groupId> <artifactId>test-webapps-parent</artifactId> - <version>9.4.51.v20230217</version> + <version>9.4.53.v20231009</version> <relativePath>../pom.xml</relativePath> </parent> <modelVersion>4.0.0</modelVersion> diff -Nru jetty9-9.4.51/tests/test-webapps/test-proxy-webapp/src/main/webapp/WEB-INF/web.xml jetty9-9.4.53/tests/test-webapps/test-proxy-webapp/src/main/webapp/WEB-INF/web.xml --- jetty9-9.4.51/tests/test-webapps/test-proxy-webapp/src/main/webapp/WEB-INF/web.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-webapps/test-proxy-webapp/src/main/webapp/WEB-INF/web.xml 2023-10-09 12:27:40.000000000 +0000 @@ -8,11 +8,11 @@ <servlet-class>org.eclipse.jetty.proxy.ProxyServlet$Transparent</servlet-class> <init-param> <param-name>proxyTo</param-name> - <param-value>https://www.eclipse.org/jetty/javadoc/jetty-11/index.html?overview-summary.html</param-value> + <param-value>https://eclipse.dev/jetty/javadoc/jetty-9/index.html?overview-summary.html</param-value> </init-param> <init-param> <param-name>hostHeader</param-name> - <param-value>www.eclipse.org</param-value> + <param-value>eclipse.dev</param-value> </init-param> <load-on-startup>1</load-on-startup> <async-supported>true</async-supported> diff -Nru jetty9-9.4.51/tests/test-webapps/test-proxy-webapp/src/test/java/org/eclipse/jetty/ProxyWebAppTest.java jetty9-9.4.53/tests/test-webapps/test-proxy-webapp/src/test/java/org/eclipse/jetty/ProxyWebAppTest.java --- jetty9-9.4.51/tests/test-webapps/test-proxy-webapp/src/test/java/org/eclipse/jetty/ProxyWebAppTest.java 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-webapps/test-proxy-webapp/src/test/java/org/eclipse/jetty/ProxyWebAppTest.java 2023-10-09 12:27:40.000000000 +0000 @@ -91,6 +91,8 @@ // this proxy configuration, not redirected to the actual website. assertThat("response status", response.getStatus(), is(HttpStatus.OK_200)); // Expecting a Javadoc / APIDoc response - look for something unique for APIdoc. - assertThat("response", response.getContentAsString(), containsString("All Classes")); + String body = response.getContentAsString(); + assertThat(body, containsString("All Classes")); + assertThat(body, containsString("<title>Overview (Jetty :: Project 9.")); } } diff -Nru jetty9-9.4.51/tests/test-webapps/test-servlet-spec/pom.xml jetty9-9.4.53/tests/test-webapps/test-servlet-spec/pom.xml --- jetty9-9.4.51/tests/test-webapps/test-servlet-spec/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-webapps/test-servlet-spec/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -4,7 +4,7 @@ <parent> <groupId>org.eclipse.jetty.tests</groupId> <artifactId>test-webapps-parent</artifactId> - <version>9.4.51.v20230217</version> + <version>9.4.53.v20231009</version> </parent> <artifactId>test-servlet-spec-parent</artifactId> <name>Jetty Tests :: Spec Test WebApp :: Parent</name> diff -Nru jetty9-9.4.51/tests/test-webapps/test-servlet-spec/test-container-initializer/pom.xml jetty9-9.4.53/tests/test-webapps/test-servlet-spec/test-container-initializer/pom.xml --- jetty9-9.4.51/tests/test-webapps/test-servlet-spec/test-container-initializer/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-webapps/test-servlet-spec/test-container-initializer/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ <parent> <groupId>org.eclipse.jetty.tests</groupId> <artifactId>test-servlet-spec-parent</artifactId> - <version>9.4.51.v20230217</version> + <version>9.4.53.v20231009</version> </parent> <artifactId>test-container-initializer</artifactId> <packaging>jar</packaging> diff -Nru jetty9-9.4.51/tests/test-webapps/test-servlet-spec/test-spec-webapp/pom.xml jetty9-9.4.53/tests/test-webapps/test-servlet-spec/test-spec-webapp/pom.xml --- jetty9-9.4.51/tests/test-webapps/test-servlet-spec/test-spec-webapp/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-webapps/test-servlet-spec/test-spec-webapp/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -4,7 +4,7 @@ <parent> <groupId>org.eclipse.jetty.tests</groupId> <artifactId>test-servlet-spec-parent</artifactId> - <version>9.4.51.v20230217</version> + <version>9.4.53.v20231009</version> </parent> <name>Jetty Tests :: Webapps :: Spec Webapp</name> <artifactId>test-spec-webapp</artifactId> diff -Nru jetty9-9.4.51/tests/test-webapps/test-servlet-spec/test-web-fragment/pom.xml jetty9-9.4.53/tests/test-webapps/test-servlet-spec/test-web-fragment/pom.xml --- jetty9-9.4.51/tests/test-webapps/test-servlet-spec/test-web-fragment/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-webapps/test-servlet-spec/test-web-fragment/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ <parent> <groupId>org.eclipse.jetty.tests</groupId> <artifactId>test-servlet-spec-parent</artifactId> - <version>9.4.51.v20230217</version> + <version>9.4.53.v20231009</version> </parent> <name>Jetty Tests :: WebApp :: Servlet Spec :: Fragment Jar</name> diff -Nru jetty9-9.4.51/tests/test-webapps/test-simple-session-webapp/pom.xml jetty9-9.4.53/tests/test-webapps/test-simple-session-webapp/pom.xml --- jetty9-9.4.51/tests/test-webapps/test-simple-session-webapp/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-webapps/test-simple-session-webapp/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -4,7 +4,7 @@ <parent> <groupId>org.eclipse.jetty.tests</groupId> <artifactId>test-webapps-parent</artifactId> - <version>9.4.51.v20230217</version> + <version>9.4.53.v20231009</version> </parent> <artifactId>test-simple-session-webapp</artifactId> diff -Nru jetty9-9.4.51/tests/test-webapps/test-simple-webapp/pom.xml jetty9-9.4.53/tests/test-webapps/test-simple-webapp/pom.xml --- jetty9-9.4.51/tests/test-webapps/test-simple-webapp/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-webapps/test-simple-webapp/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -4,7 +4,7 @@ <parent> <groupId>org.eclipse.jetty.tests</groupId> <artifactId>test-webapps-parent</artifactId> - <version>9.4.51.v20230217</version> + <version>9.4.53.v20231009</version> </parent> <artifactId>test-simple-webapp</artifactId> diff -Nru jetty9-9.4.51/tests/test-webapps/test-webapp-rfc2616/pom.xml jetty9-9.4.53/tests/test-webapps/test-webapp-rfc2616/pom.xml --- jetty9-9.4.51/tests/test-webapps/test-webapp-rfc2616/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-webapps/test-webapp-rfc2616/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -4,7 +4,7 @@ <parent> <groupId>org.eclipse.jetty.tests</groupId> <artifactId>test-webapps-parent</artifactId> - <version>9.4.51.v20230217</version> + <version>9.4.53.v20231009</version> </parent> <artifactId>test-webapp-rfc2616</artifactId> <name>Jetty Tests :: WebApp :: RFC2616</name> diff -Nru jetty9-9.4.51/tests/test-webapps/test-websocket-client-provided-webapp/pom.xml jetty9-9.4.53/tests/test-webapps/test-websocket-client-provided-webapp/pom.xml --- jetty9-9.4.51/tests/test-webapps/test-websocket-client-provided-webapp/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-webapps/test-websocket-client-provided-webapp/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ <parent> <groupId>org.eclipse.jetty.tests</groupId> <artifactId>test-webapps-parent</artifactId> - <version>9.4.51.v20230217</version> + <version>9.4.53.v20231009</version> </parent> <modelVersion>4.0.0</modelVersion> diff -Nru jetty9-9.4.51/tests/test-webapps/test-websocket-client-webapp/pom.xml jetty9-9.4.53/tests/test-webapps/test-websocket-client-webapp/pom.xml --- jetty9-9.4.51/tests/test-webapps/test-websocket-client-webapp/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-webapps/test-websocket-client-webapp/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ <parent> <groupId>org.eclipse.jetty.tests</groupId> <artifactId>test-webapps-parent</artifactId> - <version>9.4.51.v20230217</version> + <version>9.4.53.v20231009</version> </parent> <modelVersion>4.0.0</modelVersion> diff -Nru jetty9-9.4.51/tests/test-webapps/test-weld-cdi-webapp/pom.xml jetty9-9.4.53/tests/test-webapps/test-weld-cdi-webapp/pom.xml --- jetty9-9.4.51/tests/test-webapps/test-weld-cdi-webapp/pom.xml 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/tests/test-webapps/test-weld-cdi-webapp/pom.xml 2023-10-09 12:27:40.000000000 +0000 @@ -3,7 +3,7 @@ <parent> <groupId>org.eclipse.jetty.tests</groupId> <artifactId>test-webapps-parent</artifactId> - <version>9.4.51.v20230217</version> + <version>9.4.53.v20231009</version> </parent> <modelVersion>4.0.0</modelVersion> diff -Nru jetty9-9.4.51/VERSION.txt jetty9-9.4.53/VERSION.txt --- jetty9-9.4.51/VERSION.txt 2023-02-17 08:18:56.000000000 +0000 +++ jetty9-9.4.53/VERSION.txt 2023-10-09 12:27:40.000000000 +0000 @@ -1,7 +1,23 @@ +jetty-9.4.53.v20231009 - 09 October 2023 + + 10546 backport jetty-http Huffman encoders/decoders from Jetty 10.0.x + + 10573 backport hpack improvements from Jetty 10.0.x + + 10679 backport HTTP/2 rate control from Jetty 10.0.x + +jetty-9.4.52.v20230823 - 23 August 2023 + + 9476 onCompleteFailure called multiple times + + 9660 OpenId Revoked authentication allows one request (CVE-2023-41900) + + 9887 Deprecate CGI Servlet (CVE-2023-36479) + + 10066 Allow `SAXParserFactory` or `SAXParser` to be configured in Jetty's + `XmlParser` class + + 10168 NPE in websocket extension startup + + 10352 Jetty accepts "+" prefixed value in Content-Length (CVE-2023-40167) + + 10337 SizeLimitHandler does not enforce 0 responseLimit + jetty-9.4.51.v20230217 - 17 February 2023 + 9059 IteratingCallback not serializing close() and failed() - + 9181 Jetty 9 java.lang.NullPointerException - SessionHandler.checkRequestedSessionId(SessionHandler.java:1733) + + 9181 NPE in SessionHandler.checkRequestedSessionId() + + 9345 Backport Fix for CVE-2023-26048 + + 9352 Backport Fix for CVE-2023-26049 jetty-9.4.50.v20221201 - 01 December 2022 + 8774 Added SizeLimitHandler